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

Python 如何使用opencv检测图像中的矩形(白板)?,python,image,opencv,machine-learning,computer-vision,Python,Image,Opencv,Machine Learning,Computer Vision,我有下面的图像。我想检测和透视变换矩形白板 我想检测这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.cvtC

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

我想检测这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)
导入cv2,操作系统
将numpy作为np导入
从google.colab.patches导入cv2_imshow
image=cv2.imread(“img.jpg”)
orig1=image.copy()
#1)灰度图像
灰色=cv2.CVT颜色(图像,cv2.COLOR\u BGR2GRAY)
#cv2_imshow(灰色)
#2)侵蚀
内核=np.one((5,5),np.uint8)
侵蚀=cv2。侵蚀(灰色,内核,迭代次数=1)
#cv2_imshow(侵蚀)
#3)阈值(大津)
模糊=cv2.高斯模糊(侵蚀,(5,5),0)
ret3,thresh=cv2.threshold(模糊,0255,cv2.thresh\u二进制+cv2.thresh\u大津)
#cv2_imshow(阈值)
#4)等高线
复制=阈值;orig=图像;
cnts=cv2.查找对象(复制、cv2.RETR\u外部、cv2.CHAIN\u近似值\u简单)
如果len(cnts)==2个其他cnts[1],则cnts=cnts[0]
面积=-1;c1=0
对于碳纳米管中的碳:
如果面积小于cv2,则面积(c):
面积=cv2。轮廓面积(c)
c1=c
cv2.等高线图(原始[c1],0,(0255,0),3)
ε=0.09*cv2.弧长(c1,真)
近似=cv2.近似聚合(c1,ε,真)
如果长度(近似值)!=4:
#那么它将在这里失败。
通过
cood=[]
对于范围(0,len(近似))内的i:
cood.追加([约[i][0][0],约[i][0][1]]
#5)视角转换
def重新排序(myPoints):
myPoints=np.数组(myPoints).重塑((4,2))
myPointsNew=np.zeros((4,1,2),dtype=np.int32)
add=myPoints.sum(1)
myPointsNew[0]=myPoints[np.argmin(添加)]
myPointsNew[3]=myPoints[np.argmax(添加)]
差异=np.差异(myPoints,轴=1)
myPointsNew[1]=myPoints[np.argmin(diff)]
myPointsNew[2]=myPoints[np.argmax(diff)]
返回myPointsNew
pts1=np.32(再订购(cood))
w=1000;h=1000;m1=1000;m2=1000
pts2=np.float32([[0,0],[w,0],[0,h],[w,h]]
矩阵=cv2.getPerspectiveTransform(pts1,pts2)
结果=cv2.透视图(原点1,矩阵,(m1,m2))
cv2_imshow(结果)
我也经历过,但不确定如何实施。
我无法检测和透视变换电路板。如果你们中有人能帮助我,那就太好了。另外,如果我的问题需要更多细节,请务必告诉我。

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

#查找轮廓并应用透视图
尝试:
copy=thresh.copy();orig=img.copy()
cnts=cv2.查找对象(复制、cv2.RETR\u外部、cv2.CHAIN\u近似值\u简单)
如果len(cnts)==2个其他cnts[1],则cnts=cnts[0]
面积=-1;c1=0
对于碳纳米管中的碳:
ε=0.01*cv2.弧长(c,真)
近似值=cv2.approxPolyDP(c,ε,真)
如果len(近似值)=4且面积小于cv2,则面积(c):
面积=cv2。轮廓面积(c)
c1=c;近似值1=近似值
翘曲=四点变换(原始,近似1.重塑(4,2))
cv2_imshow(翘曲)
除:
打印(“图像无法转换!!\n”)
#四点变换
def订单积分(pts):
# https://www.pyimagesearch.com/2016/03/21/ordering-coordinates-clockwise-with-python-and-opencv/
xSorted=pts[np.argsort(pts[:,0]),:]
最左边的=x排序[:2,:]
最右侧=X排序[2:,:]
leftMost=leftMost[np.argsort(leftMost[:,1]),:]
(tl,bl)=最左边
D=dist.cdist(tl[np.newaxis],最右边的“欧几里德”)[0]
(br,tr)=最右边的[np.argsort(D)[::-1],:]
返回np.array([tl,tr,br,bl],dtype=“float32”)
def四点变换(图像,pts):
# https://www.pyimagesearch.com/2014/08/25/4-point-opencv-getperspective-transform-example/
rect=顺序点(pts)
(tl,tr,br,bl)=rect
宽度a=np.sqrt(((br[0]-bl[0])**2)+((br[1]-bl[1])**2))
宽度b=np.sqrt(((tr[0]-tl[0])**2)+((tr[1]-tl[1])**2))
maxWidth=max(整数(宽度A),整数(宽度B))
heightA=np.sqrt(((tr[0]-br[0])**2)+((tr[1]-br[1])**2))
高度b=np.sqrt(((tl[0]-bl[0])**2)+((tl[1]-bl[1])**2))
最大高度=最大值(整数(高度A),整数(高度B))
dst=np.array([
[0, 0],
[maxWidth-1,0],
[maxWidth-1,maxHeight-1],
[0,maxHeight-1]],dtype=“float32”)
M=cv2.getPerspectiveTransform(rect、dst)
翘曲=cv2。翘曲透视图(图像,M,(最大宽度,最大高度))
回程翘曲
这是扭曲的图像:

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