本文转载请注明出处 —— 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 - 参考资料


【AR实验室】mulberryAR : ORBSLAM2+VVSION的更多相关文章

  1. 【AR实验室】mulberryAR:并行提取ORB特征

    本文转载请注明出处 —— polobymulberry-博客园 0x00 - 前言 在[AR实验室]mulberryAR : ORBSLAM2+VVSION末尾提及了iPhone5s真机测试结果,其中 ...

  2. 【AR实验室】mulberryAR :添加连续图像作为输入

    本文转载请注明出处 —— polobymulberry-博客园 0x00 - 前言 之前mulberryAR只能利用手机相机实时捕捉图像作为系统的输入,这也比较符合用户的习惯.但是在开发的过程中,有时 ...

  3. 【AR实验室】OpenGL ES绘制相机(OpenGL ES 1.0版本)

    0x00 - 前言 之前做一些移动端的AR应用以及目前看到的一些AR应用,基本上都是这样一个套路:手机背景显示现实场景,然后在该背景上进行图形学绘制.至于图形学绘制时,相机外参的解算使用的是V-SLA ...

  4. 【AR实验室】ARToolKit之制作自己的Marker/NFT

    0x00 - 前言 看过example后,就会想自己动动手,这里改改那里修修.我们先试着添加自己喜欢的marker/nft进行识别. 比如我做了一个法拉利的marker: 还有网上找了一个法拉利log ...

  5. 【AR实验室】ARToolKit之概述篇

    0x00 - 前言 我从去年就开始对AR(Augmented Reality)技术比较关注,但是去年AR行业一直处于偶尔发声的状态,丝毫没有其"异姓同名"的兄弟VR(Virtual ...

  6. 【AR实验室】ARToolKit之Example篇

    0x00 - 前言 PS : 我突然意识到ARToolKit本质可能就是一个可以实时求解相机内外参的解决方案. 拿到一个新的SDK,90%的人应该都会先跑一下Example.拿到ARToolKit的S ...

  7. AR增强现实 Augmented Reality

    增强现实(Augmented Reality,简称 AR),是一种实时地计算摄影机影像的位置及角度并加上对应图像的技术,这样的技术的目标是在屏幕上把虚拟世界套在现实世界并进行互动.这样的技术最早于19 ...

  8. 百度用AR复现朝阳门,野心渐明直指AR平台

    近日,支付宝推出基于"AR+LBS"的AR实景红包后,BAT的另一个巨头百度也忍不住展示了自家AR技术.12月22日上午11点,百度邀请了一众媒体朋友前往朝阳门地铁站F口,体验期最 ...

  9. [译] AR SDK的种类比你想得要多!这里介绍七个棒棒哒

    作者:Eddie Offermann 原文:There are dozens more Augmented Reality SDKs than you think! Here are seven gr ...

随机推荐

  1. SQL Server on Linux 理由浅析

    SQL Server on Linux 理由浅析 今天的爆炸性新闻<SQL Server on Linux>基本上在各大科技媒体上刷屏了 大家看到这个新闻都觉得非常震精,而美股,今天微软开 ...

  2. UWP中新加的数据绑定方式x:Bind分析总结

    UWP中新加的数据绑定方式x:Bind分析总结 0x00 UWP中的x:Bind 由之前有过WPF开发经验,所以在学习UWP的时候直接省略了XAML.数据绑定等几个看着十分眼熟的主题.学习过程中倒是也 ...

  3. ABP文档 - Mvc 控制器

    文档目录 本节内容: 简介 AbpController基类 本地化 其它 过滤 异常处理和结果包装 审计日志 验证 授权 工作单元 反伪造 模型绑定器 简介 ABP通过nuget包Abp.Web.Mv ...

  4. JavaScript 字符串实用常操纪要

    JavaScript 字符串用于存储和处理文本.因此在编写 JS 代码之时她总如影随形,在你处理用户的输入数据的时候,在读取或设置 DOM 对象的属性时,在操作 Cookie 时,在转换各种不同 Da ...

  5. 利用XAG在RAC环境下实现GoldenGate自动Failover

    概述 在RAC环境下配置OGG,要想实现RAC节点故障时,OGG能自动的failover到正常节点,要保证两点: 1. OGG的checkpoint,trail,BR文件放置在共享的集群文件系统上,R ...

  6. zookeeper源码分析之三客户端发送请求流程

    znode 可以被监控,包括这个目录节点中存储的数据的修改,子节点目录的变化等,一旦变化可以通知设置监控的客户端,这个功能是zookeeper对于应用最重要的特性,通过这个特性可以实现的功能包括配置的 ...

  7. 基于改进人工蜂群算法的K均值聚类算法(附MATLAB版源代码)

    其实一直以来也没有准备在园子里发这样的文章,相对来说,算法改进放在园子里还是会稍稍显得格格不入.但是最近邮箱收到的几封邮件让我觉得有必要通过我的博客把过去做过的东西分享出去更给更多需要的人.从论文刊登 ...

  8. Asp.Net Core + Dapper + Repository 模式 + TDD 学习笔记

    0x00 前言 之前一直使用的是 EF ,做了一个简单的小项目后发现 EF 的表现并不是很好,就比如联表查询,因为现在的 EF Core 也没有啥好用的分析工具,所以也不知道该怎么写 Linq 生成出 ...

  9. (转) 将ASP.NET Core应用程序部署至生产环境中(CentOS7)

    原文链接: http://www.cnblogs.com/ants/p/5732337.html 阅读目录 环境说明 准备你的ASP.NET Core应用程序 安装CentOS7 安装.NET Cor ...

  10. 使用LogMaster4Net实现应用程序日志的集中管理

    日志在软件系统中的重要性我在此也不赘述了,几乎所有程序员每天都会更日志打交道. 那么你是否曾今为这样的一些事情而困扰过: - 远程登录到不同的服务器,找到应用程序目然后查看应用日志: - 来回切换于不 ...