答案 0 :(得分:4)
主要问题是找到 blob 的数量。为此,我宁愿使用k-Means聚类。解释k-means聚类的作用,它是如何工作的等等太长了,所以我直接跳到这一点:k-Means算法组 n 点进入 k 组(集群)。结果是一个分区空间:一个给定的点不能同时在两个簇中,一个簇由它的质心(平均点)标识。
因此,让我们导入图片并查找黑点的所有x
和y
坐标:这些确实是我们想要聚类的点。
I=imread('image.jpg');
BW = im2bw(I, graythresh(I));
[x,y]=find(BW==0);
现在是时候触发k-Means算法来分组这些点了。由于我们不知道 k ,即blob的数量,我们可以执行某种强力方法。我们为 k 选择一些候选值,并将k-Means聚类应用于所有这些值。稍后,我们通过弯头方法选择最佳的 k :我们绘制所谓的内部群集平方和(即点和它们各自的质心之间的所有距离的总和)和选择 k 值,这样添加另一个集群就不会给出更好的数据建模。
for k=1:10
[idx{k},C{k},sumd{k}] = kmeans([x y],k,'Replicates',20);
end
sumd=cellfun(@(x) sum(x(:)),sumd);
上面的代码在范围[1,10]中执行 k 的k-Means。由于在标准k-Means中,在我们的数据集中的点(即黑点)中随机选择第一个质心,我们对 k 的每个值重复k-Means 20次,然后算法将自动在20次重复中返回最佳结果。这样的结果是idx
,它是 n 点的向量(其中 n 是黑点的数量),它在第j个位置包含质心ID对于第j个黑点。 C
是质心坐标,sumd
是平方和。
然后我们绘制平方和与 k 候选者的对比:
figure(6);
plot(1:10,sumd,'*-');
根据上面解释的弯头方法,6是最佳簇数:实际上在6之后,图形趋于相当水平。
所以从上面的数组中,我们选择第6个元素:
best_k=6;
best_idx=idx{best_k};
best_C=C{best_k};
并且返回的群集是
gscatter(x,y,best_idx); hold on;
plot(best_C(:,1),best_C(:,2),'xk','LineWidth',2);
注意:图像被旋转,因为plot()
处理矩阵(坐标)与imshow()
的处理方式不同。黑色交叉点也是每个群集的质心。
最后通过计算每个聚类的点数,我们收集聚类本身的区域(即blob):
for m=1:best_k
Area(m)=sum(best_idx==m);
end
Area =
1619 46 141 104 584 765
显然,Area
中的第i个项目是第i个群集的区域,如图例所示。
进一步阅读
在此Wikipedia link中,您可以找到有关确定k-Means算法中群集数量("最佳 k ")的更多详细信息。在这些方法中,您也可以找到弯头方法。正如@rayryeng在下面的评论中正确指出的那样,肘部绘图只是一种启发式:在某些数据集中,你无法清楚地发现"膝盖"在曲线中......我们虽然幸运!
最后但并非最不重要的是,如果您想了解更多有关k-Means算法的信息,请查看以下评论中链接的@ rayryeng的答案:它是一个非常详细的答案,不仅描述了算法本身,但也讨论了我在代码中设置的重复,随机选择的初始质心以及我为了避免无休止的答案而跳过的所有这些方面。