区域生长算法

10

大家好。我真的很难理清楚这个问题的逻辑,并希望你们能帮助我。在我继续之前,我想让你知道,我是一名业余程序员,一个初学者,没有任何正式的计算机科学培训,所以请见谅。:D 此外,我正在使用Python,但我可以使用Java或类似的语言。

不管怎样,我想实现区域生长算法并用于一个简单的绘画机器人。以下是关于区域生长的文章:http://en.wikipedia.org/wiki/Region_growing

按照我的设想,描绘图像应符合以下标准:

  • 图像最多为3英寸乘3英寸,颜色深度任意

  • 图像是一个黑色连续形状,背景为白色

  • 形状可以位于背景的任何位置。

我考虑了以下解决方案。虽然某些方案在某种程度上有些作用,但每种方案都存在明显的缺陷,无论从性能还是可行性上(至少对我来说似乎不可行)。此外,因为这是一个绘画机器人,需要用一根连续的线来完成绘制。这并不意味着我不能回头走,它只消除了多个起始点(种子)的可能性。

考虑过的方法:

随机漫步:

用随机漫步来解决这个问题是我的第一反应。我想,实现这个目标的随机漫步程序可能看起来像这样:

伪代码Python...

Cells To Visit = Number of Black Cells
Cells Visited = 0
MarkColor = red
While Cells Visited < Cells To Visit:
    if currentcell is black:
        Mark Current Cell As Visited #change pixel to red
        Cells Visited +=1
    neighbors = Get_Adjacent_Cells() #returns cells either black or red
    next cell = random.choose(neighbors)
    currentCell = next cell

虽然我认为这是可行的,但对我来说似乎效率极低并且不能保证好的结果,但为了实际完成一些工作,我可能会尝试这样做... 我的伪代码逻辑是否正确?

扫描模式:

对我来说,这种方法似乎最容易实现。我的想法是,我可以在形状的一个端点(例如最左下角的点)选择一个起始点。从那里开始,它将向右绘制,仅在x轴上移动,直到遇到白色像素。从这里,它将向上移动一个像素,然后沿着x轴向左移动,直到达到白色像素。如果它上面的像素也是白色的,就回溯到x轴上找到它上面的黑色像素。

进一步检查后,发现这种方法存在一些主要缺点。当面对这样的形状时:

diagram1

结果看起来像这样:

diagram2

即使我告诉它在一段时间后开始向下扫描,中间的腿部仍将被忽略。

4/8 连通邻域:

http://en.wikipedia.org/wiki/8-connected_neighborhood

这种方法对我来说似乎是最强大和有效的,但在这一点上,我无法完全理解它,也无法想出如何实现它,而不会潜在地留下一些遗漏的区域。

在每个单元格中,我将查看相邻的黑色单元格,设计一些排序方法以确定首先访问哪一个,访问所有单元格,然后重复此过程,直到覆盖所有单元格。

我能看到的问题是首先处理完成这项任务所需的数据结构,以及仅仅弄清楚背后的逻辑。


这些是我能想到的最佳解决方案。感谢您花费时间阅读这篇文章,虽然有点长,但我认为我应该尽可能明确。非常感谢任何建议...谢谢!

编辑:

我还研究了迷宫生成和解决算法,但不确定如何在这里实现。我对迷宫解决算法的理解是它们依赖迷宫通道宽度相等。当然,我可能错了。


谢谢分享。我现在正在学习中。根据我的进度,我会告诉你/向你提问更多问题。 :P - danem
你会如何填充一个宽度为1像素的T形图案? - Stephen Denne
4个回答

5

基本区域生长算法的伪代码大致如下:

seed_point // starting point
visited // boolean array/matrix, same size as image
point_queue // empty queue

point_queue.enqueue( seed_point )
visited( seed_point ) = true

while( point_queue is not empty ) {
    this_point = point_queue.dequeue()
    for each neighbour of this_point {
        if not visited( neighbour ) and neighbour is black/red/whatever
            point_queue.enqueue( neighbour )
            visited( neighbour ) = true
    }
}

// we are done. the "visited" matrix tells
// us which pixels are in the region

我不明白你提到的排名与此有何关系。我是否遗漏了什么?

