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

机器视觉opencv教程(四):图像颜色识别与颜色替换

图像颜色识别与颜色替换

前言

图像颜色识别与替换是计算机视觉的基础应用(如交通灯识别、产品分拣、图像美化等),核心是通过HSV 颜色空间实现更直观的颜色定位,并借助掩膜(Mask) 选择性提取或修改目标颜色。相较于 RGB 颜色空间,HSV 更符合人类对颜色的感知逻辑,是颜色相关任务的首选方案。

一、核心基础:HSV 颜色空间

HSV(Hue - 色调、Saturation - 饱和度、Value - 亮度)是一种基于人眼对颜色感知的颜色模型,与 RGB(红、绿、蓝)的 “三原色叠加” 逻辑完全不同,更适合颜色分割与识别。

1.1 HSV 与 RGB 的核心区别

维度RGB 颜色空间HSV 颜色空间
表示逻辑加色法模型,通过红、绿、蓝三通道强度叠加表示颜色基于 “颜色属性”,通过色调、饱和度、亮度三维度描述颜色
人类感知匹配不直观(调整红色需同时修改 R、G、B 通道)高度匹配(人类对颜色的认知就是 “什么色、艳不艳、亮不亮”)
颜色分割难度高(通道耦合性强,易受光照影响)低(色调 H 独立区分颜色,光照影响可通过亮度 V 调整)
适用场景图像显示(屏幕、相机)颜色识别、分割、替换(计算机视觉任务)

1.2 HSV 三分量详解

HSV 通过三个独立分量精准描述颜色,各分量的定义、取值范围(含 OpenCV 适配)及意义如下:

分量中文名称定义(核心作用)标准取值范围OpenCV 取值范围(8 位像素)关键说明
H色调区分颜色种类(如红、黄、绿)0°~360°0~179(360° 压缩为 0~179)0 = 红,60 = 黄,120 = 绿,180 = 青,240 = 蓝,300 = 紫
S饱和度描述颜色纯度(鲜艳程度)0%~100%0~255S=0→灰度(无色),S=255→纯色(最鲜艳)
V亮度描述颜色明暗程度0%~100%0~255V=0→黑色,V=255→最亮(白色或纯色最亮状态)

例:纯红色的 HSV 值(标准)为 (0°, 100%, 100%),在 OpenCV 中对应 (0, 255, 255);浅红色(偏灰、较暗)可能为 (0, 100, 150)。

1.3 HSV 色域图

HSV 色域可理解为“圆锥体”结构:

  • 圆锥的高度对应亮度 V(从下到上:0→255,黑色→白色);
  • 圆锥的半径对应饱和度 S(从中心到边缘:0→255,灰度→纯色);
  • 圆锥的圆周角度对应色调 H(0°→360°,红→黄→绿→蓝→紫→红)。
    在这里插入图片描述
    在这里插入图片描述

二、关键操作:掩膜(Mask)

掩膜是颜色识别与替换的 “筛选工具”,通过二值化图像实现对目标区域的选择性操作。

2.1 掩膜的定义与特点

  • 定义:与原始图像尺寸完全相同的二值化图像(仅含 0 和 255 两个像素值)。

  • 核心特点:

    • 白色区域(像素值 = 255):“保留区”—— 后续操作仅作用于该区域;
    • 黑色区域(像素值 = 0):“遮挡区”—— 后续操作忽略该区域。

2.2 掩膜的核心作用

  1. 选择性提取:仅保留图像中符合条件的区域(如 “只提取黄色区域”);
  2. 选择性修改:仅修改图像中符合条件的区域(如 “只把红色区域换成蓝色”);
  3. 噪声过滤:结合形态学操作(如开运算),去除掩膜中的细小杂点。

三、实战 1:图像颜色识别(提取目标颜色)

通过 “HSV 转换→生成掩膜→位与运算” 三步,从图像中精准提取指定颜色(以提取黄色为例)。

