K-means能用于基于像素值的图像分割吗?

9
我正在尝试基于像素值将灰度图像分离:假设将像素从0到60放在一个箱子里,60-120放在另一个箱子里,120-180...以此类推直到255。 在这种情况下,范围大致等间距。 然而,使用K-means聚类是否可以获得更真实的像素值范围? 尝试将相似的像素放在一起,不浪费低浓度像素存在的箱子。
编辑(包括获得的结果): enter image description here enter image description here K-means聚类,聚类数= 5

听起来非常像直方图均衡化... http://fourier.eng.hmc.edu/e161/lectures/contrast_transform/node3.html - Joe Kington
正如@Throwback1986所说,它们并不是非常相似。我不是试图使直方图均衡化,而是要最有效地拆分直方图。 - AruniRC
2个回答

11
当然,K-Means可以用于颜色量化。对此非常方便。
让我们看一个Mathematica的例子:
我们从一张灰度图像(150x150)开始:

enter image description here

让我们来看看在8位表示图像时有多少个灰度级:

ac = ImageData[ImageTake[i, All, All], "Byte"];
First@Dimensions@Tally@Flatten@ac
-> 234

好的。让我们降低这234个级别。我们的第一次尝试将是让算法独立决定默认配置下有多少个聚类:

ic = ClusteringComponents[Image@ac];
First@Dimensions@Tally@Flatten@ic 
-> 3

它选择了3个聚类,相应的图像为:

enter image description here

现在,如果这样可以,或者你需要更多的聚类,那就由你决定。
假设你决定需要更精细的颜色分离。让我们请求6个聚类而不是3个:
ic2 = ClusteringComponents[Image@ac, 6];
Image@ic2 // ImageAdjust  

结果:

enter image description here

以下是每个箱子中使用的像素范围:

Table[{Min@#, Max@#} &@(Take[orig, {#[[1]]}, {#[[2]]}] & /@ 
    Position[clus, n]), {n, 1, 6}]
-> {{0, 11}, {12, 30}, {31, 52}, {53, 85}, {86, 134}, {135, 241}}

每个箱子中的像素数量:

Table[Count[Flatten@clus, i], {i, 6}]
-> {8906, 4400, 4261, 2850, 1363, 720}

所以,答案是肯定的,并且很简单。

编辑

也许这可以帮助你理解在新示例中你做错了什么。

如果我对你的彩色图像进行聚类,并使用聚类编号来表示亮度,我得到:

enter image description here

由于聚类没有按照亮度升序编号,所以出现了这种情况。
但是,如果我计算每个聚类的平均亮度值,并使用它来代表聚类值,那么我会得到:

enter image description here

在我之前的例子中,这并不是必需的,但那只是运气好(即聚类按升序亮度顺序找到)。

谢谢您提供的详细解释,我已经掌握了基本概念。不过我会使用OpenCV和VC++来完成它 - 您有任何想法这会有多直接吗? - AruniRC
@Aruni,我真的不知道,抱歉。请注意,我在一维颜色空间中进行了聚类,而不是在图像空间中进行。这意味着它对于检测对象并不有用,但可以大大压缩和简化图像。如果您需要进行空间聚类,也许均值漂移是一个不错的选择。 - Dr. belisarius
哈哈,我刚在OpenCV中运行了它。在查阅文档和雅虎讨论组后,它可以正常工作。无论如何,还是谢谢你。 - AruniRC
@Aruni 我很确定你走在正确的道路上,只有一个小误解阻碍了你完成任务。你图片的问题是你正在使用类似“集群编号”的东西来表示灰度,而你应该使用类似于聚类中像素均值的东西。等等...看起来你还忘记在聚类之前转换为灰度图像! 希望对你有帮助! - Dr. belisarius
它有所帮助。可惜我不会Mathematica——编程语言的分歧导致了实现的困惑。顺便说一句,我尝试过使用图像金字塔进行均值漂移滤波,但边缘变得模糊了:这正是我试图避免使用k-means和其他东西的原因。 - AruniRC
显示剩余3条评论

2
k-means可以应用于您的问题。如果是我,我会首先尝试从决策树中借鉴的基本方法(虽然“更简单”取决于您的精确聚类算法!)
假设存在一个bin,将像素强度塞入该bin。当bin足够“充实”时,计算bin(或节点)的均值和标准差。如果标准差大于某个阈值,则分裂节点。继续此过程,直到所有强度都完成,您将获得更有效的直方图。
当然,这种方法可以通过其他细节进行改进: 1. 您可以考虑使用峭度作为分裂标准。 2. 偏度可用于确定拆分发生的位置。 3. 您可以跨越整个决策树领域,并借用Jini指数来指导分裂(一些分裂技术依赖于更“奇特”的统计数据,如t-test)。 4. 最后,您可以执行最终的合并传递以折叠任何稀疏的节点。
当然,如果您已应用了上述所有“改进”,则基本上实现了k-means聚类算法的一种变体。
注:我不同意上面的评论-您所描述的问题与直方图均衡化似乎没有密切相关。

真正的项目是从非常模糊的街景中提取文本,因此这不是直方图均衡化——在OpenCV中有一个一行函数调用(我不会重新发明轮子)。 - AruniRC

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接