【AR实验室】mulberryAR : ORBSLAM2+VVSION
本文转载请注明出处 —— polobymulberry-博客园
0x00 - 前言
mulberryAR是我业余时间弄的一个AR引擎,目前主要支持单目视觉SLAM+3D渲染,并且支持iOS端,但是该引擎也能很方便地移植到Android端。slam模块使用的是ORB-SLAM2,3d渲染模块使用的是VVSION渲染引擎。该引擎目前实现的功能为简单的3D模型摆放,用户可以对3D模型进行平移、旋转和缩放。
先放两张mulberryAR的效果图。


0x01 - 单目视觉SLAM模块
单目视觉SLAM模块采用的是ORB-SLAM2。ORB-SLAM2是目前比较优秀的视觉SLAM系统,其输入为图像视频流,通过SLAM计算出每帧图像对应的相机位姿以及一些特征点对应的3D位置。不过mulberryAR目前只用到了每帧对应的相机位姿。
目前mulberryAR对ORB-SLAM2没有做过多的修改,但是为了集成进mulberryAR中,需要对ORB-SLAM2的接口做出一些修改以适应iOS系统的移动设备。这一部分主要参考两份资料:
- ORB_SLAM_iOS ORB-SLAM在iOS上的移植,作者去除了ORB-SLAM对ROS的依赖,并使用了iOS的Metal和Scene Kit进行渲染。相比ORB-SLAM2,还需要依赖boost库。
- ORB-SLAM2注释版 作者对ORB-SLAM2进行了详细地注释,添加了BoW(Bag of Word)的二进制文件加载方式。
修改1:ORB-SLAM2里面使用了BoW(Bag of Word)进行特征匹配。其中的BoW是通过加载ORB-SLAM2原始文件中的ORBvoc.txt获取的,不过移动端直接加载ORBVoc.txt文本文件来构建BoW非常耗时,在iPhone5s上要几分钟时间。使用ORB-SLAM2注释版中Vocabulary/bin_vocabulary.cpp可以将ORBVoc.txt转换为ORBVoc.bin。然后使用该版本DBoW2和g2o替换ORB-SLAM2中的DBoW2和g2o,ORB-SLAM2注释版里面的/Thirdparty/DBoW2/DBoW2/TemplatedVocabulary.h添加了loadFromBinaryFile函数,可以直接加载ORBVoc.bin,在iPhone5s上加载的时间也降到小于3秒钟。
修改2:ORB-SLAM2源码中的示例获取图像视频流的方式是通过解析预先处理好的视频文件,而mulberryAR需要通过iPhone设备实时捕捉图像视频。这里需要使用iOS的视频捕捉模块。一开始捕捉方式参考了我之前的博客【AR实验室】OpenGL ES绘制相机(OpenGL ES 1.0版本)中的0x02 - AVCaptureSession获取拍摄内容小节。获取到了图像就可以调用ORB-SLAM2中的System::TrackMonocular函数求解位姿。注意TrackMonocular很耗时,所以我们构建一个DISPATCH_QUEUE_SERIAL类型的线程,并将TrackMonocular抛给它。另外在主线程dispatch_get_main_queue()中利用TrackMonocular得到的相机位姿进行绘制。
修改3:图形学中绘制有一个很重要的矩阵:模型视图矩阵ModelView,就是将3D模型从模型局部坐标系转化到相机坐标系的一个转化矩阵。注意TrackMonocular函数返回的Tcw需要一定的转化才能作为模型视图矩阵,这一步完全参考了ORB_SLAM_iOS中的处理方式,因为我也不是很清楚为何要如此处理,尤其是两处取负号的部分,所以此处将代码列出供大家参考。
// poseR = mCurrentFrame.mTcw.rowRange(0,3).colRange(0,3);
// 当前帧变化矩阵的旋转部分
cv::Mat R = _slam->getCurrentPose_R();
// poseT = mCurrentFrame.mTcw.rowRange(0,3).col(3);
// 当前帧变化矩阵的平移部分
cv::Mat T = _slam->getCurrentPose_T(); // 将旋转矩阵转化为四元数,注意qy和qz的取了负号。
float qx,qy,qz,qw;
qw = sqrt(1.0 + R.at<float>(,) + R.at<float>(,) + R.at<float>(,)) / 2.0;
qx = (R.at<float>(,) - R.at<float>(,)) / (*qw);
qy = -(R.at<float>(,) - R.at<float>(,)) / (*qw);
qz = -(R.at<float>(,) - R.at<float>(,)) / (*qw);
// 将四元数转化为旋转矩阵,即r1、r2、r3。并且将平移矩阵填充到r4。
// 注意其中T.at<float>(1)和T.at<float>(2)取了负号。
vec4f r1( - *qy*qy - *qz*qz, *qx*qy + *qz*qw, *qx*qz - *qy*qw, );
vec4f r2(*qx*qy - *qz*qw, - *qx*qx - *qz*qz, *qy*qz + *qx*qw, );
vec4f r3(*qx*qz + *qy*qw, *qy*qz - *qx*qw, - *qx*qx - *qy*qy, );
vec4f r4(T.at<float>(), -T.at<float>(), -T.at<float>(), );
0x02 – 3D渲染引擎模块
3D渲染引擎模块使用的是VVSION渲染引擎。选择这款渲染引擎也是尝试过很多其他渲染方式才决定的,主要代表为cocos2d-x、vvsion和原生opengl es。下面对着三种方式的优缺点进行对比。
| cocos2d-x | vvsion | 原生opengl es | |
| 优点 | 1.支持的渲染组件很丰富,基本不需要后期添加新的功能 | 1.相对于cocos2d-x整体轻巧,易于集成和二次修改。 2.可以直接传递模型视图矩阵,不要进行转化。 |
1.完全可以根据自己的需求开发出相应的模块,不会困于已有的功能模块。 |
| 缺点 | 1.体积较大 2.我们此处获取到的为原生的模型视图矩阵,怎样直接把模型视图矩阵传递给cocos2d-x的绘制模块就成为了一个难题。我尝试了很多方式都没有成功,可能因为本身对cocos2d-x不是特别熟悉,所以放弃。 |
1.没有cocos2d-x的功能多 | 1.工作量巨大! |
vvsion本身支持一些简单的渲染功能,比如模型的导入和渲染,使用的是opengl es 2.0。不过还存在几个缺陷,mulberryAR对此进行了优化。
修改1:它本身提供的模型渲染过于简单,只是简单的贴图,此处mulberryAR在原始shader中添加了diffuse功能,主要是将模型的法向传入,做光照处理。
// vertex shader
attribute vec4 position;
attribute vec2 texCoord0;
attribute vec4 normal; varying vec2 v_texCoord;
varying vec4 v_normal; uniform mat4 matProjViewModel;
// ModelView.inverse().transpose()
uniform mat4 matNormal; void main()
{
v_texCoord = texCoord0;
v_normal = matNormal * normal;
gl_Position = matProjViewModel * position;
} // fragment shader
precision highp float; uniform sampler2D texture0;
varying vec2 v_texCoord;
varying vec4 v_normal; void main()
{
gl_FragColor = texture2D( texture0, v_texCoord);
vec3 lightDir = vec3(0.0, 0.0, 1.0); // 假设光照方向
// 求解diffuse
float dotRes = dot(normalize(v_normal.xyz), normalize(lightDir));
float diffuse = min(max(dotRes, 0.0), 1.0);
gl_FragColor.rgb = vec3(diffuse * gl_FragColor.rgb);
}
修改2:获取到的相机图像需要进行显示,此处,mulberryAR使用了贴纹理的方式进行渲染。我们使用了一个camera.obj的平面模型作为相机图像的展示平面,只需每次将camera.obj的纹理更新为相机图像即可。此处需要注意一下两点:
- camera.obj的显示使用的是正投影,并且注意其深度值设置大一点,避免遮挡住了前面的模型。
- NPOT(No Power of Two)纹理的设置选项,其中Wrap方式要设置为GL_CLAMP_TO_EDGE,Mag/Min Filter方式设置为GL_LINEAR,并且不要产生MinMap。否则纹理会显示为黑色。
修改3:为了提高模型的真实感,增加了fake shadow的效果,就是在模型底部添加一块圆形的阴影。就是在模型底部添加了一个fakeshadow.obj的模型,然后贴上透明的圆形阴影纹理。优点是简单,节省计算资源,并且还不需要考虑真实的光照方向。
0x03 - mulberryAR性能效果分析
视频效果展示(腾讯视频链接):
mulberryAR Demo:https://v.qq.com/x/page/c03635umclb.html
mulberryAR在iPhone5s上Release版本测试为6FPS。可见其帧率还无法令人满意,主要是提取ORB特征这一步耗时比较多,后期会再此基础上做一定优化。下表中ExtractORB表示每帧ORB特征提取的耗时,TrackMonocular为每帧的整个SLAM系统的耗时。

