当前位置:文档之家› 基于Kinect的三维重建

基于Kinect的三维重建

基于Kinect-OpenNI-OpenCV-OpenGL的环境三维重构
项目源码详见:/forum/viewtopic.php?f=1&t=13042
前几天刚入手了期待已久的Kinect ,用于实验室机器人项目的视觉导航与环境理解。

首先要做的是破解-->连接PC-->获取深度数据和图像数据-->三维点云显示这么几项基本工作。

开始仿照的是饮水思源[1]博客的方法(使用VS2008在windows平台上试用Kinect[2]),利用CL-NUI-Platform 来破解,它的最新版是1.0.0.1210,但我在XP上用会当机,后来换1.0.0.1121 版的就可以用了。

CL NUI 提供了十分简便易用的接口,在OpenCV 上调用很简单,另外它还提供了Kinect 底座马达的控制接口和LED 灯颜色的选择接口,其例程中可以操控Kinect 上下摆动。

如果只需要获取深度数据和图像数据,CL NUI 就够用了。

不过要做深入的应用,比如人体姿态识别、骨架提取、深度数据与图像数据的合并等等,就该用到OpenNI 了。

国的CNKINECT[3]是个不错的Kinect 开发论坛,版块丰富,有很多资料可供借鉴。

我通过论坛介绍的方法[4]成功配置了OpenNI + Kinect,先是用最新版的OpenNI+SensorKinect+NITE ,但在XP 下不能正常运行,可能跟 .net 平台有关,老实按上面论坛的方法装就成功了。

另外用CMake + VS2008 装了最新的OpenCV_SVN,开始试过在CMake 里选择With TBB,但诡异的是TBB 似乎只适用于VS2005,在VS2008 编译后试用里面的samples 老是提示报错找不到msvcp80.dll,重新用CMake 配置取消了With TBB,就一切正常了。

[编辑]
一、深度摄像机的视角调整与深度/彩色图像的合并
通过研究OpenCV_SVN 与OpenNI 相关的代码(cap_openni.cpp)发现,OpenCV 目前只支持对Kinect的深度图、视差图和彩色/灰度图及相关属性的读取,更进一步的设置还没有实现。

参考Heresy’space[5]的博客文章《透过OpneNI 合并Kinect 深度以及彩色影像资料》[6],想把深度图和彩色图合并显示,但是由于Kinect 的深度摄像机和彩色摄像机是在不同的位置,而且镜头本身的参数也不完全相同,所以两个摄像机所取得的画面会有些微的差异(如图1 左下角子图OpenGL三维点云显示窗口所示,天花板的两个日光灯对应深度图和彩色图的区域并没有重合,而是错位了)。

图1
根据Heresy 的分析,需要对深度摄像机的视角进行修正,在OpenNI 下只需要一行代码就可以实现:
// 6. correct view port
mDepthGenerator.GetAlternativeViewPointCap().SetViewPoint( mImageGenerato r );
不过在OpenCV 中并没有提供这一项设置,其源代码modules\highgui\src\cap_openni.cpp 中setDepthGeneratorProperty 并没有任何
实质的属性设置。

为此,需要改写该函数,并且要在相应的头文件modules\highgui\include\opencv2\highgui\highgui_c.h 中添加新的参数id,具体如下:
1.将cap_openni.cpp 第344 行的setDepthGeneratorProperty 改写如下:
1.在highgui_c.h 的第348 行下添加改变视角的参数ID 号:
然后在第352 行下添加:
从而使得OpenCV 的VideoCapture 属性关于OpenNI 的如下所示:
CV_CAP_OPENNI_DEPTH_GENERATOR_BASELINE =
CV_CAP_OPENNI_DEPTH_GENERATOR + CV_CAP_PROP_OPENNI_BASELINE, CV_CAP_OPENNI_DEPTH_GENERATOR_FOCAL_LENGTH =
CV_CAP_OPENNI_DEPTH_GENERATOR +
CV_CAP_PROP_OPENNI_FOCAL_LENGTH,
'''CV_CAP_OPENNI_DEPTH_GENERATOR_VIEW_POINT =
CV_CAP_OPENNI_DEPTH_GENERATOR +
CV_CAP_PROP_OPENNI_VIEW_POINT'''
改写完上述源代码后保存,并且用CMake 和VS2008 重新编译一次OpenCV,我们就可以用OpenCV 的接口来控制Kinect 深度摄像头的视角,使其深度数据和图像数据能够很好的重合起来,如图2所示,注意与图1相比,右上角的伪彩色视差图四周出现了黑边,这就是视角调整后的效果:
图2
[编辑]
二、三维点云坐标的计算
在OpenCV 中实际上已经提供了三维点云坐标计算的接口,通过Kinect 的深度数据可以很快换算出三维点云坐标,cap_openni.cpp 中这部分代码具体如下:
不过可以看到上面核心的代码就一行:
具体是怎样实现的呢?我们可以进一步找OpenNI 的源代码来分析。

不过这里我是从原来双目视觉的经验上自己编写代码来实现三维点云坐标的计算。

实际上Kinect 的深度摄像头成像也类似于普通的双目立体视觉,只要获取了两个摄像头之间的基线(baseline)和焦距(focal length)、以及视差数据,通过构造矩阵Q,利用OpenCV 的reprojectimageTo3D 函数,也可以计算出三维坐标。

下面我们通过以下代码看看矩阵Q 的构造过程:
而三维点云坐标的计算,以及深度、视差、彩色图像的读取,则如下所示:
这里值得注意的是,在计算视差时,如果视差图是采用默认的CV_8UC1 格式(参数ID是CV_CAP_OPENNI_DISPARITY_MAP),由于视差被限制在[0-255]整数围,造成一定的误差,所得到的三维坐标数据会出现分层,如图3和图4所示:
图3 Matlab绘制的三维点云,不同深度上有明显分层
图4 左为直接得到的深度数据Mesh图,中为由8位视差数据计算得到的深度数据,右为对应的视差数据
而采用32 位浮点格式来获取视差数据(参数ID:CV_CAP_OPENNI_DISPARITY_MAP_32F),则消除了这种因视差误差造成深度数值分层的现象,如图5、6所示:
图5 深度数值的分层现象基本消除
图6 两种方式得到的深度数据一致
[编辑]
三、利用OpenGL显示三维点云数据
这方面主要是基于学习笔记(15)[7]的容,不过当时是通过另设OpenCV 窗口设置Trackbar 来调整OpenGL 的视点位置和摄像机位置。

在这里则主要参考了OpenCV 论坛的帖子《[HQ] OpenCV和OpenGL编程:关于显示点云数据-Stereo Vision源码分享》[8]中villager5 提供的方法来调整摄像机位置,做了一定的修改,使得鼠标左键拖曳能够实现对上下左右的视角变换,鼠标右键拖曳能够实现视距远近的变换,不再需要用Trackbar 来调整。

下面是相关的代码:。

相关主题