Floodfill在numpy/python中分割图像

Cor*_*let 4 python numpy image image-processing image-segmentation

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

我知道我可以在PIL中使用floodfill来做这个,但我不想将矩阵从numpy来回转换为PIL.如果像skimage或sklearn这样的某个功能可以"自动标记"我的矩阵的所有不同的封闭区域,并为我提供不同的标签(它可以是单调递增的整数或颜色,那将是很好的.我不喜欢只要它代表其区域内相邻像素的正确分组,就要小心.

我已经花了很多时间来尝试实现我自己的洪水填充,此时我只是喜欢一些可以为我标出图像的开关.

ray*_*ica 7

我假设您的矩阵是二进制的,其中非零值表示提取的段,零值是您不关心的值.该模块的scikit-image label功能measure可能很有用:http://scikit-image.org/docs/dev/api/skimage.measure.html#skimage.measure.label

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

但是,默认连接将是完全连接,因此对于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)
Run Code Online (Sandbox Code Playgroud)

我们可以看到,我在左上角和右下角创建了两个独立的岛屿.运行该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)
Run Code Online (Sandbox Code Playgroud)

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