如何在微信小程序里玩转 AR

写在前面的话

公众号上次发了一个小小的 DEMO 视频,演示了小程序如何识别目标图像,并加载 3D 模型的效果。

然后,感兴趣的朋友们就开始催更了。本篇文章算是对之前的一些尝试做一个总结,给对这个方向感兴趣的朋友提供一些思路。

不过,本文不会过多阐述具体的原理,感兴趣可以看下 AI Pocket 的开源实现。

代码移植过来比较仓促,基本没有考虑工程化的最佳实践,相信阅读起来也是比较痛苦。后续是否会优化,取决于我是否会以此做些商业化的实践,以及是否有更多的业余时间。

注:对实现过程的流水帐不感兴趣的同学,直接拉到最后看原型效果和小结即可

背后的价值

如果一件事情,短期和长期都看不到价值,那就没有尝试的必要

就挺无聊

不知道大家在平时生活中,有没有一种被「无聊」氛围笼罩的感觉:一切好像都是在重复,没有啥新鲜的玩法。

玩的手游趋同化严重,换了个地图和皮肤,改了改规则就是一个新游戏;商场与商场间的差异性不大,都只不过是逛逛买买;景点设计也像是出自同一人之手,尤其是一些打着古镇旗号的商业街。

AR 怎么了

这和 AR 有什么关系?

AR 是 Augmented Reality 的缩写,中文含义为增强现实;与之紧密相关的还有 VR(Virtual Reality),意为虚拟现实。

注:除此之外,还有 MR/XR 等名词,此处不展开

Augmented reality (AR) adds digital elements to a live view often by using the camera on a smartphone.

Virtual reality (VR) implies a complete immersion experience that shuts out the physical world.

简单地说,AR 是利用手机等辅助设备,把虚拟的物体/场景融合到现实世界中;而 VR 则是完全模拟一个虚拟的世界,让人沉浸其中,比如世面上有很多 VR 眼镜。

由于 VR 往往需要专门的设备(而且通常价格不低),无法大规模应用。但 AR 就不一样了:几乎人人都有手机,而且手机性能一代更比一代强,在手机端运行 AR 应用通常不是问题。举几个例子:

AR 名片

你有没想过,个人名片也可以像这位老哥一样骚包?

AR名片

AR 教材

小朋友的教材平平无奇?那如果可以来个 360 度无死角的 3D 观赏模式呢?

AR教材

AR 游戏

还记得小时候玩的卡牌游戏吗?如果每张卡牌的小宠物都可以动起来,是不是很奇妙?另外,说到 AR 游戏,不得不提任天堂出的「Pokémon GO」。

AR游戏

注:以上提的几个应用来自 10 inspiring examples of Augmented Images

AR 营销

AR 营销相比其它几个领域,要更为常见。比如丝芙兰 AR 虚拟试妆、宜家新购物 App、可口可乐变身音乐播放器等等。

注:可以从 什么是AR营销? 了解更多有趣的应用

为何是微信小程序

从以上举的这几类例子来看,它们都有一个特点:不是必须品。

也就意味着,用户没有安装 APP 的强烈意愿,更多地希望可以用完即走。

小程序恰好具备这种特性,而微信具备庞大的用户基数,且其社交属性会给裂变效应带来可能,作为 AR 轻应用的主战场,则再合适不过。

问题和难点

AR 与 AI

AR 一般无法脱离 AI 技术单独存在,比如上篇公众号文章的视频中的示例,我们首先要识别出目标物体,然后还要计算出目标物体的坐标变换,进而加载和变换 3D 模型。其中的目标物体识别,就少不了一些 AI 领域中的图像识别、图像追踪等手段。

图像识别、图像追踪等机器视觉技术其实早就非常成熟,近年来也涌现出很多 WEB 端的 SDK/应用,比如 tracking.js、jsfeat、ar.js 等等。

但是,它们无一例外地是面向 Chrome 等标准 WEB 浏览器,小程序的定制版运行环境根本无法直接运行。举个例子:大多数的库都依赖了 Document、XMLHttpRequest、Worker 等接口/全局变量,恰好都是小程序不支持的。

WebView 不可以吗

使用 WebView 内嵌网页,网页直接使用现成的 SDK 固然降低 AR 的实现成本,但与此同时带来的是更高的使用门槛、更高的互动开发成本:

  1. 个人类型的小程序暂不支持使用 web-view 组件
  2. 需要使用 JSSDK 与小程序互动(仅支持部分接口),开发模式变化较大

咋解决呢

一个字:改!

展开描述一下,就是找到最适合移值到小程序的 SDK,有办法简单适配最好,否则就是弄懂代码后魔改,然后移植到微信小程序环境。

