如何找到这4个方格外角的坐标?(如果图像旋转,形态闭合/打开不保留正方形)

2024-06-13 14:54:00 发布

您现在位置:Python中文网/ 问答频道 /正文

在我编写代码的工具中,第一个处理步骤是找到4个大的黑色方块的外角的坐标。然后它们将被用来做一个单形变换,以便对图像进行倾斜/取消旋转(即透视变换),最终得到一个矩形图像。下面是一个-rotated and noise-input(download link here)的示例:

enter image description here

为了只保留大的正方形,我使用了morphological transformations类似的关闭/打开:

import cv2, numpy as np
img = cv2.imread('rotatednoisy-cropped.png', cv2.IMREAD_GRAYSCALE)
kernel = np.ones((30, 30), np.uint8)
img = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
cv2.imwrite('output.png', img)

输入文件(download link):

enter image description here

形态变换后的输出:

enter image description here

问题:输出的方块不再是正方形,因此方块左上角的坐标将根本不精确!在

我可以减小内核的大小,但这样会保留更多不需要的小元素。在

问题:如何更好地检测正方形的角点?


注:

  • 由于morphological closing只是一种膨胀+侵蚀,我找到了罪魁祸首:

    ^{pr2}$

    完成此步骤后,仍然可以:

    enter image description here

    那么

    img = cv2.erode(img, kernel, iterations = 1)
    

    给予

    enter image description here

    再也不行了!


Tags: 工具代码图像imgpngdownloadnplink
3条回答

你可以尝试搜索并过滤出你的特定轮廓(黑色矩形),然后用一个键对它们进行排序。然后为每个轮廓选择极值点(左、右、上、下),你就会得到这些点。请注意,此方法仅适用于此图片,如果图片是在其他方向被保护的,则必须相应地更改代码。我不是专家,但我希望这能有所帮助。在

import numpy as np
import cv2


img = cv2.imread("rotate.jpg")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, threshold = cv2.threshold(gray,150,255,cv2.THRESH_BINARY)
im, contours, hierarchy = cv2.findContours(threshold,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
contours.sort(key=lambda c: np.min(c[:,:,1]))
j = 1

if len(contours) > 0:
    for i in range(0, len(contours)):
        size = cv2.contourArea(contours[i])
        if 90 < size < 140:
            if j == 1:
                c1 = contours[i]
                j += 1
            elif j == 2:
                c2 = contours[i]
                j += 1
            elif j == 3:
                c3 = contours[i]
                j += 1
            elif j == 4:
                c4 = contours[i]
                break

Top = tuple(c1[c1[:, :, 1].argmin()][0])
Right = tuple(c2[c2[:, :, 0].argmax()][0])
Left = tuple(c3[c3[:, :, 0].argmin()][0])
Bottom = tuple(c4[c4[:, :, 1].argmax()][0])

cv2.circle(img, Top, 2, (0, 255, 0), -1)
cv2.circle(img, Right, 2, (0, 255, 0), -1)
cv2.circle(img, Left, 2, (0, 255, 0), -1)
cv2.circle(img, Bottom, 2, (0, 255, 0), -1)

cv2.imshow("Image", img)
cv2.waitKey(0)

结果:

enter image description here

您可以在二值化后使用适当的阈值将方块提取为单个斑点,并根据大小选择适当的方块。你也可以先用中值滤波器去噪。在

然后,一个紧密旋转的边界矩形将为您提供角点(您可以通过在凸面外壳上运行旋转卡钳来获得它)。在

有关如何反扭曲图像的详细说明,请参见this link。在

import cv2
import numpy as np

def corners(box):
    cx,cy,w,h,angle = box[0][0],box[0][1],box[1][0],box[1][1],box[2]
    CV_PI = 22./7.
    _angle = angle*CV_PI/180.;
    b = np.cos(_angle)*0.5;
    a = np.sin(_angle)*0.5;

    pt = []
    pt.append((int(cx - a*h - b*w),int(cy + b*h - a*w)));
    pt.append((int(cx + a*h - b*w),int(cy - b*h - a*w)));
    pt.append((int(2*cx - pt[0][0]),int(2*cy - pt[0][1])));
    pt.append((int(2*cx - pt[1][0]),int(2*cy - pt[1][1])));
    return pt

if __name__ == '__main__':

    image = cv2.imread('image.jpg',cv2.IMREAD_UNCHANGED)

    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

    n = 3
    sigma = 0.3 * (n/2 - 1) + 0.8
    gray = cv2.GaussianBlur(gray, ksize=(n,n), sigmaX=sigma)

    ret,binary = cv2.threshold(gray, 0, 255, cv2.THRESH_OTSU+cv2.THRESH_BINARY)

    _,contours,_ = cv2.findContours(binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)

    contours.sort(key=lambda x: len(x), reverse=True)

    points = []
    for i in range(0,4):
        shape = cv2.approxPolyDP(contours[i], 0.05*cv2.arcLength(contours[i],True), True)
        if len(shape) == 4:
            points.append(shape)

    points = np.array(points,dtype=np.int32)
    points = np.reshape(points, (-1,2))
    box = cv2.minAreaRect(points)
    pt = corners(box)

    for i in range(0,4):
       image = cv2.line(image, (pt[i][0],pt[i][1]), (pt[(i+1)%4][0],pt[(i+1)%4][1]), (0,0,255))


    (h,w) = image.shape[:2]
    (center) = (w//2,h//2)
    angle = box[2]

    if angle < -45:
        angle = (angle+90)
    else:
        angle = -angle

    M = cv2.getRotationMatrix2D(center, angle, 1.0)
    rotated = cv2.warpAffine(image, M, (w,h), flags=cv2.INTER_CUBIC, borderMode=cv2.BORDER_CONSTANT)

    cv2.imshow('image', image)
    cv2.imshow('rotated', rotated)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

imageresult

相关问题 更多 >