2. 图像基础与预处理:色彩空间转换、滤波与金字塔

做运动物体追踪,说白了就是让算法在每一帧里找到目标。但摄像头直接拍出来的原始图像,噪声多、颜色杂、尺寸还大。直接拿它做追踪?我试过,效果惨不忍睹。所以,图像预处理是第一步,也是决定成败的一步。

这一章,我们就把预处理的三板斧讲清楚:色彩空间转换、滤波去噪、图像金字塔与缩放。这些都是我项目里天天用的东西,你掌握了,后面写追踪算法会顺手很多。

2.1 色彩空间转换:RGB、HSV 与 Gray

摄像头拍出来的图,默认是 RGB 格式。但 RGB 并不适合做目标追踪。为什么?因为 RGB 的三个通道(红绿蓝)跟光照强度强相关。你想想看,同一个红色物体,在阳光下和阴影里,RGB 值能差好几倍。这会让追踪算法很头疼。

2.1.1 RGB 转 Gray(灰度图)

灰度图只保留亮度信息,去掉了颜色。好处是数据量变成原来的 1/3,计算更快。很多追踪算法(比如光流法)直接跑在灰度图上。

转换公式很简单:

Gray = 0.299 * R + 0.587 * G + 0.114 * B

OpenCV 里一行搞定:

import cv2
img = cv2.imread('frame.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
我的习惯: 只要不需要颜色信息,我第一件事就是转灰度。省内存、提速度,而且很多特征(如边缘、角点)在灰度图上表现更好。

2.1.2 RGB 转 HSV

HSV 把颜色拆成色调(Hue)、饱和度(Saturation)、明度(Value)。这玩意儿对光照变化不敏感。比如你要追踪一个红色球,不管它是在亮处还是暗处,它的 H 值(色调)基本不变。

我做过一个项目,追踪乒乓球。球是橙色的,在 RGB 空间里阈值怎么调都不准,一换到 HSV,用 H 通道做阈值分割,稳得很。

OpenCV 转换代码:

hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

这里有个坑——OpenCV 的 HSV 范围跟常规不一样:

通道 常规范围 OpenCV 范围
H(色调) 0° - 360° 0 - 179
S(饱和度) 0% - 100% 0 - 255
V(明度) 0% - 100% 0 - 255
我曾经踩过的坑: 用常规的 H 范围(0-360)去设阈值,结果死活分割不出来。后来才发现 OpenCV 的 H 是 0-179。记住,H 值要除以 2。

2.1.3 什么时候用什么?

  • Gray: 追求速度、不需要颜色信息时用。比如边缘检测、光流追踪。
  • HSV: 需要基于颜色做目标分割时用。比如追踪彩色球、交通标志。
  • RGB: 一般只作为原始输入,很少直接用于追踪。

2.2 滤波去噪:高斯滤波与中值滤波

摄像头传感器有热噪声,光线不好时有暗电流噪声。这些噪声会让追踪算法误判。滤波就是把这些毛刺去掉,让图像变平滑。

2.2.1 高斯滤波

高斯滤波用高斯核做加权平均。离中心越近的像素权重越大,越远权重越小。它擅长去除高斯噪声(也就是那种随机分布的噪声)。

核心参数是核大小(ksize)和标准差(sigma)。核越大,图像越模糊。

blur = cv2.GaussianBlur(img, (5, 5), 1.5)

我个人习惯用 (5,5) 核,sigma 设 1.0-1.5。太小了没效果,太大了细节全没了。

2.2.2 中值滤波

中值滤波取邻域内所有像素的中位数。它对椒盐噪声(黑白点噪声)效果极好。因为中位数不受极端值影响,一个白点周围都是黑点,取中值后白点就被去掉了。

median = cv2.medianBlur(img, 5)

核大小必须是奇数。我常用 3 或 5,再大图像会变「油画」风格。

2.2.3 怎么选?

噪声类型 推荐滤波 核大小建议
高斯噪声(随机分布) 高斯滤波 5×5
椒盐噪声(黑白点) 中值滤波 3×3 或 5×5
混合噪声 先中值后高斯 3×3 + 5×5
实战经验: 做运动物体追踪时,我一般先用中值滤波去椒盐噪声,再用高斯滤波平滑。顺序不能反,否则高斯滤波会把椒盐噪声「抹开」,更难去除。

2.3 图像金字塔与缩放

追踪算法里,图像金字塔是个好东西。它把图像按比例缩小,形成多分辨率层级。大尺寸图像细节多,小尺寸图像速度快。两者结合,既能保证精度又能提升速度。

2.3.1 高斯金字塔

高斯金字塔每一层都是上一层经过高斯滤波后下采样得到的。尺寸减半,分辨率降低。

# 下采样
lower = cv2.pyrDown(img)
# 上采样
higher = cv2.pyrUp(lower)

注意:上采样不会恢复丢失的细节,只是把图像放大。

2.3.2 拉普拉斯金字塔

拉普拉斯金字塔存的是高斯金字塔相邻层之间的差异。它保留了高频细节信息。在图像融合、纹理分析里很有用。

# 构建高斯金字塔
gaussian_pyramid = [img]
for i in range(4):
    img = cv2.pyrDown(img)
    gaussian_pyramid.append(img)

# 构建拉普拉斯金字塔
laplacian_pyramid = []
for i in range(4, 0, -1):
    size = (gaussian_pyramid[i-1].shape[1], gaussian_pyramid[i-1].shape[0])
    expanded = cv2.pyrUp(gaussian_pyramid[i], dstsize=size)
    laplacian = cv2.subtract(gaussian_pyramid[i-1], expanded)
    laplacian_pyramid.append(laplacian)

2.3.3 缩放:cv2.resize

有时候不需要金字塔,只是简单缩放。用 cv2.resize 就行。

# 缩小到一半
small = cv2.resize(img, (0, 0), fx=0.5, fy=0.5)
# 放大到两倍
large = cv2.resize(img, (0, 0), fx=2.0, fy=2.0)

插值方法要注意:缩小用 INTER_AREA,放大用 INTER_LINEAR 或 INTER_CUBIC。

我的习惯: 做实时追踪时,我会先建一个 3 层的高斯金字塔。从最顶层(最小尺寸)开始检测目标,找到大致位置后,再到下一层精确定位。这样速度能快 3-5 倍。

2.4 本章知识体系

下面这张图把本章的核心知识点串起来了。你可以看到,从原始图像到可用的追踪输入,中间经历了哪些步骤。

图像预处理知识体系 原始图像 (BGR) 色彩空间转换 滤波去噪 图像金字塔与缩放 RGB → Gray RGB → HSV 其他 (Lab, YUV) 高斯滤波 中值滤波 双边滤波 高斯金字塔 拉普拉斯金字塔 cv2.resize 预处理后的图像 适合追踪算法的输入 💡 核心思路 减少数据量 + 去除噪声 + 多尺度处理

2.5 小结

图像预处理不是花架子,是实打实影响追踪效果的关键步骤。色彩空间转换让你能更好地利用颜色信息,滤波去噪让算法不被噪声干扰,图像金字塔让你在速度和精度之间找到平衡。