使用高斯混合模型对图像进行聚类

时间:2015-03-08 06:46:55

标签: matlab machine-learning classification cluster-analysis mixture-model

我想使用GMM(高斯混合模型用于聚类二进制图像,还想在二进制图像本身上绘制聚类质心。

我用这个作为参考:   http://in.mathworks.com/help/stats/gaussian-mixture-models.html

这是我的初始代码

 I=im2double(imread('sil10001.pbm'));
  K = I(:);
  mu=mean(K);
  sigma=std(K);
  P=normpdf(K, mu, sigma);
   Z = norminv(P,mu,sigma);
  X = mvnrnd(mu,sigma,1110);
  X=reshape(X,111,10);


 scatter(X(:,1),X(:,2),10,'ko');

options = statset('Display','final');
gm = fitgmdist(X,2,'Options',options);



idx = cluster(gm,X);
cluster1 = (idx == 1);
cluster2 = (idx == 2);


 scatter(X(cluster1,1),X(cluster1,2),10,'r+');
 hold on

  scatter(X(cluster2,1),X(cluster2,2),10,'bo');
  hold off
  legend('Cluster 1','Cluster 2','Location','NW')


  P = posterior(gm,X);

 scatter(X(cluster1,1),X(cluster1,2),10,P(cluster1,1),'+')
 hold on
 scatter(X(cluster2,1),X(cluster2,2),10,P(cluster2,1),'o')
 hold off
 legend('Cluster 1','Cluster 2','Location','NW')
 clrmap = jet(80); colormap(clrmap(9:72,:))
 ylabel(colorbar,'Component 1 Posterior Probability')

但问题是我无法在主二进制图像中绘制从GMM接收的聚类质心。我该怎么做? enter image description here

**现在假设我有一个序列中的10个这样的图像我想将它们的平均位置的信息存储在两个单元格数组中然后我该怎么做。这是我的代码我的新问题**

    images=load('gait2go.mat');%load the matrix file
    for i=1:10

   I{i}=images.result{i};
  I{i}=im2double(I{i});

   %determine 'white' pixels, size of image can be [M N], [M N 3] or [M N 4]
  Idims=size(I{i});
  whites=true(Idims(1),Idims(2));

    df=I{i};
      %we add up the various color channels
 for colori=1:size(df,3)
  whites=whites & df(:,:,colori)>0.5;
 end

%choose indices of 'white' pixels as coordinates of data
[datax datay]=find(whites);

%cluster data into 10 clumps
  K = 10;               % number of mixtures/clusters
  cInd = kmeans([datax datay], K, 'EmptyAction','singleton',...
   'maxiter',1000,'start','cluster');

%get clusterwise means
 meanx=zeros(K,1);
 meany=zeros(K,1);  
  for i=1:K
   meanx(i)=mean(datax(cInd==i));
   meany(i)=mean(datay(cInd==i));

 end

 xc{i}=meanx(i);%cell array contaning the position of the mean for the 10    
 images
  xb{i}=meany(i);

figure;
gscatter(datay,-datax,cInd); %funky coordinates for plotting according to      
 image
 axis equal;
  hold on;
  scatter(meany,-meanx,20,'+'); %same funky coordinates


 end

我能够分割10个图像但没有存储在单元格数组xc和xb中的themean值。它们只存储[]代替均值

3 个答案:

答案 0 :(得分:10)

我决定发布你问题的答案(你的问题是由最大可能猜测确定的:P),但我写了一篇大量的介绍。请仔细阅读,因为我认为您很难理解您想要使用的方法,并且您很难理解为什么其他人可以帮助您解决问题的常用方法。您的问题存在一些问题,包括代码相关问题和概念问题。让我们从后者开始。

问题的问题

你说你想用高斯混合建模来聚类你的图像。虽然我通常不熟悉群集,但在查看了referencethe wonderful SO answer you cited elsewhere(以及来自@rayryeng的快速101)后,我认为你完全走错了轨道。

高斯混合建模,顾名思义,使用高斯(即正态)分布的混合对您的数据集进行建模。这种方法流行的原因在于,当您对各种数量进行测量时,在许多情况下,您会发现您的数据大多分布为正态分布(这实际上是它被称为<的原因< EM>正常)。这背后的原因是central limit theorem,这意味着在许多情况下,合理独立的随机变量的总和趋于正常。

现在,集群只是意味着根据某些标准将您的数据集分成不相交的较小的数据集。主要标准通常是(某种)距离,因此您希望找到&#34;关闭数据块&#34;在较大的数据集中。您通常需要在执行GMM之前对数据进行聚类,因为它已经很难找到基础数据的高斯,而不必猜测聚类。如果你让它们处理你的原始数据,我对所涉及的程序不太熟悉GMM算法的工作情况(但我希望许多实现始终以聚类步骤开始)。

接近你的问题:我猜你想做某种图像识别。看图片,你想得到更强烈相关的肿块。这是集群。如果你看一个动物园的照片,你会看到一头大象和一条蛇。两者都有其独特的形状,并且它们彼此很好地分开。如果你对你的图像进行聚类(并且蛇没有骑大象,neither did it eat it),你会发现两个肿块:一个大象形状的肿块和一个蛇形状的肿块。现在,在这些数据集上使用GMM是没有意义的:大象,尤其是蛇,形状不像多元高斯分布。但是,如果您只是想知道图片中不同动物的位置,那么您首先不需要这样做。

仍然坚持这个例子,你应该确保将数据集中到适当数量的子集中。如果你试图将你的动物园图片聚为3个星团,你可能会得到第二条虚假的蛇:大象的鼻子。随着群集数量的增加,您的分区可能越来越不合理。

您的方法

您的代码并没有给您任何合理的信息,而且有一个很好的理由:它从一开始就没有意义。看看开头:

I=im2double(imread('sil10001.pbm'));
K = I(:);
mu=mean(K);
sigma=std(K);
X = mvnrnd(mu,sigma,1110);
X=reshape(X,111,10);

您读取二进制图像,将其转换为double,然后将其拉伸为矢量并计算该矢量的平均值和偏差。您基本上将您的服装图像涂抹成2个值:平均强度和偏差。然后,您使用这些参数生成111*10标准法线点,并尝试在前两组111上进行GMM。这两个参数都是相同的。所以你可能会得到两个重叠的高斯,围绕同一个均值,偏差相同。

我认为您在网上找到的例子让您感到困惑。当您执行GMM时,您已经拥有了数据,因此不应涉及伪正常数字。但是当人们发布示例时,他们也会尝试提供可重复的输入(好吧,其中一些做了, nudge nudge wink wink )。一个简单的方法是生成简单高斯的并集,然后可以将其输入GMM。

所以,我的观点是,你不必生成随机数,但必须使用图像数据本身作为程序的输入。 您可能只想对图像进行聚类,而不是实际使用GMM在群集上绘制土豆,因为您希望将图像中的身体部位聚类为人类。大多数身体部位形状像多变量高斯(男性和女性有几个明显的例外)。

我认为你应该做什么

如果您真的想要对图像进行聚类,就像您添加到问题中的图形一样,那么您应该使用像k-means这样的方法。但话说回来,你已经有一个程序可以做到这一点,不是吗?所以我真的不认为我可以回答这个问题&#34;我如何用GMM对我的图像进行聚类?&#34;。相反,这里是#34的答案;我如何对我的图像进行聚类?&#34;用k-means,但至少会有一段代码。

%set infile to what your image file will be
infile='sil10001.pbm';

%read file
I=im2double(imread(infile));

%determine 'white' pixels, size of image can be [M N], [M N 3] or [M N 4]
Idims=size(I);
whites=true(Idims(1),Idims(2));

%we add up the various color channels
for colori=1:Idims(3)
    whites=whites & I(:,:,colori)>0.5;
end

%choose indices of 'white' pixels as coordinates of data
[datax datay]=find(whites);

%cluster data into 10 clumps
K = 10;               % number of mixtures/clusters
cInd = kmeans([datax datay], K, 'EmptyAction','singleton',...
    'maxiter',1000,'start','cluster');

%get clusterwise means
meanx=zeros(K,1);
meany=zeros(K,1);
for i=1:K
    meanx(i)=mean(datax(cInd==i));
    meany(i)=mean(datay(cInd==i));
end

figure;
gscatter(datay,-datax,cInd); %funky coordinates for plotting according to image
axis equal;
hold on;
scatter(meany,-meanx,20,'ko'); %same funky coordinates

这就是它的作用。它首先像你的一样读取你的图像。然后它试图确定&#34;白色&#34;通过检查每个颜色通道(其中可以是1,3或4)比0.5更亮的像素。然后,指向聚类的输入数据将是xy&#34;坐标&#34;你的白色像素(即指数)。

接下来,它通过kmeans进行群集。这部分代码基于the already cited answer of Amro。我不得不设置一个大的最大迭代次数,因为在图片中没有10个清晰的簇的意义上问题是不适定的。然后,我们为每个群集计算mean,并使用gscatter绘制群集,并使用scatter绘制平均值。请注意,为了使图片在scatter图中朝向正确的方向,您必须在输入坐标周围移动。或者,您可以在开头相应地定义dataxdatay

这是我的输出,使用您在问题中提供的已经处理的数字运行: output

答案 1 :(得分:0)

我相信你必须在情节中犯了一个天真的错误,这就是为什么你只看到一条直线:你只是在绘制x值。

在我看来,scatter命令中的第二个参数应该是X(cluster1,2)X(cluster2,2),具体取决于代码中使用的scatter命令。

答案 2 :(得分:0)

代码可以变得更简单:

%read file

I=im2double(imread('sil10340.pbm'));
%choose indices of 'white' pixels as coordinates of data
[datax datay]=find(I);
%cluster data into 10 clumps
 K = 10;               % number of mixtures/clusters
[cInd, c] = kmeans([datax datay], K, 'EmptyAction','singleton',...
'maxiter',1000,'start','cluster');
 figure;
gscatter(datay,-datax,cInd); %funky coordinates for plotting according to    
image
axis equal;
hold on;
 scatter(c(:,2),-c(:,1),20,'ko'); %same funky coordinates

我认为没有必要进行循环,因为c本身返回一个包含平均值位置的10x2双数组

enter image description here