如何:将图像中的像素打包到代表点坐标 (x,y)

信息处理 点云 形态操作 数字化
2022-01-02 00:27:25

让我们有一个如下图左侧所示的图像(灰度甚至二进制),目标是生成一个点列表,即每个包的坐标(x,y)图像中的暗像素。
有哪些合适的图像处理工具可以做到这一点,它们在哪里可用?

像素包到点坐标


更新:
1) 在这里您可以找到有关该问题的更多详细信息。(注意包装大小的变化)

细节

我可能会建议检测包以计算每个包的凸包边界,然后找到具有代表性的质心{详情请参阅此内容}

像素包到凸包到中心点


2)
这是应用距离变换产生的结果(由“Libor”建议)。注意我在图中的注释。该方法不起作用,因为它有希望!

在此处输入图像描述

3)
侵蚀消除了小包装!

from __future__ import division
from scipy import zeros, ndimage as dsp
from pylab import subplot,plot,matshow,show

img = zeros((30,30))
img[10:14,10:14] = 1
img[16:17,16:17] = 1
img[19:23,19] = 1
img[19,19:23] = 1

subplot(221)
matshow(img,0)

subplot(222)
y = dsp.binary_erosion(img,[[1,1],[1,1]])
matshow(y,0)

subplot(223)
y = dsp.binary_erosion(img,[[0,1,0],[1,1,1],[0,1,0]])
matshow(y,0)

subplot(224)
y = dsp.binary_erosion(img,[[1,1,1],[1,1,1],[1,1,1]])
matshow(y,0)

show()

在此处输入图像描述

4)
好吧,这里是一个Python(即爱的语言:))实现标记想法(也是由下面的“Jean-Yves”提出的):

subplot(221)
l,n = dsp.label(img)
sl = dsp.find_objects(l)
for s in sl:
    x = (s[1].start+s[1].stop-1)/2
    y = (s[0].start+s[0].stop-1)/2
    plot(x,y,'wo')

结果:

在此处输入图像描述

请注意,尽管由于 Scipy 的性能,它在Pythonlabel中完成得如此之快,但函数中的后台过程应该是一个令人筋疲力尽的迭代。这可以被认为是一种权衡。所以有一段时间我一直渴望寻求更有效的算法。还要注意,在上面给定的代码中,我发现几何中心非常简单,而对于复杂或不对称的形状,这可能会导致定位出现偏差。那就是它正在进行中的工作;)。

5)这是从此处
捕获的一个复杂案例(真实图像),在该案例上应用了标记建议,您可以看到结果。请注意,整个过程(包括标记和查找对象)只需要 0.015 秒。我认为Scipy家伙做得很好。哇!{右键单击图像,单击查看图像以获得完整分辨率}

在此处输入图像描述

4个回答

只是一个幼稚的建议:您知道组件标签吗?

该技术是关于找到“接触”像素的块并为它们分配一个标签,例如一个整数。然后,您可以分别询问每个缝隙,寻找共享相同标签的像素。

在 MATLAB 中,这是一个简单的函数:bwlabel

您还可以在图像上运行距离变换,然后检测局部最大值(在 3x3 像素块中搜索所有像素中具有最高/最低值的像素 - 根据原始斑点之间的预期最小距离,可能会更大)。

请注意,为了检测大小为 1-3 像素的特征,您需要将采样频率加倍(放大源图像或以亚像素精度执行距离变换/侵蚀)。

更新:

距离变换和侵蚀方法都假设您正在检测的特征是凸的。例如,具有 U 形的东西可能会在您的探测器中多次触发。

一种更精细的分割方法是基于水平集活动轮廓它从一个大的闭合曲线开始,它会迭代地适应您的特征。这种方法已在我的大学用于计数细胞和检测显微镜图像中的染色体。

一种选择是对图像应用重复的形态腐蚀,直到它被完全腐蚀。那时,上面显示的每个 blob 都会缩小到一个像素;您可以将这些像素的位置作为您要查找的点列表。

恐怕无论您选择哪种方式来执行此操作,都不会简单,因为要将目标分配给集群,您将不得不遍历图像(至少一次)。

我想获得分数是两者中更容易的问题(例如,您可能已经在应用某种形式的阈值)。

要恢复将点分组到的集群并快速完成,您可以创建一个四叉树结构,该结构包含四叉树单元区域周围某处的“连接像素链”。

通过这种方式,您可以遍历图像,一旦遇到作为目标的像素,就将其“推送”到四叉树结构中。

这种“推”操作将启动一个迭代过程,该过程将返回特定像素所在的单元格(换句话说,图像的特定区域)。然后您可以遍历分配给该单元格的所有像素链并尝试将像素“推”(再次)到像素链。如果一个像素链距离其任何已分配的像素至少有 1 个像素,则该像素链接受一个新像素。如果没有像素链“接受”新像素,则在此单元格中创建一个新像素链并将新像素分配给它。

这里的四叉树是一种限制您搜索最近像素链的方法,如果您的图像很大并且目标很多,则需要它,以便快速完成像素链推送操作。如果您知道您不会处理大量目标,那么您甚至可以跳过四叉树并维护一个简单的“像素链列表”。每次遇到“目标”时,您都可以遍历列表并尝试将像素“推”到它们上面。如果没有列表“承认”像素,则创建一个新列表并分配像素。

无论您选择哪种方式,在此过程结束时,您将拥有一组连接的“像素链”(您的集群),然后您可以将其传递给程序的另一部分,该部分将处理估计它们的地点。这可以是凸包、模型拟合(例如椭圆体或其他)或只是 x,y 坐标的平均值/中值。

我希望这有帮助。