6.5 漫水填充(floodFill)

6.5.1 漫水填充

1.定义:一种用特定的颜色填充连通区域,通过设置可连通像素的上下限及连通方式达到不同填充效果
2.基本思想:自动选中和种子点相连的区域(位于给定范围(从LowDiff到UpDiff)或在原始seedPoint像素值范围内),将该区域所有相似点填充指定的相同颜色
3.作用:标记或分离图像一部分,从输入图像获取掩码区域
4.封装函数:floodFill()函数
5.函数原型(有2个版本,另一个版本无参数2):

int floodFill(InputOutputArray image, InputOutputArray mask, Point seedPoint, Scalar newVal, Rect* rect=0, Scalar loDiff=Scalar(), Scalar upDiff=Scalar(), int flags=4)

6.参数说明
(1)输入/输出1通道或3通道,8位或浮点图像
(2)操作掩模,8位单通道,长和宽都比原图像大两个像素点,漫水填充不会填充掩模mask的非零像素区域,如,边缘检测算子输出做掩模可以防止填充边缘、多次函数调用中使用同一个掩模可以保证填充区域不重叠。注意:掩模比须填充图像大,输入图像(x,y)点对应掩模(x+1,y+1)点
(3)算法起始点
(4)像素点被染色的值,即在重绘区域像素的新值
(5)可选参数,用于设置floodFill函数将要重绘区域的最小边界矩形区域,默认0
(6)表示当前观察像素值与其附近邻域像素值或待加入的种子像素值之间的亮度或颜色之负差(lower brightness/color difference)的最大值,默认Scalar()
(7)表示当前观察像素值与其附近邻域像素值或待加入的种子像素值之间的亮度或颜色之正差(lower brightness/color difference)的最大值,默认Scalar()
(8)操作标识符,包含三个部分(用”|”连接):
  1)0~7位用于控制算法连通性,取4(默认)表示填充算法只考虑当前像素水平方向或垂直方向的相邻点,取8表示还会包含对角线方向的临近点
  2)16~23位可以为0或如下两种选项标识符的组合:FLOODFILL_RANGE表示会考虑当前像素与种子像素的差,否则会考虑当前像素与其相邻像素的差;FLOODFILL_MASK_ONLY表示不会填充改变原始图像(即忽略第3个参数newVal)而是去填充掩模图像
  3)8~15位用于指定填充掩码图像的值(后8位标识符为FLOODFILL_MASK_ONLY时),0表示掩模用1填充
Eg. 8邻域,固定填充像素值范围,填充掩模不填充原图像,填充值为38:
Flags=8|FLOODFILL_MASK_ONLY|FLOODFILL_FIXED_RANGE|(38<<8)

6.5.2 漫水填充示例

1.漫水填充简单示例

#include<opencv2/opencv.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
using namespace cv;
int main()
{//载入原图并显示Mat srcImage = imread("love.jpg");imshow("【原始图】", srcImage);//漫水填充Rect ccomp;floodFill(srcImage, Point(50, 300), Scalar(155, 255, 55), &ccomp, Scalar(20, 20, 20), Scalar(20, 20, 20));//显示效果图imshow("【效果图】", srcImage);waitKey(0);return 0;
}

运行效果:

2.综合示例

