第四章:图像采集与预处理——散斑图像采集技巧、图像去噪与增强

各位同学,大家好。我是你们的老朋友,一个在光学测量和硬件堆里摸爬滚打了十几年的工程师。今天咱们聊点实操的东西——散斑图像的采集与预处理。

说实话,散斑测量这活儿,七分靠采集,三分靠算法。你采集阶段要是搞砸了,后面算法再牛也白搭。我自己就吃过这个亏,所以今天我把压箱底的经验都掏出来,咱们一步步拆解。

4.1 散斑图像采集技巧:别让源头出问题

采集散斑图像,说白了就是“拍一张好照片”。但这里的“好”,跟咱们平时自拍可不一样。它要求高对比度、高信噪比,还得保证散斑颗粒大小合适。

我个人习惯,在搭建采集系统时,先问自己三个问题:

  • 光源稳不稳? 激光器必须预热至少15分钟。我见过有人一开机就拍,结果前几张图亮度一直在漂,数据全废了。
  • 相机曝光时间对不对? 散斑是干涉形成的,曝光时间太长,散斑会“糊”掉;太短,噪声又大。一般我建议先试几个曝光值,找到那个“刚好不过曝、背景又干净”的点。
  • 被测表面有没有震动? 哪怕是一丝微小的震动,都会让散斑图出现“鬼影”。我曾经在实验室里因为空调风太大,导致数据重复性极差,后来加了个隔振台才搞定。
小技巧: 采集时,尽量让散斑颗粒大小覆盖3-5个像素。太小了是欠采样,太大了又丢失细节。你可以通过调整光圈或物距来控制。

4.2 图像去噪:把脏东西洗掉

采集回来的散斑图,多少都有噪声。可能是传感器热噪声,也可能是环境光干扰。去噪这一步,我把它比作“洗脸”——洗得太轻,脏东西还在;洗得太狠,把五官都搓没了。

常用的三种滤波方法,我挨个说说我的使用心得。

4.2.1 均值滤波:简单但粗暴

均值滤波的原理,就是用一个窗口(比如3x3)扫过图像,把窗口内所有像素的灰度值取平均,代替中心像素的值。

// 均值滤波核心代码(C风格伪码)
for (int y = 1; y < height-1; y++) {
    for (int x = 1; x < width-1; x++) {
        int sum = 0;
        for (int dy = -1; dy <= 1; dy++) {
            for (int dx = -1; dx <= 1; dx++) {
                sum += img[y+dy][x+dx];
            }
        }
        img_filtered[y][x] = sum / 9;
    }
}

优点: 速度快,对高斯噪声有效。
缺点: 会模糊边缘。散斑的边界信息很重要,用均值滤波容易把散斑颗粒之间的边界“抹平”。
我的建议: 如果你只是做粗略的位移测量,可以用。但做高精度应变测量,慎用。

4.2.2 中值滤波:保边去噪的好手

中值滤波不是取平均,而是取窗口内所有像素的“中位数”。

// 中值滤波核心代码(C风格伪码)
for (int y = 1; y < height-1; y++) {
    for (int x = 1; x < width-1; x++) {
        // 收集窗口内9个像素值
        int values[9];
        int idx = 0;
        for (int dy = -1; dy <= 1; dy++) {
            for (int dx = -1; dx <= 1; dx++) {
                values[idx++] = img[y+dy][x+dx];
            }
        }
        // 排序并取中位数
        sort(values, 9);
        img_filtered[y][x] = values[4]; // 第5个是中位数
    }
}

这玩意儿对椒盐噪声(就是那种黑白点)特别有效。而且它不会模糊边缘,因为中位数不受极端值影响。

我遇到过的情况: 有一次在工厂现场采集,环境光有频闪,导致图像上出现周期性的亮暗条纹。用均值滤波根本去不掉,但中值滤波一上,干净多了。嗯,这里要注意,中值滤波计算量比均值大,实时性要求高的场合要权衡。

4.2.3 高斯滤波:更自然的平滑

