☰
libcimbar 性能实测:cimbar 码 850 kbit/s 吞吐背后的编码参数与相机链路分析
2026/10/2 21:34:09 网站建设 项目流程
  • 图像处理
  • 通信

【免费下载链接】libcimbar

Optimized implementation for color-icon-matrix barcodes

项目地址:https://gitcode.com/GitHub_Trending/li/libcimbar
点击查看免费下载

导读:本篇文章以 libcimbar 官方性能文档 PERFORMANCE.md 为骨架,系统拆解 cimbar 彩色图标矩阵条码的吞吐指标、容量与纠错参数、各 mode 配置的演进与取舍,并结合仓库源码(GridConf.h、Config.h、send.cpp 等)印证参数如何落地、瓶颈为何落在相机端。读完你将掌握:cimbar 每帧 7500 字节是如何由 tile 与颜色比特推演出来的、B/4C/8C/S 四种模式的性能对比与适用场景、以及如何用cimbar_send/cimbar命令行复现「显示器 + 手机相机」这一高速信道。

一、先说结论:一个值得记住的基准数字

cimbar 是一种面向「气隙(air-gapped)数据传输」的实验性条码格式:编码器在电脑/手机屏幕上播放动画条码,解码端用手机摄像头直接读取,全程不依赖互联网、蓝牙或 NFC。libcimbar 是这一格式的优化 C++ 实现,其性能文档给出的核心结论是:

  • 当前可稳定复现的吞吐:约 850 kbit/s(≈106 KB/s),由mode B(8x8、4 色、ecc=30/155)在压缩后数据口径下测得;
  • 更早的mode 4C为 ~838 kbit/s(≈104 KB/s);
  • 已被移除的mode 8C曾达到 ~943 kbit/s(≈118 KB/s),但因 8 色解码不稳定而弃用;
  • 尚处 beta 的mode S(5x5 4 色、ecc=40/216)已可稳定超过1 Mbit/s,格式仍在打磨中。

这些数字的含义与计算方式,正是本文要逐层展开的内容。完整基准记录见 PERFORMANCE.md。

二、容量从哪来:1024×1024 画面里塞进 7500 字节

2.1 码面几何:8x8 tile、9x9 栅格

mode B的码面规格为:

  • 整张码图1024×1024 像素;
  • 单个 tile 为8×8 像素,tile 间距按 9×9 栅格排布(即每个 tile 四周留 1 像素空行/空列);
  • 四角留出锚点(anchor)区域,用于解码端定位。

源码 GridConf.h 中Conf8x8给出了精确参数:cell_size = 8、cell_spacing_x/y = 9、cells_per_col_x = 112,画面尺寸1024×1024,与文档描述完全对应。而 tile 总数则要去掉四角锚点区域:total_cells() = cells_per_col_x*cells_per_col_y - corner_padding_x()*corner_padding_y()*4。

2.2 每 tile 编码 6 bit:4 bit 符号 + 2 bit 颜色

每个 tile 承载两路信息:

  1. 符号位(symbol bits):4 bit——从 16 个预定义的 8×8 图标符号中选一个。这 16 个符号彼此之间的 image-hash 汉明距离约 20 bit,即便在模糊、失真的情况下也能保持可区分性(见 DETAILS.md);
  2. 颜色位(color bits):2 bit——4 色模式在 4 种颜色中选一个,额外带来 2 bit/tile(8 色模式则为 3 bit/tile)。

合计6 bit/tile。码面有效 tile 数约 12400 个(DETAILS.md),于是理论容量:

12400 tiles × 6 bit ÷ 8 =9300 bytes/帧

2.3 ECC 开销:从 9300 到 7500

但 9300 字节不能全部用于数据,因为视频→数字的损失性链路会产生误码,必须预留纠错空间。libcimbar 默认采用Reed-Solomon 纠错,参数为 30/155:即每 155 字节块中,125 字节为真实数据、30 字节为纠错码(DETAILS.md)。由此:

