【问题标题】:How to detect a rectangle (whiteboard) in an image using opencv?如何使用opencv检测图像中的矩形(白板)?
【发布时间】:2021-07-03 06:14:15
【问题描述】:

我有以下图片。我想对矩形白板进行检测和透视变换。

我想检测这 4 个边界/角并对其应用透视变换。请看下图:

我无法检测到矩形的边界。这是我尝试过的:

import cv2, os
import numpy as np
from google.colab.patches import cv2_imshow


image = cv2.imread("img.jpg")
orig1 = image.copy()
# 1) Grayscale image
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# cv2_imshow(gray)
# 2) Erosion
kernel = np.ones((5, 5), np.uint8)
erosion = cv2.erode(gray, kernel, iterations = 1)
# cv2_imshow(erosion)

# 3) Thresholding (OTSU)
blur = cv2.GaussianBlur(erosion, (5,5),0)
ret3, thresh = cv2.threshold(blur,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
# cv2_imshow(thresh)

# 4) Contours
copy = thresh; orig = image; 
cnts = cv2.findContours(copy, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
area = -1; c1 = 0
for c in cnts:
    if area < cv2.contourArea(c):
        area = cv2.contourArea(c)
        c1 = c
cv2.drawContours(orig,[c1], 0, (0,255,0), 3)    

epsilon = 0.09 * cv2.arcLength(c1,True)
approx = cv2.approxPolyDP(c1,epsilon,True)

if len(approx) != 4:
    # Then it will fail here.
    pass 
cood = []
for i in range(0, len(approx)):
    cood.append([approx[i][0][0], approx[i][0][1]])

# 5) Perspective Transformation
def reorder(myPoints):
    myPoints = np.array(myPoints).reshape((4, 2))
    myPointsNew = np.zeros((4, 1, 2), dtype=np.int32)
    add = myPoints.sum(1)
    myPointsNew[0] = myPoints[np.argmin(add)]
    myPointsNew[3] =myPoints[np.argmax(add)]
    diff = np.diff(myPoints, axis=1)
    myPointsNew[1] =myPoints[np.argmin(diff)]
    myPointsNew[2] = myPoints[np.argmax(diff)] 
    return myPointsNew

pts1 = np.float32(reorder(cood))
w = 1000; h = 1000; m1 = 1000; m2 = 1000
pts2 = np.float32([[0, 0], [w, 0], [0, h], [w, h]])
matrix = cv2.getPerspectiveTransform(pts1, pts2)
result = cv2.warpPerspective(orig1, matrix, (m1, m2)) 
cv2_imshow(result)

我也经历过Microsoft's research,但不知道如何实现。 我无法检测和透视变换板。如果你们中的任何人都可以帮助我,那就太好了。另外,如果我的问题需要更多详细信息,请告诉我。

【问题讨论】:

  • 您尝试过基于颜色的方法吗?它总是同一个板子吗?比你知道的宽高比。然后通过一些边缘检测/轮廓检测它应该可以工作
  • 我还没有尝试过基于颜色的方法。但是,董事会可能不一样。我们无法确定坐标。有没有办法概括它?
  • 问题是曝光过度的墙壁,所以墙壁很白,而不是他的自然色灰色。所以你必须先解决这个问题。我还看到您的图像质量很差。基于母猪纹理的方法将是困难的。也许开始寻找一些模型来检测图像中的白板?
  • @Bamwani 我试过了。但是,它不起作用。

标签: python image opencv machine-learning computer-vision


【解决方案1】:

我设法获得了白板的 4 个坐标。我使用自适应阈值检测边缘而不是精明边缘检测,不确定该方法是否正确,但它给出了所需的结果。 这是相同的代码。

import ...
img = cv2.imread("path-to-image")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
thresh = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 199, 5)
cv2_imshow(thresh)

# finding contours and applying perspective
try:
    copy = thresh.copy(); orig = img.copy()
    cnts = cv2.findContours(copy, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    cnts = cnts[0] if len(cnts) == 2 else cnts[1]
    area = -1; c1 = 0

    for c in cnts:
        epsilon = 0.01 * cv2.arcLength(c,True)
        approx = cv2.approxPolyDP(c,epsilon,True)
        if len(approx) == 4 and area < cv2.contourArea(c):
            area = cv2.contourArea(c)
            c1 = c; approx1 = approx

    warped = four_point_transform(orig, approx1.reshape(4, 2))
    cv2_imshow(warped)
except:
    print("Image cannot be transformed!!\n")

# four point transform
def order_points(pts):
    # https://www.pyimagesearch.com/2016/03/21/ordering-coordinates-clockwise-with-python-and-opencv/
    xSorted = pts[np.argsort(pts[:, 0]), :]
    leftMost = xSorted[:2, :]
    rightMost = xSorted[2:, :]
    leftMost = leftMost[np.argsort(leftMost[:, 1]), :]
    (tl, bl) = leftMost
    D = dist.cdist(tl[np.newaxis], rightMost, "euclidean")[0]
    (br, tr) = rightMost[np.argsort(D)[::-1], :]
    return np.array([tl, tr, br, bl], dtype="float32")

def four_point_transform(image, pts):
    # https://www.pyimagesearch.com/2014/08/25/4-point-opencv-getperspective-transform-example/
    rect = order_points(pts)
    (tl, tr, br, bl) = rect  
    widthA = np.sqrt(((br[0] - bl[0]) ** 2) + ((br[1] - bl[1]) ** 2))
    widthB = np.sqrt(((tr[0] - tl[0]) ** 2) + ((tr[1] - tl[1]) ** 2))
    maxWidth = max(int(widthA), int(widthB))
    heightA = np.sqrt(((tr[0] - br[0]) ** 2) + ((tr[1] - br[1]) ** 2))
    heightB = np.sqrt(((tl[0] - bl[0]) ** 2) + ((tl[1] - bl[1]) ** 2))
    maxHeight = max(int(heightA), int(heightB))
    dst = np.array([
        [0, 0],
        [maxWidth - 1, 0],
        [maxWidth - 1, maxHeight - 1],
        [0, maxHeight - 1]], dtype = "float32")
    M = cv2.getPerspectiveTransform(rect, dst)
    warped = cv2.warpPerspective(image, M, (maxWidth, maxHeight))
    return warped

这是扭曲的图像:

【讨论】:

    猜你喜欢
    • 2020-07-02
    • 2013-03-23
    • 1970-01-01
    • 1970-01-01
    • 2019-11-29
    • 2012-05-21
    • 1970-01-01
    • 2016-03-18
    • 1970-01-01
    相关资源
    最近更新 更多