OpenCv漫水填充floodFill详解

1.函数原型:

 void cvFloodFill (
     IplImage * img,         // 输入图像
     CvPoint    seedPoint,    // 种子点
     CvScalar newVal,       // 像素点被染色的值
     CvScalar loDiff = cvScalarAll(0),     // 染色边界判定
     CvScalar upDiff = cvScalarAll(0),     // 染色边界判定
     CvConnectedComp * comp = NULL,        // 填充区域统计属性
     int flags = 4,                        // 连通性,相关性等参数设置。
     CvArr * mask = NULL                   // 掩码区域
);
  • image 【输入/输出】 1或者3通道、 8bit或者浮点图像。仅当参数flags的FLOODFILL_MASK_ONLY标志位被设置时image不会被修改,否则会被修改。

  • mask 【输入/输出】 操作掩码,必须为单通道、8bit,且比image宽2个像素、高2个像素。使用前必须先初始化。Flood-filling无法跨越mask中的非0像素。例如,一个边缘检测的结果可以作为mask来阻止边缘填充。在输出中,mask中与image中填充像素对应的像素点被设置为1,或者flags标志位中设置的值(详见flags标志位的解释)。此外,该函数还用1填充了mask的边缘来简化内部处理。因此,可以在多个调用中使用同一mask,以确保填充区域不会重叠。

  • seedPoint 起始像素点

  • newVal 重绘像素区域的新的填充值(颜色)

  • rect 可选输出参数,返回重绘区域的最小绑定矩形。

  • loDiff 当前选定像素与其连通区中相邻像素中的一个像素,或者与加入该连通区的一个seedPoint像素,二者之间的最大下行差异值。

  • upDiff 当前选定像素与其连通区中相邻像素中的一个像素,或者与加入该连通区的一个seedPoint像素,二者之间的最大上行差异值。

  • flags flags标志位是一个32bit的int类型数据,其由3部分组成: 0-7bit表示邻接性(4邻接、8邻接);8-15bit表示mask的填充颜色;16-31bit表示填充模式(详见填充模式解释)

flood fill填充模式:


//! floodfill algorithm flags

enum FloodFillFlags {

    /** If set, the difference between the current pixel andseed pixel is considered. Otherwise,

   the difference between neighbor pixels is considered (that is, the rangeis floating). */

   FLOODFILL_FIXED_RANGE = 1 << 16,

    /** If set, the function does not change the image ( newValis ignored), and only fills the

   mask with the value specified in bits 8-16 of flags as described above.This option only make

   sense in function variants that have the mask parameter. */

   FLOODFILL_MASK_ONLY   = 1 <<17

};

FLOODFILL_FIXED_RANGE:如果设置了该值,则考虑当前像素与seed像素之间的差异,否则考虑相邻像素之间的差异(即浮动区间)。

FLOODFILL_MASK_ONLY:如果设置了该值,floodFill函数不会修改image的内容(newVal被忽略),只使用flags标志中bit8-15的值填充mask。该选项仅在含mask参数的floodFill函数中有效。

2.函数作用:

用给定的颜色填充一个连通区域。

示例:
先创建一个 20*10 像素的灰度图像,为了便于观察,我们以 60 个灰度为一个等级填充图片:

import cv2
import numpy as np
 
img = np.zeros((20,10), dtype=np.uint8)
i = 0 
for v in img:
    v[:] = i//5 * 60
    i += 1
    
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

得到的图片输出:
在这里插入图片描述

该图片被分为4个横条块,其灰度值自顶向下依次为:0、60、120、180。

接下来,我们选定 seed=(7,7) , 该点落在这里(下图第二个横条小白点处):

在这里插入图片描述

我们选定该点作为 seedPoint ,对 img 图片进行 floodFill :

#encoding=utf-8
import cv2
import numpy as np
 
img = np.zeros((20,10), dtype=np.uint8)
i = 0 
for v in img:
    v[:] = i//5 * 60
    i += 1
    
cv2.imwrite('img_init.png', img)
 
seed = (7, 7) 
#构建mask,根据mask参数的介绍,其size必须为宽img+2,高img+2
mask = np.zeros((img.shape[0]+2, img.shape[1] +2), dtype=np.uint8)
newVal = (127) #img fill的填充值
mask_fill = 252 #mask的填充值
#floodFill充值标志
flags = 4|(mask_fill<<8)|cv2.FLOODFILL_FIXED_RANGE
#连通区范围设定
loDiff, upDiff = 20,20
#执行floodFill操作
ret, image, mask, rect = cv2.floodFill(img, mask, seed, newVal,(loDiff), (upDiff), flags)
cv2.imwrite('img.png', img)
cv2.imwrite('img_mask.png', mask)

floodFill 前、后的 img 图像:
在这里插入图片描述
对比发现,img图像的第二行颜色变了,check一下第二行的颜色值,发现变为了127。

newVal = (127) #img fill的填充值

在这里插入图片描述
再check一下得到的mask图像:
在这里插入图片描述

其像素值为:

