繁体   English   中英

如何使用 opencv 检测图像中的矩形(白板)?

[英]How to detect a rectangle (whiteboard) in an image using opencv?

我有以下图像。 我想检测和透视变换矩形白板。

在此处输入图像描述

我想检测这 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)

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

我设法获得了白板的 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

这是扭曲的图像: 扭曲的图像

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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