神刀安全网

AR 开发小记

前段时间合伙人想做一个早教类的 AR 项目,并且扔给了我一个小册子:

AR 开发小记

大概的功能是:

  • iPad 扫瞄识别右侧的积木
  • 屏幕上出现主角按照顺序执行操作
  • 最后显示运行结果,闯关是否成功

折腾了一段时间,基本做完了上述功能,可以在这里看到演示的效果。

整个项目从第一次提交代码,到最后出演示效果,花了两天的时间,看了下 git commit 累计花了 25 小时(主要是炒股浪费了不少时间,也浪费了不少钱,此处略过不谈)。

看上去最终的开发时间不多,不过前面还是做了不少功课,在此简单的记录一下。

文章中不会涉及任何工具的具体使用过程,所有的基础操作在官方文档里都有详细的讲解。

了解

正式开发之前,先做了一些准备工作,主要是搜索 AR 相关的功能,看看有哪些工具可供使用。一番调研对比和测试之后整理了以下待选方案:

  • OpenCV :计算机视觉库,主要进行右侧积木的识别。
  • Vuforia :可以方便的在软件中实现 AR 功能,主要用于关卡识别和主角模型展示。
  • Python :主要是围绕 OpenCV 的一系列科学运算工具,用于快速开发图像识别功能的原型。
  • Unity3D :一款 3D 游戏引擎,可以很方便的进行 3D 场景搭建。
  • OpenGL :如果不用 Unity3D 就需要在 iOS 项目里基于 Vuforia 手写 OpenGL 实现 AR 功能。

积木识别测试

在正式开发之前,先使用 OpenCV for Python 开发图像识别原型,看看这个项目好不好搞。

在 Jupyter Notebook 里开发图像识别项目真是一种非常流畅的体验:

AR 开发小记

加载图像之后,只需要在新的 Cell 里写图像识别相关的算法就可以了,图像数据已经被加载到了内存里,不需要每次运行都执行全部脚本。然后 OpenCV 进行图像处理, numpy 进行像素运算, matplotlib 展示图像,一条龙服务,十分方便。

具体的图像识别算法不再赘述,上一篇《 使用 OpenCV 识别 QRCode 》里基本都已包含。

iOS App

搞定了积木识别之后,接下来就是做 AR 功能,主要有两个方案可供选择: iOS App 或者 Unity3D 。

先用 iOS App 试一下效果。

Vuforia 官方的 Sample Code 里已经包含了一个可以完整运行的项目,可以下载体验一下。然后用 pod 'OpenCV' 就能装好 OpenCV for C++ ,基本的开发环境就齐全了。折腾了一段时间之后我决定放弃使用 iOS App 的方案,因为实在是太繁琐了。

首先需要一个 ARSession 对象来管理 AR 的相关事务,里面包括了视频的渲染(需要等比拉伸并裁切之后渲染在屏幕上)、资源的回收和处理(比如手机退到后台)、线程切换(绘图需要在主线程)等等;然后需要一个 ARViewController 对象来负责具体页面的显示,里面包括基础资源的加载、识别模型的激活与切换、设备相关的事件监听等等;然后需要一个 ARImageTargetGLView 来渲染 AR 场景,包括 buffer 的维护、model 的加载、shader 的渲染等等。

而最让我崩溃的,是 Swift、Objective-C、C++ 的混写,项目中大量这样的代码:

[self setFramebuffer];
glVertexAttribPointer(vertexHandle, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)buildingModel.vertices);
glEnableVertexAttribArray(textureCoordHandle);
if (offTargetTrackingEnabled) {
glBindTexture(GL_TEXTURE_2D, augmentationTexture[3].textureID);
} else {
glBindTexture(GL_TEXTURE_2D, augmentationTexture[targetIndex].textureID);
}
glUniformMatrix4fv(mvpMatrixHandle, 1, GL_FALSE, (const GLfloat*)&modelViewProjection.data[0]);
glUniform1i(texSampler2DHandle, 0);
glDisableVertexAttribArray(textureCoordHandle);

