Quel est le meilleur moyen de représenter et résoudre un labyrinthe donné sous forme d'image?
Étant donné une image JPEG (comme celle ci-dessus), quel est le meilleur moyen de la lire, de la parser dans une structure de données et de résoudre le labyrinthe? Mon premier instinct est de lire l'image pixel par pixel et de la stocker dans une liste (tableau) de valeurs booléennes: Vrai
pour un pixel blanc, et Faux
pour un pixel non blanc (les couleurs peuvent être ignorées). Le problème avec cette méthode, c'est que l'image peut ne pas être "parfaite au pixel près". Autrement dit, s'il y a un pixel blanc quelque part sur un mur, cela peut créer un chemin non voulu.
Une autre méthode (qui m'est venue après un peu de réflexion) consiste à convertir l'image en un fichier SVG - qui est une liste de chemins dessinés sur un canvas. De cette façon, les chemins pourraient être lus dans le même type de liste (valeurs booléennes) où Vrai
indique un chemin ou un mur, Faux
indiquant un espace praticable. Un problème avec cette méthode survient si la conversion n'est pas précise à 100 %, et ne connecte pas entièrement tous les murs, créant ainsi des lacunes.
Un autre problème avec la conversion en SVG est que les lignes ne sont pas "parfaitement" droites. Cela entraîne les chemins étant des courbes de Bézier cubiques. Avec une liste (tableau) de valeurs booléennes indexées par des entiers, les courbes ne seraient pas transférées facilement, et tous les points situés sur la courbe devraient être calculés, mais ne correspondraient pas exactement aux indices de la liste.
Je suppose qu'alors que l'une de ces méthodes pourrait fonctionner (bien que probablement pas), elles sont extrêmement inefficaces pour une image aussi grande, et il doit exister un moyen meilleur. Comment cela peut-il être fait de la meilleure façon (de manière la plus efficace et/ou avec le moins de complexité)? Existe-t-il même un meilleur moyen?
Ensuite vient la résolution du labyrinthe. Si j'utilise l'une des deux premières méthodes, je me retrouverai essentiellement avec une matrice. Selon cette réponse, un bon moyen de représenter un labyrinthe est d'utiliser un arbre, et un bon moyen de le résoudre est d'utiliser l'algorithme A*. Comment créer un arbre à partir de l'image? Des idées?
TL;DR
Meilleur moyen de parser? En quelle structure de données? Comment cette structure aiderait-elle/entraverait-elle la résolution?
MISE À JOUR
J'ai essayé d'implémenter ce que @Mikhail a écrit en Python, en utilisant numpy
, comme l'a recommandé @Thomas. Je pense que l'algorithme est correct, mais cela ne fonctionne pas comme espéré. (Code ci-dessous.) La bibliothèque PNG est PyPNG.
import png, numpy, Queue, operator, itertools
def is_white(coord, image):
""" Renvoie si (x, y) est approximativement un pixel blanc."""
a = True
for i in xrange(3):
if not a: break
a = image[coord[1]][coord[0] * 3 + i] > 240
return a
def bfs(s, e, i, visited):
""" Effectue une recherche en largeur. """
frontier = Queue.Queue()
while s != e:
for d in [(-1, 0), (0, -1), (1, 0), (0, 1)]:
np = tuple(map(operator.add, s, d))
if is_white(np, i) and np not in visited:
frontier.put(np)
visited.append(s)
s = frontier.get()
return visited
def main():
r = png.Reader(filename = "thescope-134.png")
rows, cols, pixels, meta = r.asDirect()
assert meta['planes'] == 3 # s'assurer que le fichier est en RGB
image2d = numpy.vstack(itertools.imap(numpy.uint8, pixels))
start, end = (402, 985), (398, 27)
print bfs(start, end, image2d, [])
15 votes
Je convertirais le labyrinthe en noir et blanc et j'utiliserais une méthode de recherche de chemin par automates cellulaires pour le résoudre.
0 votes
Avez-vous besoin de traiter uniquement cette image, ou de traiter plusieurs images comme celle-ci ? C'est-à-dire, y a-t-il une option de traitement manuel spécifique pour cette image en particulier ?
0 votes
@Mikhail Juste cette image, le traitement manuel est une option.
1 votes
@Whymarrh Je ne code pas en python, mais je suis assez sûr que tu devrais déplacer
visited.append(s)
sous unfor.if
et le remplacer parvisited.append(np)
. Un sommet est visité une fois qu'il est ajouté à la file d'attente. En fait, cet tableau devrait être nommé "queued". Tu peux également terminer le BFS une fois que tu as atteint la fin.2 votes
@Whymarrh Et vous semblez également avoir omis de mettre en œuvre le bloc d'extraction de chemin. Sans cela, vous ne pouvez savoir que si la fin est accessible ou non, mais pas comment.
0 votes
Pas tout à fait sûr de comment cela pourrait être mis en œuvre, mais pour tricher à un labyrinthe manuellement, il suffit simplement de convertir le labyrinthe en noir et blanc réels et de garder les segments de murs de remplissage de seaux (avec des couleurs distinctes pour les "îlots" adjacents) et de chercher des "rivières" entre eux. Il devrait mener du début à la fin. Le labyrinthe d'exemple du OP ne se résout pas à seulement deux îlots, mais beaucoup de labyrinthes plus simples le font souvent. Même si cela pourrait ne pas être réalisable en tant que solution autonome, cela pourrait être utilisé comme heuristique pour trouver un chemin : les chemins pour lesquels le mur gauche et le mur droit sont de la même couleur sont des impasses et ne devraient donc pas être suivis plus loin.
1 votes
Pour savoir s'il y a une solution, un UnionFind et une analyse linéaire est l'algorithme le plus rapide. Il ne vous donne pas le chemin, mais vous donne un ensemble de tuiles qui auront le chemin comme un sous-ensemble.