给定网格的某些节点,在网格上找到飞机的位置

时间:2014-03-03 21:47:41

标签: java python matrix graph sparse-matrix

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

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等等。

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

  • 如果飞机在三角形上方悬停,则返回该三角形的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)]

非常感谢!

1 个答案:

答案 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。

Triangle Partition

评估方式如下:

  1. 如果最近点(A)在中心的L / 3范围内。然后返回A.
  2. 创建一个点,p1(图中的顶点8),即从A到B和A到C的角度中间的角度。然后放置第二个点p2(图中的顶点9) ,与A到B的角度相同,距离为L.从那里你可以用十字产品来确定中心所在线的哪一侧。
  3. 如果交叉(p1,screen_center,p2)小于0,则返回AB,否则返回ABC。
  4. 然后代码如下所示。代码中有一些神奇的数学函数,但在线查找它们的算法应该不难。

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