从左上角到右下角的排序坐标

Ordering coordinates from top left to bottom right

如何尝试从左上角到右下角对不规则数组的点进行排序,如下图所示?

我考虑过的方法有:

部分困难是我不知道图像中会出现多少行和列,再加上点阵的不规则性。任何建议将不胜感激。

我提出以下想法:
1.统计点数(p)
2. 对于每个点,将其 x 和 y 坐标四舍五入为某个数字,例如
x = int(x/n)*n, y = int(y/m)*m 对于一些 n,m 3. 如果m,n太大,counts的数量会下降。迭代确定 m, n 以便点数 p 将被保留。

起始值可以与 max(x) - min(x) 对齐。对于搜索,请使用二进制搜索。 X 和 Y 缩放将彼此独立。

用自然的话来说,这将通过拉伸或缩小网格距离将各个点固定到网格点,直到所有点最多具有一个公共坐标(X 或 Y)但没有 2 个点重叠。你也可以称之为分类。

虽然问题有点老,但我最近在校准相机时遇到了类似的问题。

算法非常简单,基于this paper:

  • 求左上点:min(x+y)
  • 求右上点:max(x-y)
  • 从这些点创建一条直线。
  • 计算所有点到直线的距离
    • 如果小于圆的半径(或阈值):点在顶线。
    • 否则:点在块的其余部分。
  • 按 x 值对顶行的点进行排序并保存。
  • 重复直到没有剩余点数。

我的 python 实现如下所示:

#detect the keypoints
detector = cv2.SimpleBlobDetector_create(params)
keypoints = detector.detect(img)
img_with_keypoints = cv2.drawKeypoints(img, keypoints, np.array([]), (0, 0, 255), 
cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)

points = []
keypoints_to_search = keypoints[:]
while len(keypoints_to_search) > 0:
    a = sorted(keypoints_to_search, key=lambda p: (p.pt[0]) + (p.pt[1]))[0]  # find upper left point
    b = sorted(keypoints_to_search, key=lambda p: (p.pt[0]) - (p.pt[1]))[-1]  # find upper right point

    cv2.line(img_with_keypoints, (int(a.pt[0]), int(a.pt[1])), (int(b.pt[0]), int(b.pt[1])), (255, 0, 0), 1)

    # convert opencv keypoint to numpy 3d point
    a = np.array([a.pt[0], a.pt[1], 0])
    b = np.array([b.pt[0], b.pt[1], 0])

    row_points = []
    remaining_points = []
    for k in keypoints_to_search:
        p = np.array([k.pt[0], k.pt[1], 0])
        d = k.size  # diameter of the keypoint (might be a theshold)
        dist = np.linalg.norm(np.cross(np.subtract(p, a), np.subtract(b, a))) / np.linalg.norm(b)   # distance between keypoint and line a->b
        if d/2 > dist:
            row_points.append(k)
        else:
            remaining_points.append(k)

    points.extend(sorted(row_points, key=lambda h: h.pt[0]))
    keypoints_to_search = remaining_points

跳到这个旧线程,因为我刚刚处理了同样的事情:按从左到右、从上到下的位置对放置对象的草率对齐网格进行排序。原始 post 顶部的绘图完美地总结了它,除了此解决方案支持具有不同节点数的行。

小号。 Vogt 上面的脚本非常有用(下面的脚本完全基于 his/hers),但我的条件更窄。 Vogt 的解决方案适用于可能从水平轴倾斜的网格。我假设没有倾斜,所以我不需要比较与可能倾斜的顶线的距离,而是从单个点的 y 值。

Javascript 下面:

interface Node {x: number; y: number; width:number; height:number;}
const sortedNodes = (nodeArray:Node[]) => {
    let sortedNodes:Node[] = []; // this is the return value
    let availableNodes = [...nodeArray]; // make copy of input array
    while(availableNodes.length > 0){
        // find y value of topmost node in availableNodes. (Change this to a reduce if you want.)
        let minY = Number.MAX_SAFE_INTEGER;
        for (const node of availableNodes){
            minY = Math.min(minY, node.y)
        }
        // find nodes in top row: assume a node is in the top row when its distance from minY 
        // is less than its height
        const topRow:Node[] = [];
        const otherRows:Node[] = [];
        for (const node of availableNodes){
            if (Math.abs(minY - node.y) <= node.height){
                topRow.push(node);
            } else {
                otherRows.push(node);
            }
        }
        topRow.sort((a,b) => a.x - b.x); // we have the top row: sort it by x
        sortedNodes = [...sortedNodes,...topRow] // append nodes in row to sorted nodes
        availableNodes = [...otherRows] // update available nodes to exclude handled rows
    }
    return sortedNodes;
};

以上假设所有节点高度都相同。如果您有一些节点比其他节点高很多,请获取所有节点的最小节点高度值并使用它 而不是 迭代的“node.height”值。也就是说,您可以更改上面脚本的这一行以使用所有节点的最小高度而不是迭代的高度。

if (Math.abs(minY - node.y) <= node.height)