3、代价计算基础:像素灰度差(AD)、灰度差平方(SD)、绝对差之和(SAD)、平方差之和(SSD)
好,咱们正式开始聊代价计算。
说实话,立体匹配里最基础、最核心的一步,就是算代价。你想想看,左右两张图,怎么知道哪个像素跟哪个像素是对应的?说白了,就是比一比它们长得像不像。而“比一比”这件事,就得靠代价函数来完成。
我个人习惯把代价计算比作“找对象”——你得有个标准,看两个人合不合适。像素点也一样,得有个度量,看它们匹配不匹配。
3.1 最朴素的度量:AD 与 SD
先从最简单的说起。
AD(Absolute Difference),绝对差。就是两个像素灰度值直接相减,取绝对值。
AD = |I_left(x, y) - I_right(x - d, y)|
就这么简单。一个像素对像素,算一个差值。差值越小,说明越像。
嗯,这里要注意:AD 只考虑单个像素,没有邻域信息。所以它对噪声非常敏感。我在项目中遇到过,如果图像传感器有点噪点,AD 算出来的代价图就跟撒了芝麻一样,全是毛刺。
SD(Squared Difference),平方差。跟 AD 类似,但把差值平方了一下。
SD = (I_left(x, y) - I_right(x - d, y))²
为什么要平方?说白了就是放大差异。两个像素差 10 个灰度级,平方后变成 100;差 20 个灰度级,平方后变成 400。这样大的差异会更突出,小的差异会被压缩。
我曾经在一个高动态范围的场景里试过 SD,效果比 AD 好一些——因为强光照区域和暗区域的差异被平方后,匹配的区分度更高了。
3.2 引入邻域:SAD 与 SSD
单个像素太容易受干扰了,怎么办?
你想想看,我们看一张图,判断一个点是不是跟另一个点匹配,是不是会看看它周围一圈?对,这就是窗口的思想。
SAD(Sum of Absolute Differences),绝对差之和。把一个窗口内所有像素的 AD 值加起来。
SAD = Σ|I_left(x+i, y+j) - I_right(x-d+i, y+j)|
其中 i, j 在窗口内遍历,比如一个 3x3 的窗口,就是 9 个像素的 AD 求和。
SAD 的好处很明显:窗口平均了噪声的影响。就算某个像素被噪声污染了,周围几个像素还能拉一把。我在做工业检测项目时,SAD 是我最常用的起步方法——简单、稳定、不容易出幺蛾子。
SSD(Sum of Squared Differences),平方差之和。就是把窗口内的 SD 值加起来。
SSD = Σ(I_left(x+i, y+j) - I_right(x-d+i, y+j))²
SSD 比 SAD 更“激进”一些。它会把大的差异惩罚得更狠。你想想看,如果窗口内有一个边缘点,灰度跳变很大,SSD 会把这个差异放大,导致匹配结果更倾向于平滑区域。
3.3 四种方法的对比
我把它们放在一起,做个对比表格,方便你一眼看明白。
| 方法 | 公式 | 计算量 | 抗噪性 | 适用场景 |
|---|---|---|---|---|
| AD | |I₁ - I₂| | 极低 | 差 | 理想图像、快速验证 |
| SD | (I₁ - I₂)² | 低 | 较差 | 高对比度场景 |
| SAD | Σ|I₁ - I₂| | 中等 | 较好 | 通用场景、工业检测 |
| SSD | Σ(I₁ - I₂)² | 中等 | 中等 | 纹理丰富、边缘锐利场景 |
3.4 知识体系:代价计算的核心逻辑
为了让你更直观地理解这四种方法的关系,我画了一张图。
从这张图你可以看到,代价计算其实就两条路:要么用单个像素比(AD/SD),要么拉上邻居一起比(SAD/SSD)。最终都会生成一个代价体积,供后续的代价聚合和视差优化使用。
3.5 实战中的选择建议
说了这么多,到底该用哪个?
我个人有个简单的判断标准:
- 如果你在做快速原型验证,用 AD 就够了,代码三行搞定。
- 如果图像质量一般,有噪声,直接上 SAD,窗口大小 5x5 或 7x7 起步。
- 如果场景纹理丰富,想要更锐利的边缘,试试 SSD。
- 如果你不确定,那就都跑一遍,对比一下代价体积的可视化结果——哪个看起来更干净、更连续,就用哪个。
好了,代价计算的基础就聊到这儿。这四种方法虽然简单,但它们是整个立体匹配的基石。后面所有的优化、后处理,都是建立在代价体积之上的。所以,别嫌它们简单,多动手试试,你会找到感觉的。
公众号:蓝海资料掘金营,微信deep3321