自动生成迷宫的起点和目标位置

时间:2018-06-11 15:10:20

标签: python image-processing maze

以下代码是迷宫解算器(取自this answer)。它使用手动输入的开始和目标位置,每次更改要解决的图像时,我都需要更改这些坐标。

因此,我想找到一种基于图像自动生成这些位置的方法(它是二进制图像,0表示空方块,1表示墙壁)。

到目前为止,我的想法是做一个步行'在迷宫墙外确定这些位置。该算法将访问每个方格,如果它是零,则它将被视为进入/退出点。

所以我的问题是:有没有人知道一种方法来访问外墙的所有方块以确定进入和目标位置?或者任何其他有助于我解决这个问题的想法?

import sys
import png
from PIL import Image

# using an A* Algorithm to solve the maze

def AStar(start, goal, neighbor_nodes, distance, cost_estimate):
    def reconstruct_path(came_from, current_node):
        path = []
        while current_node is not None:
            path.append(current_node)
            current_node = came_from[current_node]
        return list(reversed(path))
    g_score = {start: 0}
    f_score = {start: g_score[start] + cost_estimate(start, goal)}
    openset = {start}
    closedset = set()
    came_from = {start: None}
    while openset:
        current = min(openset, key=lambda x: f_score[x])
        if current == goal:
            return reconstruct_path(came_from, goal)
        openset.remove(current)
        closedset.add(current)
        for neighbor in neighbor_nodes(current):
            if neighbor in closedset:
                continue
            if neighbor not in openset:
                openset.add(neighbor)
            tentative_g_score = g_score[current] + distance(current, neighbor)
            if tentative_g_score >= g_score.get(neighbor, float('inf')):
                continue
            came_from[neighbor] = current
            g_score[neighbor] = tentative_g_score
            f_score[neighbor] = tentative_g_score + cost_estimate(neighbor, goal)
    return []
def is_blocked(p):
    x,y = p
    pixel = path_pixels[x,y]
    if any(c < 225 for c in pixel):
        return True
def von_neumann_neighbors(p):
    x, y = p
    neighbors = [(x-1, y), (x, y-1), (x+1, y), (x, y+1)]
    return [p for p in neighbors if not is_blocked(p)]
def manhattan(p1, p2):
    return abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
def squared_euclidean(p1, p2):
    return (p1[0]-p2[0])**2 + (p1[1]-p2[1])**2 

start = (400, 984)
goal = (398, 25)

path_img = Image.open(sys.argv[1])
path_pixels = path_img.load()
distance = manhattan
heuristic = manhattan
path = AStar(start, goal, von_neumann_neighbors, distance, heuristic)
for position in path:
    x,y = position
    path_pixels[x,y] = (255,0,0) # the solution color path is red
path_img.save(sys.argv[2]) # or path_img.save('<outputfile>[.gif|.png|etc.]')

代码输出:

output

1 个答案:

答案 0 :(得分:0)

您发布的示例图片在开头和结尾都没有开口,因此找到这些位置需要识别边缘上写的字。

但总的来说,迷宫在其边界有开口,如下:

maze

在这种情况下,你可以按照你的建议,沿着图像边缘走,找到白色像素(在你的情况下为0)。

在Python中执行此操作的最简单方法是将四个边中的每一个提取为一维数组,并在其中查找连续的组。

我正在使用PyDIP,因为我对PIL没有任何经验。这导致一些大的快捷方式,我没有时间写出完整的逐像素算法。但这就是我们拥有的图书馆...

我希望你在这里看到大规模的概念:连通分量分析找到连续的设定像素组(路径像素),并将它们视为单个点。 'Center'功能只返回集合的几何质心(平均坐标)。相反,您可以选择集合中的任何一个像素。

如果(1)迷宫延伸到图像边界,(2)只有两个开口,则下面的代码出错了。

import numpy as np
import PyDIP as dip

# Starting with your `path_pixels` image:
img = np.array(path_pixels)   # convert to NumPy array by copy (so we don't modify original)
img = dip.Image(img)          # convert to PyDIP image (no copy made)
img = img == 255              # binarize, path is True/1
img = dip.Any(img, process=[False,False,True]) # if this is a color image, remove color dimension
img[1:-2,1:-2] = 0            # set image interior to 0, leaving only outer path
img = dip.Label(img)          # do connected component analysis -- should result in two regions
m = dip.MeasurementTool.Measure(img,features=['Center']) # find centroids for regions
start = m[1]['Center']        # randomly pick first region as start point
goal = m[2]['Center']         # ... and second region as goal point