OpenCV-漫水填充cv::floodFill

简介: OpenCV-漫水填充cv::floodFill

函数原型

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


参数说明

  floodFill函数有两个原型,第二个相比第一个多了一个掩膜区,以第二个为例介绍各个参数。


  1. InputOutputArray类型的image,输入输出图像。
  2. InputOutputArray类型的mask,掩膜区,掩膜区非零区域不被填充,且掩膜区的宽高要比输入图像各多两个像素,输入图像中(x,y)位置对应掩膜区(x+1,y+1)位置,掩膜区的具体使用将在下方进行举例演示。
  3. Point类型的seedPoint,漫水填充的起点。
  4. Scalar类型的newVal,像素点被填充后呈现的颜色。
  5. Rect*类型的rect,漫水填充后重绘区域的最小边界矩形区域。
  6. Scalar类型的loDiff,当前观测像素与种子像素颜色负差的最大值。通俗地讲,就是观测像素各个通道的值都要比种子像素小,且小的数值要低于loDiff,满足该条件才会被填充。具体使用将在下方进行举例演示。
  7. Scalar类型的upDiff,当前观测像素与种子像素颜色正差的最大值。通俗地讲,就是观测像素各个通道的值都要比种子像素大,且大的数值要低于upDiff,满足该条件才会被填充。具体使用将在下方进行举例演示。
  8. int类型的flags,操作标识符,是32位二进制数。低八位表示算法连通性,一般取4或者8,4为上下左右,8加上对角四点;高八位可选两种标识符,分别为FLOODFILL_FIXED_RANGE和FLOODFILL_MASK_ONLY,也可以用or(|)组合它们;中八位是填充掩膜的数值,搭配FLOODFILL_MASK_ONLY使用。具体使用将在下方进行举例演示。


漫水填充思想

      漫水填充法是一种常见的图像处理方法,通过选中和种子点相连相近的区域,将其转换为指定颜色,以达到标记或者分离图像的目的,进而完成对图像的一些分析和处理。类似PS中的魔术棒选择工具,点击某个点,自动框选相近的区域。


      思想并不复杂,但在使用floodFill函数的过程中,有许多细节可以进一步研究和分析,大多数人并未深入了解。为此我写下该篇文章,探讨一下OpenCV自带的漫水填充算法的一些细节。如有补充,欢迎评论留言。

loDiff和upDiff

      先看下方代码,loDiff为Scalar(1, 1, 1),upDiff为Scalar(10, 10, 10),表示当前观测点的像素X与周围已被填充的像素点数值Y,需满足X-Y<10,且Y-X<1,才被填充。

Mat src = imread("test.jpg");
Rect roi;
int flags = 8;
floodFill(src, Point(src.cols / 2, src.rows / 2), Scalar(255, 0, 255), &roi, Scalar(1, 1, 1), Scalar(10, 10, 10), flags);

      如下图所示,观察数据的填充情况,Y为种子点,X为当前观测点,符合要求,所以被填充了。而旁边几个点都不满足,所以都保持原状。

图1

      再将loDiff为Scalar(10, 10, 10),upDiff为Scalar(1, 1, 1),则需满足X-Y<1,且Y-X<10,才被填充。不难发现,8近邻的像素点被填充了好几个,而被填充后的点将作为新的种子点,继续向外探索可被填充的数据。

图2

 

掩膜

      如函数说明要求,掩膜尺寸为原尺寸的宽高再加2,这应该是算法实现过程中卷积的要求,便于计算。在下方代码中,我们定义了掩膜,并将掩膜的(src.rows/2,src.cols/2)的位置设为255,即不进行填充,而该点位对应原图中的(src.rows/2-1,src.cols/2-1)。


Mat src = imread("test.jpg");
Rect roi;
int flags = 8;
Mat mask = Mat::zeros(src.rows + 2,src.cols + 2, CV_8UC1);
mask.at<uchar>(src.rows / 2, src.cols / 2) = 255;
floodFill(src, mask, Point(src.cols / 2, src.rows / 2), Scalar(255, 0, 255), &roi, Scalar(10, 10, 10), Scalar(1, 1, 1), flags);

   除了掩膜,其他参数与图2对应的代码一致,让我们看看加了一个掩膜点后,填充的效果图。

图3

      与图2相比,中心种子点左上角,32 90 102像素点未被填充,除此之外,左上方原本应该被填充的许多像素也未被填充,说明掩膜作用在填充过程中。换句话说,当某个点受掩膜限制未被填充后,再外圈的点也将不以其为种子点进行分析。这也表明,掩膜可以为漫水填充提供方向的引导,即指挥填充的路线。

