填充操作如何在涂料应用中起作用?

时间:2008-11-08 02:08:30

标签: algorithm image-processing

所有绘画程序,无论它们多么简单或复杂,都带有填充工具。这基本上用另一种颜色替换封闭区域的颜色。我知道有不同的API可以做到这一点,但我对算法很感兴趣。什么是实现此工具的有效算法?

我能想到的一些事情很快就会出现:

  1. 将图片转换为二进制地图,其中要替换的颜色中的像素为1,其他所有颜色均为0
  2. 在要更改的点周围找到一个封闭区域,使内部所有像素均为1,所有相邻像素均为0。
  3. Sample Image

6 个答案:

答案 0 :(得分:9)

许多实现都是作为递归征服和除法算法完成的。如果你快速谷歌搜索“洪水填充算法”,你会发现很多资源,包括the topic上的优秀维基百科页面。

答案 1 :(得分:7)

Flood Fill算法是最常用的算法。以下是我的旧大学教科书“Helen Baker的计算机图形学”,第3版:

void floodFill4 (int x, int y, int fillColor, int interiorColor)
{
  int color;

  /* Set current color to fillColor, then perform the following operations */
  getPixel(x, y, color);
  if (color == interiorColor) 
  {
    setPixel(x,y);  // Set color of pixel to fillColor.
    floodFill4(x + 1, y, fillColor, interiorColor);
    floodFill4(x - 1, y, fillColor, interiorColor);
    floodFill4(x, y + 1, fillColor, interiorColor);
    floodFill4(x, y - 1, fillColor, interiorColor);
  }
}

但是,对于大图像,由于每个像素的递归,上面的内容可能会给出堆栈溢出错误。通常,此算法会被修改,以便在填充一行像素时使用迭代,然后递归填充上方和下方的行。正如@kasperjj所述,维基百科有一篇很好的文章。

答案 2 :(得分:3)

Computer Graphics: Principles and Practice详细讨论了这些算法。如果您有兴趣了解如何光栅化线条,填充多边形,编写3D代码而不使用DirectX或OpenGL API,我强烈推荐这本书。当然,对于真实世界的应用程序,您可能希望使用现有的库,但如果您对这些库的工作原理感到好奇,那么这是一个很棒的阅读。

答案 3 :(得分:1)

如果您想要一种不关心内存效率的时间效率算法,可以通过以下方式实现:

1)保留已经访问过哪些单元格的布尔记忆:Vis[]

2)保留您已访问但尚未标记邻居的点列表:Busy[]

3)将这两个开始为空

4)将您的起点添加到Busy

5)

while you have a point P in Busy:
{
    for each neighbour N of the point P for which Vis[N] is still false
    {
       if appropriate (not crossing the boundary of the fill region)
       {
           set Vis[N] to true
           update the colour of N in the bitmap
           add N to the end of Busy[]
       }
       remove P from Busy[]
    }
}

答案 4 :(得分:1)

另请阅读有关连接组件标签的信息。这是找到连接像素的有效方法,同时只访问每个像素两次。

Wikipedia article.

这样做的好处是像素值不一定必须相同,或者描述连接像素的函数可能不是原始值 - 梯度也许。

答案 5 :(得分:1)

一般概念被描述为Flood Fill Algorithm,并且对其进行了各种修改。常见的是扫描线填充。请参阅相关问题How Scanline based 2d rendering engines works?