探索和突破

小目标

方向确定了,接下来要定一个小目标:实现一个 Demo,能够识别指定的图案,在图案上加载 3D 模型,并且图案运动时,3D 模型也要跟随。

目标分解和关键技术

主要难点

小目标包含两个关键点:

  1. 目标识别和追踪
  2. 3D 模型加载和变换

其中,3D 模型的加载和变换是比较成熟的,可以使用 Three.js 实现,官方和民间都有适配库可以选用,这点更多是体力活,还不算是技术上的难点。所以,本次小目标的实现难点主要在于目标识别和追踪。

对 AI Pocket 小程序有了解的朋友应该都知道,这是一个主打 tfjs & 神经网络模型的小程序,包含了一些常见的图像识别示例,比如 COCO-SSD。

一开始,我也是想的使用 SSD 模型实现目标识别和追踪。但很快,我就打消了这个念头:模型需要大量的训练数据来保证准确性,且模型体积(即使裁剪后)也比较大,不太适合在小程序端运行。

柳暗花明又一村

就在一筹莫展的时候,我研究了下 AR.js 这个库的文档,发现它提到了 marker based image tracking 这么个关键词,然后顺着线索发现了 jsartoolkit5 这个宝藏库,给困境中的我带来了希望。

jsartoolkit5 是 ARToolKit 的 JS 实现,支持以下几种图像识别和追踪:

JSARToolKit5 support these types of markers:

  • Square pictorial markers
  • Square barcode markers
  • Multi square markers set
  • NFT (natural feature tracking) markers

其中,NFT 刚好能满足我的需求:基于它,可以在不使用神经网络模型的前提下,实现任意图片的识别的追踪。

抄谁的作业

顺着 NFT 这个关键词,我找到了一些看上去还不错的实现,经过代码和文档的粗看,最终只有两个选手角逐到最后:JSARToolKitNFTmind-ar-js

JSARToolKitNFT 是 jsartoolkit5 的轻量版,使用 TS 开发,仅保留 NFT 能力,通过 WASM 把底层实现包装起来,外层代码其实较少,代码比较容易读懂。

mind-ar-js 则是纯 JS 实现了 NFT 的功能,基于 tfjs 加速了某些耗时的运算,但是代码的组织确实有些混乱(且注释不足),需要非常集中精神(且有一定的机器视觉背景知识)。

功能相近的情况下,代码越清晰易懂,则越易于改造。所以我首选 JSARToolKitNFT 来尝试,但不久就宣告失败了:

  1. 小程序的 WASM 能力要求 wasm 文件必须在代码包内,而这个文件以后指不定就超出小程序上限(2M)
  2. JSARToolKitNFT 默认把 WASM 编译成了一个 JS 文件,但小程序依赖 wasm 文件和 imports 变量

在尝试 mind-ar-js 移植的过程中,因为代码实在是太绕了,我曾经想过再次挑战下 JSARToolKitNFT 的 WASM 编译,但依然没有成功,就只好暂时作罢。

漫长的魔改

在选定 mind-ar-js 之后,我就开始了漫长的魔改(国庆假期也在尝试)。一边阅读理解,一边修改,主要改动的几个地方:

  1. 改为 TS 编写,尽可能得补齐变量类型 & 纠正错误
  2. 找到所有依赖 Document、Fetch 等 API,根据小程序环境做适配
  3. 找到所有和 AI Pocket 使用的 tfjs 版本中不一致的 API,做相应调整
  4. 修改原库的 worker 代码
  5. 修改原库的视频/图像数据处理代码
  6. 将原库中使用 A-Frame 渲染 3D 模型的逻辑,改为基于 three.js 实现

这种大批量的修改,是非常难受的,因为效果出不来的时候,你不确定是库的问题,还是改出来的问题,还是小程序环境的问题。

而且刚开始改,都是可以称为魔改,一心只为实现小目标,哪管可维护性,根本谈不上什么工程化实践,所以现在的代码依然非常难懂。

粗糙的原型

经历艰辛的魔改过程,原型总算是出来了,直接看下效果吧。

card

总结

AR 可以给游戏、教材、营销等等场景赋予新的玩法,微信作为一款国民级应用,如果能在小程序中加持 AR,会是一个新的爆点。

但是很可惜,小程序没有提供 AR 相关的 API,需要开发者自行实现。而目前市面上的 AR 库多数针对的标准 WEB 运行环境,微信小程序没有办法直接使用。

很幸运的是,我通过一系列的努力,在微信小程序中实现了图像识别与追踪,并在其基础上成功加载了 3D 模型,实现了一个粗糙的 AR 原型,证明了这个想法的可行性。

小字:这里有未来的财富密码,你学废了吗?