【问题标题】:OpenCV join contours when rectangle overlaps another rect当矩形与另一个矩形重叠时,OpenCV 加入轮廓
【发布时间】:2019-12-07 01:11:30
【问题描述】:

我有以下输入图像:

我的目标是在红色区域绘制轮廓。为此,我有以下代码: 导入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)

我得到以下输出:

我的目标是删除所有落在较大矩形内的矩形并连接较大的矩形,例如:

我该怎么做?

【问题讨论】:

    标签: python python-3.x opencv


    【解决方案1】:

    如果您在findContours 中使用cv2.RETR_EXTERNAL 而不是cv2.RETR_TREE,则该函数将仅返回外部轮廓。所以它不会返回另一个轮廓内的轮廓。

    要合并轮廓,一种非常简单的方法是在黑色蒙版上绘制填充为白色的轮廓,然后在该蒙版上执行新的 findContours。它将返回组合轮廓的轮廓。

    要排除小轮廓:您可以使用contourArea 获取轮廓的大小,并将其与您设置的值进行比较。在下面的代码中,我添加了一个跟踪栏,以便您可以动态设置最小值。

    结果:

    注意小矩形的大小合适。它不重叠,但高于 minContourSize。如果你想排除那个轮廓,你可以增加 minContourSize,但你也可以开始排除你想要的轮廓。一个解决方案是对轮廓大小设置第二次检查,这次是在蒙版上。由于蒙版具有组合轮廓,因此您可以将阈值设置得更高。

    如果您希望将该轮廓合并到较大的轮廓:您可以通过绘制填充轮廓和具有几个像素宽的轮廓的未填充矩形来使轮廓连接到蒙版上。虽然更合适的方法是查看 Morphological Transformations,您可以将其应用于掩码。

    代码:

    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()
    

    【讨论】:

      【解决方案2】:

      您可以使用以下代码作为起点。它并不完美,但这是您进一步改进它的机会。

      # 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:中间掩码

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

      图 3:最终结果

      【讨论】:

        猜你喜欢
        • 2021-11-19
        • 2019-12-03
        • 1970-01-01
        • 1970-01-01
        • 2018-03-11
        • 1970-01-01
        • 2012-05-10
        • 2021-09-01
        • 1970-01-01
        相关资源
        最近更新 更多