【问题标题】:Find minimal number of rectangles in the image在图像中找到最少数量的矩形
【发布时间】:2020-05-29 04:18:57
【问题描述】:

我有随机放置矩形的二进制图像,我想获取这些矩形的位置和大小。 如果可能的话,我希望精确地重新创建图像所需的矩形数量最少。

左边是我的原图,右边是我申请scipys.find_objects()后得到的图像 (就像建议 this question 一样)。

import scipy

# image = scipy.ndimage.zoom(image, 9, order=0)
labels, n = scipy.ndimage.measurements.label(image, np.ones((3, 3)))
bboxes = scipy.ndimage.measurements.find_objects(labels)

img_new = np.zeros_like(image)
for bb in bboxes:
    img_new[bb[0], bb[1]] = 1

如果矩形相距很远,这很好用,但如果它们重叠并构建更复杂的结构,这个算法只会给我最大的边界框(对图像进行上采样没有区别)。我觉得应该已经存在一个 scipyopencv 方法可以做到这一点。 我很高兴知道是否有人知道如何解决这个问题,或者更了解现有的解决方案。

因此,我想要图像中的矩形列表(即左下角:右上角)。条件是,当我重绘那些填充的矩形时,我想获得与以前完全相同的图像。如果可能,矩形的数量应该最少。

这是生成示例图像的代码(以及更复杂的示例 originalscipy

import numpy as np 

def random_rectangle_image(grid_size, n_obstacles, rectangle_limits):
    n_dim = 2
    rect_pos = np.random.randint(low=0, high=grid_size-rectangle_limits[0]+1,
                                 size=(n_obstacles, n_dim))
    rect_size = np.random.randint(low=rectangle_limits[0],
                                  high=rectangle_limits[1]+1,
                                  size=(n_obstacles, n_dim))

    # Crop rectangle size if it goes over the boundaries of the world
    diff = rect_pos + rect_size
    ex = np.where(diff > grid_size, True, False)
    rect_size[ex] -= (diff - grid_size)[ex].astype(int)

    img = np.zeros((grid_size,)*n_dim, dtype=bool)
    for i in range(n_obstacles):
        p_i = np.array(rect_pos[i])
        ps_i = p_i + np.array(rect_size[i])
        img[tuple(map(slice, p_i, ps_i))] = True
    return img

img = random_rectangle_image(grid_size=64, n_obstacles=30, 
                             rectangle_limits=[4, 10])

【问题讨论】:

  • “编写这个代码应该不会太难。”ᶜᶦᵗᵃᵗᶦᵒⁿ ⁿᵉᵉᵈᵉᵈ 右侧图中有多少个矩形,在中心左侧的重叠集中? 至少 2 -- 但也可以是 3 或 4,具体取决于您的计数方式。
  • 在多次 cmets 的措辞之后好的:我希望有一个现有的算法来解决这个问题,并想问一下。如果没有,我会很乐意自己做。听起来不应该是这样的:肯定有人愚蠢(而且聪明)为我做这项工作......
  • 所以基本上你要求的是找到图像中每个直线多边形的最小矩形分区。我认为这是一个众所周知的问题,如果你用谷歌搜索,你会发现很多算法。但我不认为有一个简单的解决方案。
  • 您可以尝试使用 opencv blob 检测方法并针对此特定图像调整其参数。还可以考虑在应用斑点检测器之前对图像进行预处理,例如腐蚀和膨胀操作,以便更容易检测矩形。
  • 我突然想到你可能想多了。一个简单的算法也可以工作:定位一个矩形的左上角,扫描它的边界,从图像中删除。重复。它导致绘制更多矩形(用于重叠矩形),但它应该是万无一失的。

标签: python numpy image-processing scipy rectangles


【解决方案1】:

这里有一些东西可以帮助您入门:一种简单的算法,可以遍历您的图像并创建尽可能大的矩形。就像现在一样,它仅标记矩形,但不报告回坐标或计数。这是单独将算法可视化。

当保存为 PNG 时,它不需要任何外部库(除了 PIL)来加载和访问左侧图像。我假设可以忽略周围 15 像素的边框。

from PIL import Image

def fill_rect (pixels,xp,yp,w,h):
    for y in range(h):
        for x in range(w):
            pixels[xp+x,yp+y] = (255,0,0,255)
    for y in range(h):
        pixels[xp,yp+y] = (255,192,0,255)
        pixels[xp+w-1,yp+y] = (255,192,0,255)
    for x in range(w):
        pixels[xp+x,yp] = (255,192,0,255)
        pixels[xp+x,yp+h-1] = (255,192,0,255)

def find_rect (pixels,x,y,maxx,maxy):
    # assume we're at the top left
    # get max horizontal span
    width = 0
    height = 1
    while x+width < maxx and pixels[x+width,y] == (0,0,0,255):
        width += 1
    # now walk down, adjusting max width
    while y+height < maxy:
        for w in range(x,x+width,1):
            if pixels[x,y+height] != (0,0,0,255):
                break
        if pixels[x,y+height] != (0,0,0,255):
            break
        height += 1
    # fill rectangle
    fill_rect (pixels,x,y,width,height)

image = Image.open('A.png')
pixels = image.load()
width, height = image.size

print (width,height)

for y in range(16,height-15,1):
    for x in range(16,width-15,1):
        if pixels[x,y] == (0,0,0,255):
            find_rect (pixels,x,y,width,height)

image.show()

从输出

您可以观察到检测算法可以改进,例如,“明显”的两个左上角矩形被分成 3 个。类似地,中心较大的结构也包含一个比绝对需要的矩形。

可能的改进是调整find_rect 例程以找到最合适的¹,或存储坐标并使用数学(超出我的理解)来查找可以连接的矩形。


¹对此的进一步想法。目前,所有找到的矩形都立即用“找到”颜色填充。您可以尝试检测明显的多个矩形,然后在标记第一个矩形后,其他要检查的矩形可能是黑色红色。我想说的是,您需要尝试不同的扫描顺序(从上到下或反向、从左到右或反向)才能真正找到任意组合中最少需要的矩形数量。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-21
    • 2017-11-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多