9300 × 125/155 =7500 字节/帧

这正是文档「Numbers of note」一节的核心算式。在 GridConf.h 中,Conf8x8的ecc_bytes = 30、ecc_block_size = 155即为该参数的源码落点。

需要说明的是,文档明确点出 Reed-Solomon 对此场景并非最优:它按字节纠错,而 cimbar 的误码往往一次涉及 1~3 bit。之所以仍选它,是因为 Reed-Solomon 实现随处可得、生态成熟(本仓库使用 libcorrect 作为实现)。ECC 块还会经过交织(interleave),把相邻字节的纠错块分散到整幅图的不同位置,避免「一根手指挡住一小块」就造成成片错误(DETAILS.md)。

2.4 流式传输:zstd 压缩 + fountain 喷泉码

比 7500 字节大得多的文件怎么传?libcimbar 的协议栈分三层:

  • zstd 压缩:发送前先压缩。性能文档强调,所测吞吐的口径是「压缩后的线上比特」,即真实有效数据经过 zstd 压缩后的传输速率。压缩等级默认取 16(Config.h),压缩器按 16 KB(CHUNK_SIZE = 0x4000)分块流式压缩(zstd_compressor.h);
  • fountain(wirehair)喷泉码:把文件切成 N 个数据块,编码出任意数量的喷泉帧。解码端只要收到 N+1 个任意顺序的帧就能重建整个文件,缺帧、乱序都无所谓(DETAILS.md)。其代价是:文件内容需整体驻留内存,单文件上限被限制在 33.55 MB(压缩后);
  • Reed-Solomon ECC:对每一帧做信道级纠错。

这层协议栈的源码位于 fountain(封装 wirehair 编解码,见 FountainEncoder.h、FountainDecoder.h)与 compression 目录。

三、吞吐基准全景:四种模式逐一拆解

PERFORMANCE.md 记录的四组基准数据整理如下:

模式配置ECC吞吐(压缩后)状态
mode B8x8 4色30/1554,689,084 B / 44s ≈852 kbit/s(~106 KB/s)0.6.0 引入,当前推荐
mode 4C(legacy)8x8 4色30/1554,717,525 B / 45s ≈838 kbit/s(~104 KB/s)原始配置,基本被 B 取代
mode 8C(deprecated)8x8 8色30/1554,717,525 B / 40s ≈943 kbit/s(~118 KB/s)0.6.0 移除,8 色不稳定
mode S(beta)5x5 4色40/216稳定 >1 Mbit/s未定稿,需特殊构建

3.1 mode B 与 mode 4C 的差别到底在哪

两者都是 8x8、4 色、ecc=30/155,吞吐也几乎一致,区别主要在内部协议细节。从 Config.h 的temp_conf()可以看到:

  • mode 4C(config_mode = 4):color_bits = 2、legacy_mode = true、fountain_chunks_scalar = -10(负值表示每帧固定 10 个喷泉块);
  • mode B(config_mode = 68,默认分支):使用Conf8x8(),非 legacy 模式。

文档给出的取舍结论是:mode B 是首选,可靠性最好;mode 4C 在某些场景下可能给出更稳定的传输速率,但保留它主要是为了向后兼容。

3.2 为什么 8 色(mode 8C)被放弃

8 色模式每 tile 可编码 7 bit,理论上每帧可达约 10850 字节,吞吐理应更高(实测 ~943 kbit/s 也确实是最高的)。但文档直言:8 色一直不稳定,颜色识别在相机色偏、光照变化下误判率更高,因此 0.6.0 起被移除,需要未来重新研究。这也解释了为什么temp_conf()中不再提供 8 色分支(case 8仅保留在 legacy 通道)。

3.3 beta 的 mode S:5x5 小 tile + 更高 ECC

