有监督的多类标注(SML)的原理及matlab实现

注:本文基于北邮Web搜索课程大作业。作业题目为:任选某类图像为训练样本,编程实现其基于SML算法的类模型。
有监督的多类标注(Supervised Multiclass Labeling,SML)是一种结合有监督的二类标注和无监督的多类标注优点的图像文本标注算法。

一、基本原理

其总体方案为:将图像简单地表示为各局部特征向量的“口袋”式集合,以此估计每幅图像的混合概率密度(GMM)。将具有相同语义标注的图像的混合概率密度汇集在一起对该语义类的概率密度进行估计。
有监督的多类标注(SML)的原理及matlab实现_第1张图片
有监督的多类标注(SML)的原理及matlab实现_第2张图片
其中滑动窗口那一步,书上和原论文上都是每次滑动2个像素的窗口,但由于实际操作时会产生非常多个区域,导致在计算时很慢,因此ppt和实际编程改为了相邻的窗口叠加为2,即每次滑动6个像素。
还有做完DCT变换后可以只取30(3x10)维,若不降维则结果可能不可靠,因为越到后面的系数值越小。而且因为DCT变换后的能量集中在矩阵的上三角,即能量从高到低依此为(1,1),(2,1),(1,2),(3,1),(2,2),(1,3),(4,1),(3,2),(2,3),(1,4)…如果严格取能量最高的前30维,可以对YBR三通道交错按如上顺序各取10维即可。

二、matlab实现

整个工程包括实现单个图像的YBR空间转换,分块抽取DCT系数,并对系数进行降维 ;将每一幅图像聚类成8个混合高斯分布;读取文件夹中所有的图像,实现将多个高斯分布聚类成64个混合高斯分布。
篇幅有限只放出预处理的部分和最后整合的部分。
完整的程序详见我的GitHub:https://github.com/vivianLL/SML
getDCT.m

function [feature] = getDCT(X)
%提取图像特征即DCT系数
X=double(rgb2ycbcr(X));%将RGB颜色空间转换为YBR颜色空间
[width,length,height]=size(X); %获取图像矩阵的大小 128x192x3

% %按滑块每次移动2个像素值计算
% N_width=(width-8)/2+1; %61
% N_length=(length-8)/2+1; %93
% N=N_width*N_length; %61x93=5673
% patch_DCT=zeros(8,8,N,3);
% for k=1:height
%     n=1;
%     for i=1:2:width-7
%         for j=1:2:length-7         
%             patch_DCT(1:8,1:8,n,k)=dct2(X(i:i+7,j:j+7,k));
%             %patch_DCT(1:8,1:8,n,k)=blockproc(X(i:i+7,j:j+7,k),[8,8]);
%             n=n+1;           
%         end
%     end
% end

%按滑块每次移动6个像素值计算
N_width=(width-8)/6+1; %21
N_length=floor((length-8)/6)+1; %31,floor向下取整
N=N_width*N_length; %21x31=651
patch_DCT=zeros(8,8,N,3);
for k=1:height
    n=1;
    for i=1:6:width-7
        for j=1:6:length-7         
            patch_DCT(1:8,1:8,n,k)=dct2(X(i:i+7,j:j+7,k));         
            n=n+1;           
        end
    end
end

%将数据维度压缩到30维,并将三通道系数交错排列
feature=zeros(N,30);
for i=1:N_width*N_length  %5673 
    n=1;
    for j=1:4 
        for t=1:4-j+1       %取三通道DCT矩阵上三角的系数
            feature(i,n)=patch_DCT(j,t,i,1); %Y通道
            feature(i,n+1)=patch_DCT(j,t,i,2); %Cb通道
            feature(i,n+2)=patch_DCT(j,t,i,3); %Cr通道
            n=n+3;
        end
    end
end
end

main.m

clear;
clc;
warning('off'); %不在控制台显示警告
imgPath='Corel5k\1000\'; %图像库路径
imgDir=dir([imgPath '*.jpeg']);%遍历所有jpeg格式文件
for i = 80:length(imgDir)
    img = imread([imgPath,imgDir(i).name]);%读取每张图片
    %imgtest=imread([imgPath,num2str(i+999),'.jpeg']);
