Python经典案例之图像漫水填充分割详解
作者:Eastmount 发布时间:2021-08-25 11:41:14
一.图像漫水填充
图像漫水填充(FloodFill)是指用一种特定的颜色填充联通区域,通过设置可连通像素的上下限以及连通方式来达到不同的填充效果。漫水填充通常被用来标记或分离图像的一部分以便对其进行深入的处理或分析。
图像漫水填充主要是遴选出与种子点联通且颜色相近的像素点,接着对像素点的值进行处理。如果遇到掩码,则根据掩码进行处理。其原理类似Photoshop的魔术棒选择工具,漫水填充将查找和种子点联通的颜色相同的点,而魔术棒选择工具是查找和种子点联通的颜色相近的点,将和初始种子像素颜色相近的点压进栈作为新种子。基本工作步骤如下:
选定种子点(x,y);
检查种子点的颜色,如果该点颜色与周围连接点的颜色不相同,则将周围点颜色设置为该点颜色;如果相同则不做处理。但是周围点不一定都会变成和种子点的颜色相同,如果周围连接点在给定的范围(从loDiff到upDiff)内或在种子点的像素范围内才会改变颜色;
检测其他连接点,进行第2个步骤的处理,直到没有连接点,即到达检测区域边界停止。
二.图像漫水填充分割实现
在OpenCV中,主要通过floodFill()函数实现漫水填充分割,它将用指定的颜色从种子点开始填充一个连接域。其函数原型如下所示:
floodFill(image, mask, seedPoint, newVal[, loDiff[, upDiff[, flags]]])
– image表示输入/输出1通道或3通道,6位或浮点图像
– mask表示操作掩码,必须为8位单通道图像,其长宽都比输入图像大两个像素点。注意,漫水填充不会填充掩膜mask的非零像素区域,mask中与输入图像(x,y)像素点相对应的点的坐标为(x+1,y+1)。
– seedPoint为Point类型,表示漫水填充算法的起始点
– newVal表示像素点被染色的值,即在重绘区域像素的新值
– loDiff表示当前观察像素值与其部件邻域像素值或待加入该部件的种子像素之间的亮度或颜色之负差的最大值,默认值为Scalar( )
– upDiff表示当前观察像素值与其部件邻域像素值或待加入该部件的种子像素之间的亮度或颜色之正差的最大值,默认值为Scalar( )
– flags表示操作标识符,此参数包括三个部分:低八位0-7bit表示邻接性(4邻接或8邻接);中间八位8-15bit表示掩码的填充颜色,如果中间八位为0则掩码用1来填充;高八位16-31bit表示填充模式,可以为0或者以下两种标志符的组合,FLOODFILL_FIXED_RANGE表示此标志会考虑当前像素与种子像素之间的差,否则就考虑当前像素与相邻像素的差。FLOODFILL_MASK_ONLY表示函数不会去填充改变原始图像,而是去填充掩码图像mask,mask指定的位置为零时才填充,不为零不填充。
在Python和OpenCV实现代码中,它设置种子点位置为(10,200);设置颜色为黄色(0,255,255);连通区范围设定为loDiff和upDiff;标记参数设置为CV_FLOODFILL_FIXED_RANGE ,它表示待处理的像素点与种子点作比较,在范围之内,则填充此像素,即种子漫水填充满足:
src(seed.x, seed.y) - loDiff <= src(x, y) <= src(seed.x, seed.y) +upDiff
完整代码如下:
# -*- coding: utf-8 -*-
# By: Eastmount
import cv2
import numpy as np
#读取原始图像
img = cv2.imread('windows.png')
#获取图像行和列
rows, cols = img.shape[:2]
#目标图像
dst = img.copy()
#mask必须行和列都加2且必须为uint8单通道阵列
#mask多出来的2可以保证扫描的边界上的像素都会被处理
mask = np.zeros([rows+2, cols+2], np.uint8)
#图像漫水填充处理
#种子点位置(30,30) 设置颜色(0,255,255) 连通区范围设定loDiff upDiff
#src(seed.x, seed.y) - loDiff <= src(x, y) <= src(seed.x, seed.y) +upDiff
cv2.floodFill(dst, mask, (30, 30), (0, 255, 255),
(100, 100, 100), (50, 50, 50),
cv2.FLOODFILL_FIXED_RANGE)
#显示图像
cv2.imshow('src', img)
cv2.imshow('dst', dst)
cv2.waitKey()
cv2.destroyAllWindows()
输出结果如图1所示,左边为原始图像,右边为将Windows图标周围填充为黄色的图像。
三.图像漫水填充分割自动软件
下面补充另一段代码,它将打开一幅图像,点击鼠标选择种子节点,移动滚动条设定连通区范围的loDiff和upDiff值,并产生动态的漫水填充分割。
注意,该部分代码中涉及鼠标、键盘、滚动条等操作,希望读者下来学习相关知识,该系列文章更多是讲解Python图像处理的算法原理及代码实现。
# coding:utf-8
import cv2
import random
import sys
import numpy as np
#使用说明 点击鼠标选择种子点
help_message = '''USAGE: floodfill.py [<image>]
Click on the image to set seed point
Keys:
f - toggle floating range
c - toggle 4/8 connectivity
ESC - exit
'''
if __name__ == '__main__':
#输出提示文本
print(help_message)
#读取原始图像
img = cv2.imread('scenery.png')
#获取图像高和宽
h, w = img.shape[:2]
#设置掩码 长和宽都比输入图像多两个像素点
mask = np.zeros((h+2, w+2), np.uint8)
#设置种子节点和4邻接
seed_pt = None
fixed_range = True
connectivity = 4
#图像漫水填充分割更新函数
def update(dummy=None):
if seed_pt is None:
cv2.imshow('floodfill', img)
return
#建立图像副本并漫水填充
flooded = img.copy()
mask[:] = 0 #掩码初始为全0
lo = cv2.getTrackbarPos('lo', 'floodfill') #像素邻域负差最大值
hi = cv2.getTrackbarPos('hi', 'floodfill') #像素邻域正差最大值
print('lo=', lo, 'hi=', hi)
#低位比特包含连通值 4 (缺省) 或 8
flags = connectivity
#考虑当前像素与种子像素之间的差(高比特也可以为0)
if fixed_range:
flags |= cv2.FLOODFILL_FIXED_RANGE
#以白色进行漫水填充
cv2.floodFill(flooded, mask, seed_pt,
(random.randint(0,255), random.randint(0,255),
random.randint(0,255)), (lo,)*3, (hi,)*3, flags)
#选定基准点用红色圆点标出
cv2.circle(flooded, seed_pt, 2, (0, 0, 255), -1)
print("send_pt=", seed_pt)
#显示图像
cv2.imshow('floodfill', flooded)
#鼠标响应函数
def onmouse(event, x, y, flags, param):
global seed_pt #基准点
#鼠标左键响应选择漫水填充基准点
if flags & cv2.EVENT_FLAG_LBUTTON:
seed_pt = x, y
update()
#执行图像漫水填充分割更新操作
update()
#鼠标更新操作
cv2.setMouseCallback('floodfill', onmouse)
#设置进度条
cv2.createTrackbar('lo', 'floodfill', 20, 255, update)
cv2.createTrackbar('hi', 'floodfill', 20, 255, update)
#按键响应操作
while True:
ch = 0xFF & cv2.waitKey()
#退出
if ch == 27:
break
#选定时flags的高位比特位0
#邻域的选定为当前像素与相邻像素的差, 联通区域会很大
if ch == ord('f'):
fixed_range = not fixed_range
print('using %s range' % ('floating', 'fixed')[fixed_range])
update()
#选择4方向或则8方向种子扩散
if ch == ord('c'):
connectivity = 12-connectivity
print('connectivity =', connectivity)
update()
cv2.destroyAllWindows()
当鼠标选定的种子点为(242,96),观察点像素邻域负差最大值“lo”为138,观察点像素邻域正差最大值“hi”为147时,图像漫水填充效果如图2所示,它将天空和中心水面填充成黄色。
当鼠标选定的种子点为(328, 202),观察点像素邻域负差最大值“lo”为142,观察点像素邻域正差最大值“hi”为45时,图像漫水填充效果如图3所示,它将图像两旁的森林和水面填充成蓝紫色。
四.总结
写到这里,图像分割知识点就介绍完毕,包括基于阈值的图像分割方法、基于边缘检测的图像分割方法、基于纹理背景的图像分割方法和基于特定理论的图像分割方法。其中,基于特定理论的分割方法又分别讲解了基于K-Means聚类、均值漂移、分水岭算法的图像分割方法。最后通过漫水填充分割案例加深了读者的印象。希望读者能结合本章知识点,围绕自己的研究领域或工程项目进行深入的学习,实现所需的图像处理。
来源:https://blog.csdn.net/Eastmount/article/details/128747493


