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
猜你喜欢
- 0.引言自己在下载dlib官网给的example代码时,一开始不知道怎么使用,在一番摸索之后弄明白怎么使用了;现分享下 face_
- 最近在开发项目的过程中遇到一个问题,就是在插入一条记录的后要立即获取所在数据库中ID,而该ID是自增的,怎么做?在sql server 20
- 从今天开始,我将全面的共享出我所能理解的所有WEB标准方面的知识放在这个“WEB标准能有多难?”的专栏里。当然由于振之的水平有限,所讲并非是
- Numpy是高性能科学计算和数据分析的基础包,里面包含了许多对数组进行快速运算的标准数学函数,掌握这些方法,能摆脱数据处理时的循环。1.首先
- 内容摘要:当讨论Request对象内容时,要研究的集合之一就是ServerVariables集合。这个集合包含了两种值的结合体,一种是随同页
- 对于网站设计者而言,时常处理大批量的文件是难免的,特别是图片和一些文本文本文件,更是经常处理。而由于网站大量文件的关系,对于同类
- 本文实例讲述了js捐赠管理完整实现方法。分享给大家供大家参考。具体实现方法如下:index.html页面如下:<!DOCTYPE ht
- 监测主机存活的端口#!/usr/bin/env python# coding-utfimport argparseimport socket
- 1.在pycham官网下载安装软件https://www.jetbrains.com/pycharm/download/2.我下载的是64位
- 我们知道,任何数据库系统都无法避免崩溃的状况,即使你使用了Clustered,双机热备……仍然无
- 本程序将使用字典来构建有向无环图,然后遍历图将其转换为对应的Excel文件最终结果如下:代码:(py3) [root@7-o-1 py-da
- 1、基于字典的创建规划问题上篇中介绍了使用 LpVariable 对逐一定义每个决策变量,设定名称、类型和上下界,类似地对约束条件也需要逐一
- 本文实例讲述了python 协程 gevent原理与用法。分享给大家供大家参考,具体如下:geventgreenlet已经实现了协程,但是这
- 内置数据类型在编程中,数据类型是一个重要的概念。变量可以存储不同类型的数据,并且不同类型可以执行不同的操作。在这些类别中,Python 默认
- 报错现象File "<string>", line 1SyntaxError: unexpected EOF
- 当在函数中定义默认值时,值初始化只会进行一次,就是执行到def methodname时执行。看下面代码:from datetime impo
- 什么是接口测试接口测试主要用于检测外部系统与内部系统之间,以及系统内部各 个子系统之间的交互点。其测试的重点是,检查数据的交换、传递和控 制
- 在flask中可以像go和angular那样使用页面模版(template),可以将HTML页面显示进行模版化,通过参数传递与页面进行数据交
- 本文转自微信公众号:"算法与编程之美"1、前言之前的文章Python用HBuilder创建交流社区APP我们已经在HBu
- 前言本文使用 cpu 版本的 TensorFlow 2.4 ,分别搭建单层 Bi-LSTM 模型和多层 Bi-LSTM 模型完成文本分类任务