floodFill详解
https://blog.csdn.net/weixin_42296411/article/details/80966724
函数原型
![](/assets/blank.gif)
参数:
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函数中有效。
函数作用:
用给定的颜色填充一个连通区域。
下面我们通过Code来演示floodFill函数的用法及效果:
先创建一个20*10像素的灰度图像,为了便于观察,我们以60个灰度为一个等级填充图片。
Code-1:
- 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。
Code-2:
- #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,这与Code-2中
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方式来填充会有什么不一样。其他code保存不变,我们只需将
flags =4|(mask_fill<<8)|cv2.FLOODFILL_FIXED_RANGE
改为:
flags =4|(mask_fill<<8)|cv2.FLOODFILL_MASK_ONLY
运行程序后,发现img图片第一、第二行的值均未发生变化:
但mask图片第一、第二行的值与前面使用FLOODFILL_FIXED_RANGE时是一样的:
故此,可以验证前面对FLOODFILL_MASK_ONLY的解释,只影响mask的输出,对image无影响。
最后,对flags的0-7bit邻接性进行分析。
相邻像素
1) 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邻接。
最后,通过代码来演示一下:
Code-3-1:
- #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邻接的差异。
Code-3-2:
- #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)
img1为4邻接填充:
img2为8邻接填充:
<li class="tool-item tool-active is-like "><a href="javascript:;"><svg class="icon" aria-hidden="true"><use xlink:href="#csdnc-thumbsup"></use></svg><span class="name">点赞</span><span class="count">4</span></a></li><li class="tool-item tool-active is-collection "><a href="javascript:;" data-report-click="{"mod":"popu_824"}"><svg class="icon" aria-hidden="true"><use xlink:href="#icon-csdnc-Collection-G"></use></svg><span class="name">收藏</span></a></li><li class="tool-item tool-active is-share"><a href="javascript:;"><svg class="icon" aria-hidden="true"><use xlink:href="#icon-csdnc-fenxiang"></use></svg>分享</a></li><!--打赏开始--><!--打赏结束--><li class="tool-item tool-more"><a><svg t="1575545411852" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5717" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M179.176 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5718"></path><path d="M509.684 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5719"></path><path d="M846.175 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5720"></path></svg></a><ul class="more-box"><li class="item"><a class="article-report">文章举报</a></li></ul></li></ul></div></div><div class="person-messagebox"><div class="left-message"><a href="https://blog.csdn.net/weixin_42296411"><img src="https://profile.csdnimg.cn/0/4/8/3_weixin_42296411" class="avatar_pic" username="weixin_42296411"><img src="https://g.csdnimg.cn/static/user-reg-year/2x/2.png" class="user-years"></a></div><div class="middle-message"><div class="title"><span class="tit"><a href="https://blog.csdn.net/weixin_42296411" data-report-click="{"mod":"popu_379"}" target="_blank">weixin_42296411</a></span></div><div class="text"><span>发布了2 篇原创文章</span> · <span>获赞 10</span> · <span>访问量 2万+</span></div></div><div class="right-message"><a href="https://im.csdn.net/im/main.html?userName=weixin_42296411" target="_blank" class="btn btn-sm btn-red-hollow bt-button personal-letter">私信</a><a class="btn btn-sm bt-button personal-watch" data-report-click="{"mod":"popu_379"}">关注</a></div></div></div>
floodFill详解相关推荐
- FloodFill算法详解及应用
FloodFill算法详解及应用 啥是 FloodFill 算法呢, 最直接的一个应用就是「颜色填充」,就是 Windows 绘画本中那个小油漆桶的标志,可以把一块被圈起来的区域全部染色. 这种算法思 ...
- 【OpenCV 4开发详解】漫水填充法
本文首发于"小白学视觉"微信公众号,欢迎关注公众号 本文作者为小白,版权归人民邮电出版社发行所有,禁止转载,侵权必究! 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4 ...
- Windows API函数大全---附:windows运行命令详解
1. API之网络函数 WNetAddConnection 创建同一个网络资源的永久性连接 WNetAddConnection2 创建同一个网络资源的连 ...
- [opencv完整项目详解] 传统图像算法解决路标的检测和识别(改进升级版)
之前路标匹配[opencv完整项目详解] 传统图像算法解决路标的检测和识别 的一个改进版. 之前路标匹配存在的一个问题: 所有路标与模板的相似度都处于较高状态(基本都在50%以上),其主要原因就是虽然 ...
- [opencv完整项目详解] 传统图像算法解决路标的检测和识别
前言: 这是数字图像课程的大作业,老师要求不可以采用深度学习的方法检测和识别特定的路标,只能采用传统的图像算法提取特征从而检测出特定的车牌. 参考文章: https://blog.csdn.net/m ...
- 详解python中GPU版本的opencv常用方法介绍
更多编程教程请到:菜鸟教程 https://www.piaodoo.com/ 友情链接:好看站 http://www.nrso.net/ 高州阳光论坛https://www.hnthzk.com/ 引 ...
- 从命令行到IDE,版本管理工具Git详解(远程仓库创建+命令行讲解+IDEA集成使用)
首先,Git已经并不只是GitHub,而是所有基于Git的平台,只要在你的电脑上面下载了Git,你就可以通过Git去管理"基于Git的平台"上的代码,常用的平台有GitHub.Gi ...
- JVM年轻代,老年代,永久代详解
秉承不重复造轮子的原则,查看印象笔记分享连接↓↓↓↓ 传送门:JVM年轻代,老年代,永久代详解 速读摘要 最近被问到了这个问题,解释的不是很清晰,有一些概念略微模糊,在此进行整理和记录,分享给大家.在 ...
- docker常用命令详解
docker常用命令详解 本文只记录docker命令在大部分情境下的使用,如果想了解每一个选项的细节,请参考官方文档,这里只作为自己以后的备忘记录下来. 根据自己的理解,总的来说分为以下几种: Doc ...
最新文章
- 读《程序是怎样跑起来的》第5章
- 一起学nRF51xx 12 - flash
- 集群监控系统的设计方案
- Python手册 3.7
- centos配置单网卡双IP
- pycharm安装带激活码2018
- iOS利用代理实现界面跳转
- jQuery源码学习(一)
- Astar寻路教程!
- 等差数列及等比数列求和公式
- 学生档案信息管理系统(Java实现)
- webpack ——css兼容性处理
- 在电脑上微信无法语音聊天,微信听不到语音声音
- Guava源码解析五:Splitter源码解析
- android webview 手机兼容问题
- 【luogu CF1153F】Serval and Bonus Problem(期望)(DP)
- 怎么把解压的文件在HTML打开,解决电脑rar压缩包文件怎么打开?教你正确打开方式...
- 台式电脑如何修复计算机,大神告诉你电脑不断重启如何修复
- Java实现统计字符次数(按大写、小写、数字来统计)
- 找不到 Microsoft Excel Driver ODBC 驱动程序的安装例程 解决方案