在这里插入图片描述
我们观察mask的像素组成会发现,执行floodFill后得到的mask值,其被填充部分的值来自于:

mask_fill =252 #mask的填充值

并且,最外围边缘一周的像素点,全部被填充为1,这与mask参数的描述完全一致。 接下来,我们调整一下loDiff的值为70,我们看看会有什么不一样:

loDiff, upDiff =70,20

得到的 img 图像为:
在这里插入图片描述

与原始img图片对比:

在这里插入图片描述

观察floodFill后的img像素值:

在这里插入图片描述
我们发现img图像第一、二行的值均被置为127了,这是因为当loDiff值为70时,seed=(7,7)所在点的值为60,而60-loDiff=-10,60+upDiff=80,而img图片第一、二行的像素值分别为0和60,均值[-10,80]这个区间内,故img图片第一、二行均被填充。

以上都是基于 FLOODFILL_FIXED_RANGE 这种填充方式的,下面我们对比一下使用 FLOODFILL_MASK_ONLY 方式来填充会有什么不一样。其他保存不变,我们只需将:

flags =4|(mask_fill<<8)|cv2.FLOODFILL_FIXED_RANGE

改为:

flags =4|(mask_fill<<8)|cv2.FLOODFILL_MASK_ONLY

3.FLOODFILL_MASK_ONLY方式填充

运行程序后,发现img图片第一、第二行的值均未发生变化:
在这里插入图片描述

但mask图片第一、第二行的值与前面使用FLOODFILL_FIXED_RANGE 时是不一样的:
在这里插入图片描述

故此,可以验证前面对FLOODFILL_MASK_ONLY的解释,只影响mask的输出,对image无影响。

4.flags的0-7bit邻接性

最后,对flags的0-7bit邻接性进行分析:

相邻像素
4领域

对位于坐标(x,y)的像素p有4个水平和垂直的相邻像素,它们的坐标是:

(x+1,y), (x-1,y),(x,y+1),(x,y-1)

这组像素称为p的4邻域,用 N4(p) 表示:
在这里插入图片描述

对角相邻像素

p的四个对角像素的坐标为:

(x+1,y+1), (x+1,y-1),(x-1,y+1),(x-1,y-1)

ND(p) 表示:
在这里插入图片描述

8邻域

N4(p)ND(p) 组成像素p的8个相邻像素,称为p的8邻域,用 N8(p) 表示:
在这里插入图片描述

邻接性

4邻接-如果q在集合 N4(p) 中,则p和q是4邻接。

8邻接-如果q在集合 N8(p) 中,则p和q是8邻接。

最后,通过代码来演示一下:

#encoding=utf-8
#创建一个8x8的图片
import cv2
import numpy as np
 
size = 8
img = np.zeros((size,size), dtype=np.uint8)
img[:] = 0
img[4,4] = 1
img[3,4] = 1
img[4,3] = 1
img[4,5] = 1
img[5,4] = 1
img[2,4] = 1
img[1,5] = 1
img[1,3] = 1
img[2,2] = 1
img[3,1] = 1
img[4,0] = 1
img[5,1] = 1
img[6,2] = 1
img[7,3] = 1
print(img)

创建一个以p(4,4)为中心像素的8x8图像:

在这里插入图片描述

下面以 p(4,4) 作为seed,对该图像进行floodFill操作,对比4邻接和8邻接的差异:

#encoding=utf-8
#创建一个8x8的图片
import cv2
import numpy as np
 
size = 8
img = np.zeros((size,size), dtype=np.uint8)
img[:] = 0
seed_x = 4
seed_y = 4
img[seed_x, seed_y] = 1
img[4,4] = 1
img[3,4] = 1
img[4,3] = 1
img[4,5] = 1
img[5,4] = 1
img[2,4] = 1
img[1,5] = 1
img[1,3] = 1
img[2,2] = 1
img[3,1] = 1
img[4,0] = 1
img[5,1] = 1
img[6,2] = 1
img[7,3] = 1
 
seed = (seed_x, seed_y)
mask= np.zeros((size+2,size+2), dtype=np.uint8)
 
img1 = img.copy()
img2 = img.copy()
mask1 = mask.copy()
mask2 = mask.copy()
 
ret, img1,mask1, rect=cv2.floodFill(img1, mask1, seed,(8), (0),(0), flags=4|(3<<2)|cv2.FLOODFILL_FIXED_RANGE)
ret, img2,mask2, rect=cv2.floodFill(img2, mask2, seed,(8), (0),(0), flags=8|(3<<2)|cv2.FLOODFILL_FIXED_RANGE)
print(img)
print(img1)
print(img2)

在这里插入图片描述

在这里插入图片描述

https://blog.csdn.net/weixin_42296411/article/details/80966724?spm=1001.2101.3001.6650.2&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-2-80966724-blog-50526314.pc_relevant_paycolumn_v3&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-2-80966724-blog-50526314.pc_relevant_paycolumn_v3&utm_relevant_index=5

http://www.mamicode.com/info-detail-189295.html

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值