4、图像预处理实战:色彩空间转换(BGR2GRAY/HSV)、高斯滤波与中值滤波、直方图均衡化
图像预处理,说白了就是给原始图像“洗个澡”,让它更适合后续的算法处理。我在做目标跟踪项目时,经常遇到光线突变、噪声干扰的情况,这时候预处理做得好不好,直接决定了跟踪的成败。
今天咱们就聊聊三个最常用的预处理手段:色彩空间转换、滤波去噪、直方图均衡化。嗯,这些都是我每天都会用到的“老伙计”。
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.3 直方图均衡化
直方图均衡化,说白了就是把图像的灰度分布“拉平”。如果图像太暗或太亮,细节都藏在暗处或亮处,均衡化后就能看清了。
我曾经在黄昏时分做车辆跟踪,画面整体偏暗,车身的轮廓根本看不清。用了直方图均衡化后,对比度一下子提上来了,跟踪框终于能锁住车了。
# 全局直方图均衡化(仅适用于灰度图)
equ = cv2.equalizeHist(gray)
# 自适应直方图均衡化(CLAHE,推荐)
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
clahe_result = clahe.apply(gray)
全局均衡化会把整个图像的对比度拉平,容易放大噪声。CLAHE 在局部区域做均衡化,效果更自然。我在实际项目中几乎只用 CLAHE。
CLAHE 有两个参数:clipLimit 控制对比度限制(默认 2.0),tileGridSize 控制局部块大小(默认 8×8)。数值越大,增强效果越明显,但噪声也会被放大。嗯,这个需要根据实际场景调参。
4.4 实战组合拳
在实际的目标跟踪流程中,我通常这样组合预处理:
- 第一步: 读图,转 HSV(如果需要颜色跟踪)或转灰度
- 第二步: 中值滤波去噪(核大小 3×3 或 5×5)
- 第三步: CLAHE 增强对比度
- 第四步: 送入跟踪算法(如 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
好了,图像预处理这块就聊到这儿。这些方法看着简单,但用好了能解决很多实际问题。下次遇到跟踪失败的情况,不妨先检查一下预处理环节——八成是这里出了问题。