漫水填充也叫泛洪填充,是画图软件中的油漆桶功能,但在运用中,远不止于此,比如构造一个矩阵数据,需要检测边界,在边界的内外填入不同的数据。油漆桶是对图形的快速填充,将图象以位图数据的形式来看,其实也是一个矩阵数据或者说是二维数组,所以我们如果以数字作为矩阵数据,那么只需检测里面的数据即可。然后将数据再绘制成图像,那就是油漆桶的功能。为了保存数据,我们定义了一个数字矩阵,并在矩阵中实现相应的填充方法,代码如下。

#region DigitMatrix/// <summary>/// 数字矩阵/// </summary>public class DigitMatrix{#region 属性/// <summary>/// 行数/// </summary>public int RowCount { get; private set; }/// <summary>/// 列数/// </summary>public int ColumnCount { get; private set; }public int[,] Data { get; private set; }#endregionpublic DigitMatrix(int rowCount, int columnCount){RowCount = rowCount;ColumnCount = columnCount;Data = new int[RowCount, ColumnCount];}public override string ToString(){StringBuilder sb = new StringBuilder();for (int r = 0; r < RowCount; r++){string line = "";for (int c = 0; c < ColumnCount; c++){line += Data[r, c];}sb.AppendLine(line);}return sb.ToString();}#region FloodFill8/// <summary>/// 漫水填充(8邻域填充)/// </summary>/// <param name="r">行</param>/// <param name="c">列</param>/// <param name="newValue"></param>/// <param name="oldValue"></param>/// <param name="matrix"></param>public void FloodFill8(int r, int c, int newValue, int oldValue){//递归实现可能造成堆栈溢出错误if (r >= 0 && r < RowCount && c >= 0 && c < ColumnCount &&Data[r, c] == oldValue && Data[r, c] != newValue){Data[r, c] = newValue;FloodFill8(r + 1, c, newValue, oldValue);FloodFill8(r - 1, c, newValue, oldValue);FloodFill8(r, c + 1, newValue, oldValue);FloodFill8(r, c - 1, newValue, oldValue);FloodFill8(r + 1, c + 1, newValue, oldValue);FloodFill8(r - 1, c - 1, newValue, oldValue);FloodFill8(r - 1, c + 1, newValue, oldValue);FloodFill8(r + 1, c - 1, newValue, oldValue);}}#endregion#region FloodFill8WithStack/// <summary>/// 漫水填充(基于堆的8邻域填充)/// </summary>/// <param name="r">行</param>/// <param name="c">列</param>/// <param name="newValue"></param>/// <param name="oldValue"></param>/// <param name="matrix"></param>public void FloodFill8WithStack(int r, int c, int newValue, int oldValue){var stackRow = new Stack<int>();var stackColumn = new Stack<int>();stackRow.Push(r);stackColumn.Push(c);bool CheckNewSeed(int r1, int c1){if (r1 >= 0 && r1 < RowCount && c1 >= 0 && c1 < ColumnCount &&Data[r1, c1] == oldValue && Data[r1, c1] != newValue){Data[r1, c1] = newValue;stackRow.Push(r1);stackColumn.Push(c1);return true;}return false;}while (true){if (stackRow.Count <= 0){break;}r = stackRow.Pop();c = stackColumn.Pop();CheckNewSeed(r, c);CheckNewSeed(r + 1, c);CheckNewSeed(r - 1, c);CheckNewSeed(r, c + 1);CheckNewSeed(r, c - 1);CheckNewSeed(r + 1, c + 1);CheckNewSeed(r - 1, c - 1);CheckNewSeed(r - 1, c + 1);CheckNewSeed(r + 1, c - 1);}}#endregion#region FloodFill4/// <summary>/// 漫水填充(4邻域填充)/// </summary>/// <param name="r">行</param>/// <param name="c">列</param>/// <param name="newValue"></param>/// <param name="oldValue"></param>public void FloodFill4(int r, int c, int newValue, int oldValue){//递归实现可能造成堆栈溢出错误if (r >= 0 && r < RowCount && c >= 0 && c < ColumnCount&& Data[r, c] == oldValue && Data[r, c] != newValue){Data[r, c] = newValue;FloodFill4(r + 1, c, newValue, oldValue);FloodFill4(r - 1, c, newValue, oldValue);FloodFill4(r, c + 1, newValue, oldValue);FloodFill4(r, c - 1, newValue, oldValue);}}#endregion#region FloodFill4WithStack/// <summary>/// 漫水填充(基于堆的4邻域填充)/// </summary>/// <param name="r">行</param>/// <param name="c">列</param>/// <param name="newValue"></param>/// <param name="oldValue"></param>public void FloodFill4WithStack(int r, int c, int newValue, int oldValue){var stackRow = new Stack<int>();var stackColumn = new Stack<int>();stackRow.Push(r);stackColumn.Push(c);bool CheckNewSeed(int r1, int c1){if (r1 >= 0 && r1 < RowCount && c1 >= 0 && c1 < ColumnCount &&Data[r1, c1] == oldValue && Data[r1, c1] != newValue){Data[r1, c1] = newValue;stackRow.Push(r1);stackColumn.Push(c1);return true;}return false;}while (true){if (stackRow.Count <= 0){break;}r = stackRow.Pop();c = stackColumn.Pop();CheckNewSeed(r, c);CheckNewSeed(r + 1, c);CheckNewSeed(r - 1, c);CheckNewSeed(r, c + 1);CheckNewSeed(r, c - 1);}}#endregion#region FloodFillScanRowColumn/// <summary>/// 漫水填充(基于行扫描行列的递归填充)/// </summary>/// <param name="r">行</param>/// <param name="c">列</param>/// <param name="newValue"></param>/// <param name="oldValue"></param>public void FloodFillScanRowColumn(int r, int c, int newValue, int oldValue){//递归实现可能造成堆栈溢出错误if (oldValue == newValue) return;if (Data[r, c] != oldValue) return;int c1;//从当前位置扫描至最右边c1 = c;while (c1 < ColumnCount && Data[r, c1] == oldValue){Data[r, c1] = newValue;c1++;}//从当前位置扫描至最左边c1 = c - 1;while (c1 >= 0 && Data[r, c1] == oldValue){Data[r, c1] = newValue;c1--;}//向上检测新的扫描行c1 = c;while (c1 < ColumnCount && Data[r, c1] == newValue){if (r > 0 && Data[r - 1, c1] == oldValue){FloodFillScanRowColumn(r - 1, c1, newValue, oldValue);}c1++;}c1 = c - 1;while (c1 >= 0 && Data[r, c1] == newValue){if (r > 0 && Data[r - 1, c1] == oldValue){FloodFillScanRowColumn(r - 1, c1, newValue, oldValue);}c1--;}//向下检测新的扫描行c1 = c;while (c1 < ColumnCount && Data[r, c1] == newValue){if (r < RowCount - 1 && Data[r + 1, c1] == oldValue){FloodFillScanRowColumn(r + 1, c1, newValue, oldValue);}c1++;}c1 = c - 1;while (c1 >= 0 && Data[r, c1] == newValue){if (r < RowCount - 1 && Data[r + 1, c1] == oldValue){FloodFillScanRowColumn(r + 1, c1, newValue, oldValue);}c1--;}//由于检测到新的行之后会递归检测,所以所有的空间都将被检测到。}#endregion#region FloodFillScanRowColumnWithStack/// <summary>/// 漫水填充(基于堆的扫描行列的填充)/// </summary>/// <param name="r">行</param>/// <param name="c">列</param>/// <param name="newValue"></param>/// <param name="oldValue"></param>public void FloodFillScanRowColumnWithStack(int r, int c, int newValue, int oldValue){if (oldValue == newValue){Console.WriteLine("区域已经填充,不需要处理。");return;}var stackRow = new Stack<int>();var stackColumn = new Stack<int>();int c1;bool spanBottom;//检测下方bool spanTop;//检测上方stackRow.Push(r);stackColumn.Push(c);try{while (true){r = (stackRow.Count > 0 ? stackRow.Pop() : -1);if (r == -1) return;c = (stackColumn.Count > 0 ? stackColumn.Pop() : -1);c1 = c;while (c1 >= 0 && Data[r, c1] == oldValue) c1--; // 跳到需填充的最左位置.c1++; //向右spanBottom = spanTop = false;while (c1 < ColumnCount && Data[r, c1] == oldValue)//向上扫描到需要填充的位置{Data[r, c1] = newValue;//填充数据if (!spanBottom && r > 0 && Data[r - 1, c1] == oldValue)//没有在检测下方,而下方有需要填充的位置,将位置压入到堆栈中,然后跳过该行.{stackRow.Push(r - 1);stackColumn.Push(c1);spanBottom = true;}else if (spanBottom && r > 0 && Data[r - 1, c1] != oldValue)//检测下方,向上扫描到边界,则不再检测底边。{spanBottom = false;}if (!spanTop && r < RowCount - 1 && Data[r + 1, c1] == oldValue) //没有在检测上方, 而上方有需要填充的位置,将位置压入到堆栈中,然后跳过该行.{stackRow.Push(r + 1);stackColumn.Push(c1);spanTop = true;}else if (spanTop && r < RowCount - 1 && Data[r + 1, c1] != oldValue)//检测上方,向上扫描到边界,则不再检测上方。{spanTop = false;}c1++;//向右扫描}}}catch (Exception ex){Console.WriteLine($"{r}行,{c}列;{ex.Message}");}}#endregion}#endregion