高斯滤波跟均值滤波类似,但它的权重不是平均的,而是符合高斯分布——离中心越近的像素,权重越大。

// 高斯滤波(3x3核,sigma≈0.85)权重示例
// 核矩阵:
// 1  2  1
// 2  4  2
// 1  2  1
// 归一化因子 = 1/16

for (int y = 1; y < height-1; y++) {
    for (int x = 1; x < width-1; x++) {
        int sum = 0;
        sum += img[y-1][x-1] * 1;
        sum += img[y-1][x]   * 2;
        sum += img[y-1][x+1] * 1;
        sum += img[y][x-1]   * 2;
        sum += img[y][x]     * 4;
        sum += img[y][x+1]   * 2;
        sum += img[y+1][x-1] * 1;
        sum += img[y+1][x]   * 2;
        sum += img[y+1][x+1] * 1;
        img_filtered[y][x] = sum / 16;
    }
}

高斯滤波的效果比均值滤波更“自然”,因为它更尊重中心像素的值。在散斑处理中,我常用它来做轻微的平滑,保留大部分细节。

三种滤波对比总结:
滤波类型去噪能力边缘保留计算速度适用场景
均值滤波中等粗略测量、高斯噪声
中值滤波强(椒盐噪声)中等有异常点、椒盐噪声
高斯滤波中等偏上较好通用平滑、保留细节

4.3 图像增强:让特征更明显

去噪之后,图像干净了,但可能对比度不够。散斑图如果对比度低,后续相关计算精度会下降。这时候就需要图像增强。

最经典的方法就是直方图均衡化

4.3.1 直方图均衡化:把灰度拉开

直方图均衡化的核心思想,就是把图像的灰度分布“拉伸”开,让原本集中在某个小范围的灰度值,均匀分布到整个0-255区间。

你想想看,如果一张散斑图所有像素的灰度值都在100-120之间,那看起来就是灰蒙蒙一片。均衡化之后,黑的更黑,白的更白,对比度一下就上来了。

// 直方图均衡化核心步骤(伪码)
// 1. 统计灰度直方图
int hist[256] = {0};
for (int i = 0; i < totalPixels; i++) {
    hist[img[i]]++;
}

// 2. 计算累积分布函数(CDF)
int cdf[256];
int sum = 0;
for (int i = 0; i < 256; i++) {
    sum += hist[i];
    cdf[i] = sum;
}

// 3. 映射新灰度值
int cdf_min = cdf[0]; // 第一个非零的CDF值
for (int i = 0; i < totalPixels; i++) {
    int old_gray = img[i];
    int new_gray = (cdf[old_gray] - cdf_min) * 255 / (totalPixels - cdf_min);
    img_enhanced[i] = new_gray;
}

注意: 直方图均衡化可能会放大噪声。所以我的流程是:先滤波去噪,再做均衡化。顺序别搞反了。

避坑指南: 我曾经在测量一个高反射表面时,直接对原始散斑图做均衡化,结果把传感器本身的固定模式噪声也放大了,导致相关计算出现假峰。后来我改成先做中值滤波,再做均衡化,问题就解决了。

4.4 本章知识体系总览

下面这张图,是我自己画的整个预处理流程。你可以把它贴在工位上,每次做实验前扫一眼,保证不遗漏步骤。

散斑图像预处理流程 1. 图像采集 光源稳定·曝光合适·防震 2. 图像去噪 均值滤波 | 中值滤波 | 高斯滤波 3. 图像增强 直方图均衡化 预处理完成 ⚠️ 注意事项 • 先滤波,后均衡化 • 中值滤波保边效果好 • 均衡化可能放大噪声

这张图把整个流程串起来了。从采集开始,到去噪,再到增强,每一步都有对应的技术选型。我个人习惯在采集阶段多花点时间,因为源头好了,后面处理就轻松。

好了,这一章的内容就到这里。记住,预处理不是万能的,但没有预处理是万万不能的。下一章咱们会聊到散斑图像的相关计算,那才是真正出结果的地方。但如果你预处理没做好,再好的算法也救不了你。


专注资料整理