OpenCV学习笔记(九): 漫水填充:floodFill()

定义:
漫水填充法是一种用特定的颜色填充联通区域(自动选中了和种子点相连的区域,接着将该区域替换成指定的颜色)通过设置可连通像素的上下限以及连通方式来达到不同的填充效果的方法。
使用:
1)经常被用来标记或分离图像的一部分,以便对其进行进一步处理或分析。
2)从输入图像获取掩码区域(掩码会加速处理过程,或只处理掩码指定的像素点,操作的结果总是某个连续的区域)
算子:

int floodFill(
InputOutputArray image, // 1.输入/输出图像
InputOutputArray mask,  // 2.这是第二个版本的floodFill独享的参数,表示操作掩模(它应该为单通道、8位、长和宽上都比输入图像 image 大两个像素点的图像)
Point seedPoint,        // 3.漫水填充算法的起始点
Scalar newVal,          // 4.在重绘区域像素点被染色的新值
Rect* rect=0,          // 5.一个可选的参数,将要重绘区域的最小边界矩形区域
Scalar loDiff=Scalar(), // 6.loDiff 负差最大值(当前像素与领域像素或种子像素颜色或亮度的)
Scalar upDiff=Scalar(), // 7.upDiff 正差最大值(当前像素与领域像素或种子像素颜色或亮度的)
int flags=4            // 8.操作标志符
)

// PS:
1、漫水填充不会填充掩膜mask的非零像素区域。例如,一个边缘检测算子的输出可以用来作为掩膜,以防止填充到边缘。同样的,也可以在多次的函数调用中使用同一个掩膜,以保证填充的区域不会重叠。另外需要注意的是,
掩膜mask会比需填充的图像大,所以 mask 中与输入图像(x,y)像素点相对应的点的坐标为(x+1,y+1)。
2、
1)低八位(第0~7位)用于控制算法的连通性,可取4 (4为缺省值) 或者 8。

如果设为4,表示填充算法只考虑当前像素水平方向和垂直方向的相邻点;
如果设为 8,除上述相邻点外,还会包含对角线方向的相邻点。

2)高八位部分(16~23位)可以为0 或者如下两种选项标识符的组合:

FLOODFILL_FIXED_RANGE - 如果设置为这个标识符的话,就会考虑当前像素与种子像素之间的差,
否则就考虑当前像素与其相邻像素的差。也就是说,这个范围是浮动的。
FLOODFILL_MASK_ONLY - 如果设置为这个标识符的话,函数不会去填充改变原始图像 (也就是忽略第三个参数newVal),
而是去填充掩模图像(mask)。

3)中间八位部分,上面关于高八位FLOODFILL_MASK_ONLY标识符中已经说的很明显,需要输入符合要求的掩码。Floodfill的flags参数的中间八位的值就是用于指定填充掩码图像的值的。但如果flags中间八位的值为0,则掩码会用1来填充。

//如果想用8邻域填充,并填充固定像素值范围,填充掩码而不是填充源图像,以及设填充值为38
flags=8 | FLOODFILL_MASK_ONLY | FLOODFILL_FIXED_RANGE | (38<<8)

示例代码:

