웹 프론트엔드 H5 튜토리얼 如何用程序解图片迷宫?

如何用程序解图片迷宫?

May 17, 2016 am 09:08 AM

 英文原文:Representing and solving a maze given an image

  译注:原文是 StackOverflow 上一个如何用程序读取迷宫图片并求解的问题,几位参与者热烈地讨论并给出了自己的代码,涉及到用 Python 对图片的处理以及广度优先(BFS)算法等。

  问题 by Whymarrh:

1116.jpg

       当给定上面那样一张 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 或其他语言,下面是程序的运行结果:

1117.jpg

提问者更新:

  我用 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);
로그인 후 복사

1118.jpg

回答 by Stefano

  stefano 童鞋给出了生成搜索过程 GIF 及 AVI 文件的代码 maze-solver-python (GitHub)

以上就是如何用程序解图片迷宫的内容,更多相关内容请关注PHP中文网(www.php.cn)!


본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

Video Face Swap

Video Face Swap

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

뜨거운 도구

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전

SublimeText3 중국어 버전

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

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

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

iPhone에서 Google 지도를 기본 지도로 설정하는 방법 iPhone에서 Google 지도를 기본 지도로 설정하는 방법 Apr 17, 2024 pm 07:34 PM

iPhone의 기본 지도는 Apple의 독점 위치 정보 제공업체인 지도입니다. 지도가 점점 좋아지고 있지만 미국 이외의 지역에서는 잘 작동하지 않습니다. Google 지도와 비교하면 아무것도 제공할 수 없습니다. 이 기사에서는 Google 지도를 사용하여 iPhone의 기본 지도로 만드는 실행 가능한 단계에 대해 설명합니다. iPhone에서 Google 지도를 기본 지도로 설정하는 방법 Google 지도를 휴대전화의 기본 지도 앱으로 설정하는 것은 생각보다 쉽습니다. 아래 단계를 따르십시오. – 전제 조건 단계 – 휴대폰에 Gmail이 설치되어 있어야 합니다. 1단계 – AppStore를 엽니다. 2단계 – “Gmail”을 검색하세요. 3단계 - Gmail 앱 옆을 클릭하세요.

수정: Windows 작업 스케줄러에서 운영자 거부 요청 오류 수정: Windows 작업 스케줄러에서 운영자 거부 요청 오류 Aug 01, 2023 pm 08:43 PM

작업을 자동화하고 여러 시스템을 관리하기 위해 임무 계획 소프트웨어는 특히 시스템 관리자에게 유용한 도구입니다. Windows 작업 스케줄러는 작업을 완벽하게 수행하지만 최근 많은 사람들이 운영자 거부 요청 오류를 보고했습니다. 이 문제는 운영 체제의 모든 반복에 존재하며 널리 보고되고 다루어졌음에도 불구하고 효과적인 해결책은 없습니다. 다른 사람들에게 실제로 효과가 있을 수 있는 것이 무엇인지 알아보려면 계속해서 읽어보세요! 운영자 또는 관리자가 거부한 작업 스케줄러 0x800710e0의 요청은 무엇입니까? 작업 스케줄러를 사용하면 사용자 입력 없이 다양한 작업과 응용 프로그램을 자동화할 수 있습니다. 이를 사용하여 특정 애플리케이션을 예약 및 구성하고, 자동 알림을 구성하고, 메시지 전달을 돕는 등의 작업을 할 수 있습니다. 그것

Windows 10 및 11에서 얼굴별로 사진을 정렬하는 방법 Windows 10 및 11에서 얼굴별로 사진을 정렬하는 방법 Aug 08, 2023 pm 10:41 PM

Windows의 작동은 사용자 경험을 향상시키는 매력적인 기능을 포함하여 모든 버전에서 점점 더 좋아지고 있습니다. 사용자가 Windows 10 및 11에서 탐색하고 싶은 기능 중 하나는 사진을 얼굴별로 정렬하는 기능입니다. 이 기능을 사용하면 얼굴 인식을 사용하여 친구와 가족의 사진을 그룹화할 수 있습니다. 재미있을 것 같죠? 이 기능을 활용하는 방법을 알아보려면 계속 읽어보세요. Windows에서 사진을 얼굴별로 그룹화할 수 있나요? 예, Windows 10 및 11에서 사진 앱을 사용하여 사진을 얼굴별로 그룹화할 수 있습니다. 하지만 포토 앱 버전에서는 이 기능을 사용할 수 없습니다. 또한 인물 탭을 사용하여 이러한 사진을 연락처에 연결할 수 있습니다. 따라서 이 기능을 사용하면 다음과 같은 작업을 수행할 수 있습니다.

iPhone에 시계 앱이 없습니다. 해결 방법 iPhone에 시계 앱이 없습니다. 해결 방법 May 03, 2024 pm 09:19 PM