猜你喜欢
- 最终的目标是想这样的,在JavaScript里写一个swing来实现确定取消,来决定是否执行这个功能的,但是在执行的过程中,出现了一点问题,
- 用面向对象的思维解决问题的重点当遇到一个需求的时候不用自己去实现,如果自己一步步实现那就是面向过程;应该找一个专门做这个事的人来做。面向对象
- python PIL图像处理模块中的ImageDraw类支持各种几何图形的绘制和文本的绘制,如直线、椭圆、弧、弦、多边形以及文字等。下面直接
- 文件夹的复制文件夹复制使用的函数导入包与模块`from shutil import copytree使用方法:copytree(来源目录,
- 常用的标准库序列化模块import pickle序列化和反序列化把不能直接存储的数据变得可存储,这个过程叫做序列化。把文件中的数据拿出来,回
- 第一步:更改setting.py中的DATABASES# 配置数据库DATABASES = { 'default'
- 一、普通进度条示例代码import sysimport timedef progress_bar(): for i in ran
- 一、BLOB字段BLOB是指二进制大对象也就是英文Binary Large Object的所写,而CLOB是指大字符对象也就是英文Chara
- 一、Pandas如何对Categorical类型字段数据统计实战场景:对Categorical类型字段数据统计,Categorical类型是
- 由于众所周知的原因,ACCESS在大型站点应用中都靠不上边,主要问题就是数据量大了以后几乎无法索引。当ACCESS里数据过万后,明显可以感觉
- 在对Python中的闭包进行简单分析之前,我们先了解一下Python中的作用域规则。关于Python中作用域的详细知识,有很多的博文都进行了
- 关于mysql效率优化一般通过以下两种方式定位执行效率较低的sql语句。通过慢查询日志定位那些执行效率较低的 SQL 语句,用 --log-
- 前言题目如下:给定一个仅包含大小写字母和空格 ’ ’ 的字符串 s,返回其最后一个单词的长度。如果字
- 本文实例为大家分享了Python OpenCV图像直方图和反向投影的具体代码,供大家参考,具体内容如下当我们想比较两张图片相似度的时候,可以
- 物体跟踪效果展示 过程:一、初始化def Motor_Init(): global L_Motor, R
- 先给大家展示下效果图,大家感觉不错,请参考实现代码:实现原理:点击按钮,往需要动画的div中添加或移除拥有动画效果的class。由于微信小程
- 一、数字类型。数字类型按照我的分类方法分为三类:整数类、小数类和数字类。 我所谓的“数字类”,就是指DECIMAL
- 环境搭建1、下载所需的软件包:(1)python安装包(2)django安装包以下2个包其实是安装python包管理工具,在后面安装djan
- 代码如下:CREATE TABLE [dbo].[TbGuidTable]( [TableName] [varchar](50) NOT N
- CSS样式和JavaScript脚本是应该放在外部文件中呢?还是把它们放在页面本身之内呢?如何处理是关于一些性能规则的思维,就这些问题,我们