一种基于动态二维码的近场通信系统
2021-05-12袁林张秀萍
袁林,张秀萍
(中国地震局第二监测中心,西安710054)
0 引言
由于二维码在传输数据上的便捷性,越来越多的非接触式近场通信使用了二维码作为传输介质,但是二维码的数据容量有限,在支付、信息校验[1]、物理隔离环境通信[2]等方面得到了广泛应用,当传输数据量增大,二维码图幅及密度随之增大,对识别设备要求增高,大到一定程度,普通移动终端很难识别或识别时间无法接受,这也限制了二维码在大数据量传输方面的应用。目前也有一些系统尝试解决基于二维码传输大数据量的问题,一种基于二维码的大数据量传输方式[3]利用图像处理技术解决大数据量二维码的识别问题,但系统依赖服务器中发布的图像处理算法,系统较为庞大,实施较为复杂;QRStream:一种基于二维码流的健康数据传输方法[4]以及一种移动终端可见光数据收发系统[5],是将传输的大量数据进行分割,利用多个二维码分块传输数据,接收端识别后将分块数据进行拼接,以上两个系统利用连续分片方式生成动态二维码,在数据块较多时容易出现漏帧现象,接收方必须循环读取动态二维码以确保接收所有的数据分块,传输效率很低;基于二维码的内外网物理隔离环境下的数据交换[6]中利用Protocol Buffer 格式和LZMA 压缩算法将要传输的数据进行简化与压缩,降低传输的数据量,在数据量逐渐增大时效果并不理想。由于传输效率较低,以上系统均面对文字传输,无法传输图片等多媒体数据,应用范围受限,本系统以图片传输为例,实现较大数据量的高效传输。
1 理论基础
数字喷泉码概念由J.W.Byers 和M. Luby 于1998年提出[7],M.Luby 在2002 提出了第一种实用数字喷泉码,被命名为卢比变换(LT)码[8]。之后,Shokrollahi 又提出了性能更佳的Raptor 码[9]。所谓数字喷泉码,是指发送端可以由k 个原始分组生成任意数量的编码分组,接收端只要收到其中任意ε个编码分组,即可通过译码以高概率恢复全部原始分组。编码过程如源源不断产生水滴的喷泉,译码过程如用杯子接收水滴,数量足够即可完成译码。数字喷泉码不存在码长n 的定义,或者说码长趋于无穷大;码率R=k/n的定义也不存在,因此数字喷泉码也被称为无率码(Rateless Codes)[10]。
LT 码首次将度分布函数应用到喷泉码上,LT 码的编码过程为:每次选择数个原始分组进行异或运算,计算结果为编码分组,进行运算的原始分组个数称为编码分组的度(Degree),用d 表示。每个编码分组的度是随机产生的,由度分布函数ρ(d)确定。假设原始分组的数量为k,对度分布函数ρ(d)进行采样得到d;从k 个原始分组中随机选择d 个进行异或运算得到编码分组;重复以上步骤,不断生成编码分组直到接收端完成译码。译码时,由于度分布函数必然会产生d 为1 的编码,称之为单源编码块,将单源编码块与d 为2 的编码运算后可得出原始分块数据,继续运算,将所接收到的d 大于1 的编码解析,拼接出原始数据后译码停止。
2 系统构成
2.1 系统概述
系统由数据发送端与数据接收端两部分组成,数据发送端包括图片上传、Base64 转码模块、数据分片模块、动态二维码生成及播放模块,由于系统采用连续编码与喷泉码编码相结合的方式,所以分片模块分为连续分片与喷泉码分片两种实现方式;数据接收端包括二维码扫描与解析模块、数据合并模块、Base64 逆转码模块、原始数据展示模块,与发送端相对应,数据合并也分为连续解码合并与喷泉码解码合并两种实现方式,系统构成如图1。
图1 系统构成
2.2 数据流向
系统发送端是由C#开发的PC 界面应用,用于生成动态二维码并播放,接收端是由Java 语言开发的Android 应用,用于动态二维码的识别、解析、数据的合并与展示。对于Base64 数据与二维码的转换系统采用ZXing 库来开发,Base64 数据的分块是本系统开发的重点,分为连续分片方式与喷泉码分片方式,具体实现将在第三部分介绍,系统数据流向如图2 所示。
图2 数据流向
3 关键技术实现
3.1 连续分片方式的实现
发送端应用界面上传图片时,用户可设置输出的动态二维码的单帧容量、播放频率。动态二维码生成时间与图片大小成正比,图片上传成功后系统首先将图片转换为Base64 编码数据,并将其作为分片的原始数据。动态二维码生成步骤描述如下:
定义图片数据为data,Base64 源始数据为str,用户输入的单帧容量为chunkLen,播放频率为fps;
步骤1:转换data 为Base64 格式数据str;
步骤2:计算str 长度len;
步骤3:计算分块总数量num,
3.1 若len%chunkLen>0 则num=len/chunkLen+1;
3.2 若len%chunkLen<=0 则num=len/chunkLen;
步骤4:计算分块数据ret,
4.1 定义分块数据ret 在原始数据str 中的起点位置为start,赋初始值0,数据长度为chunkLen,终点位置为end,end=start+chunkLen,最后一块数据的终点位置同str 的终点位置,值为len,第一块数据ret1=start/len|str[start:end],“start/len”为数据头部信息;
4.2 当start 小于或等于len 时,start=start +chunkLen 转到4.1;
4.3 当start 大于len 时,返回所有分块数据;
步骤5:根据分块数据的值生成num 个二维码图片;
步骤6:根据用户输入的fps,设置二维码播放频率,最终生成gif 动图文件;
步骤7:播放gif 文件,在发送端循环展示动态二维码。
至此发送端所有流程结束,其中start 为分块数据在原始数据中的偏移量,该量用于接收端拼接数据时确定分块数据的位置。
接收端扫描并将二维码解析为字符串,之后转换为Base64 数据。连续分片方式中发送端产生的二维码需要全部被接收才能拼接出原始数据,步骤描述如下:
定义变量cache 存储start 值,用于判断当前识别到的二维码数据是否已接收,定义可变长度变量frames 存储接收到的分块数据,
步骤1:扫描单张二维码并解析为Base64 数据data;
步骤2:读取data 头部数据中的start 值,
2.1 若start 已存储在cache 中则转到步骤1;
2.2 若start 未存储在cache 中则存储;
步骤3:根据分块数据偏移量start 将数据存入frames 中;
步骤4:计算frames 的数据长度size,与头部数据中的总长度len 进行比较,
4.1 若size 小于len 则转到步骤1;
菊花喜欢阳光,如果缺乏阳光的时候,开花就比较晚一些。在夏季菊花不宜生长在烈日下,因为烈日容易灼伤花瓣。菊花喜欢湿润的土壤,如果土壤十分干旱就会造成生长比较慢,如果水分过多,就会造成根部腐烂,所以对菊花的所生产的土壤要保持湿润。另外在菊花的生长过程中,需要对病虫加强防治,因为空气潮湿会增加病虫害的发生。
4.2 若size 等于len 则返回frames;步骤5:将frames 中的Base64 数据转换为图片,并在移动端应用中展示。
接收端识别单张二维码需要一定的时间,播放频率过快时会漏掉部分序列,发送端循环播放使接收端能够在多次读取中识别完整的序列。
3.2 喷泉码分片方式的实现
喷泉码的编码与译码利用了Google 开发的gofountain 包,该包使用Go 语言实现了Luby 变换,包中的EncodeLTBlocks()函数用于生成LT 编码。函数为:
func EncodeLTBlocks(message []byte, encodedBlockIDs []int64,c Codec)[]LTBlock
第二个参数encodedBlockIDs 确定了gofountain 包中度分布函数的随机种子范围,encodedBlockIDs 的值也是最终生成二维码的个数,理想情况下,解析出N 个原始数据块使用的二维码个数应小于N,但考虑到传输噪声,跳帧等情况,需要设置一定的冗余来确保解析效果,本系统利用冗余因子方法,设定encodedBlock-IDs=N*redundancyFactor,经测试冗余因子redundancy-Factor=2 时满足系统的传输效率。喷泉码分片方式与连续分片方式的实现只有第四步与不同,步骤描述如下:
步骤4:将Base64 数据str 与encodedBlockIDs 作为第一、第二参数传入EncodeLTBlocks,函数返回LT码数组ret。分块数据ret 的头部信息为i/chunkLen/len,i 为LT 码的序号,初始值为0,最大值为encoded-BlockIDs,chunkLen 为用户设定的单帧大小,len 为原始数据总长度。
由于LT 解码时必须先找到单源编码块作为运算的基础,若单源编码块过少会使算法寻找时间过长,过多会损失冗余度。gofountain 包中Luby 变换的度分布函数会产生足够多的单源编码块,同时会产生大量的双源编码块以及一定数量的多源编码块,符合泊松分布确保解析出所有的原始数据。
对于喷泉码分片方式,接收端应用只需获取到部分序列即可拼接出完整的原始数据。接收端依然利用了gofountain 包,具体步骤如下:
步骤2:调用gofountain 函数Decode()传入数据data,Decode()函数将解析出的数据存入frames,并更新completed 变量completed=已获取的数据长度/len*100;
步骤3:调用gofountain 函数IsCompleted()判断completed 变量是否为100,100 表示解析完毕,
3.1 IsCompleted()值为true,解析完成,返回frames变量;
3.2 IsCompleted()值为false,解析未完成,转到步骤1;
步骤4:将frames 中的Base64 数据转换为图片,并在移动端应用中展示。
3.3 连续分片与喷泉码分片方式切换
使用红米Note 5A,Android 版本7.1.2 对数据传输进行测试,单帧容量越大,播放速率越快,二维码的识别效率越高,但单帧容量大于1000,播放频率大于6 时测试机很难识别出单张二维码的信息。设置单帧容量1000,播放频率6 进行两种分片方式的传输效率测试,结果如图3,可以看出当数据达到16k 时,连续编码方式传输时间超过10 秒,用户体验非常差,随着数据量的增大,传输时间将不断增长。喷泉码方式在数据量较小时传输效果较差,但大于4k 时传输时间稳定在4秒以内。
图3 数据传输效率
根据测试结果设计程序,以4k 为阈值,发送端判断上传图片大小,若小于4k 时,以连续分片方式生成动态二维码,大于4k 时以喷泉码分片方式生成,接收端识别到第一张二维码时判断头部信息,若包含一个“/”则调用连续分片的解码函数,若包含两个“/”则调用喷泉码分片的解码函数。发送端运行流程如图4,接收端运行流程如图5。
图4 发送端流程
图5 接收端流程
3.4 实验效果
通过图6 所示界面上传图片,设置单帧频率为1000,播放频率为6,测试1k 到100k 的图片传输,结果如图6。续分片方式也就是目前使用广泛的动态二维码生成方式,平均速率为2kb/s,本系统引入喷泉码分片方式,平均速率可以达到15kb/s,速率提升了7.5 倍,可以使基于二维码的近场通信在图片等多媒体信息传输方面有更广泛的应用。
图6 据传输效率测试结果
4 程序运行界面效果
发送端应用如图7,过“浏览”按键选择要上传的图片,用户可设置输出序列的单帧容量、播放频率,由于应用界面大小有限,二维码尺寸取一个合适的默认值,不允许修改。图片上传成功后点击“生成二维码”按键,应有右侧播放框中即可播放动态二维码。
图7 发送端应用界面
接收端应用如图8,点击“扫描”按键程序调用摄像头进行二维码识别,连续识别动态二维码直到数据接收完成,拼接数据后显示接收到的图片。
图8
5 结语
本文给出了基于连续分片方式与喷泉码分片方式相结合的动态二维码生成与解析方法,在传输小数据量时使用效率相对较高的连续分片方式,数据量较大时使用喷泉码分片方式,有效地解决了现有动态二维码编解码时间与数据量成正比的问题,显著提高了传输效率。对目前已有的基于二维码的近场通信系统有较大改进,具有实际意义。