2、数学基础回顾:图像卷积操作、归一化原理、相似度度量(SAD、SSD、NCC)、傅里叶变换简介

各位同学,欢迎来到第二章。

说实话,很多做嵌入式视觉的朋友,一听到「数学基础」四个字就想关页面。我当年也一样。但后来被现实狠狠教育了一顿——有一次我在STM32上跑模板匹配,结果死活对不准,折腾了两天,最后发现是归一化没做对。嗯,从那以后我再也不敢跳过这些基础了。

这一章,咱们不搞天书。我会用最直白的方式,把卷积、归一化、相似度度量、傅里叶变换这几个东西讲清楚。你只要跟着走一遍,后面写代码的时候心里就有底了。

2.1 图像卷积操作

卷积是什么?说白了就是「加权求和」。你拿一个小窗口(叫卷积核),在图像上滑来滑去,每个位置都算一遍加权和。

我习惯这么理解:图像是二维数组,卷积核是另一个小二维数组。卷积核滑到哪,就跟图像对应位置做点乘,然后求和。

核心公式:

输出图像(x, y) = Σ Σ 输入图像(x+i, y+j) * 卷积核(i, j)

其中 i, j 遍历卷积核的所有位置。

举个例子,一个 3x3 的均值滤波核:

核 = [
  [1/9, 1/9, 1/9],
  [1/9, 1/9, 1/9],
  [1/9, 1/9, 1/9]
]

这个核滑过图像,每个像素都被周围9个像素的平均值替代。效果就是图像变模糊了。

实战小技巧:

我在做模板匹配时,经常先用高斯卷积核把图像模糊一下。为什么?因为模板和原图之间总有细微的噪声差异,模糊一下能提高匹配的鲁棒性。代价就是边缘信息会丢失一点,但匹配成功率能提升不少。

嵌入式部署时要注意什么?卷积的计算量跟核大小成正比。3x3的核,每个像素要做9次乘加。如果是7x7,那就是49次。在资源受限的芯片上,我建议优先用3x3或5x5的核。

避坑指南:

我曾经在FPGA上做卷积加速,没注意边界处理。结果图像边缘出现了一圈黑边。后来才想起来,卷积操作默认在边界补零(zero padding)。如果你的应用对边缘精度要求高,记得检查边界处理方式。

2.2 归一化原理

归一化,就是把数据拉到同一个尺度上。为什么要做?你想想看,如果一张图很亮,另一张图很暗,直接比像素值肯定比不准。

我常用的归一化方式有两种:

方法 公式 适用场景
Min-Max归一化 (x - min) / (max - min) 像素值范围已知,简单粗暴
Z-score归一化 (x - μ) / σ 数据分布近似正态,抗异常点

在模板匹配里,我最常用的是「均值归一化」——把图像减去均值,再除以标准差。这样不管图像是亮是暗,都能拉到差不多的范围。

归一化后的图像特点:

  • 均值为0,标准差为1
  • 不受整体亮度变化影响
  • 匹配时对光照变化有很强的鲁棒性

有一次我在做工业视觉项目,车间灯光忽明忽暗。模板匹配老是误报。后来加了归一化预处理,问题就解决了。说白了,归一化就是给你的算法加了一层「抗干扰护甲」。

2.3 相似度度量:SAD、SSD、NCC

模板匹配的核心问题:怎么判断模板和图像某一块「像不像」?

有三种经典方法,我一个个说。

SAD(绝对差值和)

公式很简单:

SAD = Σ |模板像素 - 图像像素|

SAD越小,说明越像。计算量最小,嵌入式上跑得飞快。但缺点也很明显——对光照变化敏感。你想想,整体亮度一变,所有像素值都变了,SAD自然就大了。

我的经验:

SAD适合在光照稳定的场景下用。比如你做一个固定光源的检测工位,SAD完全够用,而且速度快。

SSD(差值的平方和)

SSD = Σ (模板像素 - 图像像素)²

SSD跟SAD类似,但做了平方。好处是放大了差异——两个像素差1,平方还是1;差10,平方就是100。这样匹配时对「大差异」更敏感。

但坏处也一样:对光照敏感。而且平方运算在嵌入式上比绝对值慢一点点(不过现代MCU基本感觉不到差别)。

NCC(归一化互相关)

这才是重头戏。公式长这样:

NCC = Σ ( (模板-μ模板) * (图像-μ图像) ) / (σ模板 * σ图像)

别被公式吓到。说白了,NCC就是先把模板和图像都归一化,再算它们的相关性。结果在-1到1之间,1表示完全匹配,-1表示完全相反。

NCC的优点:

  • 对光照变化不敏感(因为做了归一化)
  • 对对比度变化也不敏感
  • 结果直观,0.9以上基本就是匹配上了

但NCC也有代价——计算量大。每个位置都要算均值、标准差,再做乘加。在嵌入式上,我一般只在关键位置用NCC,其他地方先用SAD或SSD快速筛选。

方法 计算量 光照鲁棒性 推荐场景
SAD 光照稳定、追求速度
SSD 需要放大差异时
NCC 光照变化大、精度要求高

避坑指南:

我曾经在ARM Cortex-M4上直接跑NCC,结果一帧图像处理了3秒。后来改成先下采样,再用NCC,速度提升到0.2秒。记住:嵌入式上,精度和速度永远是 trade-off。

2.4 傅里叶变换简介

傅里叶变换,听起来高大上,其实就干一件事:把图像从「空间域」变到「频率域」。

空间域就是像素坐标,频率域就是「图像变化的快慢」。比如一张纯色图,频率很低;一张纹理丰富的图,频率很高。

公式我就不写了(网上到处都有),我直接说在模板匹配里怎么用:

  • 快速匹配:用FFT(快速傅里叶变换)把模板和图像都变到频域,在频域做相关运算。计算量从O(N²)降到O(N log N)。图像越大,优势越明显。
  • 频域滤波:在频域把高频噪声滤掉,再变回空间域。效果比空间域滤波好,但计算量大。

我的建议:

傅里叶变换在嵌入式上不太常用,因为FFT需要浮点运算,很多MCU不支持。但如果你用的是带FPU的芯片(比如STM32F4系列),或者有硬件FFT加速器,那就可以试试。我曾在i.MX RT上用过FFT做模板匹配,速度确实快了不少。

嗯,这一章的内容就到这里。数学基础看着枯燥,但后面写代码的时候你会发现,每一步都离不开这些概念。下一章咱们就开始动手,把模板匹配算法一步步搬到嵌入式平台上。

本章要点回顾:

  • 卷积就是加权求和,核大小影响计算量
  • 归一化能消除光照影响,是匹配前的必备步骤
  • SAD/SSD快但不抗光照,NCC慢但鲁棒
  • 傅里叶变换适合大图像加速,但嵌入式上慎用

有问题欢迎交流。咱们下章见。