另外,ORB-SLAM2的初始化很快,丢失后也能快速找回。整体来说,算是目前最好的单目视觉SLAM了。
0x04 - 参考资料
- ORB-SLAM2
- ORB_SLAM_iOS
- ORB-SLAM2注释版
- VVSION渲染引擎
- 【AR实验室】OpenGL ES绘制相机(OpenGL ES 1.0版本)
- https://zhuanlan.zhihu.com/computercoil
【AR实验室】mulberryAR : ORBSLAM2+VVSION的更多相关文章
- 【AR实验室】mulberryAR:并行提取ORB特征
本文转载请注明出处 —— polobymulberry-博客园 0x00 - 前言 在[AR实验室]mulberryAR : ORBSLAM2+VVSION末尾提及了iPhone5s真机测试结果,其中 ...
- 【AR实验室】mulberryAR :添加连续图像作为输入
本文转载请注明出处 —— polobymulberry-博客园 0x00 - 前言 之前mulberryAR只能利用手机相机实时捕捉图像作为系统的输入,这也比较符合用户的习惯.但是在开发的过程中,有时 ...
- 【AR实验室】OpenGL ES绘制相机(OpenGL ES 1.0版本)
0x00 - 前言 之前做一些移动端的AR应用以及目前看到的一些AR应用,基本上都是这样一个套路:手机背景显示现实场景,然后在该背景上进行图形学绘制.至于图形学绘制时,相机外参的解算使用的是V-SLA ...
- 【AR实验室】ARToolKit之制作自己的Marker/NFT
0x00 - 前言 看过example后,就会想自己动动手,这里改改那里修修.我们先试着添加自己喜欢的marker/nft进行识别. 比如我做了一个法拉利的marker: 还有网上找了一个法拉利log ...
- 【AR实验室】ARToolKit之概述篇
0x00 - 前言 我从去年就开始对AR(Augmented Reality)技术比较关注,但是去年AR行业一直处于偶尔发声的状态,丝毫没有其"异姓同名"的兄弟VR(Virtual ...
- 【AR实验室】ARToolKit之Example篇
0x00 - 前言 PS : 我突然意识到ARToolKit本质可能就是一个可以实时求解相机内外参的解决方案. 拿到一个新的SDK,90%的人应该都会先跑一下Example.拿到ARToolKit的S ...
- AR增强现实 Augmented Reality
增强现实(Augmented Reality,简称 AR),是一种实时地计算摄影机影像的位置及角度并加上对应图像的技术,这样的技术的目标是在屏幕上把虚拟世界套在现实世界并进行互动.这样的技术最早于19 ...
- 百度用AR复现朝阳门,野心渐明直指AR平台
近日,支付宝推出基于"AR+LBS"的AR实景红包后,BAT的另一个巨头百度也忍不住展示了自家AR技术.12月22日上午11点,百度邀请了一众媒体朋友前往朝阳门地铁站F口,体验期最 ...
- [译] AR SDK的种类比你想得要多!这里介绍七个棒棒哒
作者:Eddie Offermann 原文:There are dozens more Augmented Reality SDKs than you think! Here are seven gr ...
随机推荐
- 构建一个基本的前端自动化开发环境 —— 基于 Gulp 的前端集成解决方案(四)
通过前面几节的准备工作,对于 npm / node / gulp 应该已经有了基本的认识,本节主要介绍如何构建一个基本的前端自动化开发环境. 下面将逐步构建一个可以自动编译 sass 文件.压缩 ja ...
- ASP.NET Core应用的错误处理[2]:DeveloperExceptionPageMiddleware中间件如何呈现“开发者异常页面”
在<ASP.NET Core应用的错误处理[1]:三种呈现错误页面的方式>中,我们通过几个简单的实例演示了如何呈现一个错误页面,这些错误页面的呈现分别由三个对应的中间件来完成,接下来我们将 ...
- 加深一下BlockingQueue的认识
认识BlockingQueue BlockingQueue是一种可以阻塞线程的队列,java中对这种队列提供了方法抽象,BlockingQueue则是抽象的接口. add:添加元素到队列里,添加成功返 ...
- 谈谈一些有趣的CSS题目(六)-- 全兼容的多列均匀布局问题
开本系列,谈谈一些有趣的 CSS 题目,题目类型天马行空,想到什么说什么,不仅为了拓宽一下解决问题的思路,更涉及一些容易忽视的 CSS 细节. 解题不考虑兼容性,题目天马行空,想到什么说什么,如果解题 ...
- nodejs利用ajax实现网页无刷新上传图片
nodejs利用ajax实现网页无刷新上传图片 标签(空格分隔): nodejs 通常情况下上传图片是要通过提交form表单来实现的,但是这又不可避免的产生了网页转. 利用ajax技术和FormDat ...
- HTML+CSS 项目总结
在过去的大概一个月的学习,基本掌握了HTML+CSS的用法和特性. 这个星期老师给我们布置了一个PC端的实战项目,并且要求在3-4天内完成,我不惜废寝忘食,在紧迫的时间内大致地完成了,但是有些效果不能 ...
- spring applicationContext.xml和hibernate.cfg.xml设置
applicationContext.xml配置 <?xml version="1.0" encoding="UTF-8"?> <beans ...
- OpenDigg前端开源项目周报1219
由OpenDigg 出品的前端开源项目周报第二期来啦.我们的前端开源周报集合了OpenDigg一周来新收录的优质的前端开发方面的开源项目,方便前端开发人员便捷的找到自己需要的项目工具等.react-f ...
- Atiti.大企业病与小企业病 大公司病与小公司病
Atiti.大企业病与小企业病 大公司病与小公司病 1. 大企业病,一般会符合机构臃肿 .多重领导 .人才流失的特点.1 2. 大企业病避免方法1 3. 小企业病 1 3.1.1. 表现1 4. 如何 ...
- SQL*Plus生成html文件
最近使用SQL*Plus命令生成html文件,遇到一些有意思的知识点,顺便记录一下,方便以后需要的时候而这些知识点又忘记而捉急.好记性不如烂笔头吗! 为什么要用SQL*Plus生成html文件? ...