%     img=im2double(img);  %将uint型图像像素转成double型便于计算
    fprintf('%s %d %s %s\n','正在处理第',i,'张图片:',strcat(imgPath,imgDir(i).name));% 显示正在处理的图像名 
    feature = getDCT(img);%提取每幅图像的30个DCT系数值
    fprintf('已提取DCT\n');
    [GaussDistr,model]=gmmNew(feature,8);%从每幅图像中学到一个高斯混合模型
    fprintf('已学到GMM\n');
    %将每幅图像聚类得到的参数存储在矩阵中
    Miu((8*i-7):(8*i),:) = model.Miu(:,:);
    Sigma(:,:,(8*i-7):(8*i)) = model.Sigma(:,:,:);
    Pi(1,(8*i-7):(8*i)) = model.Pi(:,:);
end

%将得到所有图像的混合高斯分布聚类成64个混合高斯分布
model=[];
model.pi = Pi;
model.Miu = Miu;
model.Sigma = Sigma;
model64_30 = ClusterGMM(model,64);
save model64.mat model64_30;

相关知识点:
1. MATLAB中读入图像的数据类型是uint8,而在矩阵中使用的数据类型是double
因此I2=im2double(I1) :把图像数组I1转换成double精度类型;如果不转换,在对uint8进行加减时会产生溢出。
2. reshape把指定的矩阵改变形状,但是元素个数不变,例如,行向量:

a = [1 2 3 4 5 6]

执行下面语句把它变成3行2列:

b = reshape(a,3,2)

执行结果:

b =
1 4
2 5
3 6

3。
inv:Y=inv(X)返回方阵X的逆矩阵,如果X病态或者高度奇异,则会显示警告信息。实际上,很少需要真的把矩阵的逆求出来,常见的使用失误主要出现在求解线性方程组AX=b。一种求解方法为x=inv(A)*b,但如要达到更快,更稳定,就得用X=A\b。这个算法使用高斯消去法,因此不产生逆矩阵。

“\”:反斜线符号,矩阵左除。如果A是方阵,A\B近似等于inv(A)B,只是他们的算法不一样。如果A是n*n的方阵,B是n*1的列向量,或n?的矩阵,那么X=A\B是AX=B的解。如果A很病态或者很奇异,很会显示警告信息。A\EYE(SIZE(A))计算A的逆,参见mldivide可得到更多信息。如果A是m*n的矩阵,m!=n,B是m*1或m*?的列向量,那么X=A\B就是线性方程组AX=B(超定或者欠定)的最小二乘解。A的有效秩(effective rank)k有选主元的QR分解决定。Asolution X is computed that has at most k nonzero componentspercolumn。如果K,结果通常和pinv(A)*B不一样,后者是最小范数解。A\EYE(SIZE(A))用来求解A的广义逆。

pinv:其实就是调用另外一个built-in函数SVD进行奇异值分解,再截断奇异值进行求解而已。所以pinv实际上就是截断奇异值求逆。

4。matlab中的DCT变换实现:http://blog.csdn.net/ahafg/article/details/48808443

程序运行常见问题:
在运行GMM模型时,mvnpdf函数报错:SIGMA must be a square, symmetric, positive definite matrix.
原因:协方差矩阵为奇异矩阵,对角线元素含大量0值。求逆时不可用pinv求伪逆,可以尝试每次迭代求协方差时在对角线元素上加一个很小的值对其正则化,即岭回归。

总结

SML的类模型其实就是预处理加上两次GMM。EM算法实现GMM参见我的上上一篇博客《使用EM算法估计GMM参数的原理及matlab实现》。但虽然这个代码原理清晰注释详细,但实际运行时发现仍然会有很多错误,比如上面提到的mvnpdf中协方差矩阵的问题,而且个人能力有限无法解决。因此在最后并没有使用上述列出的所有代码,而是采用了另一个版本的GMM算法,原理是一样的,具体实现上不太一样。其中GMM算法好像重写了几个函数,比如converfixgauss、cmvnpdf.m、covfixer2.m等等,没有看太懂,但是能运行。

参考文献:
《Web搜索》郭军
Supervised Sequence Labelling with Recurrent

你可能感兴趣的:(matlab)