【图像处理】漫水填充函数的使用(flags的用法)

漫水填充的定义及基本思想

相信大家都玩过计算机中画图工具里的油漆桶,鼠标一点,一片相同颜色的区域就会被油漆桶中颜色覆盖,这便是漫水填充实现的。漫水填充的定义是用特定的颜色填充联通区域,通过设置可以连通像素正负差的上下限,或者改变连通的方式,以达到不同的填充效果的方法。漫水填充经常被用来标记或者分离图像的一部分,以便于对下一部分进行处理或分析,也可以用来输入图像获取掩码区域,掩码会加速处理过程,或只处理掩码指定的像素点,操作的结果总是某个连续的区域。
通俗来讲,漫水填充就是输入种子点,自动选择与种子点相连通的区域,接着将该区域替换成指定的颜色或者灰度,这是一个非常有用的功能。

floodFill()函数

在OpenCV的imgproc组件中,提供了2种漫水填充函数floodFill(),其API接口及定义如下:

第一种无mask版本:

int floodFill( InputOutputArray image,
                          Point seedPoint, Scalar newVal, CV_OUT Rect* rect=0,
                          Scalar loDiff=Scalar(), Scalar upDiff=Scalar(),
                          int flags=4 );
  • 第一个参数:输入与输出的Mat类变量image,表示输入要进行漫水填充的图像,并且图像漫水填充后再以该变量输出。
  • 第二个参数:Point类的seedPoint,表示种子点,即以该点为中心开始计算连通区域。简单来说,就是油漆桶所点的位置(像素点)
  • 第三个参数:Scalar类的newVal,表示通过种子点确认的目标连通区域将要填充的颜色值或者灰度值。
  • 第四个参数:Rect*类型的rect,有默认值0,一个可选的参数,用于设置floodFill函数将要重绘区域的最小边界矩形区域。
  • 第五个参数:Scalar类型的loDiff,有默认值Scalar(),表示当前观察像素值与其部件邻域像素值或者待加入该部件的种子像素之间的亮度或颜色之负差的最大值。
  • 第六个参数:Scalar类型的upDiff,有默认值Scalar(),表示当前观察像素值与其部件邻域像素值或者待加入该部件的种子像素之间的亮度或颜色之正差的最大值。
  • 第七个参数:nt类型的flags,操作表示符,此参数包含三个部分,比较复杂

低八位(0-7位)用于控制算法的连通性,可取4(4为默认值)或者8.如果为4,表示填充算法只考虑当前像素水平方向和垂直方向的相邻点;如果为8,除了上述相邻点之外,还包含对角线方向的相邻点。

高八位(16-23位)可以为0或者如下两种选项标识符的结合

  1. FLOODFILL_FIXED_RANGE:如果设置这个标识符,就会考虑当前像素与种子像素之间的差,否则就考虑当前像素与其相邻像素的差。也就是说,这个范围是浮动的。
  2. FLOODFILL_MASK_ONLY,如果设置这个标志符,函数不会去填充改变原始图像(也就是忽略第三个参数newVal),而是去填充掩膜图像(mask)。这个标识符支队第二个版本的floodFill有用,因为第一版的参数内没有mask。

中间8位,上面关于高八位FLOODFILL_MASK_ONLY标识符中已经说了,选择输入符合要求的掩码。Floodfill的flags参数的中间八位的值就是用于指定填充图像的值的。但如果flags中间8位是0,则掩码会用1来填充。
而所有flags可以用or操作符连接起来,即‘ | ’。例如,如果想用8邻域填充,并填充固定像素值范围,填充掩码而不是填充原图像,以及设置填充值为38,那么输入的参数如下:

flags = 8+(38<<8)+ FLOODFILL_MASK_ONLY;

第二种有mask的版本:

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