#include <opencv2/opencv.hpp>using namespace cv;
using namespace std;Mat g_srcImage, g_dstImage, g_grayImage, g_maskImage;        //定义原始图、目标图、灰度图、掩模图
int g_nFillMode = 1;                                         //漫水填充的模式
int g_nLowDifference = 20, g_nUpDifference = 20;             //负差最大值、正差最大值
int g_nConnectivity = 4;                                     //表示floodFill函数标识符低八位的连通值
bool g_bIsColor = true;                                      //是否为彩色图的标识
bool g_bUseMask = false;                                     //是否显示掩膜窗口的标识
int g_nNewMaskVal = 255;                                     //新的重新绘制的像素值int main()
{//显示帮助文字ShowHelpText();// 1、载入原图g_srcImage = imread("F:/C++/2. OPENCV 3.1.0/TEST/2.jpg", 1);if( !g_srcImage.data ){printf("读取图片image0错误~! \n");return false;}// 2、拷贝源图到目标图g_srcImage.copyTo(g_dstImage);// 3、转换三通道的image0到灰度图cvtColor(g_srcImage, g_grayImage, COLOR_BGR2GRAY);// 4、利用image0的尺寸来初始化掩膜maskg_maskImage.create(g_srcImage.rows+2, g_srcImage.cols+2, CV_8UC1);// 5、创建TrackbarnamedWindow( "效果图",WINDOW_AUTOSIZE );createTrackbar( "负差最大值", "效果图", &g_nLowDifference, 255, 0 );    // 无滑动条事件,只改变滑动条值(0~255)createTrackbar( "正差最大值" ,"效果图", &g_nUpDifference, 255, 0 );      // 无滑动条事件,只改变滑动条值(0~255)// 6、鼠标回调函数(鼠标点击便触发)// 将mask所有元素设置为0(背景设为黑色)g_maskImage = Scalar::all(0);     setMouseCallback( "效果图", onMouse, 0 );// 7、循环轮询按键while(1){//先显示效果图imshow("效果图", g_bIsColor ? g_dstImage : g_grayImage);//获取键盘按键int c = waitKey(0);//判断ESC是否按下,若按下便退出if( (c & 255) == 27 ){cout << "程序退出...........\n";break;}//根据按键的不同,进行各种操作switch( (char)c ){//如果键盘“1”被按下,效果图在在灰度图,彩色图之间互换case '1':if( g_bIsColor )//若原来为彩色,转为灰度图,并且将掩膜mask所有元素设置为0{cout << "键盘“1”被按下,切换彩色/灰度模式,当前操作为将【彩色模式】切换为【灰度模式】\n";cvtColor(g_srcImage, g_grayImage, COLOR_BGR2GRAY);g_maskImage = Scalar::all(0);           //将mask所有元素设置为0g_bIsColor = false;                         //将标识符置为false,表示当前图像不为彩色,而是灰度}else//若原来为灰度图,便将原来的彩图image0再次拷贝给image,并且将掩膜mask所有元素设置为0{cout << "键盘“1”被按下,切换彩色/灰度模式,当前操作为将【彩色模式】切换为【灰度模式】\n";g_srcImage.copyTo(g_dstImage);g_maskImage = Scalar::all(0);g_bIsColor = true;                  //将标识符置为true,表示当前图像模式为彩色}break;//如果键盘按键“2”被按下,显示/隐藏掩膜窗口case '2':if( g_bUseMask ){destroyWindow( "mask" );g_bUseMask = false;}else{namedWindow( "mask", 0 );//g_maskImage = Scalar::all(0); // 清空置零imshow("mask", g_maskImage);g_bUseMask = true;}break;//如果键盘按键“3”被按下,恢复原始图像case '3':cout << "按键“3”被按下,恢复原始图像\n";g_srcImage.copyTo(g_dstImage);cvtColor(g_dstImage, g_grayImage, COLOR_BGR2GRAY);g_maskImage = Scalar::all(0);break;// 改变”漫水填充“操作标识:// 1、如果键盘按键“4”被按下,使用空范围的漫水填充case '4':cout << "按键“4”被按下,使用空范围的漫水填充\n";g_nFillMode = 0;break;// 2、如果键盘按键“5”被按下,使用渐变、固定范围的漫水填充case '5':cout << "按键“5”被按下,使用渐变、固定范围的漫水填充\n";g_nFillMode = 1;break;// 3、如果键盘按键“6”被按下,使用渐变、浮动范围的漫水填充case '6':cout << "按键“6”被按下,使用渐变、浮动范围的漫水填充\n";g_nFillMode = 2;break;// 4、如果键盘按键“7”被按下,操作标志符的低八位使用4位的连接模式case '7':cout << "按键“7”被按下,操作标志符的低八位使用4位的连接模式\n";g_nConnectivity = 4;break;// 5、如果键盘按键“8”被按下,操作标志符的低八位使用8位的连接模式case '8':cout << "按键“8”被按下,操作标志符的低八位使用8位的连接模式\n";g_nConnectivity = 8;break;}}
}

输出一些帮助信息

