英文原文:Representing and solving a maze given an image
译注:原文是 StackOverflow 上一个如何用程序读取迷宫图片并求解的问题,几位参与者热烈地讨论并给出了自己的代码,涉及到用 Python 对图片的处理以及广度优先(BFS)算法等。
问题 by Whymarrh:
当给定上面那样一张 JPEG 图片,如何才能更好地将这张图转换为合适的数据结构并且解出这个迷宫?
我的第一直觉是将这张图按像素逐个读入,并存储在一个包含布尔类型元素的列表或数组中,其中 True 代表白色像素,False 代表非白色像素(或彩色可以被处理成二值图像)。但是这种做法存在一个问题,那就是给定的图片往往并不能完美的“像素化”。考虑到如果因为图片转换的原因,某个非预期的白色像素出现在迷宫的墙上,那么就可能会创造出一一条非预期的路径。
经过思考之后,我想出了另一种方法:首先将图片转换为一个可缩放适量图形(SVG)文件,这个文件由一个画布上的矢量线条列表组成,矢量线条按照列表的顺序读取,读取出的仍是布尔值:其中 True 表示墙,而 False 表示可通过的区域。但是这种方法如果无法保证图像能够做到百分之百的精确转换,尤其是如果不能将墙完全准确的连接,那么这个迷宫就可能出现裂缝。
图像转换为 SVG 的另一个问题是,线条并不是完美的直线。因为 SVG 的线条是三次贝塞尔曲线,而使用整数索引的布尔值列表增加了曲线转换的难度,迷宫线条上的所有点在曲线上都必须经过计算,但不一定能够完美对应列表中的索引值。
假设以上方法的确可以实现(虽然很可能都不行),但当给定一张很大的图像时,它们还是不能胜任。那么是否存在一种更好地方法能够平衡效率和复杂度?
这就要讨论到如何解迷宫了。如果我使用以上两种方法中的任意一种,我最终将会得到一个矩阵。而根据这个问答(http://stackoverflow.com/questions/3097556/programming-theory-solve-a-maze/3097677#3097677),一个比较好的迷宫表示方式应该是使用树的结构,并且使用A*搜索算法来解迷宫。那么如何从迷宫图片中构造出迷宫树呢?有比较好的方法么?
以上废话太多,总结起来问题就是:如何转换迷宫图片?转换成为什么样的数据结构?采用什么样的数据结构能够帮助或阻碍解迷宫?
回答 by Mikhail:
这是我的解决方案:
1. 将图片转换为灰度图像(不是直接二值),调整不同颜色的权重使得最终的灰度看起来比较统一,你可以通过简单地调节 Photoshop 图像->调整->黑白菜单中的控制条来实现。
2. 将上一步得到的灰度图片转换为二值图片,可以通过在 PS 图像->调整->阈值菜单中设定适当的阈值来实现
3. 确保正确设置了阈值。使用魔棒工具(参数设置:容差 0、取样点、连续以及消除锯齿)选择空白区域,检查所选区域的边缘不是因为错误的阈值设置而产生的假边缘。事实上,这个迷宫中从 start 到 end 应该由联通的空白区域。
4. 人为地在迷宫外部加上边界,确保迷宫漫游者^_^不会从 start 绕着迷宫跑到终点。:)
5. 选择语言实现广度优先搜索算法(BFS),从 start 处开始让程序运行。下面的代码我选择用 Matlab 实现。正如 Thomas 提到的,没必要纠结于图像的表示形式,你可以直接在二值图像上运行。
以下是用 MATLAB 实现的 BFS 代码:
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 或其他语言,下面是程序的运行结果:
提问者更新:
我用 Python 实现了一下 Mikhail 的方法,其中用到了 numpy 库,感谢 Thomas 推荐。我感觉这个算法是正确的,但是效果不太如预期,以下是相关代码,使用了 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, [])
回答 by Joseph Kern:
#!/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 [.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])
动态执行效果:
回答 by Jim
使用树搜索太繁杂了,迷宫本身就跟解路径是可分的。正因如此,你可以使用连通区域查找算法来标记迷宫中的连通区域,这将迭代搜索两次这些像素点。如果你想要更好地解决方法,你可以对结构单元使用二元运算(binary operations)来填充每个连通区域中的死路。
下面是相关的 MATLAB 代码及运行结果:
% 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);
回答 by Stefano
stefano 童鞋给出了生成搜索过程 GIF 及 AVI 文件的代码 maze-solver-python (GitHub)
以上就是如何用程序解图片迷宫的内容,更多相关内容请关注PHP中文网(www.php.cn)!

H5 및 HTML5는 다른 개념입니다. HTML5는 새로운 요소 및 API를 포함하는 HTML의 버전입니다. H5는 HTML5를 기반으로 한 모바일 애플리케이션 개발 프레임 워크입니다. HTML5는 브라우저를 통해 코드를 구문 분석하고 렌더링하는 반면 H5 응용 프로그램은 컨테이너를 실행하고 JavaScript를 통해 기본 코드와 상호 작용해야합니다.

