计算机视觉处理(OpenCV基础教学(六):基于HSV颜色空间的目标颜色识别)

OpenCV基础教学(六):基于HSV颜色空间的目标颜色识别

本文将深入讲解HSV颜色空间的原理,以及如何利用HSV进行目标颜色识别和提取,通过Python+OpenCV代码实战演示完整的颜色识别流程。


总流程图:

一、颜色空间概述

RGB颜色模型的局限性

在之前的文章中,我们一直使用RGB(或BGR)颜色模型。虽然RGB模型直观且易于理解,但它存在一些局限性

  1. 不符合人类感知:人类感知颜色是基于色调、饱和度和亮度,而不是红绿蓝三原色的强度
  2. 调整困难:在RGB空间调整颜色需要同时修改三个通道
  3. 光照敏感:RGB值对光照变化非常敏感
HSV颜色空间的特点与优势

HSV(Hue-Saturation-Value)颜色空间更符合人类对颜色的感知方式:

  • Hue(色调):颜色的种类(红、绿、蓝等)
  • Saturation(饱和度):颜色的纯度或鲜艳程度
  • Value(明度):颜色的明亮程度

HSV的优势

  1. 直观的颜色调整
  2. 对光照变化有一定鲁棒性
  3. 便于颜色分割和识别

二、HSV颜色空间详解

色调(Hue)的理解与应用

色调表示颜色的种类,使用角度表示(0°-360°):

复制代码
红色:0°(或360°)
黄色:60°
绿色:120°
青色:180°
蓝色:240°
紫色:300°

在OpenCV中,Hue的取值范围被压缩到0-180(为了适应8位无符号整数)。

饱和度(Saturation)的作用

饱和度表示颜色的纯度:

  • 0%:灰色,无色彩
  • 100%:纯色,非常鲜艳

饱和度越高,颜色越鲜艳;饱和度越低,颜色越接近灰色。

明度(Value)的影响

明度表示颜色的明亮程度:

  • 0%:纯黑色
  • 100%:最亮的颜色

明度与光照强度直接相关,调整明度可以模拟不同光照条件。

HSV与RGB的对比
特性 RGB颜色空间 HSV颜色空间
颜色表示 红、绿、蓝三通道强度 色调、饱和度、明度
人类感知 不符合 符合
光照影响 敏感 相对不敏感
颜色调整 复杂 简单直观

三、目标颜色识别原理

HSV颜色范围的设定

在HSV空间中,每种颜色都有一个特定的范围。识别特定颜色的关键是找到该颜色在HSV空间中的最小值和最大值

HSV范围设定原则

  1. Hue(色调):确定主要颜色
  2. Saturation(饱和度):排除灰色和接近灰色的区域
  3. Value(明度):排除过暗或过亮的区域
常见颜色的HSV范围(OpenCV格式)

在OpenCV中,HSV的范围如下:

  • Hue: 0-179
  • Saturation: 0-255
  • Value: 0-255

以下是常见颜色的HSV范围参考:

python 复制代码
# 常见颜色的HSV范围(OpenCV格式)
HSV_RANGES = {
    '红色': [
        ([0, 43, 46], [10, 255, 255]),     # 红色范围1
        ([156, 43, 46], [180, 255, 255])   # 红色范围2(跨越0°)
    ],
    '黄色': [([26, 43, 46], [34, 255, 255])],
    '绿色': [([35, 43, 46], [77, 255, 255])],
    '青色': [([78, 43, 46], [99, 255, 255])],
    '蓝色': [([100, 43, 46], [124, 255, 255])],
    '紫色': [([125, 43, 46], [155, 255, 255])],
    '黑色': [([0, 0, 0], [180, 255, 46])],
    '白色': [([0, 0, 221], [180, 30, 255])],
    '灰色': [([0, 0, 46], [180, 43, 220])]
}

注意:红色在HSV中需要两个范围,因为它跨越了0°(360°)边界。

掩膜(Mask)的创建与应用

掩膜是一个二进制图像,其中白色(255)表示感兴趣区域,黑色(0)表示背景区域。

掩膜的作用

  1. 隔离特定颜色区域
  2. 减少计算量
  3. 便于后续处理
按位操作提取目标区域

使用按位与操作,将原始图像与掩膜结合,只保留掩膜中白色区域对应的像素:

python 复制代码
# 按位与操作:提取目标颜色区域
result = cv2.bitwise_and(src1, src2, mask=mask)

四、代码实战:目标颜色识别

基础实现代码
python 复制代码
import cv2
import numpy as np
import matplotlib.pyplot as plt