边界数据直接填写到DigitMatrix中,然后调用 matrix.FloodFillScanRowColumnWithStack(0, 0, 2, 0);,其中2是newValue,0是oldValue。

实现后的效果图

红色区为填充部分,黑色为图形的边界,白色部分是图形的内部。

参考文章

漫水填充算法的一个简单实现(Qt版)

图像处理之泛洪填充算法(Flood Fill Algorithm)

漫水填充(泛洪填充、油漆桶)的C#实现(解决堆溢出问题)相关推荐

  1. 洪水填充算法_Flood Fill (洪水填充、泛洪填充、油漆桶)算法Java循环实现(BFS方式,非递归)...

    什么是Flood Fill (洪水填充.泛洪填充.油漆桶算法) 从一个区域中提取若干个连通的点与其他相邻区域区分开(或分别染成不同颜色)的经典算法. 因为其思路类似洪水从一个区域扩散到所有能到达的区域 ...

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

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

  3. java 画图油漆桶_Flood Fill (洪水填充、泛洪填充、油漆桶)算法Java循环实现(BFS方式,非递归)...

    什么是Flood Fill (洪水填充.泛洪填充.油漆桶算法) 从一个区域中提取若干个连通的点与其他相邻区域区分开(或分别染成不同颜色)的经典算法. 因为其思路类似洪水从一个区域扩散到所有能到达的区域 ...

  4. OpenCV+python:ROI与泛洪填充

    1,ROI 感兴趣区(Region of Interest,ROI) 是图像的一部分,它通过在图像上选择或使用诸如设定阈值(thresholding) 或者从其他文件(如矢量> 转换获得等方法生 ...

  5. OpenCV实现FloodFill泛洪填充算法的代码及相关函数详解

    图像处理开发需求.图像处理接私活挣零花钱,请加微信/QQ 2487872782 图像处理开发资料.图像处理技术交流请加QQ群,群号 271891601 FloodFill泛洪填充算法是在很多图形绘制软 ...

  6. OpenCV---ROI(region of interest)和泛洪填充

    一:ROI 感兴趣区(Region of Interest,ROIs) 是图像的一部分,它通过在图像上选择或使用诸如设定阈值(thresholding) 或者从其他文件(如矢量> 转换获得等方法 ...

  7. OpenCV中泛洪填充算法解析与应用

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 本文转自:opencv学堂 泛洪填充(Flood Fill)很多时 ...

  8. 西北乱跑娃 --- opencv泛洪填充学习笔记

    一.前言 泛洪填充算法也叫漫水填充算法.在网上查阅了很多的关于泛洪填充的案例但是一直都表示理解不了参数的具体作用,在自己的研究中才慢慢有所了解. 二.泛洪填充 import cv2 import ma ...

  9. RIO与泛洪填充——(OpenCV+Python)

    1.ROI ROI(region of interest),感兴趣区域.机器视觉.图像处理中,从被处理的图像以方框.圆.椭圆.不规则多边形等方式勾勒出需要处理的区域,称为感兴趣区域,ROI. 图片截取 ...

最新文章

  1. SpringBoot开发案例之整合Dubbo提供者(二)
  2. Py之tornado:tornado库的简介、安装、使用方法之详细攻略
  3. Zookeeper与paxos算法
  4. shell脚本把昨天的txt打成tar包
  5. 运行keras出现 FutureWarning: Passing (type, 1) or ‘1type‘ as a synonym of type is deprecated解决办法
  6. tcp中的crc检验算法原理_在数据传输过程中的CRC 算法的简单说明
  7. Java Pattern类和Matcher类的使用
  8. 【卷积神经网络】ResNet翻译详解
  9. wildfly-9.0.2 web项目部署详细步骤
  10. The problem of maze(经典迷宫问题) DFS版
  11. [转载] 【Java核心技术卷】关于除以0的计算
  12. 勒索病毒全系列补丁下载链接
  13. 迅雷Chrome插件引发的Uncaught ReferenceError: xl_chrome_menu is not defined
  14. 湖畔大学梁宁:比能力重要1000倍的,是你的底层操作系统
  15. 工作三年的Java程序员该如何规划后续的职业发展?
  16. WebPack 学习:从阮神的15个DEMO开始
  17. 14个python就业前景_python普通人学有什么用 就业前景和工资待遇怎么样
  18. odoo----权限机制
  19. css 字体颜色 样式大全
  20. 高级数据结构1—初识树状数组—快速求得前缀和和修改某一元素值

热门文章

  1. 牛客——2018年全国多校算法寒假训练营练习比赛(第一场)
  2. linux脚本攻击,一个防DDOS攻击的SHELL脚本
  3. 推荐系统笔记(一):BPR Loss个性化推荐
  4. linux解决文件上传失败的问题
  5. 小程序+node获取用户openid
  6. node怎么样安装npm
  7. PPT中如何让文本两端对齐
  8. #图像处理学习错误#---无法将参数 1 从“Y *”转换为“std::nullptr_t
  9. php 图片填充图片,PHP水印类,支持添加图片、文字、填充颜色区域的实现_php实例...
  10. 写给急功过利的百度:从此放弃百度空间