4. 图像预处理:图像灰度化、直方图均衡化、高斯滤波、中值滤波、图像增强

各位同学,欢迎来到第四讲。今天咱们聊聊图像预处理。说白了,这就是给机器视觉系统“洗把脸、化个妆”。

我做了这么多年机器视觉,发现一个规律:项目成败,七分在预处理,三分在算法。你想想看,一张脏兮兮、光照不均的图片,再牛的深度学习模型也白搭。所以,这一章的内容,我建议你反复看,最好能形成肌肉记忆。

核心观点:预处理不是可选项,是必选项。它决定了后续所有环节的上限。

4.1 图像灰度化:从彩色到单色

为什么要灰度化?说白了,就是降维。彩色图像有三个通道(R、G、B),信息量太大,处理起来慢。灰度图只有一个通道,计算量直接降到三分之一。

常用的方法有三种:

  • 最大值法:取R、G、B中最大的那个值。效果偏亮,细节容易丢失。
  • 平均值法:取三个通道的平均值。效果柔和,但对比度不够。
  • 加权平均法:按人眼敏感度加权,公式是 Gray = 0.299*R + 0.587*G + 0.114*B。这是工业界最常用的。

我个人习惯用加权平均法。记得有一次做PCB板缺陷检测,客户给的彩色图像偏暗,用平均值法灰度化后,焊点几乎看不清。换成加权平均法,问题立刻解决。嗯,这里要注意:加权系数不是死的,如果图像偏红,可以适当调高R的权重。

// C++ 示例:加权平均灰度化
cv::Mat gray;
cv::cvtColor(src, gray, cv::COLOR_BGR2GRAY);
// 或者手动实现
for (int i = 0; i < src.rows; i++) {
    for (int j = 0; j < src.cols; j++) {
        cv::Vec3b pixel = src.at<cv::Vec3b>(i, j);
        uchar gray_val = 0.299 * pixel[2] + 0.587 * pixel[1] + 0.114 * pixel[0];
        gray.at<uchar>(i, j) = gray_val;
    }
}

4.2 直方图均衡化:让对比度“活”起来

直方图均衡化,说白了就是把图像的灰度分布“拉平”。你想想看,如果一张图大部分像素都集中在暗部,那细节就全丢了。均衡化就是把这些像素“摊开”到整个灰度范围。

我遇到过最典型的案例:一个仓库的监控摄像头,因为逆光,货物标签根本看不清。用了直方图均衡化后,标签上的字清晰可见。效果立竿见影。

小技巧:如果图像整体偏暗或偏亮,先用直方图均衡化。如果只是局部光照不均,可以考虑自适应直方图均衡化(CLAHE),效果更细腻。

// C++ 示例:直方图均衡化
cv::Mat equalized;
cv::equalizeHist(gray, equalized);

4.3 高斯滤波:温柔的降噪

高斯滤波,我习惯叫它“温柔的模糊”。它用高斯核去卷积图像,每个像素的权重由距离中心点的距离决定。离得近,权重高;离得远,权重低。这样既能平滑噪声,又能保留边缘。

为什么不用均值滤波?均值滤波太“粗暴”了,会把边缘也模糊掉。高斯滤波更符合自然规律——你想想看,自然界的光斑、模糊,基本都是高斯分布的。

我曾经在检测手机屏幕划痕时,用了均值滤波,结果划痕被模糊得几乎看不见。换成高斯滤波,划痕清晰保留,噪声也被去掉了。嗯,这里要注意:高斯核的大小和标准差σ要匹配。核越大,σ越大,模糊越强。

// C++ 示例:高斯滤波
cv::Mat gaussian;
cv::GaussianBlur(gray, gaussian, cv::Size(5, 5), 1.5);

4.4 中值滤波:专治“椒盐噪声”

中值滤波,说白了就是“取中间值”。它把窗口内的像素排序,取中间那个值作为输出。这招对付椒盐噪声(黑白点噪声)特别有效。

为什么?因为椒盐噪声的像素值要么特别大(白点),要么特别小(黑点)。排序后,它们会被挤到两端,中间值一定是正常的像素。所以中值滤波能完美去除椒盐噪声,同时保留边缘。

我记得有一次做工业零件检测,图像上全是黑白噪点,用高斯滤波怎么调都不行。换成中值滤波,一次搞定。从此以后,只要看到椒盐噪声,我第一个想到的就是中值滤波。

避坑指南:我曾经在纹理丰富的图像上用了中值滤波,结果纹理被破坏了。中值滤波适合去除孤立噪声点,但不适合处理高斯噪声或纹理细节。选滤波器前,先搞清楚噪声类型。

// C++ 示例:中值滤波
cv::Mat median;
cv::medianBlur(gray, median, 5); // 核大小为5x5

4.5 图像增强:让特征“跳”出来

图像增强,说白了就是“扬长避短”。把有用的特征放大,把没用的信息压制。常用的方法有:

  • 伽马校正:调整图像的亮度曲线。γ < 1 时,暗部变亮;γ > 1 时,亮部变暗。
  • 拉普拉斯增强:通过二阶微分,强化边缘和细节。
  • 锐化:用高通滤波器,让边缘更清晰。

我个人最常用的是伽马校正。为什么?因为它简单、直观、效果好。你想想看,一张曝光不足的图像,用γ=0.5,暗部细节立刻显现。一张过曝的图像,用γ=2.0,亮部细节也能拉回来。

有一次做食品包装检测,包装上的生产日期印得很浅,肉眼都看不清。我用伽马校正把暗部提亮,再配合拉普拉斯增强,日期清晰可见。嗯,这里要注意:增强过度会引入噪声,所以增强后通常要加一点滤波。

// C++ 示例:伽马校正
cv::Mat gamma_corrected;
cv::Mat lookUpTable(1, 256, CV_8U);
uchar* p = lookUpTable.ptr();
double gamma = 0.5;
for (int i = 0; i < 256; i++) {
    p[i] = cv::saturate_cast<uchar>(pow(i / 255.0, gamma) * 255.0);
}
cv::LUT(gray, lookUpTable, gamma_corrected);

4.6 知识体系总览

下面这张图,是我自己总结的预处理流程。你照着这个顺序走,基本不会出错。

图像预处理流程 原始图像 步骤1:图像灰度化 步骤2:直方图均衡化(可选) 步骤3:滤波(高斯/中值/双边) 预处理完成

4.7 实战建议

最后,给你几条实战建议:

  1. 先看噪声类型,再选滤波器。椒盐噪声用中值滤波,高斯噪声用高斯滤波,混合噪声用双边滤波。
  2. 直方图均衡化不是万能的。如果图像本身对比度很好,用了反而会失真。先看直方图分布,再决定用不用。
  3. 预处理要“轻量”。不要过度处理,否则会丢失原始信息。我一般控制在3步以内:灰度化 → 滤波 → 增强。
  4. 参数要调,但别死磕。我见过有人调高斯滤波的σ调了一整天。其实差不多就行,后续算法会弥补。

总结一句话:预处理的目标不是“好看”,而是“好用”。让后续算法能稳定工作,就是胜利。

专注资料整理