第二讲:图像基础与预处理——从像素到滤波的实战之路
各位同学,欢迎来到第二讲。上一讲我们聊了边缘检测的整体框架,今天要扎进一个更基础但也更关键的话题——图像在计算机里到底是怎么存的?预处理又该怎么搞?
说实话,我刚开始做嵌入式视觉那会儿,觉得图像预处理就是“调调亮度、改改对比度”,没什么技术含量。直到有一次在工业相机项目上,因为滤波参数没选对,导致边缘检测结果全是噪点,被客户骂了一下午……嗯,从那以后我再也不敢小看预处理了。
一、图像在计算机中的表示
1. RGB图像——最直观的“三原色”
你想想看,我们人眼看颜色,靠的是红绿蓝三种视锥细胞。计算机也一样,用三个通道来模拟——R(红)、G(绿)、B(蓝)。每个通道的值范围是0到255,也就是8位深度。
一张640×480的RGB图像,在内存里占多大?640×480×3 = 921600字节,差不多0.88MB。这在PC上不算什么,但在嵌入式设备上,比如STM32或者树莓派,这个量级就得精打细算了。
关键点:RGB图像在内存中的排列顺序通常是BGR(蓝绿红),而不是RGB。这是OpenCV的默认格式,很多新手在这里踩过坑。
我的经验:在嵌入式平台上,我习惯用BGR565格式(16位,R和B各5位,G占6位),能省一半内存,而且人眼几乎看不出差别。
2. 灰度图像——边缘检测的“主力军”
说白了,边缘检测只需要亮度信息,不需要颜色。所以我们会把RGB转成灰度图。转换公式很简单:
Gray = 0.299 * R + 0.587 * G + 0.114 * B
为什么权重不一样?因为人眼对绿色最敏感,对蓝色最不敏感。这个公式是ITU-R BT.601标准里规定的,我建议你直接记住它。
灰度图每个像素只占1个字节,640×480的图只有307KB。处理速度比RGB快3倍以上——在嵌入式系统里,这就是实不实时的区别。
注意:不要直接用平均值 (R+G+B)/3 来转灰度,那样会丢失对比度信息,边缘检测效果会变差。我曾经试过一次,结果边缘断断续续的,后来老老实实用了加权公式。
二、像素与邻域概念
像素是图像的最小单元,这个好理解。但邻域是什么?说白了,就是某个像素周围的“邻居们”。
常见的邻域有两种:
- 4邻域:上下左右四个方向,像十字架
- 8邻域:上下左右加上四个对角,共8个方向
在边缘检测里,我们几乎只用8邻域。为什么?因为对角线方向的信息也很重要,比如45度边缘。你想想看,如果只用4邻域,斜着的边缘就检测不到了。
实战经验:我在做车道线检测时,发现8邻域能更好地提取连续边缘。但代价是计算量增加了约30%,在低端MCU上需要权衡。
三、图像滤波——去噪是第一步
原始图像里总有噪声——传感器热噪声、光照不均、量化误差……这些噪声如果不处理,边缘检测结果会惨不忍睹。滤波就是用来“平滑”图像,去除噪声的。
1. 均值滤波——简单但粗暴
均值滤波的原理很简单:用一个窗口(比如3×3)滑过图像,把窗口内所有像素的平均值赋给中心像素。
// 3×3均值滤波核
1/9 1/9 1/9
1/9 1/9 1/9
1/9 1/9 1/9
这个核的意思就是:每个邻居的权重都一样,大家平均一下。
优点:速度快,实现简单。
缺点:会模糊边缘,因为边缘处的像素也被平均了。
我的建议:均值滤波适合噪声比较均匀的场景,比如高斯噪声。但如果是椒盐噪声(黑白点),均值滤波效果很差,我建议用中值滤波。
2. 高斯滤波——更“聪明”的平滑
高斯滤波和均值滤波的区别在于:它给中心像素更高的权重,给远处的像素更低的权重。权重分布服从高斯函数(正态分布)。
3×3的高斯核(σ≈0.8):
1/16 2/16 1/16
2/16 4/16 2/16
1/16 2/16 1/16
你看,中心像素的权重是4/16,是角落像素的4倍。这样在平滑噪声的同时,能更好地保留边缘信息。
核心区别:均值滤波是“一刀切”,高斯滤波是“有重点地平滑”。在边缘检测预处理中,我几乎只用高斯滤波。
3. 滤波的嵌入式实现要点
在嵌入式平台上,滤波不能像PC那样直接算。我总结了几条经验:
- 用整数运算:避免浮点数。比如高斯核的1/16可以用右移4位实现
- 分离滤波:二维高斯滤波可以拆成两个一维滤波,先水平再垂直,计算量从O(n²)降到O(2n)
- 边界处理:图像边缘的像素没有完整的邻域,我习惯用“复制边缘”的方式,而不是补零
// 一维水平高斯滤波(3×3核,整数实现)
for (int y = 0; y < height; y++) {
for (int x = 1; x < width - 1; x++) {
int sum = src[y][x-1] + 2*src[y][x] + src[y][x+1];
dst[y][x] = sum >> 2; // 除以4
}
}
避坑指南:我曾经在STM32F4上直接用浮点运算做高斯滤波,结果一帧图像处理了200ms,完全达不到实时。后来改成整数移位运算,直接降到15ms。记住:嵌入式里,能不用浮点就不用浮点。
四、总结与实战建议
这一讲的内容,说白了就是三件事:
- 图像表示:RGB转灰度,省内存提速度
- 邻域概念:8邻域是边缘检测的基础
- 滤波选择:高斯滤波是预处理的首选
我个人习惯的预处理流程是:
RGB → 灰度 → 高斯滤波(3×3,σ=1.0)→ 边缘检测
这个流程在大多数嵌入式平台上都能跑得动,效果也够用。下一讲我们会正式进入边缘检测算法本身,到时候你会发现,今天的预处理工作做得越好,后面的边缘检测就越轻松。
嗯,今天就到这里。有问题随时交流。
公众号:蓝海资料掘金营,微信deep3321