static void ShowHelpText()
{printf("\n\n\t漫水填充示例程序~");printf("\n\n\t根据鼠标选取的点搜索图像中与之颜色相近的点,并用不同颜色标注。");printf("\n\n\t按键操作说明: \n\n""\t\t鼠标点击图中区域- 进行漫水填充操作\n""\t\t键盘按键【ESC】- 退出程序\n""\t\t键盘按键【1】-  切换彩色图/灰度图模式\n""\t\t键盘按键【2】- 显示/隐藏掩膜窗口\n""\t\t键盘按键【3】- 恢复原始图像\n""\t\t键盘按键【4】- 使用空范围的漫水填充\n""\t\t键盘按键【5】- 使用渐变、固定范围的漫水填充\n""\t\t键盘按键【6】- 使用渐变、浮动范围的漫水填充\n""\t\t键盘按键【7】- 操作标志符的低八位使用4位的连接模式\n""\t\t键盘按键【8】- 操作标志符的低八位使用8位的连接模式\n\n");
}

鼠标消息onMouse回调

static void onMouse(int event, int x, int y, int, void*)
{if (event != EVENT_LBUTTONDOWN)return;// 1、调用floodFill函数之前的参数准备部分Point seed = Point(x, y);   // 鼠标点击获取起始点位置int LowDifference = g_nFillMode == 0 ? 0 : g_nLowDifference;    //空范围的漫水填充,此值设为0,否则设为全局的g_nLowDifferenceint UpDifference = g_nFillMode == 0 ? 0 : g_nUpDifference;      //空范围的漫水填充,此值设为0,否则设为全局的g_nUpDifference// 1.1、floodFill()函数第八个参数值:flags=低八位+中八位+高八位int flags = g_nConnectivity + (g_nNewMaskVal << 8) + (g_nFillMode == 1 ? FLOODFILL_FIXED_RANGE : 0); // FLOODFILL_FIXED_RANGE// 1.2、随机生成bgr值int b = (unsigned)theRNG() & 255;//随机返回一个0~255之间的值int g = (unsigned)theRNG() & 255;//随机返回一个0~255之间的值int r = (unsigned)theRNG() & 255;//随机返回一个0~255之间的值Rect ccomp;//定义重绘区域的最小边界矩形区域// 1.3、在重绘区域像素的新值,若是彩色图模式,取Scalar(b, g, r);若是灰度图模式,取Scalar(r*0.299 + g*0.587 + b*0.114)Scalar newVal = g_bIsColor ? Scalar(b, g, r) : Scalar(r*0.299 + g*0.587 + b*0.114);Mat dst = g_bIsColor ? g_dstImage : g_grayImage;//目标图的赋值// 2、正式调用floodFill函数threshold(g_maskImage, g_maskImage, 1, 128, THRESH_BINARY);// 带掩码输出的 floodFill()int area = floodFill(dst, g_maskImage, seed, newVal, &ccomp, Scalar(LowDifference, LowDifference, LowDifference),Scalar(UpDifference, UpDifference, UpDifference), flags);// 3、关闭或显示掩码窗口if (g_bUseMask){imshow("mask", g_maskImage);}
//    else
//    {//        // 不带掩码输出的 floodFill()
//        area = floodFill(dst, seed, newVal, &ccomp, Scalar(LowDifference, LowDifference, LowDifference),
//            Scalar(UpDifference, UpDifference, UpDifference), flags);
//    }imshow("效果图", dst);cout << area << " 个像素被重绘\n";
}

结果:

