从左上到右下排序坐标

Posted

技术标签:

【中文标题】从左上到右下排序坐标【英文标题】:Ordering coordinates from top left to bottom right 【发布时间】:2015-06-20 05:21:13 【问题描述】:

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

我考虑过的方法是:

计算每个点到图像左上角的距离(毕达哥拉斯定理),但对Y 坐标应用某种加权,以尝试优先考虑相同“row”上的点,例如distance = SQRT((x * x) + (weighting * (y * y)))

将点排序为逻辑行,然后对每一行进行排序。

部分困难在于我不知道图像中会出现多少行和列以及点阵列的不规则性。任何建议将不胜感激。

【问题讨论】:

也许尝试用英语表达决定一个点是属于一行还是下一行的规则。例如,圆圈的 size 是否有意义?尝试画更大或更小,看看这是否会影响你的决定。规则是否与是否有一条清晰、通畅的水平线可以在点下方绘制而不会侵犯下一条线有关? @MarkSetchell 谢谢你的想法,你肯定给了我一些思考。 您是否假设所有行的点数都相同? 相关问答:***.com/a/38693156/10491596 有人可以在问题中添加 Python 和 Numpy 标签吗?我试图寻找这个,它是一个很好的例子!谢谢 【参考方案1】:

尽管这个问题有点老了,但我最近在校准相机时遇到了类似的问题。

算法相当简单,基于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

【讨论】:

我收到以下错误,ValueError:具有多个元素的数组的真值不明确。在这一行使用 a.any() 或 a.all(),a = sorted(keypoints_to_search, key=lambda p: (p.pt[0]) 知道如何解决它吗? 我假设该行中没有缺少 + (p.pt[1]))[0]。它应该适用于对象包含“pt”成员的任何对象列表,该成员是至少两个数字作为 keypoints_to_search 的列表。我认为有你的问题。否则,您可以自己以另一种方式编写排序(a 必须是点 x 和 y 值之和最小的点,b 必须是 x 和 y 之间差异最大的点)。你在使用 opencv 关键点吗? 好的我在这里发布了问题,目前使用轮廓而不是关键点***.com/questions/66946804/…【参考方案2】:

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

S。上面 Vogt 的脚本非常有用(下面的脚本完全基于他/她的脚本),但我的条件更窄。 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)

【讨论】:

【参考方案3】:

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

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

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

【讨论】:

以上是关于从左上到右下排序坐标的主要内容,如果未能解决你的问题,请参考以下文章

Python:使用 OpenCV 从左上角到右下角对项目进行排序

Excel 里怎么对一块区域数据从左上到右下一列列的由小到大排序?

如何从左上角到右下角排列坐标?

在矩阵中找到从左上角到右下角的路径有问题吗?

对给定模式中的以下坐标进行排序:

查找从左上角到右下角的所有路径问题。以数组为参数的递归解法输出说明