【问题标题】:findContours() function not returning the appropriate number of contoursfindContours() 函数未返回适当数量的轮廓
【发布时间】:2020-09-03 17:54:46
【问题描述】:

我正在使用Python 3.8.2openCV 4.3.0。 当我应该得到 3 时,我得到的答案是 1 轮廓。我尝试使用 RETR_TREE 而不是 RETR_EXTERNAL。在那种情况下,它会给我8 轮廓。

import cv2 as cv
def getCounters(img):
    contours,hierarchy=cv.findContours(img,cv.RETR_EXTERNAL,cv.CHAIN_APPROX_SIMPLE)
    print("Number of Contours found = " + str(len(contours)))

这是输入图像:

这是输入的 Canny 图像:

请提出所需的更改。

【问题讨论】:

  • 你得到了白色背景的轮廓。您需要对图像进行阈值处理,使对象为白色,背景为黑色。然后得到外部轮廓。
  • 对不起,我是这方面的初学者。你能建议怎么做吗?

标签: python-3.x opencv image-processing computer-vision opencv-contour


【解决方案1】:

这是在 Python/OpenCV 中执行此操作的一种方法。您的问题是由于边缘的黑色轮廓,您从白色背景中获得了外轮廓。一种方法是使用层次结构来获得第二级轮廓。我在这里使用的花药只是为了摆脱黑色边框。

  • 读取输入
  • 去掉黑色边框,变成白色
  • 转换为灰色
  • 反转灰色
  • 阈值,使对象在黑色背景上为白色
  • 获取轮廓并在输入和黑色背景上绘制
  • 保存结果

输入:

import cv2
import numpy as np

# read image
img = cv2.imread('shapes.png')
hh, ww = img.shape[:2]

# remove black border and add white border back
img2 = img[2:hh-2, 2:ww-2]
img2 = cv2.copyMakeBorder(img2, 2, 2, 2, 2, cv2.BORDER_CONSTANT, value=(255,255,255))

# convert to grayscale
gray = cv2.cvtColor(img2,cv2.COLOR_BGR2GRAY)

# invert
gray = 255 - gray

# threshold
thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY)[1]

# get contours and draw on input and on black background
result1 = img.copy()
result2 = np.zeros_like(img)
contours = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
for cntr in contours:
    cv2.drawContours(result1, [cntr], 0, (0,0,255), 1)
    cv2.drawContours(result2, [cntr], 0, (255,255,255), 1)

# save results
cv2.imwrite('shapes_modified.png',img2)
cv2.imwrite('shapes_thresh.png',thresh)
cv2.imwrite('shapes_result1.png',result1)
cv2.imwrite('shapes_result2.png',result2)

# show results  
cv2.imshow("img2", img2)
cv2.imshow("thresh", thresh)
cv2.imshow("result1", result1)
cv2.imshow("result2", result2)
cv2.waitKey(0)
cv2.destroyAllWindows()


输入黑色边框变为白色:

阈值图像:

输入轮廓:

黑色背景上的轮廓:

【讨论】:

    【解决方案2】:

    @fmw42 的回答是正确的。以下是替代方法,请阅读 cv2.RETR_CCOMP 对 findContours 的作用。

    import numpy as np
    import cv2
    
    gray = cv2.imread('shapes.png', cv2.IMREAD_GRAYSCALE)
    imgw, imgh = gray.shape
    
    th = cv2.adaptiveThreshold(gray,255, cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY_INV,3,1)
    
    _, ctrs, hierarchy = cv2.findContours(np.copy(th), cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE)
    out_test = np.zeros(th.shape[:2], dtype="uint8")
    
    for i in range(len(ctrs)):
        if(hierarchy[0][i][3] != -1): # Discard contours that are holes
            continue
        x, y, w, h = cv2.boundingRect(ctrs[i])
    
        if w * h < 0.9 * (imgw * imgh): # Eliminates white square surrounding the whole image
            cv2.drawContours(out_test, [ctrs[i]], -1, 255, -1)
    

    【讨论】:

      【解决方案3】:

      执行此操作的快速方法是:在您的代码中,使用 RETR_TREE 查找轮廓。正如你所说,这将给出总共 8 个轮廓。现在我们必须消除所有外部轮廓,即所需的轮廓是形状内边缘的轮廓。如您所见,内边缘的这些轮廓将没有子轮廓。因此,请使用此观察结果。

      Refer this for info about parent-child relation in contours

      执行此操作的一个线性代码是 -

      contours = np.asarray([contours[i] for i in range(len(contours)) if hierarchy[0][i][2] == -1])
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-01-03
        • 2012-07-03
        • 1970-01-01
        • 2021-08-21
        • 1970-01-01
        • 1970-01-01
        • 2018-01-01
        相关资源
        最近更新 更多