/*
效果:鼠标对窗口多次点击得到类似PS的魔棒效果键盘8个按键操作切换漫水填充模式
*/
#include<opencv2/opencv.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<iostream>
using namespace cv;
using namespace std;//全局变量
Mat g_srcImage, g_dstImage, g_grayImage, g_maskImage;//定义原始图、目标图、灰度图、掩模图
int g_nFillMode = 1;//漫水填充模式(0为空范围,1为固定填充像素值范围)
int g_nLowDifference = 20;//负差最大值
int g_nUpDifference = 20;//正差最大值
int g_nConnectivity = 4;//表示floodFill函数标识符低八位的连通值
int g_nNewMaskVal = 255;//新的重新绘制的像素值
int g_bIsColor = true;//是否为彩色图的标识符布尔值
bool g_bUseMask = false;//是否显示掩模窗口的布尔值//---------------------------------【onMouse()函数】----------------------
//              描述:鼠标消息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_nUpDifferenceint flags = g_nConnectivity + (g_nNewMaskVal << 8) + (g_nFillMode == 1 ? FLOODFILL_FIXED_RANGE : 0);//标识符的0~7位为g_nConnectivity,8~15位为g_nNewMaskVal左移8位的值,16~23位为CV_FLOODFILL_FIXED+RANGE或0//随机生成bgr值int b = (unsigned)theRNG() & 255;//随机返回一个0~255之间的值int g = (unsigned)theRNG() & 255;//随机返回一个0~255之间的值int r = (unsigned)theRNG() & 255;//随机返回一个0~255之间的值//定义重绘区域的最小边界矩形区域Rect ccomp;//重绘区域像素的新值,若是彩色图模式,取Scalar(b,g,r);若是灰度图模式,取Scalar(r*0.299+b*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;int area;//---------------------【<2>正式调用floodFill函数】---------------------if (g_bUseMask){threshold(g_maskImage, g_maskImage, 1, 128, THRESH_BINARY);area = floodFill(dst, g_maskImage, seed, newVal, &ccomp, Scalar(LowDifference, LowDifference, LowDifference), Scalar(UpDifference, UpDifference, UpDifference), flags);}else{area=floodFill(dst,seed,newVal,&ccomp, Scalar(LowDifference, LowDifference, LowDifference), Scalar(UpDifference, UpDifference, UpDifference), flags);}imshow("效果图", dst);cout.width(7);cout <<area << " 个像素被重绘\n";
}
//---------------------------------【ShowHelpText()函数】----------------------
//              描述:键盘操作说明
//------------------------------------------------------------------------static void ShowHelpText()
{printf("--------------------------------------------------------------------\n");printf("请鼠标点击图像观察漫水填充效果~\n");printf("按键操作说明:\n");printf("\t\t键盘按键[ESC]-退出程序\n");printf("\t\t键盘按键[1]-切换彩色图/灰度图模式\n");printf("\t\t键盘按键[2]-显示/隐藏掩模模式\n");printf("\t\t键盘按键[3]-恢复原始图像\n");printf("\t\t键盘按键[4]-使用空范围的漫水填充\n");printf("\t\t键盘按键[5]-使用新变、固定范围的漫水填充\n");printf("\t\t键盘按键[6]-使用新变、浮动范围的漫水填充\n");printf("\t\t键盘按键[7]-操作标识符的低8位使用4的连接模式\n");printf("\t\t键盘按键[8]-操作标识符的低8位使用8的连接模式\n");printf("--------------------------------------------------------------------\n");
}
int main()
{//键盘操作说明ShowHelpText();//载入原图g_srcImage = imread("love.jpg");if (!g_srcImage.data){printf("载入原图失败~!\n");return false;}//复制原图到目标图g_srcImage.copyTo(g_dstImage);cvtColor(g_dstImage, g_grayImage, COLOR_BGR2GRAY);//转换三通道的g_srcImage到灰度图g_maskImage.create(g_srcImage.rows + 2, g_srcImage.cols + 2, CV_8UC1);//利用g_srcImage尺寸初始化mask//创建效果图窗口namedWindow("效果图", WINDOW_AUTOSIZE);//创建TrackBarcreateTrackbar("负差最大值", "效果图", &g_nLowDifference, 255, 0);createTrackbar("正差最大值", "效果图", &g_nUpDifference, 255, 0);//鼠标回调函数setMouseCallback("效果图", onMouse, 0);//循环轮询按键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'://若原来为彩色,转为灰度图,并将掩模mask所有元素设为0if (g_bIsColor){cout << "按键“1”按下,切换彩色/灰度模式,当前操作为【彩色模式】切换为【灰度模式】\n";cvtColor(g_srcImage, g_grayImage, COLOR_BGR2GRAY);g_maskImage = Scalar::all(0);//将mask所有元素设为0g_bIsColor = false;//将标识符设置为false,表示当前图像不为彩色,而是灰度}//若原来为灰度,将原来彩色图g_srcImage再次复制给g_dstImage,并将掩模mask所有元素设为0else{cout << "按键“1”按下,切换彩色/灰度模式,当前操作为【灰度模式】切换为【彩色模式】\n";g_srcImage.copyTo(g_dstImage);g_maskImage = Scalar::all(0);g_bIsColor = 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;//如果按键4被按下,使用空范围的漫水填充case '4':cout << "按键“4”被按下,使用空范围的漫水填充\n";g_nFillMode = 0;break;//如果按键5被按下,使用新变、固定范围的漫水填充case '5':cout << "按键“5”被按下,使用新变、固定范围的漫水填充\n";g_nFillMode = 1;break;//如果按键6被按下,使用新变、浮动范围的漫水填充case '6':cout << "按键“6”被按下,使用新变、浮动范围的漫水填充\n";g_nFillMode = 2;break;//如果按键7被按下,操作标识符的低8位使用4的连接模式case '7':cout << "按键“7”被按下,操作标识符的低8位使用4的连接模式\n";g_nConnectivity = 4;break;//如果按键8被按下,操作标识符的低8位使用8的连接模式case '8':cout << "按键“8”被按下,操作标识符的低8位使用8的连接模式\n";g_nConnectivity = 8;break;}}return 0;
}

运行效果:


