使用opencv python预测图像中的矩形

问题描述

我想预测图像中的矩形并仅使用 opencv python 将矩形绘制为框形。我使用以下代码进行预测和绘制矩形,但无法正常工作。



    import numpy as np
    import cv2
    from PIL import Image
    import sys
    
    Path='D:\Artificial intelligence\Phyton'
    filename='Test.png'
    
    
    # Load image,grayscale,Gaussian blur,and Otsu's threshold
    image = cv2.imread('D:\Artificial intelligence\Phyton\Img21122020113231AM.Jpg')
    gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
    thresh = cv2.threshold(gray,190,255,cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
    
    # Find contours and sort using contour area
    cnts = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
    cnts = cnts[0] if len(cnts) == 2 else cnts[1]
    cnts = sorted(cnts,key=cv2.contourArea,reverse=True)
    for c in cnts:
        # Highlight largest contour
        cv2.drawContours(image,[c],-1,(36,12),3)
        break
    
    
    cv2.imwrite(filename+'_Processingimage_color.jpg',image)

我的输入图像:

Input Image

我的结果:

My Result image

解决方法

对于形状检测,有一个名为 opencv-shape-detection 的很棒的教程。然而,教程中的预处理不会帮助您找到图像中的大盒子。您需要应用 adaptiveThreshold 而不是 threshold。以下是步骤:

    1. 调整图像大小并计算比例
    1. 平滑图像
    1. 应用自适应阈值
    1. 找到并抓住轮廓。
    1. 计算周长和近似长度
    1. 如果长度等于 4(意味着正方形或矩形),则绘制轮廓。

  • 第一步

    • 我们调整了图像的大小,使计算和检测更容易。但是,我们还需要计算比率,以免丢失每个轮廓的中心。
  • 第 2 步

    • enter image description here

    • 我们应用了高斯模糊来平滑图像。图像中的大部分伪影都被移除了。

    • blr = cv2.GaussianBlur(gry,(5,5),0)
      
  • 第 3 步

    • 使用不同的参数,简单的阈值化不能产生令人满意的结果。因此我使用 adaptiveThreshold 来得到结果:

    • enter image description here

    • thr = cv2.adaptiveThreshold(blr,255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,41,21)
      
  • 第 4 步

  • 第 5 步

  • 第 6 步

    • 如果近似长度等于 4,则绘制轮廓。结果将是:

    • enter image description here


代码:


import cv2
import imutils

# Load the image
img = cv2.imread("zE2lg.jpg")

# Resize the image
rsz = imutils.resize(img,width=300)

# Calculate the ratio
ratio = img.shape[0] / float(rsz.shape[0])

# Convert to gray-scale
gry = cv2.cvtColor(rsz,cv2.COLOR_BGR2GRAY)

# Apply Gaussian-blur
blr = cv2.GaussianBlur(gry,0)

# Apply threshold
thr = cv2.adaptiveThreshold(blr,21)

# Find and grab contours
cnt = cv2.findContours(thr.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cnt = imutils.grab_contours(cnt)

# Loop over contours
for c in cnt:
    mmn = cv2.moments(c)

    if mmn["m00"] != 0:
        x = int((mmn["m10"] / mmn["m00"]) * ratio)
        y = int((mmn["m01"] / mmn["m00"]) * ratio)

        prm = cv2.arcLength(c,True)  # perimeter
        apx = cv2.approxPolyDP(c,0.09 * prm,True)  # approximation

        if len(apx) == 4:
            c = c.astype("float")
            c *= ratio
            c = c.astype("int")
            cv2.drawContours(img,[c],-1,(0,255),thickness=5)
,

按照以下步骤,您应该能够在此特定图像中检测到您的纸板箱。您应该能够使用 numpy 和 OpenCV 完成所有这些工作。不过这将是很多工作,所以我还没有完成。如果其他人想通过它并提供源代码,请随时将他们的答案标记为正确的答案而不是这个答案。

  1. 将图像的副本转换为 HSV 色彩空间。
  2. 检测您的纸板颜色,如深橙色或深黄色。如果 HSV 范围是 0-360、0-255、0-255,那么您想要检测的颜色范围将在 20-60、20-255、20-100 左右。
  3. 将结果转换为二维黑白图像。
  4. 使用较小的内核大小执行形态腐蚀以消除嘈杂的斑点。也许内核大小约为 3x3。
  5. 使用大内核大小执行形态学扩张,以连接任何断开连接的区域。也许内核大小约为 20x20。
  6. 找到最大的轮廓对象。
  7. 将轮廓转换为最适合的四边形,以去除右侧较小的纸板箱。我有时发现在将轮廓转换为四边形之前先将其转换为凸包会很有帮助。
  8. 在原始图像上绘制四边形。或者把它剪掉。或者您想用它做什么。

此 stackoverflow 帖子将有助于第 7 步: How to force approxPolyDP() to return only the best 4 corners? - Opencv 2.4.2

可以在此处找到我上面概述的方法的另一种替代潜在解决方案(在检测到棕色纸板颜色后): Extracting the dimensions of a rectangle