Skip to main content
 首页 » 编程设计

python之如何找到图像中的矩形

2025年05月04日11飞鱼

这是this answer中这段代码生成的图片(我后来画的绿色圆圈除外):

foo

形状是(707, 1028, 3),所以每个像素都有三个 channel (RGB),但是只填充了白色和黑色。如果转换成 8 位图像就更好了。

我需要获取图像中每个矩形的位置和大小。我有一些代码使用 PIL 和 .load() 来访问每个像素,但是速度太慢了。在 PIL 版本中,我寻找起始角和结束角。代码类似于 pixels[x, y] == 255 and pixels[x-1, y] == 0 and pixels[x, y-1] == 0

请您参考如下方法:

1。用单 channel 制作图像

如果您需要一个图像具有单个 channel ,则使用一个 channel 而不是三个 channel 生成它。所以不是:

output = numpy.zeros(img.shape) # (height, width, 3) 
output[~mask] = (255, 255, 255) 

写:

output = numpy.zeros(img.shape[:2]) # just (height, width) 
output[~mask] = 255 

或者,如果您加载了一张多 channel 图像并只想选择一个 channel 进行处理,请将其切片:

img = img[...,0] # red channel 

但是如果您正在进行特征检测等进一步处理,则无需在此处保存输出图像或重新加载它。您可以继续使用 mask。

2。寻找连续区域

您可以使用 scipy.ndimage.measurements.label 查找图像的连续区域.默认情况下,这只会找到正交连接的区域;如果你也想要对角连接的区域,然后传递适当的 structure 参数:

labels, n = scipy.ndimage.measurements.label(mask, numpy.ones((3, 3))) 

结果是 labels(一个与 mask 形状相同的数组,包含不同的整数,用于标记 mask 的连续区域),以及 n(找到的区域数)。然后你调用scipy.ndimage.measurements.find_objects获取边界框:

>>> bboxes = scipy.ndimage.measurements.find_objects(labels) 
>>> bboxes[0] 
(slice(0, 2, None), slice(19, 23, None)) 

所以这个物体位于 x = 19–23 和 y = 0–2(它是图像顶部边缘的黑色小条)。通过使用这对切片索引原始图像,您可以得到包含对象的子图像。这是对象 #3 中最上面的矩形:

>>> bboxes[3] 
(slice(33, 60, None), slice(10, 86, None)) 
>>> img[bboxes[3]] 
array([[255, 255,   0, ...,   0, 255, 255], 
       [255,   0,   0, ...,   0,   0, 255], 
       [  0,   0, 255, ...,   0,   0, 255], 
       ...,  
       [  0,   0,   0, ...,   0,   0, 255], 
       [255,   0,   0, ...,   0, 255, 255], 
       [255, 255, 255, ..., 255, 255, 255]], dtype=uint8) 

(其他矩形是对象 #4、#5 和 #8。)这是一种可视化它们的方法:

boxed = numpy.dstack((img,) * 3) 
for y, x in bboxes: 
    if y.stop - y.start == 27: # is this the right criterion? 
        boxed[(y.start, y.stop-1), x] = (0, 255, 0) 
        boxed[y, (x.start, x.stop-1)] = (0, 255, 0) 
imsave('boxed.png', boxed)