天天看点

透过 OpneNI 合并 Kinect 深度以及彩色影像数据

在前一篇的《透过OpneNI 读取Kinect 深度影像数据》里,已经解释过如何在 PC 上透过 OpenNI 来读取Kinect 的深度图了。而这一篇,则是进一步、同时读取它的深度图,以及一般的彩色影像、并将之做位置上的校正、合并。为了做到这个目的,除了上一篇有用到的 xn::DepthGenerator 外,这一篇还会用到 xn::ImageGenerator 来读取Kinect 的彩色影像数据;而另外为了修正两个摄影机的视角不同,也会用到 xn::AlternativeViewPointCapability 这个特别的Capability。

而由于这边的程序代码是基于上一个程序所修改的,所以在重复的地方,Heresy 不打算重复说明了,请自行回去参考上一篇文章的部分。而接下来,就直接先看程序代码的内容:

#include <stdlib.h>      
#include <iostream>      
#include <string>      
#include <XnCppWrapper.h>      
using namespace std;      
void CheckOpenNIError( XnStatus eResult, string sStatus )      
{      
  if( eResult != XN_STATUS_OK )      
    cerr << sStatus << " Error : " << xnGetStatusString( eResult ) << endl;      
}      
int main( int argc, char** argv )      
{      
  XnStatus eResult = XN_STATUS_OK;      
  // 2. initial context      
  xn::Context mContext;      
  eResult = mContext.Init();      
  CheckOpenNIError( eResult, "initialize context" );      
  // 3. create depth generator      
  xn::DepthGenerator mDepthGenerator;      
  eResult = mDepthGenerator.Create( mContext );      
  CheckOpenNIError( eResult, "Create depth generator" );      
  // 4. create image generator      
  xn::ImageGenerator mImageGenerator;      
  eResult = mImageGenerator.Create( mContext );      
  CheckOpenNIError( eResult, "Create image generator" );      
  // 5. set map mode      
  XnMapOutputMode mapMode;      
  mapMode.nXRes = 640;      
  mapMode.nYRes = 480;      
  mapMode.nFPS = 30;      
  eResult = mDepthGenerator.SetMapOutputMode( mapMode );      
  eResult = mImageGenerator.SetMapOutputMode( mapMode );      
  // 6. correct view port      
  mDepthGenerator.GetAlternativeViewPointCap().SetViewPoint( mImageGenerator );      
  // 7. tart generate data      
  eResult = mContext.StartGeneratingAll();      
  // 8. read data      
  eResult = mContext.WaitNoneUpdateAll();      
  if( eResult == XN_STATUS_OK )      
  {      
    // 9a. get the depth map      
    const XnDepthPixel*  pDepthMap = mDepthGenerator.GetDepthMap();      
    // 9b. get the image map      
    const XnUInt8*    pImageMap = mImageGenerator.GetImageMap();      
  }      
  // 10. stop      
  mContext.StopGeneratingAll();      
  mContext.Shutdown();      
  return 0;      
}      
ImageGenerator

基本上,这边的程序架构和之前单纯读取深度影像的范例是相同的。不同的地方在于,这边除了建立用来读取深度的 xn::DepthGenerator 这个node、mDepthGenerator 外,也另外建立了一个用来读取彩色影像用的 node,也就是形别是 xn::ImageGenerator 的物件 mImageGenerator。而它的使用方法基本上和 xn::DepthGenerator是相同的,一样是先宣告出他的对象后,再透过 Create() 这个成员函式来建立;程序写法的部分,可以参考上方「4. create image generator」的部分。

而同样的,在这边 Heresy 也是把彩色影像的输出模式,设定为 640 x480 @ 30FPS;而 xn::ImageGenerator 设定输出模式的方法和 xn::DepthGenerator 一样,也是呼叫 SetMapOutputMode() 做设定就可以了。(上方「5. set map mode」的部分。)

取得影像数据

相较于 xn::DepthGenerator 是透过 GetDepthMap() 这个函式来取得深度的影像,xn::ImageGenerator 则是透过 GetImageMap() 这个函式来取得彩色的影像数据。而在默认的情况下,这样取得的影像数据会是一个型别是XnUInt8(实际上就是 unsigned char)的const 指标,指向一个一维数组。而这个数组的大小会是 640 x 480 x 3,每三个为一组、分别代表他的 RGB 的值。

另外,也可以透过 GetRGB24ImageMap() 这个函式,来取得 XnRGB24Pixel 这种封装好的格式,不过实际使用上差异不大就是了。而如果有需要的话,image generator 也可以透过 SetPixelFormat(),来修改每一个像素的数据形式,不过在这边就不细提。

视角修正

接下来比较特别的地方,则是「6. correct view port 」 的部分。这边程序的目的,是要修正两个传感器取得的画面坐标,让两者画面的视角一致。为什么要做这件事呢?因为 Kinect 的深度摄影机和彩色摄影机是在不同的位置,而且镜头本身的参数也不完全相同,所以其实两个摄影机所取得的画面,是会有些微的差异的。下面就是在不修正的情况下,所抓到的画面(左边是彩色、右边是深度):

直接看的话感觉好像差不多?不过仔细看的话,是可以发现两张图的可视范围是不一样的~彩色摄影机的可视范围,基本上是比深度摄影机大一些的;而如果把两张图重迭在一起,看起来会更明显。右边的图就是直接把两张图重迭在一起的结果,可以很明显地看出来,有很多地方都没有办法对应得很好,像是天花板上的日光灯罩 和机柜上的东西,都很明显地看的出来有出入。

为了解决这个问题,OpenNI 有提供一个名为「Alternative View」的 Capability,可以帮助使用 OpenNI 的程序开发者,快速地修正这种视角上的不同;不过这项功能,基本上是要有支持的 production node 才可以用的就是了。

Alternative View 这个capability 的型别是 xn::AlternativeViewPointCapability,可以直接透过呼叫 ProductionNode 的「GetAlternativeViewPointCap()」来取得用来操作这项 capability 的对象;基本上 OpenNI 的所有 capability,都是以这样的形式来使用的。而以 xn::AlternativeViewPointCapability 来说,他有提供SetViewPoint() 这个函式,可以把其他的 production node 传进去、把目前这个 node 的视角改为指定 node 的视角。

而 Heresy 这边实际写成程序代码,就是:

mDepthGenerator.GetAlternativeViewPointCap().SetViewPoint( mImageGenerator );      

这样写的意思,就是把 mDepthGenerator 这个 depth generator 的视角、设定成和 mImageGenerator 一样了。(注:反过来想让 image generator 根据 depth generator 调整的话,OpenNI 会当掉…)

而加上这一行后, depth generator 所抓到的画面,就会变成左下方这样的图。如果和之前没有执行过视角调整的结果相比,可以发现调整过后的结果周围的黑边明显地比较大,同时也有一些几何上的修正(四边有稍微内凹);而这样取得的结果再和彩色影像重迭在一起(右下图),则可以发现位置变得相当一致,不会有之前画面内东西不一致的问题了!

所以如果有需要要将深度和彩色影像做整合的话,应该就要记得做视角修正的动作,以避免对应的位置出错。

这一篇文章大概就先写到这里了。基本上,这边主要应该算是在讲 Alternative View 这个 capability 了~而实际上,如果有需要的话,可能也可以考虑使用 Frame-Sync 这个 capability,来让深度影像与彩色影像之间的时间差更小;不过就 Heresy 目前简单的测试看来,应该差异不大就是了,如果有需要的人,可以自己玩看看了~

继续阅读