画像を与えられた迷路を表現して解決する


271

画像を与えられた迷路を表現して解決する最良の方法は何ですか?

The Scope Issue 134のカバー画像

(上記のように)JPEG画像が与えられた場合、それを読み取ってデータ構造に解析し、迷路を解決する最良の方法は何ですか?私の最初の本能は、ピクセル単位で画像を読み取って、ブール値のリスト(配列)に保存することです。True白いピクセルの場合と、白いピクセルFalse以外の場合(色は破棄できます)。この方法の問題は、画像が「ピクセル完璧」ではない可能性があることです。つまり、壁のどこかに白いピクセルがあると、意図しないパスが作成される可能性があるということです。

別の方法(少し考えてから来た)は、画像をSVGファイルに変換する方法です。これは、キャンバスに描かれたパスのリストです。このようにして、パスを同じ種類のリスト(ブール値)に読み込むことができます。True、パスまたは壁をFalse示し、移動可能なスペースを示します。この方法の問題は、変換が100%正確でなく、すべての壁を完全に接続していないためにギャップが生じている場合に発生します。

また、SVGへの変換の問題は、線が「完全に」まっすぐではないことです。これにより、パスは3次ベジェ曲線になります。整数でインデックスが付けられたブール値のリスト(配列)を使用すると、曲線は簡単に転送されず、曲線上に線を引くすべてのポイントを計算する必要がありますが、リストのインデックスと正確に一致しません。

これらの方法の1つは機能する可能性がありますが(おそらく機能しないかもしれません)、そのような大きな画像を考えると途方もなく非効率的であり、より良い方法が存在すると思います。これはどのようにして(最も効率的かつ/または最も単純な方法で)行われますか?最善の方法さえありますか?

次に、迷路の解決が始まります。最初の2つの方法のいずれかを使用すると、基本的にマトリックスになります。この答えによると、迷路を表す良い方法は木を使うことであり、それを解決する良い方法はA *アルゴリズムを使うことです。画像から木をどのように作成しますか?何か案は?

TL; DR
解析する最良の方法?どのデータ構造に?上記の構造は解決にどのように役立ちますか?

更新
私はnumpy@Thomasが推奨するように、@ MikhailがPythonで記述したものをを使用して実装することを試みました。アルゴリズムは正しいと思いますが、期待どおりに動作していません。(以下のコード。)PNGライブラリはPyPNGです。

import png, numpy, Queue, operator, itertools

def is_white(coord, image):
  """ Returns whether (x, y) is approx. a white pixel."""
  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):
  """ Perform a breadth-first search. """
  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 # ensure the file is RGB
  image2d = numpy.vstack(itertools.imap(numpy.uint8, pixels))
  start, end = (402, 985), (398, 27)
  print bfs(start, end, image2d, [])

12
私は迷路を白黒に変換し、それを解決するために経路探索セルオートマトン法を使用します。
Dan D.

その画像のみ、またはそのような多くの画像を処理する必要がありますか?つまり、この特定の画像に固有の手動処理のオプションがありますか?
ミハイル、

1
@Whymarrh私はpythonをコーディングしていませんがvisited.append(s)、aの下に移動してfor.ifで置き換える必要があると確信していますvisited.append(np)。キューに追加されると、頂点にアクセスします。実際、この配列は「queued」という名前にする必要があります。終了に達したら、BFSを終了することもできます。
ミハイル

2
@Whymarrhまた、パス抽出ブロックの実装をスキップしたようです。それがなければ、仕上がりが到達可能かどうかがわかるだけで、方法はわかりません。
ミハイル、

1
解決策あるかどうかを確認するに、UnionFindおよび線形スキャンが最速のアルゴリズムです。これはパスを提供しませんが、パスをサブセットとして持つタイルのセットを提供します。
st0le 2012年

回答:


236

