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 投影序列设计:怎么安排这些图?

投影序列设计,说白了就是决定“先投哪张,后投哪张”。

通常的做法是:

  1. 先投全亮图和全暗图:用于计算每个像素的阈值
  2. 再投编码图:从最高位到最低位,或者反过来
  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 知识体系总览

下面这张图,是我自己总结的二进制编码知识体系。你可以把它当成一张“地图”,学完这一章后,对照着检查自己有没有遗漏。

二进制编码知识体系 二进制编码 基本原理 码字生成 投影序列设计 解码流程 亮=1,暗=0 N张图编2^N个码 格雷码优先 相邻仅变1位 全亮+全暗图 编码图+校验图 阈值分割 码字还原 坐标映射

好了,二进制编码的核心内容就这些。它虽然基础,但非常重要。后面的章节我们会在这个基础上,讲更高级的编码方法。记住,基础打牢了,后面才能飞得起来。


公众号:蓝海资料掘金营,微信deep3321