4、结构光编码策略(上):时间编码
聊到结构光三维重建,编码策略是个绕不开的核心话题。说白了,我们往被测物体上投光,就是为了让相机能「看懂」每个像素对应投影仪上的哪个位置。这个对应关系怎么建立?靠的就是编码。
我个人习惯把编码策略分成两大类:时间编码和空间编码。这一章我们先啃时间编码,重点讲二进制编码、格雷码,以及格雷码的解码原理和优缺点。嗯,这些都是我早期做项目时反复踩坑又爬出来的经验,希望能帮你少走弯路。
4.1 时间编码的核心思想
时间编码,顾名思义,就是在一段时间内投射多幅图案。每一幅图案都携带一部分位置信息。相机拍摄这一系列图案后,通过比对每个像素在不同图案中的明暗变化,就能唯一确定该像素对应的投影仪列坐标(或行坐标)。
你想想看,这就像给每个像素发一个「身份证号」。这个号码由多幅图案共同决定。图案越多,编码位数越长,能区分的点数就越多。
关键点:时间编码的精度取决于投影图案的数量。理论上,投影 N 幅二值图案,可以区分 2^N 个不同的投影仪列坐标。
4.2 二进制编码
二进制编码是最直观的时间编码方式。我们直接把投影仪列坐标的二进制表示,逐位投影到物体表面。
举个例子:假设投影仪分辨率为 1024 列,我们需要 10 位二进制数(2^10 = 1024)。那么我们就投影 10 幅图案。
- 第 1 幅图案:所有列坐标最高位为 1 的列投射白条纹,其余投射黑条纹。
- 第 2 幅图案:次高位为 1 的列投射白条纹,其余投射黑条纹。
- ……以此类推。
相机拍摄后,每个像素点会得到一个 10 位的二进制序列。比如某个像素在 10 幅图案中依次看到「白、黑、白、白、黑、黑、白、黑、白、黑」,那么它的二进制码就是 1011001010,对应十进制 714。这就意味着该像素对应投影仪的第 714 列。
注意:二进制编码有一个致命问题——相邻码字之间可能有多位同时变化。比如从 0111(7)到 1000(8),四位全部翻转。如果物体表面刚好处于这两个码字的边界,相机拍摄时由于噪声或模糊,可能误判其中某一位,导致解码结果出现巨大偏差。我曾经在一个高精度检测项目中吃过这个亏,后来果断换成了格雷码。
4.3 格雷码
格雷码(Gray Code)就是为了解决二进制编码的「跳变」问题而生的。它的核心特点是:相邻两个码字之间,只有一位不同。
你想想看,这意味着什么?意味着即使解码时某一位出错,误差最多也就是一个像素的偏差,不会出现二进制编码那种「差之毫厘,谬以千里」的情况。
格雷码的生成规则很简单:从 0 开始,每次改变最右边能产生新码字的那一位。但实际工程中,我们更常用的是从二进制码到格雷码的转换公式:
// 二进制码转格雷码
gray = binary ^ (binary >> 1)
// 格雷码转二进制码(解码时用)
binary = gray;
while (gray >>= 1) {
binary ^= gray;
}
这个转换公式我建议你记牢。我在项目中写解码算法时,几乎每次都会用到它。
4.4 格雷码解码原理
格雷码的解码分为两步:
- 阈值分割:对每幅格雷码图案,判断每个像素是亮还是暗。这一步通常用全局阈值或局部自适应阈值。我习惯用 Otsu 法,效果比较稳定。
- 码字还原:将 N 幅图案得到的二值序列组合成格雷码,再通过上述公式转换为二进制码,最终得到投影仪列坐标。
这里有个细节要注意:格雷码图案通常配合「反码图案」一起使用。也就是对每幅格雷码图案,再投影一幅它的反相图案。这样做的好处是,可以通过正反相减来消除物体表面反射率不均匀的影响。
我的经验:正反相减后取符号,比直接阈值分割要鲁棒得多。尤其是在物体表面有纹理或颜色变化时,这个方法能显著降低解码错误率。我曾经在一个汽车钣金件检测项目中,用这个方法把解码成功率从 85% 提升到了 99% 以上。
4.5 格雷码的优缺点分析
| 优点 | 缺点 |
|---|---|
| 相邻码字仅一位变化,解码误差小 | 需要投影多幅图案,不适合动态场景 |
| 解码算法简单,计算量小 | 对物体表面反射率敏感(可通过反码改善) |
| 抗噪能力优于二进制编码 | 分辨率受限于投影图案数量 |
| 易于硬件实现,FPGA 友好 | 无法处理表面高光区域 |
说白了,格雷码最大的优势就是「稳」。它不像二进制编码那样容易出大错,也不像相移法那样对噪声敏感。但它的代价是时间——投影 N 幅图案就需要 N 个帧的时间。对于静态物体来说完全够用,但如果你要重建运动物体,那就得另想办法了。
嗯,这里还要提一句:格雷码的分辨率受限于投影图案数量。比如你想达到 0.1mm 的精度,可能需要投影 10 位甚至 12 位格雷码。但投影图案越多,采集时间越长,对系统稳定性的要求也越高。我在做高精度文物扫描时,曾经用过 14 位格雷码,投影加采集花了将近 10 秒,但换来了亚毫米级的重建精度。
总结一下:格雷码是时间编码中最经典、最实用的方案之一。它简单、可靠、易于实现,特别适合静态物体的高精度三维重建。如果你刚开始接触结构光系统,我建议先从格雷码入手,把基础打牢。
4.6 本章知识体系
下面这张图梳理了时间编码的核心逻辑,从编码策略到解码流程,一目了然。
从图中可以看到,时间编码的两大分支——二进制编码和格雷码,核心区别在于码字间的跳变特性。格雷码通过「相邻仅一位变化」的设计,在实际工程中更受青睐。解码流程虽然简单,但阈值分割这一步往往决定了最终精度,值得多花心思优化。
避坑指南:我曾经在一个项目中,直接用固定阈值做分割,结果物体表面有块深色区域,解码出来全是噪声。后来改用正反相减 + 局部自适应阈值,问题迎刃而解。记住:没有万能的阈值方法,要根据实际场景灵活调整。
公众号:蓝海资料掘金营,微信deep3321