CV 概览与数字图像基础:RGB/HSV 颜色空间、像素矩阵与位深度

引言

计算机视觉(Computer Vision, CV)是人工智能三大感知分支之一,核心任务是让计算机“看明白”世界——从图像/视频中提取结构化信息,完成认知层面的任务。

在啃下目标检测、图像分割、Transformer大模型这些“硬骨头”前,先搞懂「图像到底是什么」「计算机怎么存图像」「怎么把颜色给计算机说清楚」是100%必要的。本文用大白话+OpenCV代码,一次性讲透这三个核心底层。

📂 所属阶段:第一阶段 — 图像处理基石(传统 CV 篇)
🔗 相关章节:OpenCV 快速入门 · 图像增强与滤波


1. 什么是计算机视觉?

1.1 CV 的三个处理层次

抽象程度/处理复杂度,CV 任务可分为三层,层层递进:

层次输入输出核心功能代表技术
低层视觉图像 → 图像/低维信号像素级直接操作,不损失空间结构滤波、去噪、边缘/角点检测
中层视觉图像 → 结构化/半结构化信息将像素转化为“有意义的物体部件”特征匹配、目标检测、图像分割
高层视觉图像 → 语义/认知结果赋予图像“人类能理解的含义”场景理解、行为识别、图像描述

1.2 高频应用场景(身边的CV)

领域典型应用
移动互联网美颜滤镜、扫码支付、人脸解锁
自动驾驶车道线检测、行人检测、交通标志识别
工业质检缺陷检测、零件计数、尺寸测量
医疗健康肿瘤影像分割、眼底病变筛查

2. 数字图像的本质:像素矩阵

2.1 从“照片”到“矩阵”

现实世界的照片是连续的光信号,但计算机只能处理离散的数字。数码相机/扫描仪会做两步操作把光变成矩阵:

  1. 采样:把照片分成 H(高)× W(宽)个小格子——每个格子叫像素(Pixel)
  2. 量化:给每个像素的亮度/颜色分配一个数值范围

灰度图像 vs 彩色图像

图像类型存储矩阵维度每个元素含义常用值域(8位)
灰度H × W像素的灰度值0(黑)~255(白)
彩色RGBH × W × 3R/G/B三个通道的亮度每个通道0~255
import numpy as np
import cv2

# 1. 创建100×100的纯黑灰度图(全0)
black_gray = np.zeros((100, 100), dtype=np.uint8)
# 创建100×100的纯白灰度图(全255)
white_gray = np.full((100, 100), 255, dtype=np.uint8)

# 2. 创建100×100×3的纯黑RGB图(注意:OpenCV默认BGR,但这里先按概念说RGB)
black_rgb = np.zeros((100, 100, 3), dtype=np.uint8)
# 创建100×100×3的红色图(后续会讲OpenCV的BGR顺序!)
red_rgb = np.zeros((100, 100, 3), dtype=np.uint8)
red_rgb[:, :, 0] = 255  # 假设最后一维索引0是R

print(f"灰度图维度: {black_gray.shape}")
print(f"彩色图维度: {black_rgb.shape}")

2.2 位深度:决定图像的“精细度”

位深度(Bit Depth)指每个像素通道存储的二进制位数,位数越多,能表示的颜色/灰度值越丰富:

  • 8位:最常用!每个通道0~255(2⁸),总约1678万种RGB颜色
  • 16位:医学/天文影像专用,每个通道0~65535(2¹⁶)
  • 32位浮点数:深度学习/高精度处理用,亮度归一化到0.0~1.0
import numpy as np

# 生成3种位深度的随机图
img_8bit = np.random.randint(0, 256, (50, 50), dtype=np.uint8)
img_16bit = np.random.randint(0, 65536, (50, 50), dtype=np.uint16)
img_32float = np.random.rand(50, 50).astype(np.float32)

print(f"8位图的数据类型: {img_8bit.dtype}, 最小值: {img_8bit.min()}, 最大值: {img_8bit.max()}")
print(f"16位图的数据类型: {img_16bit.dtype}, 最小值: {img_16bit.min()}, 最大值: {img_16bit.max()}")
print(f"32位浮点图的数据类型: {img_32float.dtype}, 最小值: {img_32float.min():.4f}, 最大值: {img_32float.max():.4f}")

3. 两种核心颜色空间

3.1 RGB:计算机最“舒服”的格式

RGB(Red, Green, Blue)基于光的加色混合——红、绿、蓝三束光叠加形成各种颜色,是显示器/图像存储的原生格式。

常见RGB/BGR值(OpenCV用BGR!)