操作标识符

      从简单的开始说,低八位表示连通性,只需让flags=4或者8即可。若为4,则低八位的二进制数为00000100;若为8,则低八位的二进制数为00001000。其效果分别如下所示。

图4 原图

图5 4连通

图6 8连通

      这应该还是比较好理解的。

      接下来让flags变为如下形式,表示8或FLOODFILL_FIXED_RANGE。如图7所示,该值等于1<<16,即1左移16位,则是32位的二进制数00000001 00000000 00000000,该值也是65536,2的16次方。那8|FLOODFILL_FIXED_RANGE,就表示00000001 00000000 00001000。这表示漫水填充不仅要用8连通,还要用固定范围的分析。


      默认情况下,填充过程的参考种子是邻近的点,也就是用于判断是否进行填充的那个范围是动态波动的。但在FLOODFILL_FIXED_RANGE标识下,参考种子是固定的,也就是开始标记的那个点,那用于判断是否填充的范围也就变成固定的了,即起始标记点像素值的上下限制范围。

int flags = 8 | FLOODFILL_FIXED_RANGE;

图7 枚举

      如果你理解了上面的描述,那不难理解,在FLOODFILL_FIXED_RANGE标识下,填充效果将大打折扣,毕竟邻近点作为种子,更容易符合要求些。效果如图8所示。

图8 FLOODFILL_FIXED_RANGE效果图

图8 FLOODFILL_FIXED_RANGE效果图

      FLOODFILL_MASK_ONLY同理,二进制数为00000010 00000000 00000000,左移17位,如果和FLOODFILL_FIXED_RANGE取或,则为00000011 00000000 00000000。顾名思义,FLOODFILL_MASK_ONLY表示,不对原图做改动,即重绘操作,而是在掩膜上进行标记,标记的数值由32位二进制数的中间八位决定,如果要用255来标记,则如下写法。


int flags = 8 | FLOODFILL_FIXED_RANGE | FLOODFILL_MASK_ONLY | (255 << 8);

      上述写法让255的值左移8位,相当于把11111111移动到中间8位上,那完整的二进制就是00000011 11111111 00001000,该值也就是flags的值,取整是261896。对应的效果如8所示,原图不受影响,掩膜上做出标记。

图9 掩膜标记

      以上就是本篇文章所讲漫水填充的完整内容了,希望能给你带来一点帮助。

      如果文章帮助到你了,可以点个赞让我知道,我会很快乐~加油!

相关文章
|
6月前
|
算法 计算机视觉
OpenCV(四十):图像分割—漫水填充
OpenCV(四十):图像分割—漫水填充
169 0
|
4月前
|
机器学习/深度学习 人工智能 算法
Python在计算机视觉(CV)中扮演重要角色,得益于其丰富的库如OpenCV、Pillow和Scikit-image。
【7月更文挑战第5天】Python在计算机视觉(CV)中扮演重要角色,得益于其丰富的库如OpenCV、Pillow和Scikit-image。CV涉及图像处理、模式识别和机器学习,用于图像理解和生成。Python的跨平台特性和活跃社区使其成为CV的理想工具。基本流程包括图像获取、预处理、特征提取、分类识别及图像生成。例如,面部识别通过预处理图像,使用如`cv2.CascadeClassifier`进行检测;物体检测类似,但需适应不同目标;图像生成则利用GAN创造新图像。
68 4
|
3月前
|
计算机视觉 索引
OpenCV读取视频失败<无可用信息,未为 opencv_world453.dll 加载任何符号> cv::VideoCapture
本文介绍了解决OpenCV读取视频失败的错误,指出问题通常由视频路径错误或摄像头索引错误导致,并提供了相应的解决方法。
OpenCV读取视频失败<无可用信息,未为 opencv_world453.dll 加载任何符号> cv::VideoCapture
|
3月前
|
计算机视觉
OpenCV 图像类型标识符 CV_<bit_depth><S|U|F>C<number_of_channels>
OpenCV 图像类型标识符 CV_<bit_depth><S|U|F>C<number_of_channels>
38 0
|
5月前
|
存储 Cloud Native Linux
OpenCV多边形填充与绘制
OpenCV多边形填充与绘制
|
6月前
|
算法 计算机视觉
【OpenCV】漫水填充
【OpenCV】漫水填充
|
6月前
|
计算机视觉
【OpenCV】示例—漫水填充
【OpenCV】示例—漫水填充
|
6月前
|
计算机视觉 Python
OpenCV为图像扩边(填充)
OpenCV为图像扩边(填充)
64 0
|
计算机视觉
OpenCV-模板匹配cv::matchTemplate
OpenCV-模板匹配cv::matchTemplate
103 0
|
计算机视觉
OpenCV-矩形边框cv::boundingRect
OpenCV-矩形边框cv::boundingRect
102 0