HTML5의 주요 요소에는 최신 웹 페이지를 작성하는 데 사용되는 ,,,,, 등이 포함됩니다. 1. 헤드 컨텐츠 정의, 2. 링크를 탐색하는 데 사용됩니다. 3. 독립 기사의 내용을 나타내고, 4. 페이지 내용을 구성하고, 5. 사이드 바 컨텐츠 표시, 6. 바닥 글을 정의하면, 이러한 요소는 웹 페이지의 구조와 기능을 향상시킵니다.

HTML5와 H5 사이에는 차이가 없으며, 이는 HTML5의 약어입니다. 1.HTML5는 HTML의 다섯 번째 버전으로 웹 페이지의 멀티미디어 및 대화식 기능을 향상시킵니다. 2.H5는 종종 HTML5 기반 모바일 웹 페이지 또는 응용 프로그램을 참조하는 데 사용되며 다양한 모바일 장치에 적합합니다.

HTML5는 W3C에 의해 표준화 된 하이퍼 텍스트 마크 업 언어의 최신 버전입니다. HTML5는 새로운 시맨틱 태그, 멀티미디어 지원 및 양식 향상을 도입하여 웹 구조, 사용자 경험 및 SEO 효과를 개선합니다. HTML5는 웹 페이지 구조를 더 명확하게하고 SEO 효과를 더 좋게하기 위해, 등 등과 같은 새로운 시맨틱 태그를 소개합니다. HTML5는 멀티미디어 요소를 지원하며 타사 플러그인이 필요하지 않으므로 사용자 경험을 향상시키고 속도를로드합니다. HTML5는 양식 함수를 향상시키고 사용자 경험을 향상시키고 양식 검증 효율성을 향상시키는 새로운 입력 유형을 도입합니다.

깨끗하고 효율적인 HTML5 코드를 작성하는 방법은 무엇입니까? 답은 태그, 구조화 된 코드, 성능 최적화 및 일반적인 실수를 피함으로써 일반적인 실수를 피하는 것입니다. 1. 코드 가독성 및 SEO 효과를 향상시키기 위해 시맨틱 태그 등을 사용하십시오. 2. 적절한 계약과 의견을 사용하여 코드를 구성하고 읽을 수 있도록하십시오. 3. CDN 및 압축 코드를 사용하여 불필요한 태그를 줄임으로써 성능을 최적화합니다. 4. 태그가 닫히지 않은 것과 같은 일반적인 실수를 피하고 코드의 유효성을 확인하십시오.

H5는 멀티미디어 지원, 오프라인 스토리지 및 성능 최적화로 웹 사용자 경험을 향상시킵니다. 1) 멀티미디어 지원 : H5 및 요소는 개발을 단순화하고 사용자 경험을 향상시킵니다. 2) 오프라인 스토리지 : WebStorage 및 IndexedDB는 오프라인으로 사용하여 경험을 향상시킵니다. 3) 성능 최적화 : 웹 워즈 및 요소는 성능을 최적화하여 대역폭 소비를 줄입니다.

HTML5 코드는 태그, 요소 및 속성으로 구성됩니다. 1. 태그는 컨텐츠 유형을 정의하고 다음과 같은 각도 브래킷으로 둘러싸여 있습니다. 2. 요소는 컨텐츠와 같은 시작 태그, 내용 및 엔드 태그로 구성됩니다. 3. 속성 시작 태그에서 키 값 쌍을 정의하고 기능을 향상시킵니다. 웹 구조를 구축하기위한 기본 단위입니다.

HTML5는 현대적인 웹 페이지를 구축하는 핵심 기술로 많은 새로운 요소와 기능을 제공합니다. 1. HTML5는 웹 페이지 구조 및 SEO를 향상시키는 의미 론적 요소를 소개합니다. 2. 멀티미디어 요소를 지원하고 플러그인없이 미디어를 포함시킵니다. 3. 양식은 새로운 입력 유형 및 검증 속성을 향상시켜 검증 프로세스를 단순화합니다. 4. 웹 페이지 성능 및 사용자 경험을 향상시키기 위해 오프라인 및 로컬 스토리지 기능을 제공합니다.


핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

Video Face Swap
완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

인기 기사

뜨거운 도구

드림위버 CS6
시각적 웹 개발 도구

맨티스BT
Mantis는 제품 결함 추적을 돕기 위해 설계된 배포하기 쉬운 웹 기반 결함 추적 도구입니다. PHP, MySQL 및 웹 서버가 필요합니다. 데모 및 호스팅 서비스를 확인해 보세요.

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

VSCode Windows 64비트 다운로드
Microsoft에서 출시한 강력한 무료 IDE 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.
