当矩形重叠时,如何将OpenCV中的轮廓合并

4

我有一张如下的输入图像:

enter image description here

我的目标是在红色区域绘制轮廓。为此,我有以下代码:

import cv2

# Read image
src = cv2.imread("images.jpg", cv2.IMREAD_GRAYSCALE)

# Set threshold and maxValue
thresh = 150 
maxValue = 200

# Basic threshold example
th, dst = cv2.threshold(src, thresh, maxValue, cv2.THRESH_BINARY);

# Find Contours
countours,hierarchy=cv2.findContours(dst,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)

for c in countours:
    rect = cv2.boundingRect(c)
    if rect[2] < 10 or rect[3] < 10: continue
    x,y,w,h = rect
    cv2.rectangle(src,(x,y),(x+w,y+h),(255,255,255),2)

# Draw Contour
#cv2.drawContours(dst,countours,-1,(255,255,255),3)

cv2.imshow("Contour",src)
cv2.imwrite("contour.jpg",src)
cv2.waitKey(0)

我得到了以下输出:

输入图像描述

我的目标是移除所有落在大矩形中的小矩形,并连接大矩形,例如下面这样:

输入图像描述

我该怎么做?

2个回答

9
如果您在findContours中使用cv2.RETR_EXTERNAL而不是cv2.RETR_TREE,该函数将仅返回外轮廓。因此,它不会返回位于另一个轮廓内部的轮廓。
合并轮廓的一种非常简单的方法是在黑色掩模上绘制填充为白色的轮廓,然后对该掩模执行新的findContours。它将返回组合轮廓的轮廓线。
要排除小轮廓:您可以使用contourArea获取轮廓的大小,并将其与您设置的值进行比较。在下面的代码中,我添加了一个滑块,以便您可以动态设置最小值。
结果:
enter image description here 请注意右侧的小矩形。它没有重叠,但在minContourSize之上。如果要排除该轮廓,则可以增加minContourSize,但您可能还会开始排除您想要的轮廓。解决方案是在掩模上设置第二个轮廓大小检查。由于掩模具有组合轮廓,因此可以将阈值设置得更高。
如果您更愿意将该轮廓合并到较大的轮廓中:您可以通过绘制填充轮廓和带有几个像素宽度的轮廓矩形来使轮廓在掩模上连接。不过,更合适的方法是查看形态学变换,您可以将其应用于掩模。
代码:
import cv2
import numpy as np
# Read image
src = cv2.imread("3E3MT.jpg", cv2.IMREAD_GRAYSCALE)

# Set threshold and maxValue
thresh = 150 
maxValue = 200
# set an initial minimal contour size
minContourSize = 250
# create a window  (needed for use with trackbar)
cv2.namedWindow("Contour")

def setMinSize(val):
        # set the minimal contour size and find/draw contours
        global minContourSize
        minContourSize = val
        doContours()

def doContours():
        # create a copy of the image (needed for use with trackbar)
        res = src.copy()
        # find contours - external only
        countours,hierarchy=cv2.findContours(dst,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
        # create an empty mask
        mask = np.zeros(src.shape[:2],dtype=np.uint8)
        # draw filled boundingrects if the contour is large enough
        for c in countours:
                if cv2.contourArea(c) > minContourSize:
                        x,y,w,h  = cv2.boundingRect(c)
                        cv2.rectangle(mask,(x,y),(x+w,y+h),(255),-1)

        # find the contours on the mask (with solid drawn shapes) and draw outline on input image
        countours,hierarchy=cv2.findContours(mask,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
        for c in countours:
                        cv2.drawContours(res,[c],0,(255,255,255),2)
        # show image
        cv2.imshow("Contour",res)

# create a trackbar to set the minContourSize - initial is set at 250,
# maximum value is currently set at 1500, you can increase it if you like
cv2.createTrackbar("minContourSize", "Contour",250,1500,setMinSize)
# Basic threshold example
th, dst = cv2.threshold(src, thresh, maxValue, cv2.THRESH_BINARY)
# Find Contours
doContours()
# waitkey to prevent program for exiting by itself
cv2.waitKey(0)
cv2.destroyAllWindows()

1
你可以使用下面的代码作为起点。它并不完美,但这是一个让你进一步改进它的机会。
# Read image
src = cv2.imread("demo.jpg")
gray = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)

# binary thresholding
img_thresh = cv2.threshold(gray, 150, 255, cv2.THRESH_BINARY)[1]

# Find Contours
contours,hierarchy = cv2.findContours(img_thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)

mask = np.zeros(src.shape, dtype="uint8") 
for c in contours:
    # get the bounding rect
    x, y, w, h = cv2.boundingRect(c)

    if w>80 and w<100:
        cv2.rectangle(mask, (x, y), (x+w-13, y+h), (255, 255, 255), -1)
    elif w>100:
        cv2.rectangle(mask, (x+10, y+10), (x+w, y+h), (255, 255, 255), -1)

thresh = cv2.threshold(cv2.cvtColor(mask, cv2.COLOR_BGR2GRAY), 150, 255, cv2.THRESH_BINARY_INV)[1]
thresh = np.float32(thresh)

# corner detection in the above mask(find Harris corners)
dst = cv2.cornerHarris(thresh, 5, 3, 0.04)
# thresholding for an optimal value
ret, dst = cv2.threshold(dst, 0.1*dst.max(), 255, 0)
dst = np.uint8(dst)

# find centroids
ret, labels, stats, centroids = cv2.connectedComponentsWithStats(dst)

# refines the corners detected with sub-pixel accuracy
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 100, 0.001)
corners = cv2.cornerSubPix(thresh, np.float32(centroids), (5,5), (-1,-1), criteria)

#for i in corners:
#    res_corners = cv2.circle(mask, (int(i[0]), int(i[1])), 2, (255, 0, 255), 2)

# convert detected corner coordinates values from float to int 
corners = np.int32(corners)

# corner coordinate values forming a horizontal line will share same y coordinate value
# corner coordinate values forming a vertical line will share same x coordinate value
# dictionaries 
# dict1 is a dictionary where key is x in (x, y) coordinate
# For example - (12, 20) and (12, 40) forming a vertical line; 
# dict1 contains a key 12 and its corresponding element [20, 40]
dict1 = dict() 
# dict2 is a dictionary where key is y in (x, y) coordinate
# For example - (12, 20) and (40, 20) forming a horizontal line; 
# dict1 contains a key 20 and its corresponding element [12, 40]
dict2 = dict() 

# populate dictionary with coordinates values detected above.
# Sample data of dictionary:
# {9: [9, 332],
#  46: [499, 584],
#  75: [332, 206]}
for i in range(len(corners)):
    dict1.setdefault(corners[i][0], []).append(corners[i][1])
    dict2.setdefault(corners[i][1], []).append(corners[i][0])

# empty image of same shape as original image on which we draw horizontal and vertical lines using dict1 and dict2
empty = np.zeros(src.shape, dtype="uint8")    
for key, value in dict1.items():
    if len(value)==2:
        cv2.line(empty, (key, value[0]), (key, value[1]), (255,255,255), 2)

for key, value in dict2.items():
    if len(value)==2:
        cv2.line(empty, (value[0], key), (value[1], key), (255,255,255), 2)

#cv2.imshow("corner detected",res_corners)
#cv2.imshow("intermediate mask",mask)
cv2.imshow("resultant mask",empty)
cv2.waitKey(0)

输出:

图1:中间层蒙版


注:保留HTML标签不翻译。

enter image description here

图2: 使用Harris角点检测算法检测到的角点

enter image description here

图3: 最终结果

enter image description here


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接