【问题标题】:Find the location of an airplane on a grid given some nodes of the grid给定网格的一些节点,在网格上查找飞机的位置
【发布时间】:2014-03-03 21:47:40
【问题描述】:

我正在开展一个项目,其中一些飞行物体扫描地面以了解其确切位置。例如,让下面的网格是地面,字母实际上是放在地面上的。网格中的每个三角形都是独一无二的。

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) 上,H 放置在坐标 (301,201) 上,B 放置在坐标 (195,403) 上等等。

给定字母及其(近似)坐标(在图片上),以及图片中心的坐标,飞机如何准确地找到它在网格上的位置。如果可以产生以下输出,那将是最佳的:

  • 如果飞机悬停在三角形上方,则返回该三角形的 3 个字母。
  • 如果飞机大约沿着三角形的边悬停,则返回该边的 2 个字母。
  • 如果飞机大约悬停在某个节点上,则返回该节点的字母。

如果这是一个非常广泛的问题,我很抱歉,我只是不知道如何解决它。我尝试将问题表示为subgraph isomorphism problem,但该问题的解决方案是 NP 完全的。网格最多可以包含 200 个字母。

我目前正在使用 python,但是对此问题(或想法)的任何解决方案都表示赞赏。

编辑:部分问题可能有点含糊。在找到飞机在哪个顶点/边/三角形上方飞行后,我需要在给定的网格文件上找到这个顶点/边/三角形。这就是我尝试子图同构问题的原因。所以如果飞机发现它在上面盘旋:

  • 顶点H是三角形HBE的一部分,算法应该返回[(2,1)]
  • 边 HB 是三角形 HBE 的一部分,算法应该返回 [(2,1) , (2,2)]
  • 三角形HBE,算法应该返回[(2,1) , (2,2) , (3,2)]

非常感谢!

【问题讨论】:

    标签: java python matrix graph sparse-matrix


    【解决方案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。

    其评估方式如下:

    1. 如果最近点 (A) 在中心的 L/3 范围内。然后返回 A。
    2. 创建一个点 p1(图中的顶点 8),即沿着从 A 到 B 和 A 到 C 的角度之间的中间角。然后放置第二个点 p2(图中的顶点 9) ,与 A 到 B 的角度相同,距离为 L。从那里您可以使用叉积来确定中心在直线的哪一侧。
    3. 如果 cross(p1,screen_center,p2) 小于 0,则返回 AB,否则返回 ABC。

    代码如下所示。代码中有一些神奇的数学函数,但它们的算法应该不难在网上查找。

    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 是点集中的点数。但是,必须为每个图像运行它。因此,如果需要检查大量图像,最好尽量限制字母的数量。虽然,从图像中提取字母可能会更加耗时。虽然,由于算法只需要最接近的三个字母,应该是最好的

    【讨论】:

    • 很好的答案,我现在正在尝试处理它。关于运行时,不应该有太多的图像需要处理,O(N) 是完美的。
    • 嗯,这个算法非常适合找出飞机在哪个顶点/边/三角形上方飞行。但实际问题是什么(我可能在问题中解释得不够充分)是在给定网格上找到飞机的位置。我编辑了问题。
    • 啊,是的,三角钻头。我删除了,因为看起来你只是想要这些字母。实际上,非常简单,因为三角形是唯一的,但是方法取决于您所说的唯一性。我采用了最简单有效的方法让它们变得独一无二。更新:我为此添加了 3 个新函数,并稍微更改了 find_location 函数,以便它在查找网格中的三角形时效果更好。我还在整个答案中进行了一些更改,因此建议重新阅读整个内容。我也进行了更新,以涵盖您需要做的大部分事情。
    • 哦,您所做的更正是准确的。谢谢。希望我没有介绍任何新的...
    • 哦,而且之前的优化说“所以如果要检查的图片很多,最好尽量限制图片数量”,其实应该是建议限制数量的字母。该算法只需要离中心最近的三个。可能对您的情况并不重要,但对于阅读本文并确实拥有更多图像的其他人来说可能会有问题。还删除了一些关于我后来删除的代码中的数学函数的内容,并替换了一些关于它在左侧的内容,当我指的是右侧时。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-16
    • 1970-01-01
    • 2011-08-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多