第四章:图像预处理技术

图像预处理,说白了就是给原始图像“洗把脸”。

我做了这么多年嵌入式视觉,发现一个规律:预处理做得好,后面算法事半功倍;预处理糊弄过去,后面调参调到怀疑人生。你想想看,摄像头采集到的数据,受光照、噪声、抖动影响,直接扔给识别算法,结果能好才怪。

这一章,咱们就聊聊图像去噪、增强和锐化这三板斧。我会结合项目里的实际踩坑经验,把每个方法的适用场景和参数调优讲透。

核心观点:预处理不是流水线式的“全做一遍”,而是根据场景“选做”。去噪和锐化往往是矛盾的,增强和去噪也可能互相干扰。理解原理,才能做对选择。

图像预处理 图像去噪 图像增强 图像锐化 均值滤波 高斯滤波 中值滤波 直方图均衡化 伽马校正 拉普拉斯算子 目标:提升图像质量,为后续识别/检测做准备

4.1 图像去噪:先别急着滤波,搞清楚噪声类型

我刚开始做视觉项目时,拿到图像就一顿均值滤波。后来发现,有些场景越滤越糊,有些场景根本没用。为什么?因为噪声类型不同,对应的滤波器也不同

4.1.1 均值滤波

原理很简单:用邻域内所有像素的平均值代替中心像素。就像一个“和稀泥”的过程。

// C语言实现均值滤波(3x3核)
void meanFilter(uint8_t* src, uint8_t* dst, int width, int height) {
    int kernel[3][3] = {{1,1,1}, {1,1,1}, {1,1,1}};
    int scale = 9;  // 归一化系数
    for (int y = 1; y < height-1; y++) {
        for (int x = 1; x < width-1; x++) {
            int sum = 0;
            for (int ky = -1; ky <= 1; ky++)
                for (int kx = -1; kx <= 1; kx++)
                    sum += src[(y+ky)*width + (x+kx)];
            dst[y*width + x] = sum / scale;
        }
    }
}

我的经验:均值滤波适合去除高斯噪声,但会模糊边缘。我在做工业检测时,如果对边缘要求不高,会用5x5核快速去噪。但注意——核越大,图像越糊,像隔着一层毛玻璃。

4.1.2 高斯滤波

说白了就是带权重的均值滤波。离中心越近的像素,权重越大。这样能更好地保留边缘信息。

我记得有一次做车牌识别项目,光照条件很差,图像上全是传感器热噪声。均值滤波把车牌字符边缘都搞模糊了,换成高斯滤波后,效果明显改善。

// 高斯核生成示例(3x3,sigma=0.8)
// 核系数:
// 1  2  1
// 2  4  2
// 1  2  1
// 归一化因子 = 16

注意:sigma参数很关键。sigma太小(<0.5),滤波效果不明显;sigma太大(>2),图像会过度平滑。我一般从sigma=1开始试,根据效果微调。

4.1.3 中值滤波

这个我特别喜欢。它不是算平均,而是取邻域内所有像素的中位数。对付椒盐噪声(就是那种黑白点噪声),简直是神器。

我曾经在一个户外监控项目中,摄像头被雨滴和灰尘干扰,图像上全是随机白点。均值滤波搞不定,高斯滤波也一般。换成中值滤波后,白点全没了,图像干净得像擦过一样。

// 中值滤波核心逻辑(3x3邻域)
// 1. 读取9个像素值
// 2. 排序(冒泡或快速排序)
// 3. 取第5个值(中位数)作为输出

选型建议:

  • 高斯噪声 → 高斯滤波(或均值滤波)
  • 椒盐噪声 → 中值滤波
  • 混合噪声 → 先中值滤波去椒盐,再高斯滤波去高斯

4.2 图像增强:让暗部亮起来,让亮部别过曝

很多时候,摄像头采集的图像对比度太低,或者整体偏暗。这时候就需要增强处理。我常用的两种方法:直方图均衡化和伽马校正。

