Floodfill在numpy / python中分割图像

时间:2016-08-26 20:05:30

标签: python image numpy image-processing image-segmentation

我有一个numpy数组,它代表一个图像的分段二维矩阵。基本上,它是一个稀疏矩阵,具有一堆封闭的形状,这些形状是图像片段的轮廓。我需要做的是用numpy中不同的颜色/标签着色每个闭合形状中的空像素。

我知道我可以在PIL中使用Floodfill进行此操作,但我尝试不必将矩阵从numpy来回转换为PIL。如果像skimage或sklearn这样的功能可以自动标记"那将是很好的。我矩阵的所有不同的闭合区域都有不同的标签(它可以是单调递增的整数或颜色。只要它代表其区域内相邻像素的正确分组,我就不在乎)。

我已经花了很多时间尝试实施自己的垃圾填埋工具,此时我就像是可以为我开箱即可标出图像。

1 个答案:

答案 0 :(得分:5)

我假设您的矩阵是二进制的,其中非零值表示提取的段,零值是您不关心的值。可能会对scikit-image模块中的label measure函数感兴趣:http://scikit-image.org/docs/dev/api/skimage.measure.html#skimage.measure.label

它基本上执行连通组件分析,并将所有单独关闭的组件与整数一起标记。关于如何指定连接,您需要小心。有4连通性和8连通性,前者仅使用北,南,东和西方向找到连通区域,而8连通性使用所有8个方向(北,南,东,西,东北,东南,西北,西南) )。您可以使用connectivity选项,为{4}连接指定1,为8连通指定2

但是,默认连接将是完全连接,因此对于2D的情况,它将是2选项。我怀疑你会这样。矩阵中任何零点的斑点都会标记为零。不用多说,这是一个非常简单的可重复的例子:

In [1]: from skimage.measure import label

In [2]: import numpy as np

In [3]: x = np.zeros((8,8))

In [4]: x[0:4,0:4] = 1

In [5]: x[6:8,6:8] = 1

In [6]: x
Out[6]:
array([[ 1.,  1.,  1.,  1.,  0.,  0.,  0.,  0.],
       [ 1.,  1.,  1.,  1.,  0.,  0.,  0.,  0.],
       [ 1.,  1.,  1.,  1.,  0.,  0.,  0.,  0.],
       [ 1.,  1.,  1.,  1.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.,  0.,  1.,  1.],
       [ 0.,  0.,  0.,  0.,  0.,  0.,  1.,  1.]])

In [7]: label(x)
Out[7]:
array([[1, 1, 1, 1, 0, 0, 0, 0],
       [1, 1, 1, 1, 0, 0, 0, 0],
       [1, 1, 1, 1, 0, 0, 0, 0],
       [1, 1, 1, 1, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 2, 2],
       [0, 0, 0, 0, 0, 0, 2, 2]], dtype=int64)

我们可以看到我在左上角和右下角创建了两个独立的岛屿。运行label函数后,它会返回一个标签矩阵,用于标识彼此属于的像素区域。具有相同ID的像素表示属于同一区域。

为了向您展示连接如何发挥作用,这是另一个简单的例子:

In [1]: import numpy as np

In [2]: from skimage.measure import label

In [3]: y = np.array([[0,1,0,0],[1,1,1,0],[0,1,0,1]])

In [4]: y
Out[4]:
array([[0, 1, 0, 0],
       [1, 1, 1, 0],
       [0, 1, 0, 1]])

In [5]: label(y, connectivity=1)
Out[5]:
array([[0, 1, 0, 0],
       [1, 1, 1, 0],
       [0, 1, 0, 2]], dtype=int64)

In [6]: label(y)
Out[6]:
array([[0, 1, 0, 0],
       [1, 1, 1, 0],
       [0, 1, 0, 1]], dtype=int64)

输入左上角有一个十字图案,右下角有一个单独的非零值。如果我们使用4连接,则右下角将被分类为不同的标签,但如果我们使用默认连接(完整),则每个像素将被归类为相同的标签。