开发车载环视(AVM)系统时,摄像头画面直接拿过来是没法用的。雨天的噪点、夜间的椒盐干扰、广角镜头带来的桶形畸变——这些不先处理好,后面的拼接和检测都是空谈。这篇笔记整理一下滤波与畸变矫正的工程实践,附带一些 C++ 里值得注意的细节。
图像滤波与降噪
车载场景下最常见的噪声有两种:高斯噪声(画面发灰,像蒙了层雾)和椒盐噪声(随机黑白点,夜间灯光干扰时尤其明显)。滤波的核心要求是:去噪的同时别把车道线、障碍物边缘给模糊了。
高斯滤波是最基础的选择。计算量小,平滑效果自然,晴雨天都能用。OpenCV 里直接调 GaussianBlur,一般用 3×3 核,σ 取 1.5 左右就好。车速快、帧率高的时候,高斯是实时的保证。
中值滤波专治椒盐噪声。它把像素邻域排序后取中值,能有效抹掉孤立噪点。但中值滤波的耗时比高斯高不少,所以通常只在夜间或检测到大量椒盐时才切换过去。
双边滤波既能降噪又能保边缘,听起来很完美,但计算量实在太大。只在一些高端车、算力充裕的项目里用,或者只对关键区域(比如车位线周围)局部使一下。
在代码里,滤波函数的参数用 Mat& 引用传递,这是车载实时性的硬要求。OpenCV 的 Mat 对象内部存着几 MB 的图像数据,值传递会触发深拷贝,帧率直接崩掉。引用传递只传指针,没有拷贝开销。另外,为了方便调用,我在实现文件里用了 using namespace cv;,省得到处写 cv:: 前缀。头文件里别这样干,污染命名空间。
实际工程中,路况多变,需要根据光照和环境动态切换滤波算法。策略模式很适合这个场景:定义一个 FilterStrategy 接口,高斯、中值各自实现,再用一个上下文类按条件调度。新增算法(比如导向滤波)时完全不用改老代码。下面是一个精简过的实现:
#include <opencv2/opencv.hpp>
using namespace cv;
class FilterStrategy {
public:
virtual ~FilterStrategy() {}
virtual Mat filter(Mat& src) = 0;
};
class GaussianFilter : public FilterStrategy {
public:
Mat filter(Mat& src) override {
Mat dst;
GaussianBlur(src, dst, Size(3, 3), 1.5);
return dst;
}
};
class MedianFilter : FilterStrategy {
:
{
Mat dst;
(src, dst, );
dst;
}
};
{
:
FilterStrategy* strategy;
:
}
~() { strategy; }
{ strategy->(src); }
};
{
FilterStrategy* strategy = ;
(road_condition == ) {
strategy = ();
} (road_condition == ) {
strategy = ();
} {
strategy = ();
}
;
ctx.(src);
}