OpenCV学习笔记(九): 漫水填充:floodFill()相关推荐

  1. OpenCV学习笔记(九)——图像轮廓(下)

    <OpenCV轻松入门:面向Python>学习笔记(九) 1-3 查找并绘制轮廓.矩特性及Hu矩 4-5 轮廓拟合及凸包 6. 利用形状场景算法比较轮廓 6.1 计算形状场景距离 6.2 ...

  2. OpenCV学习笔记九-Canny边缘检测

    关于Canny边缘检测算法 Canny边缘检测算法主要是在其它边缘检测算子的基础上提出了改进,改进点在于提出了非极大值抑制和阈值检测.非极大值抑制消除了非边缘的但是梯度值较大的点,阈值检测使得不连续的 ...

  3. Opencv学习笔记(八) -- 图像色彩空间转换

    1.常见图像色彩空间 RGB RGB色彩模式是工业界的一种颜色标准,是通过对红(R).绿(G).蓝(B)三个颜色通道的变化以及它们相互之间的叠加来得到各式各样的颜色的,RGB即是代表红.绿.蓝三个通道 ...

  4. OpenCV学习笔记(六)(七)(八)(九)(十)

    OpenCV学习笔记(六)--对XML和YAML文件实现I/O操作 1. XML.YAML文件的打开和关闭 XML\YAML文件在OpenCV中的数据结构为FileStorage,打开操作例如: [c ...

  5. OpenCV学习笔记(十六)——CamShift研究 OpenCV学习笔记(十七)——运动分析和物体跟踪Video OpenCV学习笔记(十八)——图像的各种变换(cvtColor*+)imgproc

    OpenCV学习笔记(十六)--CamShift研究 CamShitf算法,即Continuously Apative Mean-Shift算法,基本思想就是对视频图像的多帧进行MeanShift运算 ...

  6. OpenCV学习笔记(五十六)——InputArray和OutputArray的那些事core OpenCV学习笔记(五十七)——在同一窗口显示多幅图片 OpenCV学习笔记(五十八)——读《Mast

    OpenCV学习笔记(五十六)--InputArray和OutputArray的那些事core 看过OpenCV源代码的朋友,肯定都知道很多函数的接口都是InputArray或者OutputArray ...

  7. 【学习OpenCV4】漫水填充算法使用总结

    本文分享内容来自图书<学习OpenCV 4:基于Python的算法实战>,该书内容如下: 第1章 OpenCV快速入门: 第2章 图像读写模块imgcodecs: 第3章 核心库模块cor ...

  8. OpenCv学习笔记4--图像分割之GrabCut算法

    说明: 本文章是opencv学习笔记系列的第四篇小结,可能前几篇内容太多,排版也不甚合理,所以为了更好的观看体验,这次的内容会稍微少那么一点点,再次重申 所有代码在我的github主页https:// ...

  9. OpenCV 学习笔记03 boundingRect、minAreaRect、minEnclosingCircle、boxPoints、int0、circle、rectangle函数的用法...

    函数中的代码是部分代码,详细代码在最后 1 cv2.boundingRect 作用:矩形边框(boundingRect),用于计算图像一系列点的外部矩形边界. cv2.boundingRect(arr ...

最新文章

  1. eigen 编译_OpenCV+Eigen上位机程序移植(七十一)
  2. 最近python为什么这么火-现在为什么 Python 这么火?
  3. oracle替代变量输出,【Oracle】替代变量
  4. python交互界面用图片当背景_wxPython实现窗口用图片做背景
  5. 采用oracle过程发邮件
  6. Nginx SSI指令配置详解
  7. Go 单元测试从 0 到 1
  8. Codeforces Testing Round #1_C. Circular RMQ
  9. 局域网的分类:以太网、令牌环、FDDI、ATM、WLAN
  10. 计数器代码php,php的计数器程序_php
  11. CSR烧录工具csr单个蓝牙烧录小工具qcc300x烧录软件/CSR86xx烧写工具
  12. 计算机 复制文件格式,电脑u盘文件无法复制的解决方法
  13. 深入理解什么是端口(port)
  14. 论坛勋章动态特效制作流程
  15. 解决Win10 无线显示器功能安装时失败
  16. Sentinel-2 哨兵二号数据(Level-1C)下载及预处理教程
  17. quartus 2 低版本打开IP核设置窗口的方法
  18. 手机电脑同步投屏演示工具-Wormhole
  19. 用python三角形_python 三角形
  20. AE插件-快速景深模糊插件 Aescripts Fast Bokeh Pro v2.0.7 WIN

热门文章

  1. 异常值处理 - iterrows()对 DataFrame 进行遍历,并修改遍历中的异常值 - Python代码
  2. PAT乙类1009 说反话 (20 分)
  3. Android增量代码测试覆盖率工具
  4. 阿里P8架构师谈:数据库、JVM、缓存、SQL等性能调优方法和原则
  5. 论文浅尝 | 用于学习知识图谱嵌入的一种基于注意力机制的新型异构 GNN 框架HRAN...
  6. 技术动态 | TechKG:一个面向中文学术领域的大型知识图谱
  7. pip镜像源+修改linux配置用永久生效
  8. Android官方开发文档Training系列课程中文版:管理Activity的生命周期之Activity的重建
  9. Pandas中的元素替换
  10. 企业战略咨询方法:学习SWOT分析