これが解決策です。

  1. 画像をグレースケール(まだバイナリではない)に変換し、最終的なグレースケール画像がほぼ均一になるように色の重みを調整します。これは、Photoshopの[画像]-> [調整]-> [白黒]でスライダーを制御するだけで実行できます。
  2. Photoshopの画像->調整->しきい値で適切なしきい値を設定して、画像をバイナリに変換します。
  3. しきい値が正しく選択されていることを確認します。マジックワンドツールを、許容値0、ポイントサンプル、連続、アンチエイリアスなしで使用します。選択が解除されたエッジが、誤ったしきい値によって導入された偽のエッジでないことを確認します。実際、この迷路のすべての内部ポイントには最初からアクセスできます。
  4. 迷路に人工的な境界線を追加して、仮想旅行者が迷路を歩き回らないようにします。
  5. お好みの言語で幅優先検索(BFS)を実装し、最初から実行します。私が好むMATLABをこのタスクのために。@Thomasがすでに述べたように、グラフの通常の表現を混乱させる必要はありません。2値化された画像を直接操作できます。

以下は、BFSのMATLABコードです。

function path = solve_maze(img_file)
  %% Init data
  img = imread(img_file);
  img = rgb2gray(img);
  maze = img > 0;
  start = [985 398];
  finish = [26 399];

  %% Init BFS
  n = numel(maze);
  Q = zeros(n, 2);
  M = zeros([size(maze) 2]);
  front = 0;
  back = 1;

  function push(p, d)
    q = p + d;
    if maze(q(1), q(2)) && M(q(1), q(2), 1) == 0
      front = front + 1;
      Q(front, :) = q;
      M(q(1), q(2), :) = reshape(p, [1 1 2]);
    end
  end

  push(start, [0 0]);

  d = [0 1; 0 -1; 1 0; -1 0];

  %% Run BFS
  while back <= front
    p = Q(back, :);
    back = back + 1;
    for i = 1:4
      push(p, d(i, :));
    end
  end

  %% Extracting path
  path = finish;
  while true
    q = path(end, :);
    p = reshape(M(q(1), q(2), :), 1, 2);
    path(end + 1, :) = p;
    if isequal(p, start) 
      break;
    end
  end
end

これは非常にシンプルで標準的なものであり、Pythonなどでこれを実装するのに困難はないはずです。

そしてここに答えがあります:

ここに画像の説明を入力してください


1
@Whymarrhさて、「この画像だけ」のために、あなたは実際に答えを持っています。具体的な質問はありますか?リストの項目1〜4は、私が尋ねていた手動処理です。アイテム5はBFS-グラフの非常に基本的なアルゴリズムですが、ピクセルを頂点に変換し、近傍をエッジに変換することなく、直接画像に適用できます。
ミハイル

あなたはすべてをカバーしたと感じます。私はあなたがPythonで言ったことを実装しようとしています(BFSの代わりにDFSを使用していますが、これは以前に1回コーディングしたためです)。質問を更新し、回答を少し受け入れます。
Whymarrh 2012年

2
@Whymarrh DFSは最短の方法を見つけませんが、BFSは見つけます。それらは本質的に同じですが、唯一の違いは基本的な構造です。DFSのスタック(FILO)およびBFSのキュー(FIFO)。
ミハイル

3
BFSはここでの正しい選択です。これは、コリドーが1ピクセルよりはるかに広い場合でも「適切な」パスを提供する最短パスを生成するためです。OTOH DFSは「洪水塗りつぶし」パターンで廊下や見込みのない迷路地域を探索する傾向があります。
j_random_hacker 2012年

1
@JosephKernパスは壁と重なりません。赤のピクセルをすべて削除してください。
ミハイル

160

このソリューションはPythonで書かれています。画像の準備に関するアドバイスを提供してくれたミハイルに感謝します。

アニメーションの幅優先検索:

BFSのアニメーション版

完成した迷路:

完成した迷路

#!/usr/bin/env python

import sys

from Queue import Queue
from PIL import Image

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

def iswhite(value):
    if value == (255,255,255):
        return True

def getadjacent(n):
    x,y = n
    return [(x-1,y),(x,y-1),(x+1,y),(x,y+1)]

def BFS(start, end, pixels):

    queue = Queue()
    queue.put([start]) # Wrapping the start tuple in a list

    while not queue.empty():

        path = queue.get() 
        pixel = path[-1]

        if pixel == end:
            return path

        for adjacent in getadjacent(pixel):
            x,y = adjacent
            if iswhite(pixels[x,y]):
                pixels[x,y] = (127,127,127) # see note
                new_path = list(path)
                new_path.append(adjacent)
                queue.put(new_path)

    print "Queue has been exhausted. No answer was found."