4.2.1 直方图均衡化

原理一句话:把像素值的分布“拉平”。原本集中在某个区间的像素,被映射到整个0-255范围。效果就是暗的地方变亮,亮的地方变暗,对比度提升。

但要注意——全局直方图均衡化容易过增强。我在做医疗影像项目时,一张X光片做全局均衡,结果骨骼边缘出现伪影,差点误诊。后来改用限制对比度自适应直方图均衡化(CLAHE),效果就好多了。

// 直方图均衡化步骤(伪代码)
// 1. 统计灰度直方图 hist[256]
// 2. 计算累积分布函数 cdf[i] = sum(hist[0..i])
// 3. 归一化:newPixel = (cdf[pixel] - minCdf) / (totalPixels - minCdf) * 255

我的习惯:在嵌入式平台上,如果算力有限,我会用全局均衡化。如果算力够,优先用CLAHE。OpenCV里直接调用cv::createCLAHE(),参数clipLimit我一般设2-4。

4.2.2 伽马校正

这个更直观。公式:output = input ^ (1/gamma)。gamma > 1时,图像变暗;gamma < 1时,图像变亮。

你想想看,人眼对暗部细节更敏感,但摄像头传感器是线性的。伽马校正就是模拟人眼的非线性响应。我做过一个夜间安防项目,原始图像暗部一片黑,gamma设0.5后,暗部细节全出来了。

// 伽马校正实现
void gammaCorrection(uint8_t* img, int size, float gamma) {
    uint8_t lut[256];
    for (int i = 0; i < 256; i++) {
        lut[i] = (uint8_t)(pow(i / 255.0, 1.0/gamma) * 255.0);
    }
    for (int i = 0; i < size; i++) {
        img[i] = lut[img[i]];
    }
}

避坑指南:我曾经在项目中直接对RGB三个通道分别做伽马校正,结果颜色全偏了。正确的做法是:先转成HSV或YUV,只对亮度通道做校正,色度通道保持不变。

4.3 图像锐化:让边缘“支棱”起来

去噪会让图像变模糊,锐化就是反着来——增强边缘和细节。但锐化也会放大噪声,所以先去噪,后锐化,这个顺序别搞反了。

4.3.1 拉普拉斯算子

二阶微分算子,对边缘特别敏感。公式:output = original - laplacian。说白了,就是把边缘信息提取出来,再加回原图。

// 拉普拉斯锐化核(3x3)
//  0 -1  0
// -1  5 -1
//  0 -1  0
// 注意:中心是5,相当于原图 + 拉普拉斯

我记得做PCB板缺陷检测时,焊点边缘模糊,用拉普拉斯锐化后,边缘清晰得像刀切一样。但噪声也被放大了,所以前面必须做好去噪。

锐化参数调优口诀:

  • 锐化强度不够 → 增大中心权重(如从5改成6)
  • 噪声被放大 → 先做高斯滤波(sigma=0.5-1)
  • 边缘出现振铃 → 减小锐化强度,或改用非锐化掩模

4.4 本章小结:预处理三板斧的配合

说了这么多,其实就三句话:

  • 去噪:根据噪声类型选滤波器,别盲目用均值
  • 增强:直方图均衡化提升对比度,伽马校正调整亮度
  • 锐化:先降噪再锐化,拉普拉斯算子简单有效

我在实际项目中,通常的流程是:中值滤波(去椒盐噪声)→ 高斯滤波(去高斯噪声)→ CLAHE(增强对比度)→ 拉普拉斯锐化(增强边缘)。但这不是固定的,具体场景要具体调整。

最后说一句:预处理没有银弹。多试、多看效果、多总结。我电脑里存了几十张不同预处理参数的效果对比图,每次做新项目都翻出来参考。你也试试看。


公众号:蓝海资料掘金营,微信deep3321