在图像中找到闭合的形状

时间:2013-10-03 20:51:16

标签: python image shape

我需要在图像中找到所有闭合的形状并获得它的坐标。我需要在Python中使用它,但是如何做到这一点的解释也就足够了。如果你愿意,可以随意回答Python代码。我已经在Google上搜索了很多,发现了这两件事:

第一个链接中的答案描绘了所有区域,而不是给出封闭区域的坐标。我不理解第二个链接中的第一个答案,一些评论说它不起作用。第二个链接中的第二个答案不适用于这样的图像:

some image

我也尝试制作自己的代码,但计算花费的时间超过一秒,而且速度要快得多(不是真的,非常快,但至少快于1/10秒)。

我如何找到这些区域?

PS:图像中有些线条不是闭合形状的一部分。

1 个答案:

答案 0 :(得分:4)

这是一个函数find_groups,它将图像中的每个像素分为三个类别之一:自由,闭合和边框,以及函数print_groups以便以可读的方式对其进行测试。

from collections import namedtuple
from copy import deepcopy

def find_groups(inpixels):
    """
    Group the pixels in the image into three categories: free, closed, and
    border.
        free: A white pixel with a path to outside the image.
        closed: A white pixels with no path to outside the image.
        border: A black pixel.

    Params:
        pixels: A collection of columns of rows of pixels. 0 is black 1 is
                white.

    Return:
        PixelGroups with attributes free, closed and border.
        Each is a list of tuples (y, x).
    """

    # Pad the entire image with white pixels.
    width = len(inpixels[0]) + 2
    height = len(inpixels) + 2
    pixels = deepcopy(inpixels)
    for y in pixels:
        y.insert(0, 1)
        y.append(1)
    pixels.insert(0, [1 for x in range(width)])
    pixels.append([1 for x in range(width)])

    # The free pixels are found through a breadth first traversal.
    queue = [(0,0)]
    visited = [(0,0)]
    while queue:
        y, x = queue.pop(0)

        adjacent = ((y+1, x), (y-1, x), (y, x+1), (y, x-1))
        for n in adjacent:
            if (-1 < n[0] < height and -1 < n[1] < width and
                                        not n in visited and 
                                    pixels[n[0]][n[1]] == 1):
                queue.append(n)
                visited.append(n)

    # Remove the padding and make the categories.
    freecoords = [(y-1, x-1) for (y, x) in visited if
                 (0 < y < height-1 and 0 < x < width-1)]
    allcoords = [(y, x) for y in range(height-2) for x in range(width-2)]
    complement = [i for i in allcoords if not i in freecoords]
    bordercoords = [(y, x) for (y, x) in complement if inpixels[y][x] == 0]
    closedcoords = [(y, x) for (y, x) in complement if inpixels[y][x] == 1]

    PixelGroups = namedtuple('PixelGroups', ['free', 'closed', 'border'])
    return PixelGroups(freecoords, closedcoords, bordercoords)

def print_groups(ysize, xsize, pixelgroups):
    ys= []
    for y in range(ysize):
        xs = []
        for x in range(xsize):
            if (y, x) in pixelgroups.free:
                xs.append('.')
            elif (y, x) in pixelgroups.closed:
                xs.append('X')
            elif (y, x) in pixelgroups.border:
                xs.append('#')
        ys.append(xs)
    print('\n'.join([' '.join(k) for k in ys]))

现在使用它:

pixels = [[0, 1, 0, 0, 1, 1],
          [1, 0, 1, 1, 0, 1], 
          [1, 0, 1, 1, 0, 1],
          [1, 0 ,1 ,1 ,0, 1],
          [1, 0, 1 ,0 ,1, 1],
          [1, 0, 0, 1, 1, 1],
          [1, 1, 1, 1, 1, 1]]
pixelgroups = find_groups(pixels)
print_groups(7, 6, pixelgroups)
print("closed: " + str(pixelgroups.closed))

输出:

# . # # . .
. # X X # .
. # X X # .
. # X X # .
. # X # . .
. # # . . .
. . . . . .

closed: [(1, 2), (1, 3), (2, 2), (2, 3), (3, 2), (3, 3), (4, 2)]

您会注意到随机点和条纹被归类为边框。但是你可以随时区分真实的边界和条纹。

# pseudo code
realborders = [i for i in pixelgroups.border if i has an adjacent closed pixel]
streaks = [otherwise]