当前位置: 首页 > news >正文

Python----OpenCV(图像分割——彩色图像分割,GrabCut算法分割图像)

一、彩色图像分割

        彩色图像分割是利用图像的颜色特征,将不同区域或物体从图像中分割出来的方法。 相比灰度图像,彩色图像包含更多维度的信息(通常是3个通道),分割效果更丰富。

名称组成通道特点
RGBR、G、B常规图像格式,易受光照影响
HSVH(色调)、S(饱和度)、V(亮度)色调独立,分割色彩区域效果好
LabL(亮度)、a(绿-红)、b(蓝-黄)更接近人眼感知,常用于复杂环境

        cv2.inRange() 函数用于图像阈值操作,基于指定的范围对图像进行分割。它通过将图像的像素值与指定的范围进行比较,生成一个二值图像:在指定范围内的像素值对应为白色(255),不在范围内的像素值对应为黑色(0)。

cv2.inRange(src, lowerb, upperb)
参数类型说明
src输入图像可以是彩色图像(如 BGR、HSV 等格式)或单通道图像(如灰度图像)。
lowerb数组或标量低阈值,表示每个通道的最小值。对于多通道图像,应提供对应通道的阈值数组。
upperb数组或标量高阈值,表示每个通道的最大值。对于多通道图像,应提供对应通道的阈值数组。
返回值类型说明
掩膜图像二值图像与输入图像大小相同,像素值在 [lowerb, upperb] 范围内的置为 255,否则为 0。

        cv2.bitwise_and() 函数执行按位与(AND)操作。它用于将两个图像的对应像素进行按位与操作。通常用于图像遮罩操作,它可以将掩膜图像与原图像进行“与”操作,保留原图中掩膜图像为 255(白色)区域的部分,其他部分变为黑色(0)。

cv2.bitwise_and(src1, src2, mask=None)
参数类型说明
src1输入图像1可以是单通道或多通道图像(如灰度图、BGR、HSV 等)。
src2输入图像2必须与 src1 的尺寸和数据类型相同。
mask可选掩膜如果提供,仅对掩膜中非零的像素进行按位与操作,其余部分保持原值或置零。
返回值类型说明
输出图像与输入相同类型返回 src1 & src2 的按位与结果,若提供 mask,则仅影响掩膜区域。

彩色图像分割常见问题与解决方法

问题原因解决方法
光照变化敏感RGB 亮度变化大转换到 HSV/Lab 空间,使用 H 或 a、b 分量
颜色相近区域难区分不同物体颜色接近多通道联合分割、加入位置/纹理特征
背景杂乱背景颜色复杂先滤波去噪,再基于颜色空间提取目标色域
色域交叉目标色域与背景部分重叠结合多阈值、多特征、多步骤分割,提升鲁棒性
import cv2
import numpy as np
# 读取图片 
img=cv2.imread('./images/nezha.png')# 将bgt转hsv
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)# 创建窗口
cv2.namedWindow('Trackbars')def callback(x):    pass# 创建滑动条6条  H 0-179  S V 0-255
cv2.createTrackbar('H_min', 'Trackbars', 0, 179, callback)
cv2.createTrackbar('H_max', 'Trackbars', 179, 179, callback)
cv2.createTrackbar('S_min', 'Trackbars', 0, 255, callback)
cv2.createTrackbar('S_max', 'Trackbars', 255, 255, callback)
cv2.createTrackbar('V_min', 'Trackbars', 0, 255, callback)
cv2.createTrackbar('V_max', 'Trackbars', 255, 255, callback)# 无限循环
while True:# 获取滑动条的值h_min = cv2.getTrackbarPos('H_min', 'Trackbars')h_max = cv2.getTrackbarPos('H_max', 'Trackbars')s_min = cv2.getTrackbarPos('S_min', 'Trackbars')s_max = cv2.getTrackbarPos('S_max', 'Trackbars')v_min = cv2.getTrackbarPos('V_min', 'Trackbars')v_max = cv2.getTrackbarPos('V_max', 'Trackbars')# 组装上下界 Numpy数组 分别表示hsv最小值和最大值lower = np.array([h_min, s_min, v_min])upper = np.array([h_max, s_max, v_max])#利用INRANGE函数对图像进行二值化mask = cv2.inRange(hsv, lower, upper)# 将二值图像与原图像进行位运算res = cv2.bitwise_and(img, img, mask=mask)cv2.imshow('img', img)cv2.imshow('mask', mask)cv2.imshow('res', res)# 按q键退出if cv2.waitKey(1) & 0xFF == ord('q'):breakcv2.destroyAllWindows()

