如何尝试从左上角到右下角对不规则阵列的点进行排序,如下图所示?
我考虑的方法是:
计算每个点距离图像左上角的距离(毕达哥拉斯定理),但对Y
坐标应用某种加权,以尝试优先考虑同一个'{{1例如row
将点排序为逻辑行,然后对每一行进行排序。
部分困难在于我不知道图像中将存在多少行和列以及点阵列的不规则性。任何建议都将不胜感激。
答案 0 :(得分:1)
即使问题有点老了,最近我在校准相机时也遇到了类似的问题。
该算法非常简单,并且基于this paper:
我的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
答案 1 :(得分:0)
我提出以下想法:
1.计算点数(p)
2.对于每个点,将x和y坐标向下舍入到某个数字,如
对于某些n,m x = int(x/n)*n, y = int(y/m)*m
3.如果m,n太大,计数将下降。迭代地确定m,n,以便保留点p
的数量。
起始值可能与max(x) - min(x)
一致。对于搜索采用二进制搜索。 X和Y缩放将彼此独立。
在自然语言中,这会通过拉伸或缩小网格距离将各个点固定到网格点,直到所有点最多具有一个公共坐标(X或Y)但没有2个点重叠。你也可以称之为分类。
答案 2 :(得分:0)
跳上这个旧线程,因为我刚刚处理了同样的事情:按从左到右、从上到下的位置对放置对象的草率对齐网格进行排序。原帖顶部的绘图完美地总结了它,只是该解决方案支持具有不同节点数的行。
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)