4、图像预处理实战:色彩空间转换(BGR2GRAY/HSV)、高斯滤波与中值滤波、直方图均衡化

图像预处理,说白了就是给原始图像“洗个澡”,让它更适合后续的算法处理。我在做目标跟踪项目时,经常遇到光线突变、噪声干扰的情况,这时候预处理做得好不好,直接决定了跟踪的成败。

今天咱们就聊聊三个最常用的预处理手段:色彩空间转换、滤波去噪、直方图均衡化。嗯,这些都是我每天都会用到的“老伙计”。

图像预处理 色彩空间转换 BGR→GRAY / BGR→HSV 滤波去噪 高斯滤波 / 中值滤波 直方图均衡化 增强对比度 灰度图(单通道) HSV(色调/饱和度/明度) 高斯滤波(线性) 中值滤波(非线性) CLAHE(自适应)

4.1 色彩空间转换:BGR→GRAY 与 BGR→HSV

OpenCV 默认读取的图像是 BGR 格式,不是我们熟悉的 RGB。这一点刚入坑时坑了我好几次。你想想看,用 matplotlib 显示图像时颜色全乱套了,就是因为通道顺序搞反了。

为什么要转灰度?说白了,灰度图只有一个通道,计算量小得多。在目标跟踪中,很多算法(比如光流法、模板匹配)都是在灰度图上跑的。我个人的习惯是:只要不需要颜色信息,一律先转灰度。

核心函数:
cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) — BGR 转灰度
cv2.cvtColor(img, cv2.COLOR_BGR2HSV) — BGR 转 HSV

HSV 色彩空间就更有意思了。H 是色调,S 是饱和度,V 是明度。为什么跟踪时喜欢用 HSV?因为颜色信息集中在 H 通道,不受光照变化影响。我在做行人跟踪时,就靠 H 通道来区分不同颜色的衣服,效果比 BGR 好太多了。

import cv2
import numpy as np

# 读取图像
img = cv2.imread('track_target.jpg')

# 转灰度
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 转HSV
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

# 提取H通道(用于颜色跟踪)
h_channel = hsv[:, :, 0]
小技巧: 做颜色目标跟踪时,先用 cv2.inRange() 在 HSV 空间做阈值分割,比在 BGR 空间稳定得多。比如跟踪红色物体,H 值范围设在 0~10 和 160~180 即可。

4.2 高斯滤波与中值滤波

图像噪声是跟踪的大敌。传感器热噪声、光照闪烁、传输丢包,都会产生噪点。滤波就是把这些“坏点”抹掉。

高斯滤波是线性滤波,它用高斯核做加权平均。说白了,就是中心像素的权重最大,越往边缘权重越小。适合处理高斯噪声(比如传感器噪声)。

中值滤波是非线性的,它取邻域内所有像素的中值。这个对椒盐噪声(黑白点噪声)特别有效。我记得有一次做无人机跟踪,画面里全是白点,用高斯滤波怎么调都没用,换成中值滤波一下就干净了。

# 高斯滤波
gaussian_blur = cv2.GaussianBlur(img, (5, 5), 1.5)

# 中值滤波
median_blur = cv2.medianBlur(img, 5)
滤波类型 核大小 适用噪声 计算速度 边缘保留
高斯滤波 3×3, 5×5, 7×7 高斯噪声 快 一般
中值滤波 3×3, 5×5 椒盐噪声 中等 较好
注意: 核大小必须是奇数。我见过有人写成 (4, 4),结果程序直接报错。另外,核越大图像越模糊,实时跟踪时建议用 3×3 或 5×5,别贪大。

4.3 直方图均衡化

直方图均衡化,说白了就是把图像的灰度分布“拉平”。如果图像太暗或太亮,细节都藏在暗处或亮处,均衡化后就能看清了。

我曾经在黄昏时分做车辆跟踪,画面整体偏暗,车身的轮廓根本看不清。用了直方图均衡化后,对比度一下子提上来了,跟踪框终于能锁住车了。

# 全局直方图均衡化(仅适用于灰度图)
equ = cv2.equalizeHist(gray)

# 自适应直方图均衡化(CLAHE,推荐)
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
clahe_result = clahe.apply(gray)
为什么推荐 CLAHE?
全局均衡化会把整个图像的对比度拉平,容易放大噪声。CLAHE 在局部区域做均衡化,效果更自然。我在实际项目中几乎只用 CLAHE。

CLAHE 有两个参数:clipLimit 控制对比度限制(默认 2.0),tileGridSize 控制局部块大小(默认 8×8)。数值越大,增强效果越明显,但噪声也会被放大。嗯,这个需要根据实际场景调参。

4.4 实战组合拳

在实际的目标跟踪流程中,我通常这样组合预处理:

  1. 第一步: 读图,转 HSV(如果需要颜色跟踪)或转灰度
  2. 第二步: 中值滤波去噪(核大小 3×3 或 5×5)
  3. 第三步: CLAHE 增强对比度
  4. 第四步: 送入跟踪算法(如 KCF、CSRT)
def preprocess_pipeline(img):
    # 转灰度
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    # 中值滤波去噪
    denoised = cv2.medianBlur(gray, 5)
    # CLAHE 增强
    clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
    enhanced = clahe.apply(denoised)
    return enhanced
我的经验: 在嵌入式设备上(比如树莓派、Jetson Nano),滤波和均衡化都很耗时。建议用 3×3 核,CLAHE 的 tileGridSize 用 8×8,别用 16×16,否则帧率会掉得厉害。

好了,图像预处理这块就聊到这儿。这些方法看着简单,但用好了能解决很多实际问题。下次遇到跟踪失败的情况,不妨先检查一下预处理环节——八成是这里出了问题。

可可精品资料库