《OpenCV3编程入门》学习笔记6 图像处理(五)漫水填充相关推荐

  1. 原创 OpenCV3编程入门 学习笔记(总)

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/qq_36163358/article/ ...

  2. OpenCV3编程入门 学习笔记(总)

    OpenCV3编程入门 学习笔记 2018.12.12-2018.12.29 此博客为在看过毛星云版<OpenCV3编程入门>后所总结的一本笔记,可供复习使用. 文章目录 OpenCV3编 ...

  3. Opencv3编程入门学习笔记(五)之通道分离(split)与合并(merge)

    若要对Opencv中(BGR)颜色通道进行单一处理,那必然会涉及到通道分离(split)与合并(merge).那么本篇博客笔者记录了两个方法的使用方法和案例.案例来源于<Opencv3编程入门学 ...

  4. 【OpenCV3编程入门学习笔记】——第1章 邂逅OpenCV

    邂逅OpenCV 文章目录 邂逅OpenCV 前言 1.1 OpenCV周边概念认知 1.1.1 图像处理.计算机视觉与OpenCV 1.1.2 OpenCV概述 1.1.3 起源及发展 1.1.4 ...

  5. Opencv3编程入门学习笔记(三)之访问图像像素的三种方法

    访问图像像素的三种方法:指针访问,迭代器访问,动态地址访问.访问最快的为指针访问,以下算法在几毫秒,但指针访问容易造成内存泄漏:其次为迭代器访问:最后为动态地址访问. 以下程序是根据<OpenC ...

  6. 【OpenCV3编程入门学习笔记】——第3章 HighGUI图形用户界面初步

    文章目录 前言 3.1 图形的载入.显示和输出到文件 3.1.1 OpenCV的命名空间 3.1.2 Mat类简析 3.1.3 图像的载入与显示概述 3.1.4 图像的载入:imread()函数 3. ...

  7. Opencv3编程入门学习笔记(四)之split通道分离Debug过程中0xC0000005内存访问冲突问题

    这是笔者学习<Opencv3编程入门>的第四篇博客,这篇博客主要是解决在Windows系统下VS 2013中Debug含有split分离通道色彩函数时报出的0xC0000005内存访问冲突 ...

  8. Opencv3编程入门学习笔记(二)之显式创建Mat对象

    以下总结是基于<Opencv3编程入门>一书4.1节总结的内容进行验证与总结,验证环境均为Windows10 ---VS2013 C++环境,验证Opencv3.0提供的开发包. 1. 方 ...

  9. Python快速编程入门#学习笔记03# |第二章 :Python基础(代码格式、标识符关键字、变量和数据类型、数字类型以及运算符)

    全文目录 ==先导知识== 学习目标: 2.1 代码格式 2.1.1 注释 2.1.2 缩进 2.1.3 语句换行 2.2 标识符和关键字 2.2.1 标识符 2.2.2 关键字 2.3 变量和数据类 ...

  10. 01.Java 编程入门学习笔记20210307

    Java 编程入门学习笔记-day01 第0章:编程入门 1.计算机的概述 计算机 = 硬件 + 软件 1.1硬件:冯诺依曼体系 CPU: CPU的衡量标准:速度的计量单位是赫兹(Hz),1Hz相当于 ...

最新文章

  1. hbase参数配置及优化
  2. c 使用matlab引擎,[转载]C与MATLAB混合编程之调用MATLAB引擎
  3. js jquery 函数回调
  4. 【52】写了placement new也要写placement delete
  5. 2019 最新蚂蚁花呗Java三面题目:红黑树+并发容器+CAS+Solr+分布式等
  6. it资产管理系统php,开源IT资产管理软件(GIPI)
  7. 在PhpStorm9中与Pi的xdebug进行调试
  8. Android Studio 3.1.0.0 拖入控件显示问题
  9. 《深入浅出设计模式》小结
  10. excel处理html文件,html网页显示excel表格数据-html读取本地excel文件并展示
  11. 愚人节里的巧合与必然:BAT等亮出的AI招牌故事
  12. Python处理Excel,学会这十四个方法,工作量减少大半!
  13. 2021-03-06
  14. 编程题——真题训练一(WYYX)
  15. rounded-{0 | top | right | bottom | left | circle } 边角半径设置 - bootStrap4常用CSS笔记(2019-05-16 09:38)...
  16. web前端学习笔记26-事件类型——一般事件、页面事件、表单事件
  17. 百度LBS服务我们自己上传数据,我们客户端获取数据然后进行小黄车和膜拜单车定位描点等骚操作
  18. 微信小程序云开发|个人博客小程序
  19. 标准计算机准备室,各功能室建设要求标准.docx
  20. iOS类对象的初始化+initialize

热门文章

  1. 二元学习法3.0:三把学习大剑,打通学习的底层密码_学习方法
  2. LeetCode简单题之图片平滑器
  3. 动态表单工作量给后端
  4. 色彩(颜色)空间原理(中)
  5. 常用深度学习框——Caffe/TensorFlow / Keras/ PyTorch/MXNet
  6. 自动驾驶的分级和行业现状
  7. 数据结构算法 简单的面试思考题
  8. 2021年大数据Flink(一):乘风破浪的Flink-Flink概述
  9. [JS]题解 | #魔法数字#
  10. Error:Execution failed for task ':app:mergeDebugResources'. Error: java.lang.RuntimeException: Som