if __name__ == '__main__':

    # invoke: python mazesolver.py <mazefile> <outputfile>[.jpg|.png|etc.]
    base_img = Image.open(sys.argv[1])
    base_pixels = base_img.load()

    path = BFS(start, end, base_pixels)

    path_img = Image.open(sys.argv[1])
    path_pixels = path_img.load()

    for position in path:
        x,y = position
        path_pixels[x,y] = (255,0,0) # red

    path_img.save(sys.argv[2])

注:訪問した白のピクセルを灰色にマークします。これにより、訪問済みリストは不要になりますが、パスを描画する前に、ディスクからイメージファイルを2回ロードする必要があります(最終パスとすべてのパスの複合イメージが必要ない場合)。

私が使用した迷路の空白バージョン。


13
あなたの質問に答えた後でも、あなたは戻って私に賛成票を投じるのに十分なほど素晴らしかったので、私はBFSのアニメーションgifを作成して、プロセスの視覚化を支援しました。
Joseph Kern

1
いいね、ありがとう。私がそうしたように、これで遊んでみたい他の人のために、私が直面した困難に基づいて私のヒントを共有したいと思います。1)画像を純粋な白黒に変換するか、「isWhite()」関数を変更して、ほぼ白|黒を受け入れます。すべてのピクセルを前処理して純粋な白または黒に変換する 'cleanImage'メソッドを作成しました。それ以外の場合、アルゴリズムはパスを見つけることができません。2)画像をRGBとして明示的に読み込む[base_img = Image.open(img_in); base_img = base_img.convert( 'RGB')]。gifを取得するには、いくつかの画像を出力してから、「convert -delay 5 -loop 1 * .jpg bfs.gif」を実行します。
stefano

1
13行目にインデントがありません
sloewen

81

私はこの問題に対してA-Star検索を実装してみました。以下に示すフレームワークとアルゴリズムの疑似コードに対するJoseph Kernの実装に厳密に従いまし

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 []

A-Starはヒュ​​ーリスティック検索アルゴリズムであるため、目標に到達するまでの残りのコスト(ここでは距離)を推定する関数を考え出す必要があります。次善のソリューションに慣れていない限り、コストを過大評価すべきではありません。保守的な選択は、ここではマンハッタン(またはタクシー)の距離になりますます。これは、使用されたフォンノイマン近隣のグリッド上の2点間の直線を表すためです。(この場合、コストを過大評価しません。)

しかし、これは手元にある特定の迷路の実際のコストを大幅に過小評価します。したがって、比較のために、他の2つの距離メトリックの2乗ユークリッド距離と、マンハッタン距離に4を掛けたものを追加しました。ただし、これらは実際のコストを過大評価する可能性があり、そのため最適ではない結果をもたらす可能性があります。

これがコードです:

import sys
from PIL import Image

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)

# invoke: python mazesolver.py <mazefile> <outputfile>[.jpg|.png|etc.]

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) # red

path_img.save(sys.argv[2])

これは、結果を視覚化するためのいくつかの画像です(Joseph Kernによって投稿されたものに触発されました)ます)。アニメーションは、メインのwhileループを10000回繰り返した後の新しいフレームをそれぞれ示しています。

幅優先検索:

幅優先検索

Aスターマンハッタンの距離:

Aスターマンハッタンの距離

Aスター2乗ユークリッド距離:

Aスター2乗ユークリッド距離

Aスターマンハッタン距離に4を掛けたもの:

Aスターマンハッタン距離に4を掛けたもの

結果は、迷路の探索された領域が、使用されているヒューリスティックに対してかなり異なることを示しています。そのため、ユークリッド距離の2乗は、他のメトリックとは異なる(最適ではない)パスを生成します。

終了までの実行時間に関するA-Starアルゴリズムのパフォーマンスに関しては、距離とコスト関数の多くの評価が、「目的」の評価のみを必要とする幅優先検索(BFS)と比較して加算されることに注意してください。各候補者の役職。これらの追加機能評価のコスト(A-Star)がチェックするノードの数(BFS)のコストを上回るかどうか、特にパフォーマンスがアプリケーションにとってまったく問題であるかどうかは、個人の認識の問題ですもちろん、一般的に答えることはできません。

