OpenNI + OpenCV

OpenCV 的全名是「Open Source Computer Vision」(官方网站中文网站),是一套采用 BSD 授权的开放原始码的计算机视觉函式库,在相关领域来说,算是一套相当之行的函式库;在 OpenCV 里面,包含了很多图像处理的功能,同时也包含了基本的图形接口、以及摄影机的操作等功能。

而对于 OpenNI 这样、针对深度影像和彩色影像做处理的架构,其实如果不是单纯只是想靠NITE 来追踪人体骨架的话,OpenCV 是一个相当适合拿来搭配使用的函式库;实际上,OpenCV 现在也可以直接整合 OpenNI 来读取影像(请参考《Using Kinect and other OpenNIcompatible depth sensors》)。

这篇呢,Heresy 则是以简单的范例,大概讲一下怎么把 OpenNI 的深度和彩色数据,读出来转换成 OpenCV 的格式。下面就直接看原始码吧~

//OpenNI Header
#include<XnCppWrapper.h>

// link OpenNI library
#pragmacomment( lib, "OpenNI.lib" )

// OpenCV Header
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>

// Link OpenCV Library
#ifdef_DEBUG
 #pragma comment(lib, "opencv_core242d.lib" )
 #pragma comment(lib, "opencv_highgui242d.lib" )
 #pragma comment(lib, "opencv_imgproc242d.lib" )
#else
 #pragma comment(lib, "opencv_core242.lib" )
 #pragma comment(lib, "opencv_highgui242.lib" )
 #pragma comment(lib, "opencv_imgproc242.lib" )
#endif

// main function
int main( intargc, char** argv )
{
 // 1a. initial OpenNI
 
xn::Context xContext;
 
xContext.Init();

 // 1b. create depth generator
 
xn::DepthGenerator xDepth;
 
xDepth.Create( xContext );

 // 1c. create image generator
 
xn::ImageGenerator xImage;
 
xImage.Create( xContext );

 // 1d. set alternative view point
 
xDepth.GetAlternativeViewPointCap().SetViewPoint( xImage );

 // 2. create OpenCV Windows
 
cv::namedWindow( "Depth Image", CV_WINDOW_AUTOSIZE );
 
cv::namedWindow( "Color Image", CV_WINDOW_AUTOSIZE );
 
cv::namedWindow( "Depth Edge", CV_WINDOW_AUTOSIZE );
 
cv::namedWindow( "Color Edge", CV_WINDOW_AUTOSIZE );

 // 3. start OpenNI
 
xContext.StartGeneratingAll();

 // main loop
 while( true )
 
{
   // 4. update data
   
xContext.WaitAndUpdateAll();

   // 5. get image data
   
{
      xn::ImageMetaData xColorData;
     
xImage.GetMetaData( xColorData );

     // 5a. convert to OpenCV form
     
cv::Mat cColorImg( xColorData.FullYRes(),xColorData.FullXRes(),
                         CV_8UC3, (void*)xColorData.Data());

     // 5b. convert from RGB to BGR
     
cv::Mat cBGRImg;
     
cvtColor( cColorImg, cBGRImg, CV_RGB2BGR );
     
cv::imshow( "Color Image", cBGRImg );

     // 5c. convert to signle channel and do edge detection
     
cv::Mat cColorEdge;
     
cvtColor( cColorImg, cBGRImg, CV_RGB2GRAY );
     
cv::Canny( cBGRImg, cColorEdge, 5,100 );
      cv::imshow( "Color Edge", cColorEdge );
   
}

   // 6. get depth data
   
{
      xn::DepthMetaData xDepthData;
     
xDepth.GetMetaData( xDepthData );

     // 6a. convert to OpenCV form
     
cv::Mat cDepthImg( xDepthData.FullYRes(),xDepthData.FullXRes(),
                         CV_16UC1, (void*)xDepthData.Data());

     // 6b. convert to 8 bit
     
cv::Mat c8BitDepth;
     
cDepthImg.convertTo( c8BitDepth, CV_8U, 255.0 / 7000 );
     
cv::imshow( "Depth Image", c8BitDepth );

     // 6c. convert to 8bit, and do edge detection
     
cv::Mat CDepthEdge;
     
cv::Canny( c8BitDepth, CDepthEdge,5, 100 );
      cv::imshow( "Depth Edge", CDepthEdge );
   
}

    cv::waitKey( 1 );
  }
}