二、 GrabCut算法分割图像

        GrabCut是一种基于图像分割的半监督算法,它在图像分割中通过将前景和背景建模为图像的高斯混合模型(GMM),以此来实现高效且准确的图像分割。GrabCut 结合了 图像边缘信息 和 用户输入的前景/背景框,可以快速分割出图像中的目标区域。

👉核心思想:

  • 高斯混合模型:对前景和背景分别建立高斯混合模型,并计算每个像素属于前景或背景的概率。

  • 迭代优化:通过迭代过程优化前景和背景的分割边界,使其逐步精确。

应用场景

  • 🎨 目标提取(如人像抠图、物体分割)。

  • 🖼️自动化图像编辑(如替换背景、去除背景)。

  • 🩺医学图像分析(如肿瘤检测、细胞分割)。

GrabCut 原理流程

  1. 用户输入矩形区域

    • 将矩形区域内作为潜在前景,矩形外作为背景。

  2. 高斯混合模型(GMM)建模

    • 利用 GMM 对前景和背景像素颜色分布进行建模。

  3. 构建图模型

    • 像素作为节点,节点之间根据像素相似性设置边的权重。

  4. 图割(Graph Cut)

    • 利用最小割/最大流算法,计算出前景和背景的最优分割。

  5. 迭代优化

    • 重复更新 GMM 参数,优化分割结果。

        GrabCut 是基于图割的前景提取算法,OpenCV 中直接封装成了 cv2.grabCut() 函数,调用简单。 

