我想使用高斯混合模型(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获得的聚类中心点。我该怎么做?
**现在假设我有一系列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中。它们只存储了[]而不是平均值的位置信息
回答:
我决定回答你的问题(你的问题是通过最大似然估计确定的:P),但我写了一个详细的介绍。请仔细阅读,因为我认为你对你想使用的方法理解有困难,而且你也难以理解为什么别人无法用你通常的提问方式帮助你。你的问题有几个问题,包括代码相关和概念上的问题。让我们从后者开始。
问题的症结
你说你想用高斯混合模型对图像进行聚类。虽然我对聚类不太熟悉,但在查看了你的参考资料和你在他处引用的精彩的SO回答(以及来自@rayryeng的快速入门)后,我认为你完全走错了路。
高斯混合模型,正如其名,是用高斯(即正态)分布的混合来建模你的数据集。这种方法之所以流行,是因为当你对各种量进行测量时,在许多情况下,你会发现你的数据大多像正态分布(这实际上是它被称为正态的原因)。其背后的原因是中心极限定理,它暗示在许多情况下,合理独立的随机变量的总和往往是正态的。
现在,聚类另一方面,仅仅意味着根据某些标准将你的数据集分成不相交的较小组。主要标准通常是(某种形式的)距离,所以你想在你的大数据集中找到“接近的数据块”。你通常需要在执行GMM之前对数据进行聚类,因为在不需要猜测聚类的情况下,找到数据背后的高斯分布已经足够困难了。我对所涉及的程序不够熟悉,无法判断如果只是让GMM算法在你的原始数据上工作,它们能工作得有多好(但我预计许多实现都会从聚类步骤开始)。
更接近你的问题:我猜你想做某种图像识别。看那张图片,你想得到更强相关的块。这就是聚类。如果你看一张动物园的图片,你会看到,比如说,一头大象和一条蛇。它们都有各自独特的形状,并且彼此很好地分开。如果你对图像进行聚类(并且蛇没有骑在大象上,也没有吃掉它),你会发现两个块:一个是大象形状的块,一个是蛇形状的块。现在,在这些数据集上使用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);
你读取你的二值图像,将其转换为双精度,然后将其拉伸成一个向量并计算该向量的均值和标准差。你基本上是将整个图像抹成了两个值:一个平均强度和一个偏差。然后你用这些参数生成111*10
个标准正态点,并尝试对前两组111个点进行GMM。这两组都是独立的正态分布,具有相同的参数。所以你可能会得到两个重叠的高斯分布,围绕着相同的均值和相同的偏差。
我认为你在线找到的例子让你感到困惑。当你进行GMM时,你已经有了你的数据,所以不应该涉及伪正态数。但当人们发布示例时,他们也试图提供可重现的输入(嗯,其中一些人会这样做,暗示暗示)。一种简单的方法是生成简单高斯分布的联合,然后将其输入到GMM中。
所以,我的观点是,你不需要生成随机数,而是应该使用图像数据本身作为你的程序的输入。而且你可能只是想聚类你的图像,而不是实际使用GMM在你的聚类上画土豆,因为你想在关于人的图像中聚类身体部位。大多数身体部位不像多元高斯分布(对于男性和女性有一些明显的例外)。
我认为你应该做的事情
如果你真的想像你在问题中添加的图中那样聚类你的图像,那么你应该使用像k-means这样的方法。但话说回来,你已经有一个可以做到这一点的程序,不是吗?所以我真的不认为我能回答“如何用GMM聚类我的图像?”的问题。相反,这里是回答“如何聚类我的图像?”的问题,使用k-means,但至少这里会有一段代码。
%set infile to what your image file will beinfile='sil10001.pbm';%read fileI=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 channelsfor 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 clumpsK = 10; % number of mixtures/clusterscInd = kmeans([datax datay], K, 'EmptyAction','singleton',... 'maxiter',1000,'start','cluster');%get clusterwise meansmeanx=zeros(K,1);meany=zeros(K,1);for i=1:K meanx(i)=mean(datax(cInd==i)); meany(i)=mean(datay(cInd==i));endfigure;gscatter(datay,-datax,cInd); %funky coordinates for plotting according to imageaxis equal;hold on;scatter(meany,-meanx,20,'ko'); %same funky coordinates
这是它所做的。它首先像你的一样读取你的图像为双精度。然后它尝试通过检查每个颜色通道(可以是1、3或4)的亮度是否大于0.5来确定“白色”像素。然后你输入到聚类中的数据点将是你的白色像素的x
和y
“坐标”(即索引)。
接下来它通过kmeans
进行聚类。这部分代码大致基于已经引用的Amro的回答。我不得不设置一个大的最大迭代次数,因为这个问题在图片中没有10个明显的聚类的情况下是病态的。然后我们计算每个聚类的mean
,并使用gscatter
绘制聚类,使用scatter
绘制均值。请注意,为了在scatter
图中使图片朝向正确的方向,你必须调整输入坐标。或者你可以在开始时相应地定义datax
和datay
。