使用OpenCV校正遮罩中形状的边

2024-09-23 16:19:26 发布

您现在位置:Python中文网/ 问答频道 /正文

我需要纠正一个形状(多边形)的边缘,如下面的一个

enter image description here

它是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)

有些边界不直。我需要它们完全垂直或水平。 我试图修改ε值,但没有成功


Tags: intruefor多边形cv2边缘形状closed
1条回答
网友
1楼 · 发布于 2024-09-23 16:19:26

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

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

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

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

结果:
enter image description here

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

相关问题 更多 >