cv2.grabCut(img, mask, rect, bgdModel, fgdModel, iterCount, mode)
参数类型说明
img输入图像(3通道 BGR)需要进行前景分割的彩色图像(BGR 格式)。
mask单通道掩膜图像初始化的掩膜,取值:
• 0cv2.GC_BGD):背景
• 1cv2.GC_FGD):前景
• 2cv2.GC_PR_BGD):可能背景
• 3cv2.GC_PR_FGD):可能前景
如果使用 cv2.GC_INIT_WITH_RECT,该参数会被修改。
rect(x, y, w, h) 元组包含前景的矩形区域(仅 mode=cv2.GC_INIT_WITH_RECT 时使用)。
bgdModelnp.float64 数组内部背景模型,需初始化为 np.zeros((1, 65), np.float64)
fgdModelnp.float64 数组内部前景模型,需初始化为 np.zeros((1, 65), np.float64)
iterCountint算法的迭代次数(通常 5 次即可,更高次数可能优化结果)。
modeint(可选)运行模式:
• cv2.GC_INIT_WITH_RECT(默认,用矩形初始化)
• cv2.GC_INIT_WITH_MASK(用掩膜初始化)
import cv2
import numpy as np
# 读取图像
img=cv2.imread('./images/nezha.png')# 复制图像
img_copy = img.copy()   # ROI 区域fromCenter false 表示从左上角开始选择,true表示从中心开始选择 showCrosshair 是否显示十字架
rect = cv2.selectROI("请选择目标区域,然后按ENTER确定",img_copy, fromCenter=False, showCrosshair=True)
print(rect) # 输出选择的区域
cv2.destroyAllWindows()# 创建掩膜
mask = np.zeros(img.shape[:2], np.uint8) # 创建一个全零的图像,大小和原图像一样,数据类型为uint8
# 创建前景和背景模型
bgd_model = np.zeros((1, 65), np.float64) # 初始化背景模型。 使用高斯混合模型 存储背景信息
fgd_model = np.zeros((1, 65), np.float64)# 初始化背前景模型。 使用高斯混合模型 存储背景信息# GreabCut算法
cv2.grabCut(img,mask, rect, bgd_model,fgd_model,5, cv2.GC_INIT_WITH_RECT)# 0 确定的背景 1 确定前景 2  可能背景 3 可能前景
# 生成最终的掩膜  uint8 8位无符号整数
# #  mask = [[0,1,2],[3,0,1]]   变成  [[0,1,0],[1,0,1]]
mask2 = np.where((mask==2)|(mask==0),0,1).astype('uint8')# 将掩膜应用到原图像上
# 维度不匹配  (400,600,1)
result = img * mask2[:, :, np.newaxis] # 将掩膜应用到原图像上,np.newaxis增加一个维度cv2.imshow('img',img)
cv2.imshow('result', result)
cv2.waitKey(0)
cv2.destroyAllWindows()

        实现了一个基于GrabCut算法的图像分割功能,能够从背景中提取用户指定的前景目标。整个过程可以分为几个关键步骤:首先通过交互式方式让用户选择目标区域,然后利用机器学习算法自动完成精细分割,最后输出分割结果。

        在初始阶段,代码会加载图像并创建一个副本用于交互操作。通过调用selectROI函数,系统会弹出一个交互窗口,用户可以用鼠标拖拽的方式框选目标物体。这个矩形区域会被记录下来,作为后续分割的初始输入。为了进行图像分割,代码需要准备三个关键数据结构:一个全零的掩膜矩阵用于记录像素分类结果,以及两个65维的浮点数组作为前景和背景的高斯混合模型参数。

        核心处理阶段调用grabCut函数执行实际的分割算法。该函数会根据用户提供的矩形区域,对图像像素进行初步分类:矩形外标记为确定背景,矩形内标记为可能前景。通过5次迭代优化,算法会不断调整分类结果,逐步精确目标边界。在掩膜处理环节,代码将所有背景类像素(包括确定背景和可能背景)统一标记为0,前景类像素标记为1,生成一个二值掩膜。

        最终输出阶段,这个二值掩膜被应用到原始图像上。通过增加维度使掩膜与彩色图像对齐,然后进行逐像素乘法运算,保留前景区域的原始颜色,将背景区域置为黑色。程序最后会并列显示原始图像和分割结果,用户可以通过观察结果评估分割质量。如果效果不理想,可以调整初始选择区域或手动修改掩膜后重新运行算法。整个过程结合了用户交互和自动计算,能够有效地从复杂背景中提取目标对象。

http://www.lryc.cn/news/586877.html

相关文章:

  • LeetCode--44.通配符匹配
  • Mybatis 两级缓存可能导致的问题
  • Java4种设计模式详解(单例模式、工厂模式、适配器模式、代理模式)
  • 笔记/sklearn中的数据划分方法
  • 赛力斯6月新能源汽车销量46086辆,同比增长4.44%
  • JavaScript加强篇——第九章 正则表达式高级应用(终)
  • Linux编程:6、进程通信-信号量与共享内存
  • OpenLayers 入门指南【二】:坐标系与投影转换
  • linux进程信号II
  • Node.js特训专栏-实战进阶:16. RBAC权限模型设计
  • 基于YOLOv7的改进模型:集成Swin Transformer和ASFF模块
  • 26-计组-数据通路
  • 【软件开发】使用 Spring WebFlux 进行请求校验
  • iOS ish app 打印时间
  • HJ8 合并表记录 10:35
  • Vue中的render()函数
  • 【LeetCode数据结构】单链表的应用——反转链表问题、链表的中间节点问题详解
  • 为什么要有延时回调?
  • 【实证分析】上市公司绿色战略数据集(2000-2023年)
  • 如何设计一个合理的 Java Spring Boot 项目结构
  • C++ 强制类型转换
  • 【读书笔记】《C++ Software Design》第六章深入剖析 Adapter、Observer 和 CRTP 模式
  • 开机自动启动同花顺,并设置进程优先级为高
  • Linux驱动开发1:设备驱动模块加载与卸载
  • 【Linux学习笔记】认识信号和信号的产生
  • JAVA JVM虚拟线程
  • HTML 初体验
  • 软件文档体系深度解析:工程视角下的文档架构与治理
  • OneCode3.0 VFS分布式文件管理API速查手册
  • jenkins使用Jenkinsfile部署springboot+docker项目