mode S 是未定稿格式(需要特殊构建),关键参数在 GridConf.h 的Conf5x5中:cell_size = 5、symbol_bits = 2、color_bits = 2(共 4 bit/tile)、ecc_bytes = 40、ecc_block_size = 216、cells_per_col_x = 162。更高的 ECC 比例(40/216 ≈ 18.5%,高于 mode B 的 30/155 ≈ 19.4%,接近)配合更小的 tile,换取更高的帧率与更细密的码面,目标是稳定超过 1 Mbit/s。注意:该模式尚未定稿,参数与性能数据仍可能变化,不宜作为生产依据。

四、测量环境与「850 kbit/s」的边界条件

要让基准数字可复现、可理解,必须知道它的测量环境:

  • 解码端:Android 应用 cfc,运行在 4 个 CPU 线程的骁龙 625(Qualcomm Snapdragon 625)上——这是一颗面向中端机型的旧 SoC。文档特别指出:更新的手机 CPU 能更快跑解码器,但对整体吞吐帮助不大,因为真正的瓶颈是摄像头;
  • 发送端:cimbar.org 的 WASM 实现(等价的命令行是./cimbar_send /path/to/file,见 send.cpp)。cimbar.org 启用了shakycam选项,让接收端在扫描阶段就能检测并丢弃「中间过渡帧」,从而把更多处理时间花在解码真实数据上;
  • 口径:所有数字都是压缩后数据的线上比特速率,即用户实际能拿到的文件数据量;
  • 瞬时速率(burst rate)可以更高或更低:更低的 ECC 设置能提升突发速率,文档作者的目标是在性能与可靠性之间取平衡,因此默认 30/155 并非为「极限突发」调优。

五、实践操作:如何复现这条高速信道

5.1 命令行发送端

构建后(Linux 下cmake . && make -j7 && make install,产物默认装入./dist/bin/,详见 README.md),用cimbar_send直接在屏幕上播放动画条码:

./cimbar_send inputfile.pdf

cimbar_send支持的与性能强相关的参数(send.cpp):

参数含义默认值
-f, --fps目标帧率15
-m, --mode模式:B / Bm / Bu / 4CB
-p, --padding码图周围黑色留白(像素)32
-z, --compression压缩等级,0 表示不压缩16
-i, --in源文件(位置参数)—

其中-m Bm(对应Conf8x8_mini,1024×720)与-m Bu(对应Conf8x8_micro,736×637)是 0.6.x 新增的横屏变体配置(GridConf.h),供不同屏幕比例下使用。

5.2 命令行解码端

用cimbar工具解码一张或多张编码图,并把还原的文件写入输出目录:

./cimbar outputprefix*.png -o /tmp

也可以从 stdin 读入文件列表:

echo outputprefix*.png | ./cimbar -o /tmp

解码端常用开关(cimbar.cpp):--color-correct(颜色校正,2=完整模式,1=简单,0=关闭)、--color-correction-file(调试用,导出校正矩阵)、--no-fountain(关闭喷泉码,同时禁用压缩)。

5.3 编码为静态图片

无需屏幕,也可把文件编码为一组 PNG:

./cimbar --encode -i inputfile.txt -o outputprefix

注意:大文件可能生成大量 PNG,注意磁盘空间(README 已明确提醒)。

六、影响实拍吞吐的 7 个实操因素

性能文档的「other notes」部分是实拍经验的高度浓缩,逐条对应着源码与信号链路:

  1. 光照是最大的变量:更好的环境光通常带来更稳定的结果。cimbar.org 采用(近乎)白色背景正是为此;cfc 使用 Android 自动曝光/自动对焦,充足的环境光——或白色背景——能带来更一致的画质。屏幕亮度够用,但环境光优于屏幕光;
  2. 横竖屏:由于曝光问题,横屏(landscape)可能优于竖屏(portrait)——这解释了Bm/Bu横屏模式的存在;
  3. 让码图尽量占满屏幕:跟随画面中的 guide 定位框(bitmap/guide-horizontal-、guide-vertical-即其素材)。该格式设计上可低至700×700 分辨率解码,但性能会下降;
  4. 尽量正对拍摄:斜角拍摄仍可解码,但「较小」一侧的图区错误可能超过 ECC 纠错能力;
  5. 警惕光源眩光(glare);
  6. 手抖会影响帧间对齐与扫描稳定;
  7. 帧率与相位:shakycam这类「丢弃过渡帧」的策略(发送端 WASM 版本启用)能显著提升有效解码占比。

