繁体   English   中英

如何检测照片中的精确矩形 opencv

[英]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来检测所有东西的角落。 没关系,但可以简化。 我提出了一个与上次非常相似的行动计划:

  1. 尝试使用颜色分割矩形,让我们计算一个基于HSV的掩码
  2. 让我们使用区域过滤器和一些形态来清除面罩的噪音
  3. 寻找contours ——我们正在寻找最大的绿色contour ,即矩形。
  4. 感兴趣的轮廓具有定义的特征。 使用areaaspect ratio过滤垃圾轮廓。
  5. 一旦你有了感兴趣的轮廓/斑点,就可以近似它的角。

让我们看看代码:

# 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 完全相同)然后closingdilate然后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并根据areaaspect 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM