Python 如何在网格中对cv2轮廓进行排序,这可能会有一些失真?

Python 如何在网格中对cv2轮廓进行排序,这可能会有一些失真?,python,python-3.x,opencv,computer-vision,opencv3.0,Python,Python 3.x,Opencv,Computer Vision,Opencv3.0,我已经编写了一个python文件来检测cv2网格中的轮廓,并通过从左到右向下的列对它们进行排序。(请参见下面的grid1图像) 这是一个非常简单的排序方法。我拉过轮廓的左上角,按其x进行排序,然后按其y坐标进行排序,然后使用排序后的角对轮廓列表进行排序。当网格完全笔直时,此操作效果良好 现在,如果网格有变形,那么从网格2看,这不再有效。我们可以看到,标记为2的工件左上角的x坐标小于标记为1的工件左上角的x坐标(如绿线所示) 因此,当我应用为grid1工作的排序函数时,它按x然后y排序,因此标记

我已经编写了一个python文件来检测cv2网格中的轮廓,并通过从左到右向下的列对它们进行排序。(请参见下面的grid1图像)

这是一个非常简单的排序方法。我拉过轮廓的左上角,按其
x
进行排序,然后按其
y
坐标进行排序,然后使用排序后的角对轮廓列表进行排序。当网格完全笔直时,此操作效果良好

现在,如果网格有变形,那么从网格2看,这不再有效。我们可以看到,标记为
2
的工件左上角的
x
坐标小于标记为
1
的工件左上角的
x
坐标(如绿线所示)

因此,当我应用为grid1工作的排序函数时,它按
x
然后
y
排序,因此标记为
2
的工件被错误地排序为排序轮廓的第一个元素,而不是第二个元素

我正在寻找一个好的方法来正确分类这两种情况


任何人有什么建议吗?

您可以根据原点的拐角距离和相对拐角位置来选择订购

  • 查找轮廓和层次结构。
    保持轮廓无子对象(基于层次)
  • 查找边界矩形的角点
根据以下条件分析角点(或查找更简单的条件):

  • 左上角等高线是具有左上角最小距离的等高线
  • 右下角等高线是左上角距离最大的等高线
  • 其他两个轮廓可以用最大x和最大y分开(去掉左上角和右下角后)
下面的解决方案以颜色绘制边界矩形以进行测试:

  • 红色的
  • 绿色的
  • 蓝色的
  • 黄色的
  • 这是一个工作代码示例(请阅读注释):

    结果:

    请添加一些代码!我真的不明白你想做什么。你能解释一下你不明白的部分吗?我将尝试澄清?谢谢你的回答我没有时间回顾并尝试实现我的代码,但如果一切顺利,我将在下周查看并接受:)谢谢你的回答。它确实适用于
    2x2
    网格。不幸的是,我想要的东西可以用于自然数n,m的
    nxm
    网格。不过,我确实提出了一个涉及排序和次排序的通用解决方案。我接受这个答案,因为它确实适用于上述问题。
    import numpy as np
    import cv2
    
    # Read input image as Grayscale
    img = cv2.imread('img.png', cv2.IMREAD_GRAYSCALE)
    
    # Convert img to uint8 binary image with values 0 and 255
    # All black pixels goes to 0, and other pixels goes to 255
    ret, thresh_gray = cv2.threshold(img, 1, 255, cv2.THRESH_BINARY)
    
    # Find contours in thresh_gray.
    cnts, hiers = cv2.findContours(thresh_gray, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)[-2:]  # [-2:] indexing takes return value before last (due to OpenCV compatibility issues).
    
    corners = [] # List of corners
    dist = np.array([]) # Array of distance from axes origin
    
    # Iterate cnts and hiers, find bounding rectangles, and add corners to a list
    for c, h in zip(cnts, hiers[0]):
        # If contours has no child
        if h[2] == -1:
            # Get bounding rectangle
            x, y, w, h = cv2.boundingRect(c)
    
            # Append corner to list of corners - format is corners[i] holds a tuple: ((x0, y0), (x1, y1))
            p0 = (x, y)
            p1 = (x+w, y+h)
            corners.append((p0, p1))
    
            # Distance of corners from origin
            d = np.array([np.linalg.norm(p0), np.linalg.norm(p1)])
    
            if dist.size == 0:
                dist = d
            else:
                dist = np.vstack((dist, d))
    
    
    top_left = np.argmin(dist[:,0]) # Index of top left corner (assume minimum distance from origin)
    bottom_right = np.argmax(dist[:,1]) # Index of top bottom right corner (assume maximum distance from origin)
    
    tmp_corners = np.array(corners)
    tmp_corners[top_left, :, :] = np.array(((0,0), (0,0))) #Ignore top_left corners
    tmp_corners[bottom_right, :, :] = np.array(((0,0), (0,0))) #Ignore bottom_right corners
    bottom_left = np.argmax(tmp_corners[:,1,1]) #Maximum y is bottom left
    tmp_corners[bottom_left, :, :] = np.array(((0,0), (0,0))) #Ignore bottom_left corners
    top_right = np.argmax(tmp_corners[:,1,0])  #Maximum x is top right
    
    # Convert Grayscale to BGR (just for testing - for drawing rectangles in green color).
    out = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
    
    # Draw rectangles (for testing)
    # 1. Red
    # 2. Green
    # 3. Blue
    # 4. Yellow
    cv2.rectangle(out, corners[top_left][0], corners[top_left][1], (0, 0, 255), thickness = 2)
    cv2.rectangle(out, corners[bottom_left][0], corners[bottom_left][1], (0, 255, 0), thickness = 2)
    cv2.rectangle(out, corners[top_right][0], corners[top_right][1], (255, 0, 0), thickness = 2)
    cv2.rectangle(out, corners[bottom_right][0], corners[bottom_right][1], (0, 255, 255), thickness = 2)
    
    cv2.imwrite('out.png', out)  #Save out to file (for testing).
    
    
    # Show result (for testing).
    cv2.imshow('thresh_gray', thresh_gray)
    cv2.imshow('out', out)
    cv2.waitKey(0)
    cv2.destroyAllWindows()