OpenCV计算机视觉实战(16)——图像分割技术
OpenCV计算机视觉实战(16)——图像分割技术
- 0. 前言
- 1. 分水岭算法
- 1.1 应用场景
- 1.2 实现过程
- 2. GrabCut 交互式分割
- 2.1 应用场景
- 2.2 实现过程
- 3. FloodFill
- 3.1 应用场景
- 3.2 实现过程
- 小结
- 系列链接
0. 前言
图像分割是计算机视觉中将像素划分为具有特定语义或结构的区域。面对目标紧密相连或前景背景对比不明显的复杂场景,仅凭简单的阈值往往捉襟见肘。本文深入讲解并演示了三种经典而高效的分割方法——分水岭算法借鉴地形水漫模型精准分离粘连目标,GrabCut
交互式抠图通过最小割迭代优化实现细节丰富的前景提取,以及 FloodFill
以种子点为起点快速覆盖同质区域。
1. 分水岭算法
将灰度图看作地形高程图,把“低谷”视为种子点,利用梯度图构造“水漫”过程,最终在“山脊线”处形成分割边界,适合处理前景连通但边界黯淡的场景。
1.1 应用场景
- 重叠目标分离:当前景对象相互粘连时(如重叠的硬币、细胞团),分水岭能精确沿“山脊”将它们分开
- 纹理分割:结合梯度图,能处理前景背景亮度相近但纹理不同的场景
- 预分割:常作为后续目标检测或特征提取的预处理步骤,提供连通组件
1.2 实现过程
- 读取图像与预处理
- 转灰度并做高斯模糊,减少噪声
- 计算梯度图 (
Sobel
或Laplacian
) 以突出边缘
- 二值化与距离变换
- 对图像做阈值化,得到粗略二值前景
- 对前景做距离变换并归一化
- 标记种子区域
- 对距离变换结果做阈值,提取“确实前景”作为种子标记
- 将未知区域标为
0
,背景标为1
- 调用分水岭
cv2.watershed
会修改标记矩阵,将边界点标记为–1
- 在原图上将边界涂为红色
import cv2
import numpy as np# 1. 读取与预处理
img = cv2.imread('2.jpeg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (5, 5), 0)# 2. 梯度与二值化
grad = cv2.Laplacian(blur, cv2.CV_8U, ksize=3)
_, binary = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)# 3. 距离变换与种子标记
dist = cv2.distanceTransform(binary, cv2.DIST_L2, 5)
_, fg = cv2.threshold(dist, 0.4 * dist.max(), 255, 0)
fg = np.uint8(fg)
bg = cv2.dilate(binary, np.ones((3,3), np.uint8), iterations=3)
unknown = cv2.subtract(bg, fg)# 4. 连通组件与标记
_, markers = cv2.connectedComponents(fg)
markers = markers + 1 # 背景标记为 1
markers[unknown == 255] = 0 # 未知区域标记为 0# 5. 分水岭
markers = cv2.watershed(img, markers)
output = img.copy()
output[markers == -1] = [0, 0, 255] # 边界标红cv2.imshow('Watershed Segmentation', output)
cv2.waitKey(0)
cv2.destroyAllWindows()
关键函数解析:
cv2.distanceTransform(src, distType, maskSize)
:计算二值图中每个前景像素到最近背景的距离,用于挖掘前景核心区域cv2.connectedComponents(src)
:对前景二值图进行连通组件标记,生成初始标记矩阵cv2.watershed(image, markers)
:以markers
为种子,在彩色图像上执行分水岭算法,输出带边界的标记图
2. GrabCut 交互式分割
GrabCut
利用图割 (Graph Cut
) 模型结合少量用户标注(矩形或前景/背景涂抹),自动学习前景与背景像素分布,实现高质量分割,适合人物/物体抠图。
2.1 应用场景
- 半自动抠图:用户只需框选对象,后续可用笔刷细化边缘,比如头发、树叶等复杂轮廓
- 视频抠像:在关键帧交互后,将模型应用于相邻帧,实现半自动背景替换
- 图形编辑工具:集成
GrabCut
,让非专业用户也能轻松抠图
2.2 实现过程
- 读取图像与定义感兴趣区域 (
Region of Interest
,ROI
)- 用户给定一个大致含前景的矩形框
rect
- 用户给定一个大致含前景的矩形框
- 初始化掩码与模型
mask
初始化为全 “可能背景”bgModel
与fgModel
用于内部高斯混合模型 (Gaussian Mixture Model
,GMM
)
- 调用 GrabCut
cv2.grabCut
根据rect
或用户刷涂的mask
迭代优化- 模型会不断更新前景/背景分布
- 提取结果
- 将
mask
中标记为前景/可能前景的像素保留,其余设为背景
- 将
import cv2
import numpy as npimg = cv2.imread('2.jpeg')
mask = np.zeros(img.shape[:2], np.uint8)# 1. 用户定义矩形 ROI (x,y,w,h)
rect = (50, 50, img.shape[1]-100, img.shape[0]-100)# 2. 初始化模型
bgModel = np.zeros((1,65), np.float64)
fgModel = np.zeros((1,65), np.float64)# 3. 执行 GrabCut
cv2.grabCut(img, mask, rect, bgModel, fgModel, 5, cv2.GC_INIT_WITH_RECT)# 4. 构建前景掩码并应用
mask2 = np.where((mask==cv2.GC_FGD)|(mask==cv2.GC_PR_FGD),255,0).astype('uint8')
result = cv2.bitwise_and(img, img, mask=mask2)cv2.imshow('GrabCut Result', result)
cv2.waitKey(0)
cv2.destroyAllWindows()
关键函数解析:
cv2.grabCut(img, mask, rect, bgdModel, fgdModel, iterCount, mode)
:在指定rect
区域或已有mask
上运行GrabCut
mode=cv2.GC_INIT_WITH_RECT
:使用矩形初始化mode=cv2.GC_INIT_WITH_MASK
:根据用户细化涂抹结果再运行
mask
标签值:GC_BGD(0)
,GC_FGD(1)
,GC_PR_BGD(2)
,GC_PR_FGD(3)
,可提取出最终前景
3. FloodFill
FloodFill
从给定种子点开始,将相似像素“漫水填充”到边界,可用于区域生长、缺陷检测与交互式标注。
3.1 应用场景
- 缺陷检测:从划痕起点填充,快速定位裂纹区域
- 交互式分割:点击图像生成精确区域掩码,配合
GrabCut
等方法 - 色块分割:在质感均匀的背景或卡通图像中,快速提取色块
3.2 实现过程
- 读取图像
- 指定种子点
(x, y)
- 设置填充参数
loDiff
/upDiff
:允许填充的像素与种子点最大差异flags
:控制填充方式、掩码使用
- 调用
FloodFill
- 返回填充后的像素数与更新后的图像
import cv2
import numpy as npimg = cv2.imread('1.jpeg')
h, w = img.shape[:2]# 1. 构建掩码,需比原图多两像素边缘
mask = np.zeros((h+2, w+2), np.uint8)# 2. 漫水填充参数
seed_point = (700, 500)
newVal = (0, 0, 255) # 填充颜色:红色
loDiff = (20, 20, 20) # 下限差异
upDiff = (20, 20, 20) # 上限差异
flags = 4 | cv2.FLOODFILL_FIXED_RANGE | (255<<8)# 3. 执行 FloodFill
num, img_flood, mask, rect = cv2.floodFill(img.copy(), mask, seed_point,newVal, loDiff, upDiff, flags)cv2.imshow('FloodFill Result', img_flood)
cv2.waitKey(0)
cv2.destroyAllWindows()
关键函数解析
cv2.floodFill(image, mask, seedPoint, newVal, loDiff, upDiff, flags)
:从seedPoint
开始填充,loDiff
/upDiff
控制像素相似度flags
参数含义:cv2.FLOODFILL_FIXED_RANGE
:像素差异相对种子点cv2.FLOODFILL_MASK_ONLY
:仅更新mask
小结
本节从分水岭的高程地图思路切入,讲解如何借助距离变换与连通组件构建水漫分割,再通过 GrabCut
的图割模型与用户交互实现更高精度的前景去背,最后以 FloodFill
的种子驱动方式演示快速区域生长。三者各有侧重,却可互为补充:分水岭适合自动化预分割,GrabCut
适合复杂边缘细化,FloodFill
则胜在简单直观和交互式应用。
系列链接
OpenCV计算机视觉实战(1)——计算机视觉简介
OpenCV计算机视觉实战(2)——环境搭建与OpenCV简介
OpenCV计算机视觉实战(3)——计算机图像处理基础
OpenCV计算机视觉实战(4)——计算机视觉核心技术全解析
OpenCV计算机视觉实战(5)——图像基础操作全解析
OpenCV计算机视觉实战(6)——经典计算机视觉算法
OpenCV计算机视觉实战(7)——色彩空间详解
OpenCV计算机视觉实战(8)——图像滤波详解
OpenCV计算机视觉实战(9)——阈值化技术详解
OpenCV计算机视觉实战(10)——形态学操作详解
OpenCV计算机视觉实战(11)——边缘检测详解
OpenCV计算机视觉实战(12)——图像金字塔与特征缩放
OpenCV计算机视觉实战(13)——轮廓检测详解
OpenCV计算机视觉实战(14)——直方图均衡化
OpenCV计算机视觉实战(15)——霍夫变换详解