ができ(例えばA-スターなど)の情報に検索アルゴリズムは、網羅的な探索(例えば、BFS)に比べてより良い選択かもしれないかどうかについての一般的に言うことは以下の通りです。迷路の次元数、つまり検索ツリーの分岐係数によって、徹底的な検索(徹底的に検索すること)のデメリットは指数関数的に増大します。複雑さが増すにつれ、実行することがますます難しくなり、ある時点で、(ほぼ)最適であるかどうかにかかわらず、任意の結果パスにかなり満足します


1
「Aスターマンハッタンの距離×4」?ヒューリスティックが距離を過大評価できる場合、A-StarはA-Starではありません。(したがって、最短経路を見つけることも保証されません)

@exampleもちろん、許容できないヒューリスティック関数を適用すると、アルゴリズムが最適なソリューションを見つけられない可能性があります(私の回答で指摘したように)。しかし、その理由から、基本的なアルゴリズムの名前を変更することはしません。
moooeeeep 2014年

38

ツリー検索が多すぎます。迷路は本質的にソリューションパスに沿って分離可能です。

(これを私に指摘してくれたRedditのrainman002に感謝します。)

このため、接続されたコンポーネントをすばやく使用できますを、迷路の壁の接続されたセクションを識別。これは、ピクセルを2回繰り返します。

それをソリューションパスの素敵な図に変えたい場合は、構造化要素と共にバイナリ演算を使用して、接続された各領域の「行き止まり」経路を埋めることができます。

以下は、MATLABのデモコードです。微調整を使用して結果をより適切にクリーンアップし、より一般化して、より高速に実行できます。(午前2時30分でない場合もあります。)

% read in and invert the image
im = 255 - imread('maze.jpg');

% sharpen it to address small fuzzy channels
% threshold to binary 15%
% run connected components
result = bwlabel(im2bw(imfilter(im,fspecial('unsharp')),0.15));

% purge small components (e.g. letters)
for i = 1:max(reshape(result,1,1002*800))
    [count,~] = size(find(result==i));
    if count < 500
        result(result==i) = 0;
    end
end

% close dead-end channels
closed = zeros(1002,800);
for i = 1:max(reshape(result,1,1002*800))
    k = zeros(1002,800);
    k(result==i) = 1; k = imclose(k,strel('square',8));
    closed(k==1) = i;
end

% do output
out = 255 - im;
for x = 1:1002
    for y = 1:800
        if closed(x,y) == 0
            out(x,y,:) = 0;
        end
    end
end
imshow(out);

現在のコードの結果


24

しきい値の連続充填にキューを使用します。入口の左側のピクセルをキューにプッシュしてから、ループを開始します。キューに入れられたピクセルが十分に暗い場合、それは薄い灰色(しきい値より上)に着色され、すべての隣接ピクセルがキューにプッシュされます。

from PIL import Image
img = Image.open("/tmp/in.jpg")
(w,h) = img.size
scan = [(394,23)]
while(len(scan) > 0):
    (i,j) = scan.pop()
    (r,g,b) = img.getpixel((i,j))
    if(r*g*b < 9000000):
        img.putpixel((i,j),(210,210,210))
        for x in [i-1,i,i+1]:
            for y in [j-1,j,j+1]:
                scan.append((x,y))
img.save("/tmp/out.png")

解決策は、灰色の壁と色付きの壁の間の廊下です。この迷路には複数のソリューションがあることに注意してください。また、これは単に機能しているように見えます。

解決


1
壁に直接触れる方法に基づく興味深い素朴な解決策。確かに、最高のものではありませんが、私はそれが好きです。
zessx 2013

23

どうぞ:maze-solver-python(GitHub)

ここに画像の説明を入力してください

私はこれで遊んで楽しんで、ジョセフ・カーンに拡張しましたの答え。それを損なうことはありません。私はこれで遊んでみたいと思っている人のためにちょっとした追加をしました。

これは、BFSを使用して最短経路を見つけるPythonベースのソルバーです。当時の私の主な追加は以下のとおりです。

  1. 画像は検索前にクリーンアップされます(つまり、純粋な白黒に変換されます)。
  2. GIFを自動生成します。
  3. AVIを自動生成します。

現状では、このサンプル迷路の開始/終了ポイントはハードコードされていますが、適切なピクセルを選択できるように拡張する予定です。


