代码之家  ›  专栏  ›  技术社区  ›  Sam12

检测棋盘中的方块OpenCV

  •  0
  • Sam12  · 技术社区  · 3 年前

    我在python中使用OpenCV检测到一个棋盘,使用:

    • 计算图像的边缘
    • 计算霍夫变换
    • 求Hough变换的局部极大值
    • 提取图像线条

    然后我用 findContours drawContours 功能:

      im_gray = cv2.imread('redLines.png', cv2.IMREAD_GRAYSCALE)
      kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (2, 2))  
      morphed = cv2.dilate(im_gray, kernel, iterations=1)
      (ret, thresh) = cv2.threshold(morphed, 128, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
      contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
      cv2.drawContours(thresh, contours, -1, (255, 255, 255), 3)
    

    效果很好,上一次的imshow看起来是这样的:

    enter image description here

    现在,我尝试检测网格中的每个正方形,并将其点保存在向量中的唯一索引中。

    我知道我可以用等高线阵列来做。但当我打印轮廓的长度时,它一直在快速变化,从2号到112号。。

    所以我想它没有很好地识别网格。

    如有任何帮助,我们将不胜感激。

    1 回复  |  直到 3 年前
        1
  •  6
  •   nathancy    3 年前

    一种方法是使用 contour area filtering + shape approximation 由于一个正方形有4个角,如果一个轮廓有四个顶点,我们可以假设它是一个正方形。

    检测到的绿色方块

    enter image description here

    孤立正方形

    enter image description here

    import cv2
    import numpy as np
    
    # Load image, grayscale, Gaussian blur, Otsu's threshold
    image = cv2.imread("1.png")
    mask = np.zeros(image.shape, dtype=np.uint8)
    original = image.copy()
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    blur = cv2.GaussianBlur(gray, (5,5), 0)
    thresh = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
    
    # Remove noise with morph operations
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3,3))
    opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=1)
    invert = 255 - opening
    
    # Find contours and find squares with contour area filtering + shape approximation
    cnts = cv2.findContours(invert, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    cnts = cnts[0] if len(cnts) == 2 else cnts[1]
    for c in cnts:
        area = cv2.contourArea(c)
        peri = cv2.arcLength(c, True)
        approx = cv2.approxPolyDP(c, 0.02 * peri, True)
        if len(approx) == 4 and area > 100 and area < 10000:
            x,y,w,h = cv2.boundingRect(c)
            cv2.drawContours(original, [c], -1, (36,255,12), 2)
            cv2.drawContours(mask, [c], -1, (255,255,255), -1)
    
    cv2.imshow("original", original)
    cv2.imshow("mask", mask)
    cv2.waitKey()