Python - 将二进制掩码转换为多边形

4

给定一个简单的二进制掩码(例如矩形的边界)。

二进制掩码

如何使用多边形获取x-y坐标?

到目前为止,我尝试过以下方法:

coords = np.transpose(np.nonzero(mask))

然而,这种方法会生成一个填充的对象,而不是所期望的边界。
plt.plot(coords[:, 1], coords[:,0])

不必要的输出

基本上,我需要一个白色像素的x-y坐标列表,使用这个列表重新绘制矩形(非填充)。

4个回答

7

使用cv2.findContours既适用于复杂形状,也适用于多个对象。 Polygons列表包含coords列表,每个列表看起来像这样[x1,y1,x2,y2,x3,y3,...]。

contours, _ = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
polygons = []

    for object in contours:
        coords = []
        
        for point in object:
            coords.append(int(point[0][0]))
            coords.append(int(point[0][1]))

        polygons.append(coords)

1
我喜欢这个解决方案,但是函数的输入是二进制掩码。如果我的图像有多个类别,并且我知道每个类别的调色板,那么我该怎么做呢? - Satya Prakash Dash
1
我能想到两种方法。1. 你可以找到一种方法,基于平均像素值或它们的坐标来为每个多边形分配相应的类别(函数应该识别所有类别)。2. 你可以遍历类别并为每个类别生成二进制掩码,然后运行该函数。其中一种方法是使用numpy.where()函数。 - Andrej_Rbr

5
你可以使用 np.column_stack()np.where()。思路是确定二进制图像中的白色像素,然后按照相应的 (x, y) 顺序排序。
coords = np.column_stack(np.where(image > 0))

另一种方法是使用OpenCV的cv2.boundingRect()查找边界矩形的坐标。这将给出宽度、高度和左上角的(x,y)坐标。以下是一个示例,查找坐标,然后在空白掩膜上绘制多边形:

import cv2
import numpy as np

image = cv2.imread('1.png', 0)
x,y,w,h = cv2.boundingRect(image)
mask = np.ones(image.shape, dtype=np.uint8) * 255
mask = cv2.merge([mask,mask,mask])
cv2.rectangle(mask, (x, y), (x + w, y + h), (36,255,12), 2)

cv2.imshow('mask', mask)
cv2.waitKey()

谢谢nathancy。我尝试了你的解决方案,但对于“coord”得到了相同的输出结果。你可以具体说明一下你所指的按(x,y)坐标排序是什么吗? - Kamu
我是指获取多边形的(x,y)坐标。也许我没有正确理解你的问题,你能详细说明一下“不是所需边界”的含义吗?或者可以添加一个预期输出图像。 - nathancy
我编辑了原始帖子,但输出结果是错误的。期望的输出图像应该与原始输出相同(矩形的边界-未填充)。希望这可以帮助到您。 - Kamu
检查更新,您可以找到边界矩形坐标,然后使用它在另一张图片上绘制。 - nathancy

2
您可以将正方形视为一个对象,并使用skimage.measure.regionprops函数访问其属性。
我强烈建议查看文档,因为在许多情况下,这是一个非常有用的函数:

https://scikit-image.org/docs/dev/api/skimage.measure.html#skimage.measure.regionprops

此外,还有skimage.measure.regionprops_table,它可以提供一个字典,可转换为Pandas数据框。以下是我的解决方案:
from skimage.io import imread
from skimage.measure import regionprops_table
from pandas import DataFrame

import numpy as np
import matplotlib.pyplot as plt

rectangle = imread('rectangle_img.png')    
props_rect = DataFrame(regionprops_table(rectangle, properties=['coords']))

new_img = np.zeros((rectangle.shape[0], rectangle.shape[1]))

for point in props_rect['coords'][0]:

    new_img[point[0], point[1]] = 1


plt.imshow(new_img)

0
contours, _ = cv2.findContours(binary_mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
polygons = [np.array(polygon).squeeze() for polygon in contours]

polygons 是一个包含形状为 N, 2arrayslist,其中 N 对应于点的数量,2 对应于 xy 坐标。


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