【问题标题】:How to detect rectangles with rounded corners more accurately如何更准确地检测圆角矩形
【发布时间】:2022-01-17 05:39:39
【问题描述】:

我正在尝试创建一个需要很长时间才能在这里解释的程序,所以我会告诉你们我需要帮助的部分。

这里我需要检测一个矩形(在我们的示例中将是一个车牌)。它几乎完美地完成了识别,但我希望它更精确。这是我使用的示例图像。

如您所见,它在找到它方面做得相当不错,但我也想考虑圆角。

这里是源代码

import numpy as np
import cv2
import imutils

def find_edges(image):
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    gray = cv2.GaussianBlur(gray, (3, 3), 0)
    edged = cv2.Canny(image=gray, threshold1=100, threshold2=200)
    cnts = cv2.findContours(edged.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
    cnts = imutils.grab_contours(cnts)
    cnts = sorted(cnts, key = cv2.contourArea, reverse = True)[:5]
    for c in cnts:
        peri = cv2.arcLength(c, True)
        approx = cv2.approxPolyDP(c, 0.02 * peri, True)
        if len(approx) == 4:
            screenCnt = approx
            break
    return screenCnt


image = cv2.imread('img/plate.jpeg')
cnt = find_edges(image)
cv2.drawContours(image, [cnt], -1, (0, 255, 0), 2)
cv2.imshow('Outline', image)
cv2.waitKey(0)
cv2.destroyAllWindows()

我有什么方法可以实现这一点以及如何实现,还是我在这方面努力太多了?

编辑:添加示例图片。很抱歉之前没有包括在内,我的错。

【问题讨论】:

  • 你已经有了一个很好的轮廓近似值。您可以沿垂直于侧面的短段对图像进行采样,并检测从白色到黑色(或从蓝色到黑色)的过渡。这将为您提供更准确的点,您可以使用拟合线连接这些点。
  • @fmw42 添加了示例图片。
  • 您还可以尝试在 ROI 中调整边缘周围的霍夫线。
  • 从你想要的轮廓,得到旋转的矩形。请参阅docs.opencv.org/4.1.1/d3/dc0/… 的 cv2.minAreaRect()
  • 你想买黑色外盘架吗?如果是这样,为什么?为什么不直接获取数字周围的白色矩形?

标签: python opencv image-processing cv2


【解决方案1】:

首先,在您的find_edges 函数中,我将screenCnt = approx 替换为screenCnt = c,以便将所有坐标保留在生成的检测轮廓中:

def find_edges(image):
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    gray = cv2.GaussianBlur(gray, (3, 3), 0)
    edged = cv2.Canny(image=gray, threshold1=100, threshold2=200)
    cnts = cv2.findContours(edged.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
    cnts = imutils.grab_contours(cnts)
    cnts = sorted(cnts, key = cv2.contourArea, reverse = True)[:5]
    for c in cnts:
        peri = cv2.arcLength(c, True)
        approx = cv2.approxPolyDP(c, 0.02 * peri, True)
        if len(approx) == 4:
            screenCnt = c
            break
    return screenCnt

然后,我定义了一个函数get_opposites,它将接收一个轮廓,并从轮廓返回彼此相距最远的两个坐标:

def get_opposites(cnt):
    current_max = 0
    c = None
    for a, b in combinations(cnt, 2):
        current_distance = np.linalg.norm(a - b)
        if current_distance > current_max:
           current_max = current_distance
           c = a, b
    return c

接下来,我将从图像中检测到的轮廓 (使用您定义的 find_edges 函数 + 我的更改) 分为两部分;第一部分包含轮廓的左上角 + 右下角四分之一,第二部分包含轮廓的右上角 + 左下角四分之一:

image = cv2.imread('img/plate.jpeg')
cnt = find_edges(image)
xs = cnt[..., 0]
ys = cnt[..., 1]
x_mid = (np.amin(xs) + np.amax(xs)) // 2
y_mid = (np.amin(ys) + np.amax(ys)) // 2
tl_br = cnt[((ys < y_mid) & (xs < x_mid)) | ((ys > y_mid) & (xs > x_mid))]
tr_bl = cnt[((ys > y_mid) & (xs < x_mid)) | ((ys < y_mid) & (xs > x_mid))]

最后,我使用``函数从每个部分获取两个坐标,并将它们放入一个numpy数组中以绘制到图像上:

p1, p3 = get_opposites(tl_br)
p2, p4 = get_opposites(tr_bl)
cv2.polylines(image, np.array([[p1, p2, p3, p4]], np.int32), True, (0, 255, 0), 2)
cv2.imshow('Outline', image)
cv2.waitKey(0)
cv2.destroyAllWindows()

输出:

大家一起:

import numpy as np
import cv2
import imutils
from itertools import combinations
       
def find_edges(image):
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    gray = cv2.GaussianBlur(gray, (3, 3), 0)
    edged = cv2.Canny(image=gray, threshold1=100, threshold2=200)
    cnts = cv2.findContours(edged.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
    cnts = imutils.grab_contours(cnts)
    cnts = sorted(cnts, key = cv2.contourArea, reverse = True)[:5]
    for c in cnts:
        peri = cv2.arcLength(c, True)
        approx = cv2.approxPolyDP(c, 0.02 * peri, True)
        if len(approx) == 4:
            screenCnt = c
            break
    return screenCnt

def get_opposites(cnt):
    current_max = 0
    c = None
    for a, b in combinations(cnt, 2):
        current_distance = np.linalg.norm(a - b)
        if current_distance > current_max:
           current_max = current_distance
           c = a, b
    return c

image = cv2.imread('img/plate.jpeg')
cnt = find_edges(image)
xs = cnt[..., 0]
ys = cnt[..., 1]
x_mid = (np.amin(xs) + np.amax(xs)) // 2
y_mid = (np.amin(ys) + np.amax(ys)) // 2
tl_br = cnt[((ys < y_mid) & (xs < x_mid)) | ((ys > y_mid) & (xs > x_mid))]
tr_bl = cnt[((ys > y_mid) & (xs < x_mid)) | ((ys < y_mid) & (xs > x_mid))]

p1, p3 = get_opposites(tl_br)
p2, p4 = get_opposites(tr_bl)
cv2.polylines(image, np.array([[p1, p2, p3, p4]], np.int32), True, (0, 255, 0), 2)
cv2.imshow('Outline', image)
cv2.waitKey(0)
cv2.destroyAllWindows()

【讨论】:

  • 解释清楚也很好,谢谢!
  • @Onur 我的荣幸!
猜你喜欢
  • 2011-08-28
  • 2013-11-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多