在学OpenCV的时候遇到个函数floodFill()函数有点不解,特地在这里记录一下。
先说说它的参数
floorFill(image, mask , seedPoint, newVal, loDiff, upDiff, flags)
参数 | 说明 |
---|---|
image | 处理对象 |
mask | 掩膜(后面会说明) |
seedPoint | 填充的起点 |
newVal | 填充的颜色 |
loDiff | 填充时下限像素的差 |
upDiff | 填充时上限像素的差 |
flags | 填充的方式 :FLOODFILL_FIXED_RANGE 和FLOODFILL_MASK_ONLY |
先看例子,先理解一下flags的作用
先看flags=FLOODFILL_FIXED_RANGE的时候
def image_fill(image):
src = image.copy() #先创建一个副本
mask = np.zeros([src.shape[0]+2, src.shape[1]+2, 1], np.uint8) #根据副本形状建一个掩膜, 注意,长和宽必须要+2,类型只能是uint8
cv2.floodFill(src, mask, (60, 60), (0, 0, 255), (50,50,50), (50,50,50), cv2.FLOODFILL_FIXED_RANGE)
#(60,60)代表起始点;(0,0,255)代表填充颜色;loDiff=(50,50,50)代表只能填充比填充颜色小对应数值的点,upDiff同理
cv2.imshow('flood_fill', src)
cv2.imshow('mask', mask)
image1 = cv2.imread('lena.jpg') #原图
cv2.imshow('image1', image1)
image_fill(image1)
c = cv2.waitKey(0)
cv2.destroyAllWindows()
来看看结果
这里mask的作用是限制填充的范围,即floodFill只会填充处理对象对应的mask为0的区域,上面我将mask设置为全部都是0,所以作用范围是整张图片 (注意,作用范围是整张图片不代表会填充整张图,同时还要满足像素和填充颜色的像素差在[loDiff,upDiff]范围内) 那么,如果mask只设置一部分为0会怎么怎么样呢
(下面代码只需要重点关注mask的修改,其余部分同上)
def image_fill(image):
src = image.copy()
mask = np.ones([src.shape[0]+2, src.shape[1]+2, 1], np.uint8) #掩膜,这里将zeros改成了ones
mask[30:150, 30:150] = 0 #这里将掩膜部分区域设置为0,所有下面限制了只会填充这一部分区域
cv2.floodFill(src, mask, (60, 60), (0, 0, 255), (50,50,50), (50,50,50), cv2.FLOODFILL_FIXED_RANGE)
cv2.imshow('flood_fill', src)
cv2.imshow('mask', mask)
image1 = cv2.imread('lena.jpg') #原图
cv2.imshow('image1', image1)
image_fill(image1)
c = cv2.waitKey(0)
cv2.destroyAllWindows()
和前面的对比可以看到,这里的填充被截掉了一块,这是就是mask的作用,在前面的代码中mask的像素全部为0,因此对应到图像中就是整张图片都在范围内,而后一次我修改了mask,使其只在 [30:150, 30:150] 这一区域为0,所以填充范围也会被限制在这里。
下面看看flags=cv2.FLOODFILL_MASK_ONLY的例子,在这个填充模式下,可以理解为强制填充,即不需要loDiff和upDiff,范围内全部强制填充,但是有个前提,就是floodFill不会填充他认为不需要填充的地方,这个后面会解释
这里用一个新的例子,在后面还会用lena图来加以区别
def image_fill():
src = np.zeros([300,300,3], np.uint8)
mask = np.ones([src.shape[0]+2, src.shape[1]+2, 1], np.uint8) #掩膜
mask[30:150, 30:150] = 0
cv2.floodFill(src, mask, (60, 60), (0, 0, 255), cv2.FLOODFILL_MASK_ONLY)
cv2.imshow('flood_fill', src)
cv2.imshow('mask', mask)
image_fill()
c = cv2.waitKey(0)
cv2.destroyAllWindows()
这里可以看到,处理对象对应mask为0的区域被强制填充了,这个很好理解,那么什么叫 不会填充认为不需要填充的区域,再来看个例子
这里相比于上面的例子只是在处理对像多添加了一块灰色的区域,直接看结果即可
def image_fill():
src = np.zeros([300,300,3], np.uint8)
src[:150, :150] = 255
src[100:150, 100:150] = 180
mask = np.ones([src.shape[0]+2, src.shape[1]+2, 1], np.uint8) #掩膜
mask[30:150, 30:150] = 0
cv2.floodFill(src, mask, (60, 60), (0, 0, 255), cv2.FLOODFILL_MASK_ONLY)
cv2.imshow('flood_fill', src)
cv2.imshow('mask', mask)
image_fill()
c = cv2.waitKey(0)
cv2.destroyAllWindows()
可以看到,这里有一小块灰色区域没被填充到,这块灰色的就是之前设置的灰色区域,floorFill函数会认为这一部分不需要填充
下面再来看看lena图
def image_fill(image):
src = image.copy()
mask = np.ones([src.shape[0]+2, src.shape[1]+2, 1], np.uint8) #掩膜
mask[30:150, 30:150] = 0
cv2.floodFill(src, mask, (60, 60), (0, 0, 255), cv2.FLOODFILL_MASK_ONLY)
cv2.imshow('flood_fill', src)
cv2.imshow('mask', mask)
image1 = cv2.imread('lena.jpg') #原图
cv2.imshow('image1', image1)
image_fill(image1)
c = cv2.waitKey(0)
cv2.destroyAllWindows()
发现没有任何变化,这是因为在mask为0区域内存在各种像素,floodFill就会和上面一样认为不需要填充
下面对lena图设置一块黑色区域来看看
def image_fill(image):
src = image.copy()
src[10:150, 10:150] = 0 #设置原图指定区域为0
mask = np.ones([src.shape[0]+2, src.shape[1]+2, 1], np.uint8) #掩膜
mask[30:150, 30:150] = 0
cv2.floodFill(src, mask, (60, 60), (0, 0, 255), cv2.FLOODFILL_MASK_ONLY)
cv2.imshow('flood_fill', src)
cv2.imshow('mask', mask)
image1 = cv2.imread('lena.jpg') #原图
cv2.imshow('image1', image1)
image_fill(image1)
c = cv2.waitKey(0)
cv2.destroyAllWindows()
解决完了最麻烦的flags,下面就简要说明一下其他参数
seedPoint代表的是起点,即开始填充的点,可以理解为坐标
loDiff和upDiff相当于 填充的像素范围区间 ,即 [填充颜色-loDiff , 填充颜色+upDiff]