def color_detection(image_path, target_color='yellow', show_steps=True):
    """
    检测图像中的特定颜色
    Args:
        image_path: 图像路径
        target_color: 目标颜色
        show_steps: 是否显示处理步骤
    Returns:
        处理结果
    """
    # 1. 读取图像
    image_bgr = cv2.imread(image_path)
    image_bgr = cv2.resize(image_bgr, (700, 700))
    image_rgb = cv2.cvtColor(image_bgr, cv2.COLOR_BGR2RGB)
    
    # 2. 转换为HSV颜色空间
    image_hsv = cv2.cvtColor(image_bgr, cv2.COLOR_BGR2HSV)
    
    # 3. 定义目标颜色的HSV范围
    if target_color == 'yellow':
        # 黄色范围
        lower = np.array([26, 43, 46])
        upper = np.array([34, 255, 255])
    elif target_color == 'red':
        # 红色范围(需要两个范围)
        lower1 = np.array([0, 43, 46])
        upper1 = np.array([10, 255, 255])
        lower2 = np.array([156, 43, 46])
        upper2 = np.array([180, 255, 255])
    elif target_color == 'blue':
        # 蓝色范围
        lower = np.array([100, 43, 46])
        upper = np.array([124, 255, 255])
    else:
        # 默认使用黄色
        lower = np.array([26, 43, 46])
        upper = np.array([34, 255, 255])
    
    # 4. 创建掩膜
    if target_color == 'red':
        # 红色需要两个掩膜
        mask1 = cv2.inRange(image_hsv, lower1, upper1)
        mask2 = cv2.inRange(image_hsv, lower2, upper2)
        mask = cv2.bitwise_or(mask1, mask2)
    else:
        mask = cv2.inRange(image_hsv, lower, upper)
    
    # 5. 应用掩膜提取目标颜色
    result = cv2.bitwise_and(image_bgr, image_bgr, mask=mask)
    result_rgb = cv2.cvtColor(result, cv2.COLOR_BGR2RGB)
    
    # 6. 可视化结果
    if show_steps:
        plt.figure(figsize=(15, 10))
        
        plt.subplot(2, 3, 1)
        plt.imshow(image_rgb)
        plt.title('Original Image')
        plt.axis('off')
        
        plt.subplot(2, 3, 2)
        # 显示HSV的H通道
        h_channel = image_hsv[:, :, 0]
        plt.imshow(h_channel, cmap='hsv')
        plt.title('Hue Channel')
        plt.colorbar()
        plt.axis('off')
        
        plt.subplot(2, 3, 3)
        # 显示HSV的S通道
        s_channel = image_hsv[:, :, 1]
        plt.imshow(s_channel, cmap='gray')
        plt.title('Saturation Channel')
        plt.colorbar()
        plt.axis('off')
        
        plt.subplot(2, 3, 4)
        # 显示HSV的V通道
        v_channel = image_hsv[:, :, 2]
        plt.imshow(v_channel, cmap='gray')
        plt.title('Value Channel')
        plt.colorbar()
        plt.axis('off')
        
        plt.subplot(2, 3, 5)
        plt.imshow(mask, cmap='gray')
        plt.title(f'Mask for {target_color}')
        plt.axis('off')
        
        plt.subplot(2, 3, 6)
        plt.imshow(result_rgb)
        plt.title(f'Detected {target_color} Region')
        plt.axis('off')
        
        plt.tight_layout()
        plt.show()
    
    return mask, result_rgb