휴대폰에 시계 앱이 없나요? 날짜와 시간은 iPhone의 상태 표시줄에 계속 표시됩니다. 그러나 시계 앱이 없으면 세계 시계, 스톱워치, 알람 시계 및 기타 여러 기능을 사용할 수 없습니다. 따라서 누락된 시계 앱을 수정하는 것이 해야 할 일 목록의 맨 위에 있어야 합니다. 이러한 솔루션은 이 문제를 해결하는 데 도움이 될 수 있습니다. 수정 1 - 시계 앱 배치 실수로 홈 화면에서 시계 앱을 제거한 경우 시계 앱을 다시 제자리에 배치할 수 있습니다. 1단계 – iPhone을 잠금 해제하고 앱 라이브러리 페이지에 도달할 때까지 왼쪽으로 스와이프합니다. 2단계 – 다음으로 검색창에 “시계”를 검색하세요. 3단계 – 검색 결과 아래에 “시계”가 표시되면 길게 누르고

C++로 간단한 카운트다운 프로그램을 작성하는 방법은 무엇입니까? C++로 간단한 카운트다운 프로그램을 작성하는 방법은 무엇입니까? Nov 03, 2023 pm 01:39 PM

C++는 카운트다운 프로그램을 작성하는 데 매우 편리하고 실용적인 프로그래밍 언어로 널리 사용됩니다. 카운트다운 프로그램은 매우 정확한 시간 계산 및 카운트다운 기능을 제공할 수 있는 일반적인 애플리케이션입니다. 이 기사에서는 C++를 사용하여 간단한 카운트다운 프로그램을 작성하는 방법을 소개합니다. 카운트다운 프로그램 구현의 핵심은 타이머를 사용하여 시간의 경과를 계산하는 것입니다. C++에서는 time.h 헤더 파일의 함수를 사용하여 타이머 함수를 구현할 수 있습니다. 다음은 간단한 카운트다운 프로그램의 코드입니다.

작업 스케줄러를 사용하여 웹사이트를 여는 방법 작업 스케줄러를 사용하여 웹사이트를 여는 방법 Oct 02, 2023 pm 11:13 PM

매일 같은 시간에 같은 웹사이트를 자주 방문하시나요? 이로 인해 여러 브라우저 탭을 열어두고 일상적인 작업을 수행하는 동안 브라우저가 복잡해지는 데 많은 시간을 소비하게 될 수 있습니다. 그렇다면 브라우저를 수동으로 실행할 필요 없이 열어보는 것은 어떨까요? 매우 간단하며 아래와 같이 타사 앱을 다운로드할 필요가 없습니다. 웹사이트를 열려면 작업 스케줄러를 어떻게 설정하나요? 키를 누르고 검색 상자에 작업 스케줄러를 입력한 다음 열기를 클릭합니다. Windows 오른쪽 사이드바에서 기본 작업 생성 옵션을 클릭합니다. 이름 필드에 열려는 웹사이트의 이름을 입력하고 다음을 클릭하세요. 그런 다음 트리거에서 시간 빈도를 클릭하고 다음을 클릭합니다. 이벤트를 반복할 기간을 선택하고 다음을 클릭하세요. 활성화 선택

특정 앱에 대해 iPhone 방향 잠금을 자동으로 전환하는 방법 특정 앱에 대해 iPhone 방향 잠금을 자동으로 전환하는 방법 Jun 06, 2023 am 08:22 AM

iOS에서는 iPhone을 세로에서 가로로 회전하면 많은 앱이 서로 다른 보기를 표시합니다. 앱과 사용 방법에 따라 이 동작이 항상 바람직한 것은 아니므로 Apple은 제어 센터에 방향 잠금 옵션을 포함합니다. 그러나 일부 앱은 방향 잠금이 비활성화된 상태에서 더 유용하게 작동합니다. YouTube나 사진 앱을 생각해 보세요. 기기를 가로 방향으로 회전하면 전체 화면 보기 환경이 더 좋아집니다. 잠금 상태를 유지하려면 이러한 유형의 앱을 열 때마다 전체 화면 경험을 얻기 위해 제어 센터에서 해당 기능을 비활성화해야 합니다. 그런 다음 앱을 닫을 때 방향 잠금을 다시 켜야 한다는 것을 기억해야 하는데 이는 이상적이지 않습니다. 다행히도 다음을 만들 수 있습니다.

iPhone에서 카메라 및 마이크에 대한 접근을 허용할 수 없습니다 iPhone에서 카메라 및 마이크에 대한 접근을 허용할 수 없습니다 Apr 23, 2024 am 11:13 AM

앱을 사용하려고 할 때 "카메라 및 마이크에 대한 접근을 허용할 수 없습니다"라는 메시지가 표시됩니까? 일반적으로 필요에 따라 특정 사람에게 카메라 및 마이크 권한을 부여합니다. 단, 권한을 거부할 경우 카메라와 마이크가 작동하지 않으며 대신 이런 오류 메시지가 표시됩니다. 이 문제를 해결하는 것은 매우 기본적이며 1~2분 안에 완료할 수 있습니다. 수정 1 – 카메라, 마이크 권한 제공 설정에서 직접 필요한 카메라 및 마이크 권한을 제공할 수 있습니다. 1단계 - 설정 탭으로 이동합니다. 2단계 – 개인 정보 보호 및 보안 패널을 엽니다. 3단계 - 거기에서 "카메라" 권한을 켭니다. 4단계 - 내부에서 휴대폰 카메라에 대한 권한을 요청한 앱 목록을 찾을 수 있습니다. 5단계 - 지정된 앱의 "카메라"를 엽니다.

See all articles