你是在指我提到的8个相邻单元格方法中的排名吗?如果是这样,我的意思是,基于这样一个假设:对于任何给定的八个邻居,都有一个最佳的单元格可以先访问。因此,我认为我需要找出哪些是最好的访问方式以及如何对它们进行排名... 或者我可能完全错了哈哈。另外,在尝试理解您的示例时,visited数组是否具有与其坐标相对应的布尔值?此外,这个解决方案会按顺序访问每个点吗?感谢您的帮助。您的示例给了我一些启示! - danem
是的,visited数组将具有与坐标对应的布尔值。我会检查算法,因为它可能不是100%正确的,但是思路在那里 :) 是的,关于排名。如果您需要找到整个黑色区域,那么顺序如何重要呢?毫无疑问,任何顺序都和其他任何顺序一样好(因此我错过了什么吗)?为了了解这里的顺序如何工作(广度优先),您可以获取一个空的填字游戏,并尝试手动执行算法,从某个种子点开始。 - YXD
好的,没问题。我现在有很多信息要处理。在我研究完所有给出的答案后,我会告诉你我的进展情况。非常感谢! - danem
关于我的进展,我想更新一下... 我已经成功地实现了一个递归回溯的方法,它运行得非常好,但是有一些严重的缺点... 这些缺点是由于算法的工作方式,每个单独的单元格都会增加另一层递归。所以当处理一个1000x1000像素的图像时......我将尝试实现您的解决方案。 - danem
是的,递归方法肯定会限制区域的大小。祝你实现成功。 - YXD

2

我对这个非常长的问题感到困惑。

你确定你不是在尝试进行泛洪填充吗?


1
这正是E先生的答案所做的。我只想指出这个问题非常全面的维基百科文章。 - hugomg
一种特定类型的泛洪填充算法——其中每个新设置的像素都与先前设置的像素相邻。 - Stephen Denne

1
一个简单的技巧可以帮助解决一些迷宫问题,就是保持一只手靠在墙上。
但请注意,如果你选择了一个随机的起点,你可能会选择一个点,无论你从哪个方向出发,都会阻挡掉一部分路线。例如,如果你从沙漏形状的中间开始,你只能填充其中的一半。

我原本计划指定一个特定的起点,但这对我来说已经很困难了,我无法想象要处理所有可能的起点... D:为了看看我是否理解你的解决方案,你建议的方法会得到一条沿着最外层边缘运行并最终螺旋式进入自身的路径吗?如果是这样的话,是否仍然有可能像沙漏一样封锁部分区域?关于迷宫求解,我曾考虑过,但无法想出如何在这里实现... - danem
是的,螺旋填充区域。我的意思是说,总会有可能无法创建单个非分支路径来填充任意区域。 - Stephen Denne
我建议您尝试这种沿墙方法,但是有一个额外的步骤:测试一下,如果您要移动到的下一个像素处形成了“瓶颈”,即左右两侧都有墙壁,请改变方向并沿着另一侧的墙壁行进。重复此过程,直到除了通过“瓶颈”(左、右和后面都有墙壁)之外没有其他地方可去。我认为这种方法适用于沙漏形状。 - so12311

1

这里有一个非常好的小视频,讲解如何编写递归迷宫求解器:http://thinkcode.tv/catalog/amazing-python/

我认为这可能会给你一些解决问题的思路。

此外,这是一个我在观看视频后编写的递归迷宫求解脚本http://pastie.org/1854582。等宽通道并不是必需的,唯一必要的是开放空间、墙壁和某种结束条件,例如找到迷宫的出口。

如果你不想使用递归,另一种方法是使用“回溯”方法。你可以在这个页面上看到它被用于随机生成迷宫的一个小例子:http://weblog.jamisbuck.org/2011/2/7/maze-generation-algorithm-recap(页面上的第一个例子)。

听起来相关吗?如果是的话,请告诉我是否需要我更详细地解释一些内容。

编辑:

这篇关于在Python中进行填充算法讨论似乎非常好 http://www.daniweb.com/software-development/python/threads/148874


非常感谢。一开始我考虑使用回溯法,因为在维基百科上看到了简要的描述,但是由于我是编程新手,数据结构似乎有些令人望而生畏。我一定会去看看那些资料的。 - danem
说句题外话,在第三个链接中展示的回溯演示非常棒!我将花一段时间从中学习... - danem
有没有办法处理大量递归?虽然我认为我已经正确实现了它,但由于我不是在制作迷宫,而是在跟踪图像,算法的性质是每个像素都会添加新级别。因此,在处理400x400像素图像时,对于信息更密集的图片,递归限制很快就会达到。如果您想看一下我的代码,请访问http://pastebin.com/Uqf20f4。感谢您的帮助! - danem
我已经添加了一个链接,指向一个关于在Python中实现泛洪填充的有用讨论。另外,pastebin链接已经失效。 - Acorn
糟糕...希望这个链接有效... pastebin.com/Uqf20f4u 我一定会去查看的。 - danem

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接