floodFill详解

https://blog.csdn.net/weixin_42296411/article/details/80966724

函数原型

参数:

       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:

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

得到的图片输出(为方便观察,使用画图软件打开,下同):

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

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

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

Code-2:

    
    
  1. #encoding=utf-8
  2. import cv2
  3. import numpy as np
  4. img = np.zeros(( 20, 10), dtype=np.uint8)
  5. i = 0
  6. for v in img:
  7. v[:] = i// 5 * 60
  8. i += 1
  9. cv2.imwrite( 'img_init.png', img)
  10. seed = ( 7, 7)
  11. #构建mask,根据mask参数的介绍,其size必须为宽img+2,高img+2
  12. mask = np.zeros((img.shape[ 0]+ 2, img.shape[ 1] + 2), dtype=np.uint8)
  13. newVal = ( 127) #img fill的填充值
  14. mask_fill = 252 #mask的填充值
  15. #floodFill充值标志
  16. flags = 4|(mask_fill<< 8)|cv2.FLOODFILL_FIXED_RANGE
  17. #连通区范围设定
  18. loDiff, upDiff = 20, 20
  19. #执行floodFill操作
  20. ret, image, mask, rect = cv2.floodFill(img, mask, seed, newVal,(loDiff), (upDiff), flags)
  21. cv2.imwrite( 'img.png', img)
  22. 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)中,则pq是4邻接。

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

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

Code-3-1:


   
   
  1. #encoding=utf-8
  2. #创建一个8x8的图片
  3. import cv2
  4. import numpy as np
  5. size = 8
  6. img = np.zeros((size,size), dtype=np.uint8)
  7. img[:] = 0
  8. img[ 4, 4] = 1
  9. img[ 3, 4] = 1
  10. img[ 4, 3] = 1
  11. img[ 4, 5] = 1
  12. img[ 5, 4] = 1
  13. img[ 2, 4] = 1
  14. img[ 1, 5] = 1
  15. img[ 1, 3] = 1
  16. img[ 2, 2] = 1
  17. img[ 3, 1] = 1
  18. img[ 4, 0] = 1
  19. img[ 5, 1] = 1
  20. img[ 6, 2] = 1
  21. img[ 7, 3] = 1
  22. print(img)

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


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

Code-3-2:


   
   
  1. #encoding=utf-8
  2. #创建一个8x8的图片
  3. import cv2
  4. import numpy as np
  5. size = 8
  6. img = np.zeros((size,size), dtype=np.uint8)
  7. img[:] = 0
  8. seed_x = 4
  9. seed_y = 4
  10. img[seed_x, seed_y] = 1
  11. img[ 4, 4] = 1
  12. img[ 3, 4] = 1
  13. img[ 4, 3] = 1
  14. img[ 4, 5] = 1
  15. img[ 5, 4] = 1
  16. img[ 2, 4] = 1
  17. img[ 1, 5] = 1
  18. img[ 1, 3] = 1
  19. img[ 2, 2] = 1
  20. img[ 3, 1] = 1
  21. img[ 4, 0] = 1
  22. img[ 5, 1] = 1
  23. img[ 6, 2] = 1
  24. img[ 7, 3] = 1
  25. seed = (seed_x, seed_y)
  26. mask= np.zeros((size+ 2,size+ 2), dtype=np.uint8)
  27. img1 = img.copy()
  28. img2 = img.copy()
  29. mask1 = mask.copy()
  30. mask2 = mask.copy()
  31. ret, img1,mask1, rect=cv2.floodFill(img1, mask1, seed,( 8), ( 0),( 0), flags= 4|( 3<< 2)|cv2.FLOODFILL_FIXED_RANGE)
  32. ret, img2,mask2, rect=cv2.floodFill(img2, mask2, seed,( 8), ( 0),( 0), flags= 8|( 3<< 2)|cv2.FLOODFILL_FIXED_RANGE)
  33. print(img)
  34. print(img1)
  35. 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="{&quot;mod&quot;:&quot;popu_824&quot;}"><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="{&quot;mod&quot;:&quot;popu_379&quot;}" 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="{&quot;mod&quot;:&quot;popu_379&quot;}">关注</a>
                                    </div>
                            </div>
                    </div>
    
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值