从 Python 中的二值图像中获取像素边界坐标(不是边缘)
Get pixel boundary coordinates from binary image in Python (not edges)
我有一个包含单个连续斑点的二值图像,没有孔。我想根据边缘像素的外边缘创建一个多边形对象。我知道如何获取边缘像素本身,但我想要像素边界的实际坐标,顺时针或逆时针排序。所有像素都具有整数坐标。
例如,假设我在 (2,2) 处有一个像素。多边形的顶点将是:
(2.5, 2.5)
(2.5, 1.5)
(1.5, 1.5)
(1.5, 2.5)
(2.5, 2.5)
有没有一种精确的、非近似的方法来做到这一点?最好在 Python?
参见示例:
from PIL import Image, ImageFilter, ImageChops
import math
a = [['.','.','.','.','.','.','.'],
['.','.','.','.','.','.','.'],
['.','.','.','.','.','.','.'],
['.','#','#','#','.','.','.'],
['.','#','#','#','.','.','.'],
['.','.','.','.','.','.','.']]
sz=(len(a[0]), len(a))
flat_list = [j=='.' for i in a for j in i]
image=Image.new('1', sz)
image.putdata(flat_list)
contour=ImageChops.difference(image, image.filter(ImageFilter.MinFilter(3)))
contour_list=list(contour.getdata())
points=[divmod(i,sz[0]) for i in range(len(contour_list)) if contour_list[i]]
points_x,points_y=zip(*points)
avg=lambda x: sum(x)/len(x)
mean_x=avg(points_x)
mean_y=avg(points_y)
phase=[(math.atan2(points_y[i]-mean_y, points_x[i]-mean_x),i) \
for i in range(len(points))]
phase.sort()
for i in range(len(points)):
print(*points[phase[i][1]])
根据评论,这是我实施的方法:
将所有像素坐标乘以 10,以便我们只处理整数。
对于每个像素,通过添加 +/- 5 生成 4 个角。例如,对于 (20,20),角为 (25, 25) (25, 15) (15 , 15) (15, 25) (25, 25)。并将所有角存储在列表中。
计算每个角出现的次数。如果计数是奇数,则它是 blob 的一个角。使坐标整数使这一步变得容易。计算浮点数有问题。
将斑点角坐标除以 10,得到原始分辨率。
使用标准算法顺时针对角进行排序。
我有一个包含单个连续斑点的二值图像,没有孔。我想根据边缘像素的外边缘创建一个多边形对象。我知道如何获取边缘像素本身,但我想要像素边界的实际坐标,顺时针或逆时针排序。所有像素都具有整数坐标。
例如,假设我在 (2,2) 处有一个像素。多边形的顶点将是: (2.5, 2.5) (2.5, 1.5) (1.5, 1.5) (1.5, 2.5) (2.5, 2.5)
有没有一种精确的、非近似的方法来做到这一点?最好在 Python?
参见示例:
from PIL import Image, ImageFilter, ImageChops
import math
a = [['.','.','.','.','.','.','.'],
['.','.','.','.','.','.','.'],
['.','.','.','.','.','.','.'],
['.','#','#','#','.','.','.'],
['.','#','#','#','.','.','.'],
['.','.','.','.','.','.','.']]
sz=(len(a[0]), len(a))
flat_list = [j=='.' for i in a for j in i]
image=Image.new('1', sz)
image.putdata(flat_list)
contour=ImageChops.difference(image, image.filter(ImageFilter.MinFilter(3)))
contour_list=list(contour.getdata())
points=[divmod(i,sz[0]) for i in range(len(contour_list)) if contour_list[i]]
points_x,points_y=zip(*points)
avg=lambda x: sum(x)/len(x)
mean_x=avg(points_x)
mean_y=avg(points_y)
phase=[(math.atan2(points_y[i]-mean_y, points_x[i]-mean_x),i) \
for i in range(len(points))]
phase.sort()
for i in range(len(points)):
print(*points[phase[i][1]])
根据评论,这是我实施的方法:
将所有像素坐标乘以 10,以便我们只处理整数。
对于每个像素,通过添加 +/- 5 生成 4 个角。例如,对于 (20,20),角为 (25, 25) (25, 15) (15 , 15) (15, 25) (25, 25)。并将所有角存储在列表中。
计算每个角出现的次数。如果计数是奇数,则它是 blob 的一个角。使坐标整数使这一步变得容易。计算浮点数有问题。
将斑点角坐标除以 10,得到原始分辨率。
使用标准算法顺时针对角进行排序。