# 图像颜色识别:提取指定颜色(黄色)
import cv2
import numpy as np# 步骤1:图像读取与预处理
# cv2.imread:读取图像(OpenCV默认读取为BGR格式,非RGB)
image_np = cv2.imread('./color.png')
# cv2.resize:调整图像大小(700x700),方便观察(非必需,按需调整)
image_np = cv2.resize(image_np, (700, 700))# 步骤2:将BGR图像转换为HSV图像(颜色识别的关键一步)
# cv2.COLOR_BGR2HSV:OpenCV专用的BGR→HSV转换标识(必须用这个,不能用COLOR_RGB2HSV)
hsv_image_np = cv2.cvtColor(image_np, cv2.COLOR_BGR2HSV)# 步骤3:定义目标颜色(黄色)的HSV范围,生成掩膜
# lowerb:HSV范围下限(H=26, S=43, V=46)——黄色的最低阈值
lowerb = np.array([26, 43, 46])
# upperb:HSV范围上限(H=34, S=255, V=255)——黄色的最高阈值
upperb = np.array([34, 255, 255])
# cv2.inRange:生成掩膜——HSV值在[lowerb, upperb]内的像素设为255(白),否则设为0(黑)
mask_image_np = cv2.inRange(hsv_image_np, lowerb, upperb)# 步骤4:位与运算——用掩膜提取目标颜色
# cv2.bitwise_and:仅保留掩膜中白色区域(255)的原图像素,其他区域设为0(黑)
color_image_np = cv2.bitwise_and(image_np, image_np, mask=mask_image_np)# 步骤5:显示结果
cv2.imshow("掩膜(Mask)", mask_image_np)    # 显示掩膜
cv2.imshow("提取的黄色区域", color_image_np)  # 显示提取的目标颜色
cv2.waitKey(0)  # 等待任意按键关闭窗口(0表示无限等待)
cv2.destroyAllWindows()  # 释放窗口资源

3.2 关键步骤解析

(1)图像读取:注意 BGR 格式
  • OpenCV 的cv2.imread()默认将图像读取为BGR 格式(红和蓝通道颠倒),后续转 HSV 必须用cv2.COLOR_BGR2HSV,而非COLOR_RGB2HSV(否则颜色转换错误)。
(2)HSV 范围确定:核心难点
  • 目标颜色的 HSV 范围(lowerbupperb)需根据实际需求调整,可通过 “颜色拾取工具” 或 “调试法” 确定(例:红色的 HSV 范围可能是[0,43,46]~[10,255,255])。
  • 参考常用颜色的 OpenCV-HSV 范围:
    红色:[0,43,46]~[10,255,255] | 绿色:[35,43,46]~[77,255,255] | 蓝色:[100,43,46]~[124,255,255]
(3)位与运算:掩膜的应用
  • cv2.bitwise_and(src1, src2, mask):当src1=src2=原图时,掩膜mask会筛选出原图中需保留的区域 —— 仅mask=255的位置保留src1&src2(即原图像素),mask=0的位置结果为 0(黑色)。

四、实战 2:图片颜色替换(修改目标颜色)

在颜色识别的基础上,增加 “掩膜优化(开运算去噪)” 和 “颜色替换” 步骤,将指定颜色修改为目标颜色(以 “红色→蓝色” 为例)。

4.1 完整代码

# 图片颜色替换:将红色区域替换为蓝色
import cv2
import numpy as np# 步骤1:图像读取与初始显示
image_np = cv2.imread('./color.png')
cv2.imshow("原始图像", image_np)  # 显示原图# 步骤2:将BGR图像转换为HSV图像(减少光照干扰,便于颜色定位)
image_hsv = cv2.cvtColor(image_np, cv2.COLOR_BGR2HSV)# 步骤3:制作目标颜色(红色)的掩膜,并优化(开运算去噪)
# 3.1 定义红色的HSV范围
color_lower = np.array([0, 43, 46])    # 红色HSV下限
color_high = np.array([10, 255, 255])  # 红色HSV上限
# 3.2 生成初始掩膜
image_mask = cv2.inRange(image_hsv, color_lower, color_high)
# 3.3 开运算:先腐蚀再膨胀,去除掩膜中的细小白色噪点(避免替换时误改杂点)
# 构建3x3矩形核(结构化元素)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
# 执行开运算(cv2.MORPH_OPEN表示开运算)
image_mask_open = cv2.morphologyEx(image_mask, cv2.MORPH_OPEN, kernel)# 步骤4:执行颜色替换(核心步骤)
# 方式1:数组索引(高效,推荐)——直接将掩膜白色区域的像素设为蓝色(BGR格式:(255,0,0))
image_np[image_mask_open == 255] = (255, 0, 0)  # 注意:OpenCV中蓝色是(255,0,0),非(0,0,255)# 方式2:循环遍历(低效,不推荐)——适合理解原理,大图像耗时
# for i in range(image_mask_open.shape[0]):  # 遍历行(高度)
#     for j in range(image_mask_open.shape[1]):  # 遍历列(宽度)
#         if image_mask_open[i, j] == 255:  # 若为掩膜白色区域
#             image_np[i, j] = (255, 0, 0)  # 替换为蓝色# 步骤5:显示结果
cv2.imshow("优化后的掩膜", image_mask_open)  # 显示去噪后的掩膜
cv2.imshow("颜色替换后图像", image_np)      # 显示替换结果
cv2.waitKey(0)
cv2.destroyAllWindows()

