【问题标题】:Rectify edges of a shape in mask with OpenCV使用 OpenCV 校正蒙版中形状的边缘
【发布时间】:2020-05-30 07:48:38
【问题描述】:

我需要矫正如下图所示形状(多边形)的边缘。

这是cv2.approxPolyDPm 的结果,近似于cv2.findContours 结果:

for (i, c) in enumerate(cnts):
    peri = cv2.arcLength(c, closed=True)
    approx = cv2.approxPolyDP(c, epsilon=0.01 * peri, closed=True)

有些边框不是直的。我需要它们完全垂直或水平。 我尝试修改 epsilon 值但没有成功。

【问题讨论】:

    标签: python numpy opencv mask contour


    【解决方案1】:

    您需要添加另一个阶段,强制轮廓顶点仅形成水平和垂直直线。

    如果两个顶点p1、p2 的 y 坐标非常接近(比如低于 10 像素),则需要将 p1 的 y 坐标固定为等于 p2 的 y 坐标,反之亦然。

    这是一个工作代码示例(请阅读 cmets):

    import cv2
    import numpy as np
    
    font = cv2.FONT_HERSHEY_COMPLEX
    
    img = cv2.imread('img.png', cv2.IMREAD_COLOR)
    
    # Remove image borders
    img = img[20:-20, 20:-20, :]
    
    imgray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    
    # https://pysource.com/2018/09/25/simple-shape-detection-opencv-with-python-3/
    # From the black and white image we find the contours, so the boundaries of all the shapes.
    _, threshold = cv2.threshold(imgray, 127, 255, cv2.THRESH_BINARY)
    _, contours, _ = cv2.findContours(threshold, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    
    c = contours[0]
    
    peri = cv2.arcLength(c, closed=True)
    approx = cv2.approxPolyDP(c, epsilon=0.01 * peri, closed=True)
    
    # Delat threshold
    t = 10
    
    # n - Number of vertices
    n = approx.shape[0]
    
    for i in range(n):
        #      p1              p2
        #       *--------------*
        #       |
        #       |
        #       |
        #       *
        #      p0
    
        p0 = approx[(i+n-1) % n][0]    # Previous vertex
        p1 = approx[i][0]              # Current vertex
        p2 = approx[(i + 1) % n][0]    # Next vertex
        dx = p2[0] - p1[0]             # Delta pixels in horizontal direction
        dy = p2[1] - p1[1]             # Delta pixels in vertical direction
    
        # Fix x index of vertices p1 and p2 to be with same x coordinate ([<p1>, <p2>] form horizontal line).
        if abs(dx) < t:
            if ((dx < 0) and (p0[0] > p1[0])) or ((dx > 0) and (p0[0] < p1[0])):
                p2[0] = p1[0]
            else:
                p1[0] = p2[0]
    
        # Fix y index of vertices p1 and p2 to be with same y coordinate ([<p1>, <p2>] form vertical line).
        if abs(dy) < t:
            if ((dy < 0) and (p0[1] > p1[1])) or ((dy > 0) and (p0[1] < p1[1])):
                p2[1] = p1[1]
            else:
                p1[1] = p2[1]
    
        approx[i][0] = p1
        approx[(i + 1) % n][0] = p2
    
    cv2.drawContours(img, [approx], 0, (0, 255, 0), 1)
    
    # Finally we display everything on the screen:
    cv2.imshow("img", img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    

    结果:

    注意:解决方案需要一些抛光(我的目的是获得面积最小的轮廓)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-09-12
      • 1970-01-01
      • 1970-01-01
      • 2023-03-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多