颜色标准RGBOpenCV BGR
(255,0,0)(0,0,255)
绿(0,255,0)(0,255,0)
(0,0,255)(255,0,0)
(255,255,255)同上
灰(中)(128,128,128)同上

OpenCV 颜色空间转换的关键坑

OpenCV 早期适配硬件时选了 BGR 顺序,至今保留。和 Matplotlib/Pillow 一起用必须转换

import cv2
import numpy as np

# 假设读入一张真实图片
img_bgr = cv2.imread("test.jpg")

# 核心转换函数
img_rgb = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB)  # 用于matplotlib显示
img_gray = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2GRAY)  # 转灰度
img_hsv = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2HSV)  # 转HSV(下一节的重点)

# 简单验证:手动切片反转通道
img_rgb_manual = img_bgr[:, :, ::-1]  # 第三个维度(通道)倒序
print(np.array_equal(img_rgb, img_rgb_manual))  # 应该输出True

3.2 HSV:人类最“直观”的格式

HSV(Hue, Saturation, Value)将颜色属性分离——更符合我们说“红色鲜艳一点、暗一点”的逻辑,是颜色分割/检测的首选

三个分量的含义(OpenCV专属值域!)

分量含义OpenCV值域
Hue(色调)基本颜色(红→黄→绿→青→蓝→紫→红)0~179(压缩了360°的标准色轮)
Saturation(饱和度)颜色的“纯度/鲜艳度”,0是灰色,255是纯色0~255
Value(亮度)颜色的“明暗程度”,0是黑色,255是最亮0~255

实战:用HSV做红色物体检测

红色有特殊处理——在标准色轮上从350°到10°,对应OpenCV的010和170179两个区间:

import cv2
import numpy as np

def detect_red(image_path):
    # 1. 读入并转HSV
    img_bgr = cv2.imread(image_path)
    if img_bgr is None:
        print("请输入正确的图片路径!")
        return None, None
    img_hsv = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2HSV)

    # 2. 定义红色的HSV两个区间
    lower1 = np.array([0, 100, 100])
    upper1 = np.array([10, 255, 255])
    lower2 = np.array([170, 100, 100])
    upper2 = np.array([180, 255, 255])

    # 3. 生成掩码(mask):红色区域为白色(255),其他为黑色(0)
    mask1 = cv2.inRange(img_hsv, lower1, upper1)
    mask2 = cv2.inRange(img_hsv, lower2, upper2)
    mask = cv2.bitwise_or(mask1, mask2)  # 合并两个区间

    # 4. 用掩码提取红色区域
    result = cv2.bitwise_and(img_bgr, img_bgr, mask=mask)

    return img_bgr, mask, result

# (可选)本地运行时取消注释
# original, mask, res = detect_red("red_flower.jpg")
# cv2.imshow("原图", original)
# cv2.imshow("红色掩码", mask)
# cv2.imshow("红色检测结果", res)
# cv2.waitKey(0)
# cv2.destroyAllWindows()

4. 实战项目:快速分析一张图像的信息

整合前面的知识点,写一个函数打印图像的核心属性:

import cv2

def analyze_image(image_path):
    img = cv2.imread(image_path)
    if img is None:
        print("❌ 图片读取失败,请检查路径!")
        return

    # 1. 基础属性
    h, w = img.shape[:2]
    channels = img.shape[2] if len(img.shape) == 3 else 1
    dtype = img.dtype

    print(f"✅ 图像基本信息:")
    print(f"   - 尺寸: {w} × {h}")
    print(f"   - 通道数: {channels}")
    print(f"   - 数据类型: {dtype}")
    print(f"   - 总像素数: {w * h:,}")  # 加逗号分隔大数字

    # 2. BGR各通道的统计(仅彩色图)
    if channels == 3:
        print(f"\n✅ BGR通道统计:")
        for idx, name in enumerate(['Blue', 'Green', 'Red']):
            ch = img[:, :, idx]
            print(f"   - {name}: min={ch.min()}, max={ch.max()}, mean={ch.mean():.2f}")

# 本地运行示例
# analyze_image("test.jpg")

5. 总结

核心知识点回顾

  1. 图像本质:连续光→离散像素矩阵(H×W或H×W×3)
  2. 位深度:常用8位(0~255),决定图像精细度
  3. 颜色空间
    • RGB/BGR:计算机原生,硬件友好
    • HSV:人类直观,颜色分离,颜色检测首选
  4. OpenCV坑点:默认BGR,和其他库配合需转换

💡 最后提醒:像素矩阵是CV的一切!所有高级算法(比如CNN)本质上都是在“玩矩阵”——加减乘除、卷积、池化……建议多手动生成小矩阵、修改像素值,建立直观的“矩阵感”!


相关教程