算法别名:

漫水填充算法、种子填充算法(Seed Fill)

作用:

用于确定连接到多维数组中给定节点的区域,可以用来标记或者分离图像的一部分,实现如Ps中自动选区功能。

基本思想:

顾名思义就像洪水漫过一样,把一块连通的区域填满。

当然水要能漫过需要满足一定的条件,可以理解为满足条件的地方就是低洼的地方,水才能流过去。

在图像处理中就是给定一个种子点作为起始点,向附近相邻的像素点扩散,把颜色相同或者相近的所有点都找出来,并填充上新的颜色,这些点形成一个连通的区域。

算法参数:

  1. 起始节点(start node)
  2. 目标颜色(target color)
  3. 替换颜色(replacement color)

算法实现:

漫水填充算法实现最常见有四邻域像素填充法,八邻域像素填充法,基于扫描线的填充方法。根据代码实现方式又可以分为递归与非递归。

1、四邻域递归实现

将像素点(x,y)周围的上下左右四个点分别进行着色。

//Recursive 4-way floodfill, crashes if recursion stack is full
public void floodFill4(int x, int y, int newColor, int oldColor)
{  if(x >= 0 && x < width && y >= 0 && y < height   && getPixel(x, y) == oldColor && getPixel(x, y) != newColor)   {   setPixel(x, y, newColor); //set color before starting recursion  floodFill4(x + 1, y, newColor, oldColor);  floodFill4(x - 1, y, newColor, oldColor);  floodFill4(x, y + 1, newColor, oldColor);  floodFill4(x, y - 1, newColor, oldColor);  }
}

2、八邻域递归实现

将一个像素点的上下左右,左上,左下,右上,右下都进行着色。

public void floodFill8(int x, int y, int newColor, int oldColor)
{  if(x >= 0 && x < width && y >= 0 && y < height &&   getPixel(x, y) == oldColor && getPixel(x, y) != newColor)   {   setPixel(x, y, newColor); //set color before starting recursion  floodFill8(x + 1, y, newColor, oldColor);  floodFill8(x - 1, y, newColor, oldColor);  floodFill8(x, y + 1, newColor, oldColor);  floodFill8(x, y - 1, newColor, oldColor);  floodFill8(x + 1, y + 1, newColor, oldColor);  floodFill8(x - 1, y - 1, newColor, oldColor);  floodFill8(x - 1, y + 1, newColor, oldColor);  floodFill8(x + 1, y - 1, newColor, oldColor);  }
} 

3、扫描线算法(Scanline Fill):

利用填充线来加速算法, 它不是在堆栈上推动每个潜在的未来像素坐标,而是检查相邻线(前一个和下一个)以找到可能在未来通过中填充的相邻段, 线段的坐标(开始或结束)被推到堆栈上。 在大多数情况下,该扫描线算法至少比每像素算法快一个数量级。

该算法的过程是:先扫描一行或者一列内的连通像素,然后再上下行或者左右列扫描,可以减少递归栈的深度。

递归方式:

递归实现算法好理解,但当连通的区域很大时,很可能会导致栈溢出

void floodFillScanline(int x, int y, int newColor, int oldColor){if(newColor==oldColor) return;if(screen[x][y]!=oldColor) return;int x1=x;while(x1<w&&screen[x1][y]==oldColor){screen[x1][y]=newColor;x1++;}x1=x-1;while(x1>=0&&screen[x1][y]==oldColor){screen[x1][y]=newColor;x1--;}x1=x;while(x1<w&&screen[x1][y]==newColor){if(y<h-1&&screen[x1][y+1]==oldColor) floodFillScanline(x1,y+1,newColor,oldColor);x1++;}x1=x-1;while(x1>0&&screen[x1][y]==newColor){if(y>0&&screen[x1][y+1]==oldColor) floodFillScanline(x1,y+1,newColor,oldColor);x1--;}x1=x;while(x1<w&&screen[x1][y]==newColor){if(y<h-1&&screen[x1][y-1]==oldColor) floodFillScanline(x1,y+1,newColor,oldColor);x1++;}x1=x-1;while(x1>0&&screen[x1][y]==newColor){if(y>0&&screen[x1][y-1]==oldColor) floodFillScanline(x1,y+1,newColor,oldColor);x1--;}
}

非递归方式:

void floodFillScanline(int x, int y, int newColor, int oldColor){if(newColor==oldColor) return;if(screen[x][y]!=oldColor) return;emptyStack();int x1;bool spanAbove, spanBelow;if(!push(x,y)) return;while(pop(x,y)){x1=x;while(x1>0&&screen[x1][y]==oldColor) x1--;x1++;spanAbove = spanBelow = 0;while(x1<w&&screen[x1][y]==oldColor){screen[x1][y]=newColor;if(!spanAbove&&y>0&&screen[x1][y-1]==oldColor){ //这里判断出了上行的元素可以被染色,可能为了修改screen的访存连续性,所以这里没修改。而且你改了上行的值,却没考虑其四周,会有完备性的问题。if(!push(x1,y-1)) return;spanAbove=1;}else if(spanAbove&&y>0&&screen[x1][y-1]!=oldColor){spanAbove=0; //不压入重复过多的元素}if(!spanBelow&&y<h-1&&screen[x1][y+1]==oldColor){if(!push(x1,y+1)) return;spanBelow=1;}else if(spanBelow&&y<h-1&&screen[x1][y+1]!=oldColor){spanBelow=0;}x1++;}}
}

4、OpenCV 的 floodFill 函数

在OpenCV中,漫水填充算法由floodFill函数实现,可以从指定的种子点开始填充一个连通域。连通性由像素值的接近程度来衡量。

OpenCV2.X 有两个C++重载的floodFill函数:

/* fills the semi-uniform image region starting from the specified seed point*/
CV_EXPORTS int floodFill( InputOutputArray image,Point seedPoint, Scalar newVal, CV_OUT Rect* rect=0,Scalar loDiff=Scalar(), Scalar upDiff=Scalar(),int flags=4 );/* fills the semi-uniform image region and/or the mask starting from thespecified seed point*/
CV_EXPORTS int floodFill( InputOutputArray image,InputOutputArray mask,Point seedPoint, Scalar newVal, CV_OUT Rect* rect=0,Scalar loDiff=Scalar(), Scalar upDiff=Scalar(),int flags=4 );

• image 要处理的图片,既是入参也是出参,接受单通道或3通道,8位或浮点类型的图片。如果提供了Mask而且设置了 FLOODFILL_MASK_ONLY 的flag,输入图像才不会被修改,否则调用本方法填充的结果会修改到输入图像中。

• mask 掩码图像,既是入参也是出参,接受单通道8位的图片,要求比要处理的图片宽和高各大两个像素。mask要先初始化好,填充算法不能漫过mask中非0的区域。比如可以用边缘检测的结果来做为mask,以防止边缘被填充。做为输出参数,mask对应图片中被填充的像素会被置为1或者下面参数指定的值。因此当多次调用floodFill方法,使用同一个mask时,可以避免填充区域叠加和重复计算。 因为 mask比image大,所以image中的点 p(x,y),对应mask中的点 p(x+1, y+1)

• seedPoint 填充算法的种子点,即起始点

• newVal 填充的颜色

• loDiff 最小的亮度或颜色的差值

• upDiff 最大的亮度者颜色的差值

• rect 可选的输出参数,返回一个最小的矩形,可以刚好把填充的连通域包起来。

• flags

- 低八位[0-7]表示连通性,默认值4表示四领域填充,8表示八领域填充。

- [8-15]位表示用来填充mask的颜色值[1-255]默认是1

- 比如flag值(4|(255«8)) 表示使用四领域填充,mask填充色值是255。

- 剩余的位有两个值可以单独设置或者用(|)同时设置:      

FLOODFILL_MASK_ONLY 表示不修改原始输入图像,只把结果输出到mask图中,在mask中将填充区域标上前面flag中指定的值。newVal的参数值将被忽略。

FLOODFILL_FIXED_RANGE 表示待填充像素只和种子点比较。如果不设置这个标记,表示待填充的像素是和相邻的像素比较(相当于差值范围是浮动的),这种情况下填充区域的像素可能会和种子点相差越来越大。

参考链接

以下为本博客的参考内容:

  1. 图像处理之漫水填充算法(flood fill algorithm) - 腾讯云开发者社区-腾讯云 (tencent.com)
  2. Flood fill Algorithm // 谭邵杰的计算机奇妙旅程 (ustc.edu.cn)
  3. 图像分割经典算法--《泛洪算法》(Flood Fill)_我的她像朵花的博客-CSDN博客_泛洪算法

算法介绍 | 泛洪算法(Flood fill Algorithm)相关推荐

  1. 图像处理------泛洪填充算法(Flood Fill Algorithm) 油漆桶功能

    泛洪填充算法(Flood Fill Algorithm) 泛洪填充算法又称洪水填充算法是在很多图形绘制软件中常用的填充算法,最熟悉不过就是 windows paint的油漆桶功能.算法的原理很简单,就 ...

  2. 洪水填充算法_洪水填充(Flood fill)算法

    洪水填充(Flood fill)算法 从一个起始节点开始把附近与其连通的节点提取出或填充成不同颜色颜色,直到封闭区域内的所有节点都被处理过为止,是从一个区域中提取若干个连通的点与其他相邻区域区分开(或 ...

  3. Flood fill algorithm

    Flood fill算法是从一个区域中提取若干个连通的点与其他相邻区域区分开的经典算法.因为其思路类似洪水从一个区域扩散到所有能到达的区域而得名.在GNU Go和扫雷中,Flood Fill算法被用来 ...

  4. REDIS09_LBS出现背景、GEO算法介绍、算法步骤、剖析、邻近网格位置推算

    文章目录 ①. LBS出现的背景 ②. 重新认识经纬度 ③. 感性认识GeoHash ④. Geohash算法介绍 ⑤. Geohash算法步骤 ⑥. 更深入剖析GeoHash ⑦. 邻近网格位置推算 ...

  5. 算法提高课-搜索-Flood fill算法-AcWing 1106. 山峰和山谷:flood fill、bfs

    题目分析 来源:acwing 分析:这道题还是flood fill算法的应用,不同点在于八个方向扫描,习惯性采用二重循环来扫描周围的8个方向:其次,这里需要统计周围比它高的和比它矮的,这点用bool变 ...

  6. 算法提高课-搜索-Flood fill算法-AcWing 1097. 池塘计数:flood fill、bfs

    Flood fill 算法简介: 像洪水一样,一圈一圈往外蔓延,像bfs. flood fill 算法可以在线性复杂度内,找到某个点所在的连通块. 题目分析 来源:acwing ac代码 #inclu ...

  7. 算法提高课-搜索-Flood fill算法-AcWing 1098. 城堡问题:flood fill、bfs

    题目分析 来源:acwing 分析:找房间个数,也就是找连通的个数. 样例画出来的房间个数如下图:其中'|' 和'-'不是墙,只有#是墙. 分析:这题不用建图,直接bfs(flood fill)来做, ...

  8. python协同过滤算法_协同过滤算法介绍及算法实现

    一.协同过滤算法简介 协同过滤算法是一种较为著名和常用的推荐算法,它基于对用户历史行为数据的挖掘发现用户的喜好偏向,并预测用户可能喜好的产品进行推荐.也就是常见的"猜你喜欢",和& ...

  9. 协同过滤算法介绍及算法实现

    一.协同过滤算法简介 协同过滤算法是一种较为著名和常用的推荐算法,它基于对用户历史行为数据的挖掘发现用户的喜好偏向,并预测用户可能喜好的产品进行推荐.也就是常见的"猜你喜欢",和& ...

最新文章

  1. 计算摄影 | 计算机如何学会自动裁剪图片(自动构图)?
  2. SSH实现分页查询(转)
  3. python字典可以切片吗_7.map(感觉跟python中的字典有点像)数组,切片(make)傻傻分不清楚,多多指点...
  4. redis key设计技巧
  5. cigarettes(香烟)
  6. 【探究】信号槽到底能不能有返回值?
  7. LeetCode 1458. 两个子序列的最大点积(动态规划,类似编辑距离)
  8. struts2下的Action配置的各项默认值
  9. 【自动驾驶】一文读懂自动驾驶汽车产业链上下游|湾区人工智能
  10. windows 清除IE浏览器缓存的脚本
  11. 跨境电商ERP综合解决方案丨汇信
  12. 51单片机引脚内部电路
  13. Jenkins | 搭建你第一个Jenkins应用
  14. 陶哲轩实分析 3.4
  15. ROG GL552VW BIOS 编程器官方固件
  16. ctf web3 30 flag就在这里快来找找吧http://123.206.87.240:8002/web3
  17. C++入门级编程题(基础)
  18. 转载:mongo常规操作 大于/小于/不等于……
  19. 转计算机大牛-崔添翼
  20. oracle crs 4563,重启机器后,节点2无法启动crs,Oracle你生产的RAC为何如此的脆弱,有图有真相。求解...

热门文章

  1. iosetup mysql_InnoDB: Error: io_setup() failed with EAGAIN
  2. 一个大牛的acm历程(很棒 优秀的人真的很多)
  3. JVM垃圾回收器-CMS并发标记清除
  4. android 申请移动应用的签名生成方法
  5. 【labview】限幅子vi +源程序
  6. 首次实战Vue高仿移动端QQ音乐项目解析
  7. 开源 iOS 项目分类索引大全 - 待整理
  8. 使用隐马尔科夫模型实现分词
  9. 电子木鱼网页版(教学+源码带注释)
  10. vue即时通讯,一个很好用的插件