在给定图像边界的情况下查找填充区域

Posted

技术标签:

【中文标题】在给定图像边界的情况下查找填充区域【英文标题】:Find filled regions given its boundaries in an image 【发布时间】:2021-12-22 00:41:21 【问题描述】:

我有一个带边界的二值图像,像这样:

我想找到一个包含与这些边界对应的填充区域的二进制图像。我是在Paint上手动完成的,结果应该是这样的:

我一直在寻找解决方案,我刚刚找到了this post,但是如果图像主要由背景组成,那么提供的解决方案就可以工作,这可能不一定是我的情况。我尝试使用scipy.ndimage.binary_fill_holes,但它不适用于接触边界的区域:

是否有其他方法可以使 所有 区域(包括那些接触边界的区域)工作?

编辑:我不介意哪个是填充区域,哪个不是。即,如果将值反转,也可以。我只需要一个二进制除法,填哪些填哪些没关系,只要边界正确地分开这两种即可。

【问题讨论】:

如何定义必须填充的形状?比如右下角:为什么不填充小斑点,而周围的是? 看看opencv的floodFill函数 @jeandemeusy 我已经用一些相关信息更新了这个问题,感谢您指出。 首先你需要用opencv CLEARLY定义所有的轮廓。那么 fillPolly 或 fillConvexPolly 会帮助你 @YunusTemurlenk “清楚地”是什么意思?为什么说轮廓没有定义? 【参考方案1】:

自从我上一个回答错过了角落问题的重点。 我试图找到一个更合适的解决方案: 我还尝试了像 cv2.morphologyEx 这样的形态转换 但最后结果一点都不好。

那么:为什么不添加人工边框来关闭所有轮廓? 一般工作流程: a) 扩展图像并添加边框 b)应用一些高斯滤波器 c) 转换为灰度 d) 在树层次结构中找到轮廓 e) 使用结构找到正确的轮廓

所以代码看起来像:

import cv2
from random import randrange

# read the image
image = cv2.imread('QFqC8m.jpeg')

#we extend the image to add a small border
borderSize = 1
image = cv2.copyMakeBorder(image,borderSize,borderSize,borderSize,borderSize,cv2.BORDER_CONSTANT,value=[255,255,255])

# convert the image to grayscale format
img_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
cv2.imshow('Binary image', img_gray)
cv2.waitKey(0)

#we apply GaussianBlur filter
image_blured = cv2.GaussianBlur(img_gray,(3,3),0)
cv2.imshow('Blured image', image_blured)
cv2.waitKey(0)

# apply binary thresholding
ret, img_thres = cv2.threshold(image_blured, 50, 200, cv2.THRESH_BINARY)
# visualize the binary image
cv2.imshow('Threshold image', img_thres)
cv2.waitKey(0)

# detect the contours on the
contours, hierarchy = cv2.findContours(image=img_thres, mode=cv2.RETR_TREE, method=cv2.CHAIN_APPROX_NONE)

hierarchy = hierarchy[0]  # Remove redundant dimension of hiers.
# we iterate the hierachy
# openCV represents it as an array of four values :
# 0      1            2          3 
#[Next, Previous, First_Child, Parent]
# Find contour with the maximum area our artifical box is the largest contour
# its the outside square box
rootSquareContour = max(contours, key=cv2.contourArea)
rootSquareContourArea = cv2.contourArea(rootSquareContour)

# we do search the right first tree lvl via hand
#first lvl
root_idx = contours.index(rootSquareContour)
root_hierarchy = hierarchy[root_idx]
child_idx = root_hierarchy[2]  # Index of the first child

while child_idx != -1:    
    child_hierarchy = hierarchy[child_idx]
    #get the contour
    c = contours[child_idx]
    #we draw it with random color
    cv2.fillPoly(image,pts=[c],color=(randrange(255),randrange(255),randrange(255)))
    #get next element
    child_hierarchy = hierarchy[child_idx]
    child_idx = child_hierarchy[0]  #get next element on same lvl

    #TODO might need not all lvl ? 
    if child_idx==-1: #switch to next lvl
        child_idx = child_hierarchy[2] 
                

cv2.imshow("Filled Contours", image)
cv2.imwrite("filled.jpg", image)

cv2.waitKey(0)
cv2.destroyAllWindows()

还有一些工作要做,但代码解释了背后的想法。 关于层次结构的一个很好的解释可以在here

找到

【讨论】:

这显然与我在问题中明确指出的问题相同。 我一定错过了这一点,但既然你确实有轮廓,你可以简单地将边缘点添加到轮廓中以某种方式看到一些类似的问题:***.com/q/19809030/14105642 我更新了示例,现在它解决了您的问题

以上是关于在给定图像边界的情况下查找填充区域的主要内容,如果未能解决你的问题,请参考以下文章

在图像中查找拼字游戏板的角点

图像形态学提取边界和区域填充

给定每个区域的边界和纬度/经度,以编程方式查找州/县

在图像中查找 RGB 颜色的边界框

NumPy 填充大型数组的给定边界框坐标内的值

查找给定多边形 w.r.t 的两个“边界”顶点。已知(光源)点