Python 在图像中找到最小数量的矩形

Python 在图像中找到最小数量的矩形,python,numpy,image-processing,scipy,rectangles,Python,Numpy,Image Processing,Scipy,Rectangles,我有随机放置矩形的二值图像,我想得到这些矩形的位置和大小。 如果可能的话,我需要最小数量的矩形来准确地重建图像 左边是我的原始图像,右边是我应用scipys.find_objects()后得到的图像 (就像建议的那样) 导入scipy #image=scipy.ndimage.zoom(图像,9,顺序=0) 标签,n=scipy.ndimage.measurements.label(图像,np.one((3,3))) bboxes=scipy.ndimage.measurements.fin

我有随机放置矩形的二值图像,我想得到这些矩形的位置和大小。 如果可能的话,我需要最小数量的矩形来准确地重建图像

左边是我的原始图像,右边是我应用
scipys.find_objects()后得到的图像
(就像建议的那样)

导入scipy
#image=scipy.ndimage.zoom(图像,9,顺序=0)
标签,n=scipy.ndimage.measurements.label(图像,np.one((3,3)))
bboxes=scipy.ndimage.measurements.find_对象(标签)
img_new=np.zeros_like(图像)
对于bboxes中的bb:
img_new[bb[0],bb[1]]=1
如果矩形相距较远,这很好,但如果它们重叠并构建更复杂的结构,此算法只会给我最大的边界框(对图像进行上采样没有任何区别)。我觉得应该已经存在一种
scipy
opencv
方法来实现这一点。 我很高兴知道是否有人对如何解决这个问题有想法,或者更了解现有的解决方案

因此,我希望在图像中有一个矩形列表(即左下角:右上角)。条件是,当我重新绘制那些填充的矩形时,我希望得到与以前完全相同的图像。如果可能的话,矩形的数量应该是最小的

下面是生成示例图像的代码(以及更复杂的示例vs)


这里有一些东西可以让你开始:一个天真的算法,它可以遍历你的图像并创建尽可能大的矩形。现在,它只标记矩形,而不报告坐标或计数。这是为了将算法单独可视化

当保存为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()
从PIL导入图像
def填充矩形(像素、xp、yp、w、h):
对于范围(h)内的y:
对于范围(w)内的x:
像素[xp+x,yp+y]=(255,0,0255)
对于范围(h)内的y:
像素[xp,yp+y]=(255192,0255)
像素[xp+w-1,yp+y]=(255192,0255)
对于范围(w)内的x:
像素[xp+x,yp]=(255192,0255)
像素[xp+x,yp+h-1]=(255192,0255)
def find_rect(像素,x,y,maxx,maxy):
#假设我们在左上方
#获得最大水平跨度
宽度=0
高度=1
当x+width
从输出

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

可能的改进是调整
find_rect
例程以找到最佳拟合的ª,或者存储坐标并使用数学(超出我的知识范围)来查找可以连接的矩形



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

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