1
ありがとう、BSD / Darwin / Macでは動作しませんでした。Macで試してみたい人のために、いくつかの依存関係とシェルスクリプトに小さな変更が必要でした:[maze-solver-python]:github.com/holg/maze- solver-python
HolgT 2014年

@HolgT:お役に立ててうれしいです。これに対するプルリクエストを歓迎します。:)
stefano 2014年

5

私はMatrix-of-Bolsオプションを選びます。標準のPythonリストでは効率が悪すぎる場合は、numpy.bool代わりに配列を。1000x1000ピクセルの迷路のストレージは、わずか1 MBです。

ツリーやグラフのデータ構造を作成することに煩わされないでください。これは単なる考え方の1つですが、必ずしもそれをメモリで表現するための良い方法とは限りません。ブール行列は、コーディングが簡単で効率的です。

次に、A *アルゴリズムを使用してそれを解決します。距離ヒューリスティックには、マンハッタン距離(distance_x + distance_y)を使用します。

(row, column)座標のタプルでノードを表します。アルゴリズム(Wikipedia pseudocode)が「近傍」を要求するときはいつでも、それは4つの可能な近傍をループする(画像の端を気にする!)だけの問題です。

それでも遅すぎる場合は、ロードする前に画像を縮小してみてください。プロセスで狭いパスを失わないように注意してください。

Pythonで1:2のダウンスケーリングを行うことも可能かもしれません。実際に可能なパスが失われていないことを確認してください。興味深いオプションですが、もう少し考える必要があります。


この優れたブログ投稿は、mathematicaで迷路を解決する方法を示しています。メソッドをPythonに変換することは問題になりません
Boris Gorelik

質問を更新しました。boolean値の代わりにRGBトリプルを使用することを選択した場合でも、ストレージは比較されますか?その場合、マトリックスは2400 * 1200になります。BFSを超えるA *は、実際の実行時間に大きな影響を与えるでしょうか。
Whymarrh

@Whymarrh、ビット深度はそれを補うために縮小できます。ピクセルあたり2ビットで十分です。
ブライアンカイン

5

ここにいくつかのアイデアがあります。

(1.画像処理:)

1.1画像をRGBピクセルマップとして読み込みます。ではC#のそれが使用して簡単ですsystem.drawing.bitmap。イメージングを単純にサポートしていない言語では、イメージを ポータブルピクスマップフォーマット(PPM)(Unixテキスト表現、大きなファイルを生成)、またはBMPTGAなどの簡単に読み取れる単純なバイナリファイルフォーマットに変換するだけです。UnixではImageMagick、WindowsではIrfanView

1.2先に述べたように、各ピクセルの(R + G + B)/ 3をグレートーンのインジケーターとして取り、値をしきい値処理して白黒のテーブルを作成することで、データを簡略化できます。0 =黒、255 =白と仮定すると、200に近いものがJPEGアーティファクトを取り除きます。

(2.ソリューション:)

2.1深さ優先検索:空のスタックを開始位置で初期化し、利用可能なフォローアップムーブを収集し、ランダムに1つ選択してスタックにプッシュし、最後に到達するか行き止まりになるまで続行します。スタックをポップすることによる行き止まりのバックトラックでは、マップ上のどの位置にアクセスしたかを追跡する必要があるため、利用可能な移動を収集するときに、同じパスを2回使用することはありません。アニメ化するのは非常に興味深い。

2.2幅優先検索:上記と同様ですが、キューのみを使用します。アニメ化も面白い。これは、画像編集ソフトウェアの塗りつぶしのように機能します。このトリックを使ってPhotoshopの迷路を解決できるかもしれません。

2.3 Wall Follower:幾何学的に言えば、迷路は折りたたまれた/複雑なチューブです。壁に手を置いていると、やがて出口が見つかるでしょう;)これはいつもうまくいくとは限りません。完全な迷路など、特定の仮定があります。たとえば、特定の迷路には島が含まれています。調べてください。それは魅力的です。

(3.コメント:)

これはトリッキーです。各要素が北、東、南、西の壁と訪問済みフラグフィールドを持つセルタイプであるいくつかの単純な配列形式で表されている場合、迷路を解決するのは簡単です。しかし、あなたが手描きのスケッチを与えられてこれをやろうとしているとすると、それは面倒になります。正直に言って、スケッチを合理化しようとすることはあなたを狂わせると思います。これは、かなり複雑なコンピュータビジョンの問題に似ています。おそらく、イメージマップに直接移動する方が簡単ですが、より無駄になります。


