[英]How to detect a precise rectangle in a photo opencv
我使用这段代码来检测照片上的矩形,起初它运行良好,直到我意识到我会有一个 object,它也是中间的一个正方形:
问题:
我怎样才能正确检测到第一张结果图片上的 4 个角,而不检测正方形中间的东西的角。 非常感谢。
代码:
import numpy as np
import cv2
img = cv2.imread('Photos/lastBoard.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
canny = cv2.Canny(gray, 100, 200)
corners = cv2.goodFeaturesToTrack(gray, 25, 0.01, 50)
corner_list = []
for corner in corners:
x, y = corner.ravel()
if(y < 700 and (50 < x < 800 )):
corner_list.append([int(x), int(y)])
cv2.circle(img, (x, y), 5, (36, 255, 12), -1)
cv2.imshow("yo", img)
cv2.waitKey(0)
结果(中间没有东西):
我需要它处理的新图片:
错误的结果
我的男人,你没有使用我们在上一个问题中介绍的技术和处理,这让我心碎。 您已经有很多可以重复使用的功能。 您尝试分割的矩形具有独特的颜色(绿色),并且具有定义的面积和纵横比,看看您桌子上的所有东西,它们都比矩形小! 另外,矩形几乎是正方形! 这意味着它的纵横比接近1.0
。 如果你以某种方式分割矩形,近似它的角应该是相对容易的。
这是有价值的信息,因为它可以让您跟踪您的行动计划。 我看到你正在使用cv2.goodFeaturesToTrack
来检测所有东西的角落。 没关系,但可以简化。 我提出了一个与上次非常相似的行动计划:
HSV
的掩码contours
——我们正在寻找最大的绿色contour
,即矩形。area
和aspect ratio
过滤垃圾轮廓。让我们看看代码:
# imports:
import numpy as np
import cv2
# image path
path = "D://opencvImages//"
fileName = "table1.jpg"
# Reading an image in default mode:
inputImage = cv2.imread(path + fileName)
inputCopy = inputImage.copy()
# The HSV mask values:
lowerValues = np.array([58, 151, 25])
upperValues = np.array([86, 255, 75])
# Convert the image to HSV:
hsvImage = cv2.cvtColor(inputImage, cv2.COLOR_BGR2HSV)
# Create the HSV mask
mask = cv2.inRange(hsvImage, lowerValues, upperValues)
第一步旨在创建HSV
掩码。 与上次非常相似,我已经定义了感兴趣的HSV
范围并应用了与以前完全相同的东西。 稍后您可以(并且应该)探索更多奇特的技术,但让我们暂时坚持我们所知道的工作,因为该项目肯定很快就会到期。 这是结果:
你看到面具已经很漂亮了吗? 只有绿色圆盘和矩形在thresholding
处理中幸存下来。 矩形不完整并不重要,因为我们要用一个bounding rectangle
来近似它的轮廓,好吧。 让我们把这个坏男孩清理得更好一点。 使用filterArea
(这与我们上次看到的 function 完全相同)然后closing
( dilate
然后erode
)只是为了得到一个漂亮的面具:
# Run a minimum area filter:
minArea = 50
mask = areaFilter(minArea, mask)
# Pre-process mask:
kernelSize = 3
structuringElement = cv2.getStructuringElement(cv2.MORPH_RECT, (kernelSize, kernelSize))
iterations = 2
mask = cv2.morphologyEx(mask, cv2.MORPH_DILATE, structuringElement, None, None, iterations, cv2.BORDER_REFLECT101)
mask = cv2.morphologyEx(mask, cv2.MORPH_ERODE, structuringElement, None, None, iterations, cv2.BORDER_REFLECT101)
这是过滤后的掩码,噪音基本消失了:
现在,让我们找到contours
并根据area
和aspect ratio
进行过滤,就像上次一样。 然而,参数是不同的,因为我们的目标不是弹拨,而是矩形:
# Find the big contours/blobs on the filtered image:
contours, hierarchy = cv2.findContours(mask, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE)
# Store the poly approximation and bound
contoursPoly = [None] * len(contours)
# Store the corners of the square here:
detectedCorners = []
# Look for the outer bounding boxes:
for _, c in enumerate(contours):
# Approximate the contour to a polygon:
contoursPoly = cv2.approxPolyDP(c, 3, True)
# Convert the polygon to a bounding rectangle:
boundRect = cv2.boundingRect(contoursPoly)
# Get the bounding rect's data:
rectX = boundRect[0]
rectY = boundRect[1]
rectWidth = boundRect[2]
rectHeight = boundRect[3]
# Calculate the rect's area:
rectArea = rectWidth * rectHeight
# Calculate the aspect ratio:
aspectRatio = rectWidth / rectHeight
delta = abs(1.0 - aspectRatio)
# Set the min threshold values to identify the
# blob of interest:
minArea = 2500
epsilon = 0.2
好吧,到目前为止一切顺利,我希望。 如您所见,我将轮廓近似为 4 顶点多边形,然后计算其bounding rectangle
。 这个近似值应该非常适合我们感兴趣的 blob。 现在,应用轮廓过滤器并使用边界矩形数据来近似角。 我逐个逼近每个角,并将它们存储在detectedCorners
的Corners 数组中。 然后,我们可以绘制它们。 在这里,仍然在for
循环中:
# Is this bounding rectangle we
# are looking for?
if rectArea > minArea and delta < epsilon:
# Compute the corners/vertices:
# Corner 1 (top left)
corner1 = (rectX, rectY)
detectedCorners.append(corner1)
# Corner 2 (top right)
corner2 = (rectX + rectWidth, rectY)
detectedCorners.append(corner2)
# Corner 3 (bottom left)
corner3 = (rectX, rectY + rectHeight)
detectedCorners.append(corner3)
# Corner 4 (bottom right)
corner4 = (rectX + rectWidth, rectY + rectHeight)
detectedCorners.append(corner4)
# Draw the corner points:
for p in detectedCorners:
color = (0, 0, 255)
cv2.circle(inputCopy, (p[0], p[1]), 5, color, -1)
cv2.imshow("Square Corners", inputCopy)
cv2.waitKey(0)
这是两张图片的结果。 近似的角是红点:
下面是areaFilter
function的定义和实现:
def areaFilter(minArea, inputImage):
# Perform an area filter on the binary blobs:
componentsNumber, labeledImage, componentStats, componentCentroids = \
cv2.connectedComponentsWithStats(inputImage, connectivity=4)
# Get the indices/labels of the remaining components based on the area stat
# (skip the background component at index 0)
remainingComponentLabels = [i for i in range(1, componentsNumber) if componentStats[i][4] >= minArea]
# Filter the labeled pixels based on the remaining labels,
# assign pixel intensity to 255 (uint8) for the remaining pixels
filteredImage = np.where(np.isin(labeledImage, remainingComponentLabels) == True, 255, 0).astype('uint8')
return filteredImage
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.