infrost
(Frost)
1
live demo: https://qr.linkto.host/
github 链接: GitHub - infrost/RaptorQR: Ultra-fast offline file and text transfer over animated QR codes with WASM fast_qr, ZXing and RaptorQ. · GitHub
这个项目大概是前段时间突发奇想,想看看“离线摄像头拍屏幕识别数据”这条赛道的上限大概在哪。
如果你不想看我叨叨的话,结论就是:工程实现上已经能稳定100-200多KB/s,上限应该在几百KB/s。,iPhone16上扫码传6.5MB文件用时44s,目前我应该是做到了这个赛道的全网最快。
一开始是想像 sz3/libcimbar / Cimbar 那种自定义彩色码或者Aztec Code之类的编码,后来发现虽然彩色码信息高,但是识别逻辑远没有二维码成熟,ZXing还有wasm的识别方案,能做到我手机上测得平均每秒钟识别100+个V30二维码(V20甚至能测到了每秒钟300个码)
二维码传文件编码上面难点就是漏扫二维码/不按顺序扫/怎么办。不过好消息是fountain code并不是个特别冷门的领域,而且很多卫星向地球广播的方案都要用类似编码。为了速度和正确性我就没有重复造轮子,拿了raptorQ标准(RFC6330)的rust实现,然后我把它编译成了wasm。
最后的瓶颈是二维码生成,大部分现有的纯二维码传文件项目速度其实都卡在这里。我也是同样的操作把rust实现的fastqr编译成了wasm,然后js(typescript)直接内存直读fastqr的生成区的原始二维码矩阵,后台走web worker多线程并行生成,然后用rAF丢到canvas里面去画二维码再插值放大。这个三板斧下来,生成可以在我浏览器上8个二维码@60fps也就是每秒钟480个二维码都没有压力。
(zxing writer其实也能生成二维码,但是测下来zxing的二维码生成能力甚至不如纯js的二维码生成逻辑,可能是因为来回拷贝数据和gc的问题,所以我编译wasm的时候直接让它划出一块区间永远在上面写数据,就不用gc了)
直觉上根据传奇祖师爷香农的guide,要想完美还原信号,采样率至少要是原始信号频率的两倍。手机摄像头api能暴露出来的最多就60fps,那比较不浪费资源的生成速率实际上只有30fps了。虽然我这个直觉毫无道理吧,但我在测试上真就发现,对于一个60fps的摄像头来说,30fps确实是个甜点区间,再高的话二维码识别速率其实反而会降低,我不知道是因为物理屏幕刷新率和二维码生成帧之间的某种问题,还是LCD像素切换的残影问题(我是165HZ的屏幕,可能240HZ的会比较好),还是实际上手机采样率根本到不了60fps又或者是快门速度问题,总之就是效果没那么好,但具体为什么还需要后续去验证。
我屏幕是16寸的,测试下来大概是4个二维码平行扫描,大小是V30,30fps能达到最佳的效率。
这个项目用了monorepo,所以想要底层的wasm包来研究,可以直接npm/pnpm install我的包;或者玩玩就用我的live demo或者自己vercel跑跑玩玩。
just for fun
2 个赞
shadows
(shadows)
2
这种项目应该提供一个离线使用的单网页版比较好,使用更简单
After the first load, you can open the same link again even without an internet connection.
问题是很多需要用到的场景就是无网的,只允许文件进出的,压根不能完成第一步…
至于cli在终端输出二维码,这…完全看终端能力吧,cmd上真的不会有问题吗
一个很有意思的概念验证项目,而且逻辑上做的挺好的
想问的是
- 如果二维码被遮挡,或者本身有破损,会有多大程度的效率下降。这个情况会在有人经过摄像头,或者有个虫子飞过摄像头的时候发生
- 如果二维码有几何变形(就类似于手机不是平行于二维码平面,而是有倾角,导致视觉上二维码的一边比另一边更大),又会多大程度上影响效率。这个问题会在摄像头架设的时候发生
- 如果二维码的对比度不够,不是严格的纯黑纯白,而是白底灰色二维码,或者白底浅灰二维码,又会再多大程度上影响扫描。这个会在老式显示器,或者低质量显示器上发生
infrost
(Frost)
4
已经考虑到了这个问题,这个项目本身已经是“离线使用”的单网页版了。
-
这个项目是有service worker的,已经是完整的PWA了。也就是说你第一次打开后,即使是断网,你再访问那个链接,甚至是刷新那个网页,也是能打开的并正常用的(只要你不手动把浏览器缓存清掉,你可以试试。
-
build之后的纯静态html可以在apps\web\dist里面找到(我仓库没给,如果有需要我可以给一份静态的在release里面),只需要在那个目录下起一个http server就可以了比如python -m http.server
-
cli输出二维码没有问题,因为cli的能力借助的是node.js的运行时画的,也就是你先要装node.js,无关终端能力,cmd、powershell、zsh都可以
infrost
(Frost)
6
好问题。
关于被遮挡问题:会下降,下降程度取决于你丢了多少帧以及你在raptorq的参数里设置了多少的repair rate(默认10%,可以调)。
实际上的话,扫码miss是常态发生,在10% repair的情况下,按你说的只是虫子飞过,影响微乎其微,有人经过的情况,基本上也丢失不会很多。10% repair你可以粗略理解为,如果丢了一帧,接下来可以用正常的10帧的冗余可以把这丢掉的一帧通过数学算法恢复出来。如果中间丢掉了很长的一段帧,那就会恢复的比较慢,丢掉太多的话可能需要等待二维码loop回原始帧。
给你个参考,其他的基于fountain code的信息通信项目(像我提到的卫星往地球广播消息),他们大多数设置的repair rate是5%。我个人觉得二维码良好条件下10%,恶劣环境可以试20%-50%。
关于变形问题,这个其实取决于底层zxing库的能力而不是我项目的能力,我可以说的是zxing对这方面的优化还是很不错的,然后可以通过高级设置里面勾选try harder、try rotate(try rotate我记得好像是可以提供倾角大于45度的尝试,小于45度默认就能处理的了)等参数尝试解决,可能会增加CPU占用,在好的设备上表现不会很明显,但是差的设备我确实不知道。我也提供了几个Decode preset(fast到robust,robust为最大解码尝试)可以供实验。
关于对比度问题,同上,这个我可以确定的是现有的解码算法已经非常成熟了,基本上不影响。而且默认的二值化参数是LocalAverage,已经是最稳健的了,大多数情况都能正确处理复杂的光照条件。
但是对于频闪严重的那种老式逐行扫描的显示器来说,影响扫描的不是对比度,而是摄像头有可能在高快门速度下拍出来的二维码是条状的而不是正常二维码,这种情况基本没什么解决办法,因为是网页应用,没办法去访问设备相机硬件调参数。
此外,二维码标准里其实就带了ECC纠错,项目也支持。默认是最低一档,可以调高增加识别率(代价是单张二维码承载信息减少)
1 个赞
shadows
(shadows)
7
第一次打开后
我解释了,完全不连接网络的机器就没法做到打开
能提供html就行
关于终端cli,看来是与win7无缘了…别问为什么还是win7
另外,理论速度是比libcimbar快吗?
jark006
(JARK006)
9
先Star,还没细看。如果只是单向传输,可以简单说说如何保证传输完整的吗,比如漏帧怎么办?
infrost
(Frost)
10
是的,理论速度比libcimbar快,实测也做到了比libcimbar快,但是所有的这类软件落到具体设备上的极限速度可能会有差异。
都按极限速度来算,limcimbar测到的速度是106 KB/s,是一个拿4.5MB的文件用时44秒测出来的。我这里iPhone16实测,相同的44秒,我能传6.5MB的文件,也就是183.6KB/s(这可能还不是上限),大约有1.7倍的速度提升。
更重要的是,limcimbar这个速度只能在原生安卓端测出来,其他端他们的网页版速度更慢。我这里理论上是没有这种设备区别的,因为是纯浏览器的原生实现。
infrost
(Frost)
11
项目用了fountain code算法,具体实现是RaptorQ(RFC6330)标准。
从原理上来讲,您可以理解为这个算法是一个巨大的方程组。对于携带的信息而言,是这个方程组的系数,只要我们能拿到足够多的系数,剩下的方程未知系数可以通过这个方程算出来,从而解决漏帧问题。
项目默认的repair rate为10%,您可以简单理解为如果丢了一帧,接下来可以用正常的10帧的冗余可以把这丢掉的一帧通过数学算法恢复出来。可以提高这个值以获得更强的抗漏帧能力,但是传输速率会下降。
jark006
(JARK006)
12
哦嗷,明白了,和ECC内存、RAID5/6的自动纠错差不多
shadows
(shadows)
14
跑本地服务器还是要多一步,所以找ai给改成输出单文件了
测试了一下,4个二维码,V30以上的码,默认接码设置时识别率好像不高,传输速度反而慢了只有10KB/s多……
速度快一点的也只有40+KB/S
shadows
(shadows)
15
识别时,我发现需要尽量让框对准、占满,又不超出范围……这个网页界面的扫描框略微小了一点,比较影响手机端扫码时控制对准
实际使用时,感觉速度不太稳定,我尝试的大部分时候还是只能低速10KB/S的速度
infrost
(Frost)
16
你有试过同条件下libcimbar的性能吗?这个跟电脑屏幕和扫码端设备关系还是挺大的,需要带上设备信息反馈才能分析的了;另外让改到单文件我不确定worker那边ai是怎么处理的,file: url这种单文件html直接开的方法多线程worker是不支持的,要是ai丢弃了这个或者ai用blob worker处理了但是浏览器不支持(file:// 协议本身各浏览器有细节差异,需要测试),对发送端性能影响是非常可观的,所以抱歉我没法在不控制变量的情况下做performance claim
shadows
(shadows)
17
libcimbar不显示速度,速度也差不多这速度吧,但是不容易出现进度停止或者难以对焦的情况
不知道是不是因为网页调用摄像头的默认分辨率有关?
收发都是用你网站测试的
shadows
(shadows)
18
我又试了一次。
一个3mb的文件。显示器是60hz的。
V25,30fps,2QR,文件分成2k多帧,实际上要接收6k多帧才完成传输,并且越到后面越慢,耗时8min。感觉可能因为重复的帧浪费了很多时间
用libcimbar的话,用B模式,大约2min,整个过程的进度都比较平滑…