2

Rを使用したソリューションを次に示します。

### download the image, read it into R, converting to something we can play with...
library(jpeg)
url <- "https://i.stack.imgur.com/TqKCM.jpg"
download.file(url, "./maze.jpg", mode = "wb")
jpg <- readJPEG("./maze.jpg")

### reshape array into data.frame
library(reshape2)
img3 <- melt(jpg, varnames = c("y","x","rgb"))
img3$rgb <- as.character(factor(img3$rgb, levels = c(1,2,3), labels=c("r","g","b")))

## split out rgb values into separate columns
img3 <- dcast(img3, x + y ~ rgb)

RGBからグレースケール、https://stackoverflow.com/a/27491947/2371031を参照

# convert rgb to greyscale (0, 1)
img3$v <- img3$r*.21 + img3$g*.72 + img3$b*.07
# v: values closer to 1 are white, closer to 0 are black

## strategically fill in some border pixels so the solver doesn't "go around":
img3$v2 <- img3$v
img3[(img3$x == 300 | img3$x == 500) & (img3$y %in% c(0:23,988:1002)),"v2"]  = 0

# define some start/end point coordinates
pts_df <- data.frame(x = c(398, 399),
                     y = c(985, 26))

# set a reference value as the mean of the start and end point greyscale "v"s
ref_val <- mean(c(subset(img3, x==pts_df[1,1] & y==pts_df[1,2])$v,
                  subset(img3, x==pts_df[2,1] & y==pts_df[2,2])$v))

library(sp)
library(gdistance)
spdf3 <- SpatialPixelsDataFrame(points = img3[c("x","y")], data = img3["v2"])
r3 <- rasterFromXYZ(spdf3)

# transition layer defines a "conductance" function between any two points, and the number of connections (4 = Manhatten distances)
# x in the function represents the greyscale values ("v2") of two adjacent points (pixels), i.e., = (x1$v2, x2$v2)
# make function(x) encourages transitions between cells with small changes in greyscale compared to the reference values, such that: 
# when v2 is closer to 0 (black) = poor conductance
# when v2 is closer to 1 (white) = good conductance
tl3 <- transition(r3, function(x) (1/max( abs( (x/ref_val)-1 ) )^2)-1, 4) 

## get the shortest path between start, end points
sPath3 <- shortestPath(tl3, as.numeric(pts_df[1,]), as.numeric(pts_df[2,]), output = "SpatialLines")

## fortify for ggplot
sldf3 <- fortify(SpatialLinesDataFrame(sPath3, data = data.frame(ID = 1)))

# plot the image greyscale with start/end points (red) and shortest path (green)
ggplot(img3) +
  geom_raster(aes(x, y, fill=v2)) +
  scale_fill_continuous(high="white", low="black") +
  scale_y_reverse() +
  geom_point(data=pts_df, aes(x, y), color="red") +
  geom_path(data=sldf3, aes(x=long, y=lat), color="green")

出来上がり!

最短経路を正しく見つけるソリューション

これは、いくつかの境界ピクセルを入力しないとどうなるかです(Ha!)...

ソルバーが迷路を回るソリューションバージョン

完全な開示:この質問に出会う前に、私自身も非常によく似た質問に答えました。次に、SOの魔法を通して、これをトップの「関連する質問」の1つとして見つけました。私はこの迷路を追加のテストケースとして使用すると思いました...私の回答がこのアプリケーションでもほとんど変更なしで機能することを知って、とても嬉しく思いました。


0

良い解決策は、ピクセルで近傍を見つける代わりに、セルで行われることです。これは、コリドーが15pxを持つことができるため、同じコリドーで左または右のようなアクションを実行できる一方で、ディスプレイスメントのように行われた場合立方体だったので、上、下、左、右のような単純なアクションになります


あなたのポイントを検証するための残りの回答のように、ソリューショングラフとアルゴリズムを追加できますか?他の人が実際にあなたの答えをより理解できるように、それらをあなたの答えにもっと重み付けを加えるために追加できるなら、それはより良いでしょう。
Himanshu Bansal
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.