在 这边的例子里,Heresy 并没有去使用整合 OpenNI 的 OpenCV,而是独立使用 OpenNI 来做数据的读取,然后再转换成 OpenCV 的格式。实际上,如果只是要使用 OpenNI 的影像数据的话,使用整合过的 OpenCV 可以直接使用内建的 VideoCapture 来做画面的读取,在使用上会比较单纯、简单一点,不过由于这样会少掉一些 OpenNI 的功能,所以在这边 Heresy 不使用这样的方法。

所以,在上面的范例里面,1a 到 1d 的部分,就是用标准 OpenNI 的流程,来进行初始化的动作;详细的说明,请参考《透过OpneNI 读取Kinect 深度影像数据》。而接下来 2 的部分,则是使用 OpenCV 的 highgui 这个模块的namedWindow() 这个函式(官方文件),来建立四个不同名称的窗口、作为画面的显示。

接下来,则是透过一个无穷循环,来不停地更新数据了~里面主要分成两块,也就是5、读取 Image Generator 的彩色影像、以及 6、读取 DepthGenerator 的深度影像的部分。

其中,在 5a 和 6a 的部分,就是把 OpenNI 读出来的 map(xn::ImageMetaData 和 xn::DepthMetaData)转换成 OpenCV 的影像格式、cv::Mat 的部分(官方文件)。

以彩色影像来说,就是在建立 cv::Mat 对象的时候,把影像的大小、也就是 Y 轴、X 轴的分辨率,以及数据的形式、数据的地址,都传递给建构子、以建立出一张 OpenCV 的影像、cColorImg。其中,CV_8UC3 是指 3 channel 的 8bit 正整数(unsignedchar)的资料(参考)。

不过,由于 OpenCV 所使用的彩色影像的色彩,默认是以 Blue、Green、Red 来做排列,和一般Red、Green、Blue 排列不同,所以要拿来用的话,还需要先做一个转换;在这边(5b)就是透过 cvtColor() 这个 OpenCV 的 imgproc 这个模块里的函式(官方文件),把本来的 RGB 影像、转换成 BGR 的影像(cBGRImg)。而在转换好之后,则就是在透过 imshow() 这个函式,把转换完成的影像、显示在对应的窗口(这边是 ColorImage)上了。

而接下来(5c),Heresy 则是试着用 OpenCV 提供的 Canny 这种方法的边缘侦测(官方文件)。不过由于 OpenCV 所提供的 Canny edge 只有针对 8bit 1 channel 的影像作处理,所以这边要先再用 cvtColor(),把影像转成灰阶的、然后再来进行;而之后,则是一样透过imshow() 这个函式,把侦测完的结果、显示在对应的窗口上。

深度的部分(6a)也是类似的,不过由于OpenNI 的深度影像的单一像素的格式是 XnDepthPixel、实际上是单一 channel 的 16bit 的正整数(unsigned short),所以在建立 cv::Mat 的时候的数据型别,则是要设定为 CV_16UC1。

不 过,虽然 OpenNI 的深度影像是 16bit 的正整数,理论上值的范围是 0 - 65,535,但是实际上深度的最大值只会到 10,000,所以如果不处理、直接画的话,会有整个画面偏暗的问题(基本上,画面会接近全黑);所以在这边,Heresy 也先透过 cv::Mat 的 convertTo() 的函式,把这个 16bit 的影像里的每一个像素都乘上一个scale(255.0 / 7000)后,转换成 8bit 的影像(c8BitDepth)。再之后,就是一样把转换好的影像,进行 canny edge 侦测了~

而这样的程序执行的结果,会有下面这样、四个不同数据的窗口,分别代表彩色影像、基于彩色影像的边缘侦测结果、深度影像、以及基于深度影像进行边缘侦测的结果。

这篇就先到这了。基本上,Heresy 是把这篇文章定位成一个极为简单的 OpenNI 和 OpenCV 的数据整合范例;而由于 OpenCV 还有提供相当多的图像处理的功能,接下来要怎么做,就是看自己想要做什么了~
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值