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

时间:2018-06-18 12:52:56

标签: python opencv image-processing cv2 image-morphology

我正在编码的工具中的第一个处理步骤之一是找到4个大黑方的外角的坐标。然后它们将用于进行单应变换,以便对图像进行去偏斜/不旋转(a.k.a透视变换),最终得到矩形图像。这是一个例子 - 旋转和嘈杂 - 输入(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只是一种扩张+侵蚀,我找到了罪魁祸首:

    import cv2, numpy as np
    img = cv2.imread('rotatednoisy-cropped.png', cv2.IMREAD_GRAYSCALE)
    kernel = np.ones((30, 30), np.uint8)
    img = cv2.dilate(img, kernel, iterations = 1)
    

    在这一步之后,它仍然可以:

    enter image description here

    然后

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

    给出

    enter image description here

    它已经不行了!

3 个答案:

答案 0 :(得分:4)

有关如何对图像进行校正的详细说明,请参阅this link

import libraries

Flask code

Tkinter code

if __name__ == '__main__':

    window.mainloop() #for tkinter This will run first
    app.run() #for flask This will run when I close the Tkinter windows

image result

答案 1 :(得分:2)

您可以尝试搜索并过滤掉您的特定轮廓(黑色矩形)并使用键对其进行排序。然后为每个轮廓(左,右,顶部,底部)选择极值点,您将获得点。请注意,此方法仅适用于此图片,如果图片在其他方向受到影响,则必须相应地更改代码。我不是专家,但我希望这有点帮助。

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

答案 2 :(得分:0)

您可以在使用合适的阈值进行二值化后将方块提取为单个blob,并根据大小选择合适的方块。如果需要,您也可以先使用中值滤波器去噪。

然后一个紧密旋转的边界矩形将为您提供角落(您可以通过在凸形船体上运行旋转卡尺来获得它。)