我正在开展一个项目,其中一些飞行物体扫描地面以了解其确切位置。例如,让下面的网格成为地面,字母字面意思放在地上。网格中的每个三角形都是唯一的。
A---B---C---D
\ / \ / \ / \
E---A---H---G
/ \ / \ / \ / \
H---F---B---E---A
飞行物体可以访问包含这些字母的文件,以空格分隔。零表示空节点。
A B C D 0
E A H G 0
H F B E A
飞行物体拍摄地面照片,但由于它靠近地面,它只能看到地面的一部分。
A---H---G
\ / \ /
B---E
飞机使用OpenCV扫描此模式,识别数字。它还可以在每个扫描的数字上放置一个坐标。例如,A
放置在拍摄照片上的坐标(100,200),坐标(301,201)上的H
,坐标(195,403)上的B
等等。
给定带有(近似)坐标(在图片上)的字母,以及图片中心的坐标,飞机如何准确找出它在网格上的位置。如果可以产生以下输出,那将是最佳的:
如果这是一个非常广泛的问题,我很抱歉,我根本不知道如何解决它。我尝试将问题表示为subgraph isomorphism problem,但该问题的解决方案是NP完全的。网格最多可包含200个字母。
我目前正在使用python,但是对此问题(或想法)的任何解决方案都表示赞赏。
编辑:问题的一部分可能有点模糊。在找到飞机飞行的顶点/边/三角形之后,我需要在给定的网格文件上找到这个顶点/边/三角形。这就是我尝试子图同构问题的原因。因此,如果飞机发现它悬停在上面:
非常感谢!
答案 0 :(得分:1)
一个问题是你过度复杂了。子图同构比你想做的要困难得多。
假设您能够分析想象并确定每个字母的近似坐标(在图像上)。您应该能够获取字母的点集,每个点唯一地映射到一个字母,并进行线性搜索以找到最接近图像中心的三个点。
下一步是三角形查找。首先,重要的是要知道由于网格中的每个三角形都是唯一的,您可以简单地遍历网格中的所有三角形,标准化(通过标准化)它们,然后将它们添加到字典中以提供快速查找。因此,构建查找字典的代码如下所示:
def canonize_triangle_letters(letter_triple):
# Used in larger algorithm below
return tuple(sorted(list(letter_triple)))
def triangle_lookup_from_grid(triangle_grid)
# This is a preprocessing step
# Only needs to be done once if the grid doesn't change.
# If grid does change, a more complex approach will be needed.
triangle_lookup = {} # Used in larger algorithm below
for points_triple in get_points_triples(triangle_grid):
letter_to_point = dict((point_to_letter[p],p) for p in points_triple)
triangle = canonize_triangle_letters(letter_to_point.keys())
triangle_lookup[triangle] = letter_to_point
return triangle_lookup
下一步是确定返回顶点,边或三角形。一个简单但相当主观的方法,例如,如果你想让算法偏向于返回边缘而不是顶点或三角形,那么它非常有用。
更平衡,更精确的方式需要一些额外的数学。下图显示了如何进行操作。为了避免在返回顶点的区域(A)之间产生混淆,返回边缘(AB)或返回三角形(ABC)以及数学。顶点A标记为5,顶点B标记为6,顶点C标记为7.注意,L / 3显示其中的半径,其中L是边的长度。该图像假设最接近中心的点是A,然后是B然后是C.因此,一个点永远不会位于从顶点5和8开始的线的右侧,因为它打破了点更靠近A的假设。 B比C。
评估方式如下:
然后代码如下所示。代码中有一些神奇的数学函数,但在线查找它们的算法应该不难。
def find_nearest_triangle(points, screen_center):
# Returns the nearest triangle, sorted by distance to center
dist_to_center = lambda p: distance(p, screen_center)
# Use the first three points in the list to create the inital triangle
nearest_triangle = set(points[:3])
farthest_point = max(nearest_triangle, key=dist_to_center)
farthest_dist = dist_to_center(farthest_point)
for point in points[3:]:
dist = dist_to_center(point)
if dist < farthest_dist: # Check for a closer point
farthest_dist = dist
nearest_triangle.remove(farthest_point)
nearest_triangle.add(point)
# Find the new farthest point
farthest_point = max(nearest_triangle, key=dist_to_center)
return sorted(list(nearest_triangle), key=dist_to_center)
def get_location(nearest_triangle, screen_center):
# nearest_triangle should be the same as returned by find_nearest_triangle.
# This algorithm only returns the 1-3 points that make up the triangle.
A, B = nearest_triangle[:2]
side_length = distance(A, B)
vertex_radius = side_length / 3.0
if distance(A, screen_center) < vertex_radius:
return [A], nearest_triangle
def cross(o, a, b): # Cross product
return (a[0] - o[0]) * (b[1] - o[1]) - (a[1] - o[1]) * (b[0] - o[0])
angle_AB = angle(A, B)
angle_AC = angle(A, C)
middle_angle = ((angle_AB + angle_AC) % 360) / 2.0 # For angle in degrees
p1 = offset_point_by_angle_dist(A, middle_angle, distance)
p2 = offset_point_by_angle_dist(p1, angle_AB, side_length)
if cross(p1,screen_center,p2) < 0:
return [A,B]
return [A,B,C]
def lookup_location(triangle_lookup, image_point_to_letter, points, screen_center):
nearest_triangle = find_nearest_triangle(points, screen_center)
triangle = canonize_triangle_letters([image_point_to_letter[p] for p in nearest_triangle])
letter_to_position = triangle_lookup[triangle]
location = get_location(nearest_triangle, screen_center)
letters = [image_point_to_letter[p] for p in location]
return [letter_to_position[L] for L in letters]
注意上述算法的运行时间为O(N),其中N是点集中的点数。但是,必须为每个图像运行它。因此,如果需要检查大量图像,最好尝试限制字母数量。虽然,从图像中提取字母可能会更耗时。虽然,因为算法只需要最接近的三个字母,所以它应该是最好的