Opencv学习笔记(五)漫水填充参数详解附验证代码

编程入门 行业动态 更新时间:2024-10-08 18:31:33

Opencv学习笔记(五)漫水填充参数<a href=https://www.elefans.com/category/jswz/34/1770044.html style=详解附验证代码"/>

Opencv学习笔记(五)漫水填充参数详解附验证代码

大纲

  • 一、漫水填充
    • 1. 基本原理
    • 2.重点参数介绍及代码
      • 第二个参数mask
      • 第五个参数rect
      • 第八个参数flag

一、漫水填充

1. 基本原理

漫水填充就是自动选择与所设“种子"相邻的区域,并将其替换成预设的颜色。可以用来标记或者分离图片中某一块相似区域,也可以用来从输入图像中获取掩码区域。

2.重点参数介绍及代码

OpenCV中漫水填充的函数原型为:

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

第一个参数为输入输出图像,应该为CV8U、CV16U、单精度浮点型之一,通道数不限;

第二个参数mask

可选填,若填写的话,它起掩模的作用,长度和宽度都要比输入图像多两个像素,单通道灰度图。后续进行填充时不会对掩模的非零区域进行操作,也就是说我们可以利用图像的边缘图作为掩模只在轮廓范围内进行漫水填充;也可以直接全部置零,表示对图像整体进行漫水填充。在函数运行完后从mask中可以得到此次填充所包括的区域和之前的非零区域(默认用1填充,也可在后续flag中修改)。代码验证如下:

int main()
{Mat src = imread("E:\\material\\assassin.jpeg");Mat mask = Mat::zeros(src.size[0] + 2, src.size[1] + 2, CV_8U);//Mat roi = mask(Rect(0, 0, 100, 100));  //roi = Scalar::all(255);   //掩模设置非零区域Point seed = Point(200, 300);Rect rect(0,0,100,100);floodFill(src,mask,seed, Scalar(233, 122, 189), &rect, Scalar(10, 10, 10), Scalar(10, 10, 10), 8 | (255 << 8 | 0));imshow("src", src);waitKey(0);}

原图:

若使用全零掩模,函数运行后原图结果:

若使用全零掩模,函数运行后掩模结果(灰色部分为截图痕迹)如下,可以看到原图中颜色被填充的部分在mask上都表现为像素值变为255(预设为255<<8),为发生变化区域仍为0。

若使用含非零区域的掩模(设为左上角100×100区域),原图结果:

若使用含非零区域的掩模(设为左上角100×100区域),掩模结果如下,可以看到虽然非零区域有部分是无法被填充的(从第一次实验结果可看出),但是在函数运行后这部分仍然被设置为了255。

第三个参数为漫水填充开始的种子,起始点;
第四个参数为原图填充区域新的像素值;

第五个参数rect

为floodfill函数重绘区域的最小值,即记录囊括重绘区域的最小矩形,初值可赋可不赋,代码验证如下:

int main()
{Mat src = imread("E:\\material\\assassin.jpeg");Mat mask = Mat::zeros(src.size[0] + 2, src.size[1] + 2, CV_8U);Point seed = Point(56, 69);Rect rect(0,0,100,100);floodFill(src,mask,seed, Scalar(233, 122, 189), &rect, Scalar(10, 10, 10), Scalar(10, 10, 10), 8 | (255 << 8 | 0));imshow("src", src);waitKey(0);}

mask结果:

可以看出此次填充只包括了左上角的一小部分区域,而Rect结果也正是包围这一区域的最小矩形:

第六、七个参数给出了判断某个像素值是否需要被填充的极差上下界,当该像素值与锚点像素值的差值位于这一范围内时则被替换,锚点像素值的选定与flag的选择有关;

第八个参数flag

是最为复杂的参数,它需要分为三个部分来介绍。

  • 前八位:选填4时则填充模式为4联通;选填8时则填充模式为8联通,4联通指的是朝待计算像素上、下、左、右填充,遇到边界停止;8联通则是朝着包围待计算像素的方形区域填充,遇到边界停止,默认为4通道。代码验证如下:
int main()
{Mat src = Mat::zeros(Size(5,5),CV_8U);Mat mask = Mat::zeros(src.size[0] + 2, src.size[1] + 2, CV_8U);src.at<uchar>(0, 0) = 255;src.at<uchar>(1, 1) = 255;src.at<uchar>(2, 2) = 255;src.at<uchar>(3, 2) = 255;src.at<uchar>(2, 3) = 255;src.at<uchar>(4, 1) = 255;src.at<uchar>(4, 3) = 255;Point seed = Point(2, 2);Rect rect;floodFill(src,mask,seed, Scalar(101), &rect, Scalar(0), Scalar(0), 8 | (255 << 8 | 0));imshow("src", src);waitKey(0);}

原图:

8联通结果:

4联通结果:

  • 高8位:选填FLOODFILL_FIXED_RANGE或者FLOODFILL_MASK_ONLY,如果两个都不填的话则为默认的FLOODFILL_FLOATING_RANGE(实际不存在这个标识符,只是方便记忆)。
    FLOODFILL_FIXED_RANGE和FLOODFILL_FLOATING_RANGE是用于确定之前介绍过的“锚点”的,对于前者而言锚点始终是种子点,与待计算像素点无关;而对于后者而言锚点则是其联通范围内任意一个已经被认为是需要填充的点。
    FLOODFILL_MASK_ONLY则表示不进行实际的填充,也就是说最终结果原图不发生变化,只有mask发生变化,前提是使用mask.
    代码验证如下:
int main()
{Mat src = Mat::zeros(Size(5,5),CV_8U);Mat mask = Mat::zeros(src.size[0] + 2, src.size[1] + 2, CV_8U);src.at<uchar>(src.size[0] / 2, src.size[1] / 2) = 123;for (int i = 0;i < src.size[0];i++){uchar* it = src.data + i * src.step[0];for (int j = 0;j < src.size[1];j++){it[j] = src.at<uchar>(src.size[0] / 2, src.size[1] / 2) + (i - src.size[0] / 2) + (j - src.size[1] / 2);}}Point seed = Point(2, 2);Rect rect;floodFill(src,mask,seed, Scalar(101), &rect, Scalar(1), Scalar(1),4|255<<8|FLOODFILL_FIXED_RANGE);imshow("src", src);waitKey(0);}

原图:

使用FLOOD_FIXED_RANGE:

使用FLOODFILL_FLOATING_RANGE(实际不写这8位标识符即可):

  • 中8位:中8位就是用于替换mask中待填充区域的,写入是需要将填充在左移8为,样例应该是”填充值<<8",初步猜测可能是因为像素值uchar在0~255之间,左移8位正好不会发生数据丢失,直接截取倒数9~16位,至于为啥要截取,尚不得知。

参考文献
花老湿学习OpenCV:floodFill()漫水填充的使用
OpenCv漫水填充floodFill详解

更多推荐

Opencv学习笔记(五)漫水填充参数详解附验证代码

本文发布于:2024-02-27 22:32:17,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1766619.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:详解   学习笔记   参数   代码   Opencv

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!