这些因素之所以关键,根源在于 DETAILS.md 指出的误差模型:tile 模糊、过暗、错位、镜头畸变、图太小导致 tile 失去定义,且这些问题往往局部化(图的一半好解码、另一半全是误读级联)。交织与 ECC 能缓解,但超过一定程度就只能靠提高 ECC 或输入分辨率。

七、从解码器看性能成本的来源

吞吐数字背后是解码端持续在做的工作。核心解码循环(伪代码,见 DETAILS.md):

for i, bits, distance, drift in next_decode(): results[deinterleave(i)] = bits position_tracker.update(i, drift, distance) decoded_data = error_correct(results)
  • 每个 cell 通过 image-hash 距离(distance,越低越可信)选择最佳符号,距离同时充当置信度指标——高置信度的 cell 优先解码;
  • drift是一个 (x,y) 偏移,跟踪局部形变,上限 ±7px;高置信度 cell 的 drift 会被优先采用,用于校正邻近 cell 的采样位置;
  • 解码顺序是乱序的,配合deinterleave还原真实位序——这正是 mode B/4C 在解码阶段最耗 CPU 的部分之一。

源码对应物为 CimbDecoder.cpp(get_best_symbol/decode_symbol/ 颜色校正矩阵update_color_correction)与 extractor(锚点定位 + Deskewer 透视变换)。这也解释了为什么解码端跑在骁龙 625 这种老 SoC 上时,4 线程即够用且瓶颈仍在相机。

八、结论与可引用的事实清单

围绕 PERFORMANCE.md,可以安全引用的事实包括:

  • 码面规格:1024×1024 像素,8×8 tile 按 9×9 栅格排布,mode B 每帧 7500 字节(ECC 后);
  • 比特账目:16 符号/tile(4 bit)+ 4 色(2 bit)= 6 bit/tile → 理论 9300 B/帧,ECC 30/155 折减为 7500 B/帧;
  • 当前基准:mode B 约 852 kbit/s(~106 KB/s);mode S(beta)可超 1 Mbit/s;mode 8C 因不稳定已移除;
  • 链路构成:zstd 压缩 → wirehair fountain 喷泉码(上限 33.55 MB,需整文件驻留内存)→ Reed-Solomon ECC(30/155);
  • 瓶颈归属:解码 CPU(4 线程骁龙 625 已够)不是主瓶颈,相机才是;光照、取景占比、拍摄角度直接影响吞吐。

适用前提与限制:上述吞吐为「压缩后数据」口径,测于显示器 + 骁龙 625 解码端 + WASM 发送端(cimbar.org,启用 shakycam)的固定组合;burst 速率可随 ECC 设置浮动;mode S 未定稿、需特殊构建;所有参数以当前仓库 GridConf.h 与 Config.h 为准。

延伸阅读:README.md(构建与用法总览)、DETAILS.md(编码/解码原理)、TODO.md(后续改进方向)。

  • 图像处理
  • 通信

【免费下载链接】libcimbar

Optimized implementation for color-icon-matrix barcodes

项目地址:https://gitcode.com/GitHub_Trending/li/libcimbar
点击查看免费下载
上一篇:在 DataHub 中使用 Apache Ranger 配置授权(Authorization):插件部署与策略管理实战指南
下一篇:Dagger TypeScript SDK 中的 InputTypeDefID:输入类型定义标识符的类型别名与底层实现解析

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询