除了第二个参数代表掩膜区域,其他参数定义都与第一个版本相同。
关于mask参数,有如下说明:
mask应该位单通道,8位,长宽都比输入图像image大两个像素点的图像。需要注意的是,漫水填充不会填充mask的非零像素区域。例如,一个边缘检测算子的输出可以用来作为掩膜,以防止填充到边缘。同样的,也可以在多此的函数调用中使用同一个掩膜,以保证填充的区域不会重叠。还有需要注意的是,掩膜mask会比需填充的图像大,所以mask中与输入图像(x,y)像素点对应的点坐标为(x+1,y+1).
下面举例说明最后标志位flags的用法:
第一个版本的没有mask参数的floodFill()函数
设置flags = 4+(255<<8)+ FLOODFILL_FIXED_RANGE.
意思是:

  • 填充算法只考虑当前像素水平方向和垂直方向的相邻点;
  • 掩码区的填充数据为1111_1111(对于第一个版本的floodFill()并没有实质性的的用途,因为没有mask区域)
  • 考虑当前像素与种子像素之间的差,确认需要填充的范围。(通俗来讲,填充范围是固定的)
    源码以及效果图如下:
#include<opencv2\imgproc\imgproc.hpp>
#include<opencv2\highgui\highgui.hpp>
#include<core\core.hpp>
using namespace cv;
using namespace std;

void main()
{
	Mat image = imread("1.jpg");
	imshow("原图", image);
	
	//参数准备
	Rect ccomp;
	int a = 255;
	int flags = 8 + (a << 8) + FLOODFILL_FIXED_RANGE;

	floodFill(image,Point(50, 300), Scalar(155 * 0.299, 255 * 0.587, 55 * 0.114), &ccomp, Scalar(30, 30, 30), Scalar(30, 30, 30), flags);
	
	imshow("效果图", image);
	
	waitKey(0);
}

在这里插入图片描述
可以看到鼬神的鼻子被绿了。哈哈啊。
而当设置flags = 4+(255<<8)+ 0;
如图:在这里插入图片描述
整个图像几乎都绿了,,可见动态范围的漫水填充比固定范围的漫水填充的范围会大很多。
第二版的floodFill()函数,由于存在mask参数,所以flags的设置比较复杂。
源码如下:

#include<opencv2\imgproc\imgproc.hpp>
#include<opencv2\highgui\highgui.hpp>
#include<core\core.hpp>
using namespace cv;
using namespace std;

void main()
{
	Mat image = imread("1.jpg");
	Mat mask;
	imshow("原图", image);
	//参数准备
	mask.create(image.rows + 2, image.cols + 2, CV_8UC1);
	mask = Scalar::all(0);
	Rect ccomp;
	int a = 255;
	int flags = 8 + (a << 8) + FLOODFILL_FIXED_RANGE;


	floodFill(image,mask, Point(50, 300), Scalar(155 * 0.299, 255 * 0.587, 55 * 0.114), &ccomp, Scalar(10, 10, 10), Scalar(10, 10, 10), flags);
	
	imshow("效果图", image);
	imshow("mask", mask);
	waitKey(0);
}

flags = 8 + (255 << 8) + FLOODFILL_FIXED_RANGE; 时,意思是:

  1. 除上下左右相邻的点外,判断填充时,还需考虑两个对角线的像素点。
  2. 对与mask区域(灰度图)填充时,填充的颜色为纯白色(255)。
  3. 动态填充,填充时会将源图像以及mask图像一起填充。
    效果如下:在这里插入图片描述
    鼬神的鼻梁变绿了,右侧的mask图记录了鼬神鼻梁的形状。前面定义时说过,mask区域需要准备,漫水填充不会填充非零像素区域,所以在准备时,将mask全部置为0,即黑色区,所以mask就记录了鼬神鼻子的形状了。

flags = 8 + (255 << 8) + FLOODFILL_MASK_ONLY;
函数不会去填充源图像,只会去填充mask图像。效果图如下:
在这里插入图片描述
很明显,第二章图片没有被填充,而mask图像有点小帅。
flags = 8 + (a << 8) + 0;
图像为固定范围的满水填充,效果图如下:
在这里插入图片描述
和上种效果相同,但是由于没有设置FLOODFILL_MASK_ONLY,所以鼬神的脸被绿了。
第四种情况,我们讨论一下中间8位参数的值。
当 int flags = 8 + (150 << 8) + 0;
效果图如下:
在这里插入图片描述
很明显,鼬神的脸颜色没有变,而记录的mask中填充的颜色编程了灰色,所以flags的中间8位,是用来填充mask图像的灰度值。
以上便是flags参数的基本用法,感谢鼬神友情客串,晚安。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值