最后发现写了上千行代码,几十个文件,才只是搭建好了一个基础的 AR 开发环境,还不包括自定义的 3D 效果和自己的业务代码,细思恐极,赶紧放弃。

Unity3D

接下来就是转投 Unity3D 的怀抱。

遇到的第一个问题是如何集成 OpenCV ,通过买买买这个 OpenCV for Unity 插件解决了,它是基于 OpenCV for Java 的,所以接口和 Python C++ 相比略有些变化,不过基本是相同的。在整合 OpenCV 和 Vuforia 的时候看到了 OpenCV for Unity 开发团队的 Voforia with OpenCV for Unity Sample 这个示例项目,再结合自带的 Samples 文件基本就没问题了。

遇到的第二个问题是 Unity3D 中如何处理项目文件的问题,在 iOS 项目里我的项目目录是这样的:

  • General
    • Macro
    • View
    • Extension
  • Section
  • Vendor

在 Unity3D 里,由于项目里不止是代码文件,还包括 fbx 之类的模型文件、 mat 等材质文件、prefab 等预设文件、unity 等场景文件,如果都放在一起十分混乱,很难检索。

参照 iOS 的项目目录,现在 Unity3D 里的项目里是这样安排的:

  • General:全局通用的文件
    • Scripts:通用的代码文件
      • Class:自定义的通用类
      • Extension:基础模块的扩展,比如 List 的方差运算等等
      • Static:静态工具类
  • Section:业务相关的文件,一个场景一个文件夹
    • Scene1:具体场景的文件夹,包括所有该场景下的资源
      • Scripts:该场景所需的代码
      • Prefabs:该场景内的预设对象
      • Resources:该场景下的其他资源
        • Materials:该场景下的材质

基本上单个场景的目录结构和 General 的目录结构是一致的, General 像是所有场景的『基类』。

遇到的第三个问题是 OpenCV 绘图如何处置的问题。我希望能够将 OpenCV 的一些 Debug 信息绘制在屏幕上,比如找到的 contours 、比如计算出的方差/均值、比如画面里的积木总数等等,可以很方便的了解图像识别的情况,找到出现问题的原因。本来是通过注释掉绘图代码的方式进行状态切换,后来发现实在是太麻烦了,于是在所有的 OpenCV 绘图方法外面套了一层,放在 CVUtil 里:

public class CVUtil {
public class Draw {
public static void Text(Mat mat, string str, double x, double y,
double fontScale = 1, Scalar color = null,
LogLevel level = LogLevel.Debug) {
if (level >= Global.CurrentLogLevel) {
Imgproc.putText (mat, str, new Point (x,y), Core.FONT_HERSHEY_PLAIN, fontScale, color);
}
}

public static void Rectangle(Mat mat, OpenCVForUnity.Rect rect,
Scalar color = null, int thickness = 1,
LogLevel level = LogLevel.Debug) {
if (level >= Global.CurrentLogLevel) {
Imgproc.rectangle (mat, rect.tl (), rect.br (), color, thickness);
}
}
}
}

然后这样只要切换全局变量 Global.CurrentLogLevel 就能控制 Debug 内容的显示和隐藏了。

整个 Unity3D 项目里,AR 相关的渲染完全不用操心,只需要把 Vuforia 里的 ImageTarget 这个 Prefab 脱拽到场景中就能实现基础的 AR 功能。

小结

就简单的写这么多啦,没什么干货,只是简单回顾一下自己的开发过程。

AR 开发的技术门槛并不是很高,目前现成的 SDK 很多,可以自行选择。而如何通过 AR 做出有趣的产品,这才是核心所在。

玩得开心。

转载本站任何文章请注明:转载至神刀安全网,谢谢神刀安全网 » AR 开发小记

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址