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 还有提供相当多的图像处理的功能,接下来要怎么做,就是看自己想要做什么了~

OpenNI + OpenCV相关推荐

  1. Kinect+OpenNI+OpenCV使用

    关于OpenNI,已经可以使用2.0,可以不再使用PrimeSense: 这里的是转载其他人的 OpenCV系列: 原文:http://blog.csdn.net/chenxin_130/articl ...

  2. 【转载】Ubuntu下安装配置OpenNI, OpenCV(来自韶子空间)

    链接: http://www.cnblogs.com/sunshy/archive/2011/11/30/2268370.html

  3. Kinect+OpenNI学习笔记之4(OpenNI获取的图像结合OpenCV显示)

    前言 本文来结合下opencv的highgui功能显示kinect采集得来的颜色图和深度图.本来在opencv中自带了VideoCapture类的,使用该类可以直接驱动kinect设备,具体的可以参考 ...

  4. Kinect+OpenNI学习笔记之13(Kinect驱动类,OpenCV显示类和手部预分割类的设计)

    前言 为了减小以后项目的开发效率,本次实验将OpenNI底层驱动Kinect,OpenCV初步处理OpenNI获得的原始数据,以及手势识别中的分割(因为本系统最后是开发手势识别的)这3个部分的功能单独 ...

  5. OpenCV单kinect多帧静止场景的深度图像去噪

    from: OpenCV单kinect多帧静止场景的深度图像去噪 老板kinect去噪的任务下达已经有半个多月了,前期除了看了几天文献之外就打酱油了,好像每天都很忙,可是就是不知道在忙什么.这几天为了 ...

  6. 使用OpenCV进行相机标定

    1. 使用OpenCV进行标定 相机已经有很长一段历史了.但是,伴随着20世纪后期的廉价针孔照相机的问世,它们已经变成我们日常生活的一种常见的存在.不幸的是,这种廉价是由代价的:显著的变形.幸运的是, ...

  7. 三维重建:QT+OpenNI+Kinect图像校正

    后记: 当时能不放弃这个方向是因为这里面涉及了一种很有效的三位场景存储方式,可能给出除图元建模之外的一种三维场景描述方式.这和Flash与位图的对比一样,基于图元的flash始终抵不过基于点描述的位图 ...

  8. Kinect+OpenNI学习笔记之8(Robert-Walter手部提取代码的分析)

    前言 一般情况下,手势识别的第一步就是先手势定位,即手势所在部位的提取.本文是基于kinect来提取手势识别的,即 先通过kinect找出人体的轮廓,然后定位轮廓中与手部有关的点,在该点的周围提取出满 ...

  9. kinect的openni总结

    Kinect到手快一个月了,期间查阅了很多资料,见识了很多牛人,他们的工作如此漂亮,让我大开眼界.现将自己所掌握的资料汇总于此,以便随时查阅. 首先是csdn上小斤童鞋的系列文章: Kinect开发教 ...

最新文章

  1. silverlight带有复选框的列
  2. android gpio操作
  3. MySQL基于SSL协议的主从复制
  4. 源码解析:Git的第一个提交是什么样的?
  5. mysql函数封装_Mysql对文件操作的封装
  6. java入门从哪下手_java新手0基础如何最快速的入门
  7. 美团Android开发工程师岗位职能要求,真香
  8. 【数据结构笔记27】树习题:完全二叉搜索树(Complete Binary Search Tree)
  9. ASP.NET的路由系统
  10. 推荐几款好用的电脑定时执行软件 - 定时执行专家
  11. win10熄屏时间不对_Windows10下显示时间不正确的原因及解决技巧
  12. 详解线上线下收单业务(2)
  13. Unity中帧数FPS的显示查看
  14. netlify 部署 github page, 使用https域名
  15. 解决使用layui上传文件时提示“请求上传接口出现异常”
  16. QQ客服 与陌生人临时对话
  17. 服务器虚拟化vmware价格,vmware服务器虚拟化实施方案(vmware服务器虚拟化收费)...
  18. Ubuntu如何安装无线网卡驱动
  19. SQL插入数据时连表查询(利用子查询一次性 insert 多条数据)
  20. frame单选Java_Java Swing JRadioButton:单选按钮组件

热门文章

  1. 我的2007-written in BIT
  2. 全新企业建站体验 视频着陆页设计
  3. 你如何理解前端的工作(面试题)
  4. javacv 视频转换
  5. 使用Gitee用于进行团队合作,(配合数据库迁移)
  6. JavaSE——网络编程
  7. matlab butter()函数解析
  8. 「动画演示」勾股定理的证明
  9. 如何覆盖docker.service文件中的配置,解决一次docker.service启动不成功的问题
  10. D3.js的v5版本入门教程(第六章)——做一个简单的图表