# 使用示例
mask, result = color_detection('./color.png', target_color='yellow')
多颜色同时识别
python 复制代码
def detect_multiple_colors(image_path, colors=['red', 'green', 'blue']):
    """
    同时检测多种颜色
    """
    # 读取并预处理图像
    image_bgr = cv2.imread(image_path)
    image_bgr = cv2.resize(image_bgr, (700, 700))
    image_hsv = cv2.cvtColor(image_bgr, cv2.COLOR_BGR2HSV)
    
    # 定义颜色范围
    color_ranges = {
        'red': [([0, 43, 46], [10, 255, 255]), 
                ([156, 43, 46], [180, 255, 255])],
        'yellow': [([26, 43, 46], [34, 255, 255])],
        'green': [([35, 43, 46], [77, 255, 255])],
        'blue': [([100, 43, 46], [124, 255, 255])]
    }
    
    # 为每种颜色创建掩膜
    masks = {}
    for color in colors:
        if color in color_ranges:
            color_masks = []
            for lower, upper in color_ranges[color]:
                lower_np = np.array(lower)
                upper_np = np.array(upper)
                color_masks.append(cv2.inRange(image_hsv, lower_np, upper_np))
            
            # 合并多个范围(如红色)
            if len(color_masks) > 1:
                combined_mask = cv2.bitwise_or(color_masks[0], color_masks[1])
                for i in range(2, len(color_masks)):
                    combined_mask = cv2.bitwise_or(combined_mask, color_masks[i])
                masks[color] = combined_mask
            else:
                masks[color] = color_masks[0]
    
    # 可视化结果
    plt.figure(figsize=(15, 10))
    
    # 显示原图
    plt.subplot(2, 3, 1)
    plt.imshow(cv2.cvtColor(image_bgr, cv2.COLOR_BGR2RGB))
    plt.title('Original Image')
    plt.axis('off')
    
    # 显示每种颜色的掩膜
    for idx, (color, mask) in enumerate(masks.items(), 2):
        plt.subplot(2, 3, idx)
        plt.imshow(mask, cmap='gray')
        plt.title(f'{color.capitalize()} Mask')
        plt.axis('off')
    
    # 显示所有颜色合并的结果
    plt.subplot(2, 3, 6)
    combined_result = np.zeros_like(image_bgr)
    color_map = {
        'red': (0, 0, 255),      # BGR格式
        'green': (0, 255, 0),
        'blue': (255, 0, 0),
        'yellow': (0, 255, 255)
    }
    
    for color, mask in masks.items():
        if color in color_map:
            color_mask = np.zeros_like(image_bgr)
            color_mask[:, :] = color_map[color]
            color_region = cv2.bitwise_and(color_mask, color_mask, mask=mask)
            combined_result = cv2.add(combined_result, color_region)
    
    plt.imshow(cv2.cvtColor(combined_result, cv2.COLOR_BGR2RGB))
    plt.title('All Detected Colors')
    plt.axis('off')
    
    plt.tight_layout()
    plt.show()
    
    return masks

# 使用示例
masks = detect_multiple_colors('./color.png', colors=['red', 'green', 'blue', 'yellow'])

五 、总结与应用场景

颜色识别的实际应用
  1. 工业分拣:识别和分拣不同颜色的产品
  2. 交通标志识别:识别红绿灯、交通标志的颜色
  3. 医学图像分析:识别病理图像中的特定颜色区域
  4. 机器人视觉:引导机器人识别和抓取特定颜色的物体
  5. 游戏开发:颜色追踪和交互
  6. 农业应用:识别成熟水果的颜色
HSV颜色识别的优缺点

优点

  1. 对光照变化有一定鲁棒性
  2. 颜色分离效果好
  3. 计算相对简单
  4. 实时性好

缺点

  1. 需要预先知道目标颜色的HSV范围
  2. 对颜色渐变处理不够好
  3. 在极端光照条件下可能失效
进一步学习方向
  1. 机器学习方法:使用分类器进行颜色识别
  2. 深度学习:使用卷积神经网络进行像素级颜色分类
  3. 颜色恒常性:在不同光照条件下保持颜色识别的一致性
  4. 多光谱成像:使用超出可见光范围的光谱信息
实践建议
  1. 实验不同的HSV范围:使用交互式工具找到最佳范围
  2. 结合形态学操作:优化识别结果
  3. 考虑光照条件:在不同光照下测试算法
  4. 使用多个颜色模型:结合RGB、HSV、LAB等模型提高鲁棒性

📌 下期预告

下一期我们将学习图像的特征检测与描述(SIFT、SURF、ORB等),掌握如何在图像中寻找和描述关键特征点。


扩展思考

  1. 如何处理颜色渐变区域?
  2. 如何在没有先验知识的情况下识别未知颜色?
  3. 如何提高颜色识别在复杂背景下的鲁棒性?

欢迎在评论区分享你的实践经验和遇到的问题!


如果觉得本文有帮助,欢迎点赞、收藏、关注!
你的支持是我持续创作的最大动力!

相关推荐
2501_946233892 小时前
Flutter与OpenHarmony我的作品页面实现
android·javascript·flutter
holeer2 小时前
React UI组件封装实战——以经典项目「个人博客」与「仿手机QQ」为例
前端·javascript·react.js·ui·前端框架·软件工程
chilavert3182 小时前
技术演进中的开发沉思-277 AJax :Calendar
前端·javascript·microsoft·ajax
chilavert3182 小时前
技术演进中的开发沉思-276 AJax : Menu
javascript·ajax·交互
白日做梦Q2 小时前
U-Net及其变体:医学图像分割的里程碑
人工智能·深度学习·神经网络·计算机视觉
week_泽2 小时前
OpenCV图像拼接实践笔记(第一部分)
人工智能·笔记·opencv
朱穆朗2 小时前
electron升级到33.0.x版本后,devtools字体的修改方法
前端·javascript·electron
2501_944452233 小时前
智能洞察 Cordova 与 OpenHarmony 混合开发实战
javascript
Irene19913 小时前
insertAdjacentHTML() 详解
javascript·dom