【问题标题】:OpenCV: Can't find large rectangle contourOpenCV:找不到大矩形轮廓
【发布时间】:2021-09-01 08:38:57
【问题描述】:

Opencv 版本:4.5

我正在尝试通过将对象设置在网格上并尽可能接近自上而下的照片来重新创建对象的尺寸,然后我将获得最大边界矩形的轮廓,然后进行透视翘曲。

我目前无法获得大边界正方形的轮廓,但是它不断地只找到较小的矩形/正方形,我认为这些矩形/正方形不够大,无法正确修复视角。

第一张图片:原图

第二张图片:我使用 openCV 的代码得到了什么

第三张图片:接近我的理想状态

我的代码:

import imutils
import numpy as np
import cv2 as cv

# load the query image
image = cv.imread("path/to/image")

# make image greyscale, blur, find edges
grayscale_image = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
thresh = cv.adaptiveThreshold(grayscale_image, 255, cv.ADAPTIVE_THRESH_GAUSSIAN_C,
                              cv.THRESH_BINARY, 11, 2)

# find contours in the threshed image, keep only the largest
# ones
cnts = cv.findContours(
    thresh.copy(), cv.RETR_LIST, cv.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
cnts = sorted(cnts, key=cv.contourArea, reverse=True)[:5]

# draw contours for reference
cv.drawContours(image, cnts, -1, (0, 255, 0), 3)

我尝试在精明边缘检测中使用双边滤波器或高斯模糊,而不是自适应阈值处理,但结果仍然找不到大矩形。

任何帮助将不胜感激,因为我不知道为什么它无法检测到更大的正方形。另外,如果人们认为有更好的方法来固定视角以便我可以准确地重新创建电路板尺寸,请告诉我。

【问题讨论】:

  • 没有必要画一个大的矩形,已知的网格点就足以适应透视,即使是不规则的放置。我建议您分解水平和垂直部分中的所有轮廓以找到角落(删除倾斜部分)。如果需要,您可以只保留靠近图像边缘的那些。

标签: python opencv image-processing opencv-contour


【解决方案1】:

您可以申请以下阶段:

  • 使用cv2.threshold(而不是cv2.adaptiveThreshold)应用阈值。
  • 应用带有长列向量的开口以仅保留垂直线。
  • vert_lines 中查找轮廓。
  • 从左到右对等高线进行排序。
  • 在草图(黑色)图像上绘制最左边和最右边的轮廓。
  • 应用带有长行向量的开口以仅保留水平线、查找轮廓、从上到下排序以及绘制顶部和底部轮廓。
  • 在草图图像中查找内部轮廓(包括左、右、顶和底线)。
    内轮廓是最小的。

这是一个代码示例:

import imutils
import numpy as np
import cv2

# load the query image
image = cv2.imread("image.png")

# make image greyscale, blur, find edges
grayscale_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

#thresh = cv2.adaptiveThreshold(grayscale_image, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2)
thresh = cv2.threshold(grayscale_image, 0, 255, cv2.THRESH_OTSU)[1]  # Apply automatic threshold (use THRESH_OTSU).

rect_im = np.zeros_like(thresh)  # Sketch image

# Apply opening with long column vector for keeping only the vertical lines.
vert_lines = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, np.ones(50))

# Apply opening with long row vector for keeping only the horizontal lines.
horz_lines = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, np.ones((1,50)))

# Find contours in vert_lines
cnts = imutils.grab_contours(cv2.findContours(vert_lines, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE))

# Sort contours left to right.
cnts = sorted(cnts, key=lambda c: cv2.boundingRect(c)[0])  # cv2.boundingRect(c)[0] is the left side x coordinate.

cv2.drawContours(rect_im, [cnts[0], cnts[-1]], -1, 255, -1) # Draw left and right contours

# Find contours in horz_lines
cnts = imutils.grab_contours(cv2.findContours(horz_lines, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE))

# Sort contours top to bottom.
cnts = sorted(cnts, key=lambda c: cv2.boundingRect(c)[1])  # cv2.boundingRect(c)[1] is the top y coordinate.

cv2.drawContours(rect_im, [cnts[0], cnts[-1]], -1, 255, -1)  # Draw top and bottom contours

# Find contours in rect_im
cnts = imutils.grab_contours(cv2.findContours(rect_im, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE))  # Note: use RETR_TREE for getting inner contour.

c = min(cnts, key=cv2.contourArea)  # Get the smallest contour

# Draw contour for reference
cv2.drawContours(image, [c], -1, (0, 255, 0), 3)

结果:

thresh:

vert_lines:

horz_lines:

左右行:

rect_im:

image(输出):

【讨论】:

  • 太棒了,感谢您提供如此彻底的分析。
猜你喜欢
  • 2018-03-11
  • 2021-11-19
  • 1970-01-01
  • 1970-01-01
  • 2011-11-27
  • 1970-01-01
  • 2018-02-13
  • 2012-05-10
  • 2019-12-03
相关资源
最近更新 更多