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

一、漫水填充

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详解

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
漫水填充Flood Fill)是一种常用的图像处理技术,它可以用于图像分割、图像修复等方面。在OpenCV中,可以使用cv::floodFill()函数来实现漫水填充。下面是一个简单的示例代码,可以演示如何使用OpenCV实现漫水填充: ```c++ #include <opencv2/opencv.hpp> #include <iostream> using namespace cv; using namespace std; int main(){ Mat img = imread("image.jpg", IMREAD_COLOR); // 读取图片 if (img.empty()) { cout << "Can't read image file." << endl; return -1; } Mat mask(img.rows + 2, img.cols + 2, CV_8UC1, Scalar::all(0)); // 创建掩膜 Point seed(100, 100); // 设置种子点 Scalar new_color(0, 0, 255); // 设置新的颜色 int lo_diff = 20; // 低阈值 int up_diff = 20; // 高阈值 int connectivity = 4; // 连通性 int flags = connectivity | (new_color[0] << 8) | FLOODFILL_FIXED_RANGE | FLOODFILL_MASK_ONLY; int area = floodFill(img, mask, seed, new_color, 0, Scalar(lo_diff, lo_diff, lo_diff), Scalar(up_diff, up_diff, up_diff), flags); // 进行漫水填充 imshow("Image", img); // 显示填充后的图片 waitKey(0); return 0; } ``` 在这个示例中,我们读取了一张图片,并且定义了一个种子点seed和一个新的颜色new_color。然后,我们创建了一个掩膜mask,并且使用cv::floodFill()函数进行漫水填充操作。最后,我们将填充后的图片显示出来。 需要注意的是,这个示例只是一个简单的实现方式,实际应用中需要根据具体需求进行调整和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值