4.2 关键步骤解析

(1)掩膜优化:开运算的作用
  • 初始掩膜(image_mask)可能包含细小白色噪点(如图像中的灰尘、光斑),若直接用于替换,会导致 “误改无关区域”。
  • 开运算(cv2.MORPH_OPEN):先腐蚀(消除小噪点)再膨胀(恢复目标区域大小),既能去除噪点,又不影响目标区域的整体形状。
(2)颜色替换:注意 BGR 通道顺序
  • OpenCV 中颜色用BGR 格式表示,而非 RGB:
    蓝色 → (255, 0, 0)(B=255,G=0,R=0);
    红色 → (0, 0, 255)(B=0,G=0,R=255);
    绿色 → (0, 255, 0)(B=0,G=255,R=0)。
  • 数组索引方式(image_np[image_mask_open == 255] = (255,0,0))比循环遍历高效 10~100 倍,尤其适合大图像。

五、关键总结与注意事项

5.1 常见问题与解决方案

  1. 颜色提取错误
    • 原因:HSV 范围设置不当,或用了COLOR_RGB2HSV(而非COLOR_BGR2HSV)。
    • 解决:调整lowerbupperb(参考常用颜色范围),确保转换标识正确。
  2. 替换后有杂色
    • 原因:掩膜含细小噪点,导致误替换。
    • 解决:增加开运算(cv2.MORPH_OPEN),或调大核尺寸(如(5,5))。
  3. 颜色替换后显示异常
    • 原因:混淆 BGR 和 RGB 格式(如将蓝色设为(0,0,255))。
    • 解决:牢记 OpenCV 用 BGR,蓝色是(255,0,0),红色是(0,0,255)

5.2 操作流程梳理

任务核心流程关键差异
颜色识别读取图像→BGR 转 HSV→生成掩膜→位与提取→显示无需形态学操作(简单场景),需位与运算
颜色替换读取图像→BGR 转 HSV→掩膜制作→开运算去噪→颜色替换→显示需掩膜优化(开运算),需数组索引替换
http://www.dtcms.com/a/360342.html

相关文章:

  • 【开题答辩全过程】以 基于SpringBoot的流浪猫狗领养系统为例,包含答辩的问题和答案
  • C语言中如何使用NULL
  • 【Linux】系统部分——ELF文件格式与动态库加载
  • Asible管理变量和事实和实施任务控制
  • 科学研究系统性思维的方法体系:研究设计相关模版
  • 【Unity3D实例-功能-切换武器】切换武器(一)动画配置
  • IAR 用JLINK 下载代码设置步骤
  • FLEXPART 拉格朗日粒子扩散模式建模技术及研究大气污染物源-汇关系中的实践
  • 订餐后台管理系统-day06菜品分类模块
  • 工业软件领域SAAS模式为何不能得到普及?
  • 上海交大具身导航中的感知智能、社会智能和运动智能全面综述
  • 网络端口与服务对应表 - 白帽子安全参考指南
  • Android开发-设计规范
  • 安装proteus,并实现stm32仿真
  • 当 AI 开始 “筛选” 信息:算法偏见会加剧认知鸿沟吗?如何构建公平的 AI 生态?
  • 深入解析 Oracle 并发与锁机制:高并发环境下的数据一致性之道
  • Log File Sync等待事件分析
  • linux日志同步
  • strtok()字符串分隔函数
  • OpenStack 01:介绍
  • Batch Normalization 批归一化
  • 实现自己的AI视频监控系统-第三章-信息的推送与共享1
  • AI辅助编程日记和chat历史开源Series 1:VSCode + GitHub Copilot 自动下载及安装软件
  • 大模型训练全流程
  • 在deepseek v3.1上加自信度参数的外挂方案,plugin,朝向一步一步
  • [光学原理与应用-361]:ZEMAX - 分析 - 像差分析
  • Win32学习笔记 | recv函数
  • MVC架构模式
  • XXL-JOB任务执行The access token is wrong问题分析解决及原理源码解析
  • 【Linux】linux进程 vs 线程