Автоматическое создание стартовых и целевых позиций для лабиринта - PullRequest
0 голосов
/ 11 июня 2018

Код ниже - решатель лабиринта (взят из этого ответа ).Он использует позиции начала и цели, которые были введены вручную, и мне нужно менять эти координаты каждый раз, когда я изменяю изображение для решения.

Таким образом, я хочу найти способ автоматически генерировать эти позиции на основеimage (это двоичное изображение, 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 голосов
/ 13 июня 2018

Пример изображения, которое вы разместили, на самом деле не имеет отверстия в начале и в конце, поэтому для поиска этих позиций потребуется определить слова, написанные на полях.

Но в целом, лабиринты имеют отверстия вих границы, как этот:

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
...