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 |
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。
2.4 本章知识体系
下面这张图把本章的核心知识点串起来了。你可以看到,从原始图像到可用的追踪输入,中间经历了哪些步骤。
2.5 小结
图像预处理不是花架子,是实打实影响追踪效果的关键步骤。色彩空间转换让你能更好地利用颜色信息,滤波去噪让算法不被噪声干扰,图像金字塔让你在速度和精度之间找到平衡。