4. 时间编码之二进制编码:基本原理、码字生成、投影序列设计及解码流程
各位同学,今天我们来聊聊时间编码里最经典的一种——二进制编码。说实话,我刚入行那会儿,第一次接触结构光系统,用的就是二进制编码。它简单、直观,而且效果稳定。你想想看,一个能把复杂问题拆解成“0”和“1”的方法,能不好用吗?
4.1 基本原理:从“亮”和“暗”说起
二进制编码的核心思想,说白了就是用一系列黑白条纹图像,给投影仪的每个像素编一个独一无二的“身份证号”。
怎么编呢?
- 亮条纹代表二进制“1”
- 暗条纹代表二进制“0”
举个例子,假设投影仪的水平分辨率是1024像素。我需要用10张图(2^10 = 1024)来给每个像素编码。第一张图,左边一半亮、右边一半暗;第二张图,四分之一亮、四分之一暗……以此类推。
我在项目中遇到过一个问题:如果环境光太强,暗条纹容易被误判成亮条纹。嗯,这里要注意,解码时一定要做自适应阈值处理。
核心公式:
投影仪列坐标 = ∑ (bi × 2i-1),其中 bi 是第 i 张图的解码值(0或1)
4.2 码字生成:如何设计一套好用的码本?
码字生成,其实就是设计一组二进制序列。我个人习惯用格雷码(Gray Code)代替普通二进制码。为什么?因为格雷码相邻两个码字之间只有一位不同,抗干扰能力更强。
举个例子:
| 十进制 | 二进制码 | 格雷码 |
|---|---|---|
| 0 | 000 | 000 |
| 1 | 001 | 001 |
| 2 | 010 | 011 |
| 3 | 011 | 010 |
| 4 | 100 | 110 |
你看,从3到4,二进制码从011变成100,三位全变了。如果解码时有一点点噪声,很容易出错。但格雷码从010到110,只变了一位,容错性就好很多。
我的经验:在工业级项目中,我建议优先使用格雷码。我曾经在一个高反光物体扫描项目中,用二进制码死活解不对,换成格雷码后一次通过。
4.3 投影序列设计:怎么安排这些图?
投影序列设计,说白了就是决定“先投哪张,后投哪张”。
通常的做法是:
- 先投全亮图和全暗图:用于计算每个像素的阈值
- 再投编码图:从最高位到最低位,或者反过来
- 最后投一张校验图:用于检测运动模糊
我见过很多新手直接投编码图,结果解码时阈值选不对,满屏都是噪点。你想想看,没有全亮和全暗图做参考,你怎么知道每个像素的“亮”和“暗”到底是多少?
避坑指南:我曾经在一个高速扫描项目中,为了省时间跳过了全亮/全暗图。结果解码出来的点云全是空洞,后来老老实实加上了,效果立竿见影。
4.4 解码流程:从图像到三维坐标
解码流程,我把它拆成三步:
- 第一步:阈值分割——把每张图的像素分成“亮”和“暗”
- 第二步:码字还原——把每张图的二值结果拼成一个二进制数
- 第三步:坐标映射——用这个二进制数找到投影仪上的对应列坐标
代码实现大概是这样的:
// 伪代码:二进制解码
for each pixel (x, y):
code = 0
for i = 0 to N-1:
if pixel_value[i] > threshold[i]:
code |= (1 << i)
projector_col = code
// 然后用三角测量法计算三维坐标
嗯,这里要注意,阈值不是固定的。每个像素的阈值都不一样,最好用全亮图和全暗图算出来:
threshold[i] = (bright_value + dark_value) / 2
这样算出来的阈值,能适应不同区域的亮度变化。我在做汽车钣金件扫描时,就靠这个办法解决了反光区域的解码问题。
4.5 知识体系总览
下面这张图,是我自己总结的二进制编码知识体系。你可以把它当成一张“地图”,学完这一章后,对照着检查自己有没有遗漏。
好了,二进制编码的核心内容就这些。它虽然基础,但非常重要。后面的章节我们会在这个基础上,讲更高级的编码方法。记住,基础打牢了,后面才能飞得起来。
公众号:蓝海资料掘金营,微信deep3321