扫描的那一瞬间,手机里正在发生什么
仅仅 1 秒之间,7 个处理接连跑完
把手机摄像头对准黑白的图案,约 1 秒后链接指向的页面便打开了。就在这 1 秒之间,手机内部有 7 个处理以极高的速度依次执行:(1)摄像头拍下一帧画面,(2)从图像中检出图案的候选区域,(3)确定三个定位图案,据此算出位置与倾斜,(4)把图案分割成网格,逐格判断黑白,(5)把二进制数据换算成字符串,(6)用纠错修复受损的数据,(7)识别出这是网址,启动浏览器。
这些处理由手机的中央处理器与图像处理芯片分工完成。在一般的手机上,摄像头每秒拍摄 30 至 60 帧,并对每一帧实时尝试检测图案。也就是说,从举起摄像头的那一刻起,每秒就有 30 至 60 次「寻找图案」的处理在跑。
步骤 1 至 2:拍摄与候选区域的检出
摄像头拍下的图像,是数百万个像素的集合。要从其中找出图案所在的位置,首先要把图像转换成黑白两色,这一步叫作二值化。接着,把黑色像素密集聚集的区域检出为「图案的候选」。
这个处理中最关键的是「对比度」。白底上清晰地印着黑色图案时,候选区域的检出一瞬间就能完成。可是在昏暗的地方,或者图案的颜色偏浅时,白与黑的界线变得模糊,检出便会耗时,甚至失败。之所以常被提醒「请在明亮的地方扫描」,就是为了提高这一步的精度。
步骤 3 至 4:位置的确定与网格分割
找到候选区域后,接下来要寻找三个定位图案,也就是那三个大的方形标记。从这三者的位置关系,可以算出图案准确的位置、大小与倾斜角度。斜着扫描也读得出来,正是因为这一步的计算把倾斜校正掉了。
位置确定之后,把整个图案像棋盘的格子那样分割成网格,逐格判断是白还是黑。这个判断并不是单纯地看「亮还是暗」,而是拿周围的格子作比较,按相对的明暗来定。照明不均匀时依然能准确读取,靠的就是这种相对判断。
举个例子:图案的左半边落在窗边的阳光下,右半边留在阴影里,这时整张图像里「亮」的绝对数值差得很远。若只按一个统一的门槛判断,阴影侧的白格就会被误判成黑。改成与相邻格子相比较,明暗的落差在局部依然成立,判断因此不会乱。
步骤 5 至 6:解码与纠错
黑白的判断结果会变成 0 与 1 的序列,也就是比特串。按照图案的规格,把这串比特换算成字符串,这一步叫作「解码」。开头的若干比特里记录着数据的种类(数字、英数字、汉字等)与长度,解码器先把这部分读出来,再去换算数据本体。
与解码同时进行的,还有纠错的处理。因污渍或划痕而有部分格子未能正确读出时,就用备用的数据,也就是纠错码,把原本的数据复原回来。这一处理基于名为里德-所罗门码的数学算法,按规格,在纠错等级最高的设置下最多可以从 30% 的损坏中复原。
一瞬的处理造就体感
从把相机对准码到目标页面打开,我们只感到短短一瞬。然而其背后,拍摄、发现图案、确定位置、读取明暗、纠正错误、识别网址等诸多处理在依次运行。正因为这些毫无停滞地衔接起来,我们才几乎不会怀有被等待的感觉。若在某一处处理上绊住,读取便会失败,需要重来。不经意的一瞬的舒适,由内部精确累积起来的处理之链所支撑。
读不出时背后发生的事
读取不顺利时,智能手机内部,处理的某一处未能完成而停了下来。找不到图案、位置定不下来、分辨不出明暗、信息缺失到无法纠正。原因各异,但都是在一连串处理的某处绊住的状态。正因如此,稍微改变距离、调整明亮度、或擦去码上的污渍,停住的处理便会向前推进,读取便会成功。把读不出的现象,理解为内部正在发生的处理的中断,便更容易找到应对的头绪。
步骤 7:识别网址与启动浏览器
解码出的字符串若是网址,也就是以 https:// 开头的字符串,手机的操作系统便会识别出来,启动浏览器打开那个页面。若是网址以外的数据,例如电话号码、邮件地址、Wi-Fi 信息、纯文本,则会各自启动对应的应用。
在 iPhone 上,相机应用检测到网址时,屏幕上方会显示一条黄色的横幅,点一下便打开浏览器。在 Android 上,各机型的表现不尽相同,多数情况下会自动启动浏览器。连这最后一步都算进去,全部处理仍能在 1 秒以内跑完,这体现出智能手机的处理能力之高。