前言

  网上有不少使用Qt做界面,OpenNI为库来开发kinect。或许大家的第一个问题就是询问该怎样使用Kinect来获取颜色信息图和深度信息图呢?这一节就是简单来回答这个问题的。

  开发环境:QtCreator2.5.1+OpenNI1.5.4.0+Qt4.8.2

  实验说明:

  在使用OpenNI来驱动读取kinect数据时,我们需要了解context object这个名词。查看了下OpenNI UserGuide文档,简单翻译下这个名词的意思:

  Context是openNI中一个主要的object,它掌握了OpenNI使用过程中应用程序的全部状态,以及这些状态的prodection chains,一个应用程序有多个context,但是这些context之间不能共享信息。例如一个中间件节点不能使用另一个context的驱动节点。Context在使用前必须被立即初始化,因此此时所有嵌入的模块被下载和分析。为了释放context的内存,应用程序需调用shutdown程序。

  虽然翻译得不准确,但是它的大概意思就是告诉我们在驱动kinect时,需要用到context这个类,且我们需要安装一定顺序去使用,这与一些常见的库驱动差不多,比如opengl,这些都需要什么初始化啊,设置属性啊等。因此我们只需要直接去看懂他人的一个工程实例就ok了。

  好了,本文参考Heresy的教程中的源码写的。

  在新建好工程文件后,需要包含XnCppWrapper头文件,且需在Qt工程中设置好头文件目录和库文件目录。

  使用OpenNI读取颜色图和深度图的步骤如下(这个是程序的核心部分):

  1. 定义一个Context对象,并 调用该对象的Init()方法来进行初始化。

  2. 定义一个XnMapOutputMode格式对象,设置好分图像分辨率和帧率。

  3. 定义颜色图和深度图的节点对象,并用其Create()方法来创建,参数为Context对象.

  4. 设置颜色和深度图的输出模式,调用的方法是SetMapOutputMode();参数为步骤2中定义和设置好了的XnMapOutputMode对象。

  6. 如果深度图和颜色图在一张图上显示,则必须对深度图像进行校正,校正的方法是调用深度图的如下方法:.GetAlternativeViewPointCap().SetViewPoint();

  7. 调用context对象的StartGeneratingAll()来开启设备读取数据开关。

  8. 调用context对象的更新数据方法,比如WaitAndupdateAll()方法。

  9. 定义颜色图和色彩图的ImageMetaData对象,并利用对应的节点对象的方法GetMetaData(),将获取到的数据保存到对应的ImageMetaData对象中。

  10. 如果需要将深度图转换成灰度图来显示,则需要自己将深度值转换成0~255的单通道或者多通道数据,然后直接用来显示。

  注意如果没有设置视觉校正,则深度图的显示与颜色图的显示会出现对应不上的情况,后面的实验可以看出这2者的区别,另外对于是否需要设置镜像就要看自己的具体应用场合了。

  实验结果:

  下面分别分是否设置图像镜像,是否对深度图像进行校正来给出实验结果.

  无镜像无校正:

  

  无镜像有校正:

  

  有镜像无校正:  

  

  有镜像有校正:

  

  从有无镜像可以看出,设置镜像的效果与字面的理解是一样的,即有镜像时就相当于取镜子中的图像。有无校正可以看出,没有校正时,深度图片和颜色图片同一个物体都对应不起来,可以看下天花板上的吊灯就可以发现,没校正,2者不重合,且相差不少。有校正时效果就好多了,只是此时的深度图像显示的范围要稍小些。

  实验主要部分代码及注释(附录有工程code下载链接):

  首先来个最小工程,即去掉那些错误处理代码:

  main.cpp:

#include <QtGui>
#include <XnCppWrapper.h> //包含OpenNI的头文件using namespace xn;//使用OpenNI库中的命名空间//全局的OpenNI object
Context g_context;
ImageGenerator g_image_generator;
DepthGenerator g_depth_generator;//全局的Qt Object
QGraphicsPixmapItem *g_image_map;
QGraphicsPixmapItem *g_depth_map;//CTimer类的定义
class CTimer : public QObject
{
public:void start() {        g_context.StartGeneratingAll();//开启设备读取数据的开关startTimer(33);//使用startTimer()启动定时器,每当时间到时会自动调用timerEvent()函数
    }
private:void timerEvent(QTimerEvent *) {g_context.WaitAndUpdateAll();//更新数据//颜色数据
        ImageMetaData image_map;g_image_generator.GetMetaData(image_map);//为g_image_map设置图片,图片的数据来源于外部硬件设备g_image_map->setPixmap(QPixmap::fromImage(QImage(image_map.Data(), image_map.XRes(),image_map.YRes(), QImage::Format_RGB888)));//深度数据
        DepthMetaData depth_map;g_depth_generator.GetMetaData(depth_map);XnDepthPixel max_depth_value = depth_map.ZRes();QImage depth_img(depth_map.XRes(), depth_map.YRes(), QImage::Format_ARGB32);//格式为ARGB32型的for(unsigned int i = 0; i < depth_map.XRes(); i++)for(unsigned int j = 0; j < depth_map.YRes(); j++){XnDepthPixel depth_value_ij = depth_map(i, j);//获取x,y处的坐标值if(depth_value_ij == 0) {depth_img.setPixel(i, j, qRgba(0, 0, 0, 0));}//如果捕捉不到深度信息,则将其设置为0else {float fscale = 1.0f*depth_value_ij/max_depth_value;//当前深度的比例因子depth_img.setPixel(i, j, qRgba(255*(1-fscale), 0, 255*fscale, 255*(1-fscale)));}}g_depth_map->setPixmap(QPixmap::fromImage(depth_img));}
};int  main(int argc, char **argv)
{QApplication app(argc, argv);g_context.Init();//context初始化g_context.SetGlobalMirror(true);//设置全局镜像,就像照镜子一样,与设置为false时的2张图片镜像XnMapOutputMode xmode;//定义图像的输出模式xmode.nXRes = 640;//x方向分辨率xmode.nYRes = 480;//y方向分辨率xmode.nFPS = 30;//帧率//设置颜色节点属性
    g_image_generator.Create(g_context);g_image_generator.SetMapOutputMode(xmode);//设置深度节点属性
    g_depth_generator.Create(g_context);g_depth_generator.SetMapOutputMode(xmode);//视觉校正,否则深度图和颜色图感应到的区域不能一一对应
    g_depth_generator.GetAlternativeViewPointCap().SetViewPoint(g_image_generator);//Qt场景设置
    QGraphicsScene scene;g_image_map = scene.addPixmap(QPixmap());g_image_map->setZValue(1);//设置为z方向上的第1层g_depth_map = scene.addPixmap(QPixmap());g_depth_map->setZValue(2);//设置为z方向上的第2层//Qt视图创建QGraphicsView view(&scene);view.resize(660, 500);//设置定时器,每隔一段时间读取kinect的颜色信息和深度信息
    CTimer timer;timer.start();view.show();return app.exec();
}

  加入错误处理部分后的完整main.cpp:

#include <QtGui>
#include <XnCppWrapper.h> //包含OpenNI的头文件using namespace xn;//使用OpenNI库中的命名空间//全局的OpenNI object
XnStatus g_status;
Context g_context;
ImageGenerator g_image_generator;
DepthGenerator g_depth_generator;
bool g_has_image_generator = true;//全局的Qt Object
QGraphicsPixmapItem *g_image_map;
QGraphicsPixmapItem *g_depth_map;//CTimer类的定义
class CTimer : public QObject
{
public:void start() {g_status = g_context.StartGeneratingAll();//开启设备读取数据的开关if(g_status == XN_STATUS_OK) {startTimer(33);//使用startTimer()启动定时器,每当时间到时会自动调用timerEvent()函数
        }else {QMessageBox::critical(NULL, "Create Data Error!", xnGetStatusString(g_status));//显示创建数据失败,该消息框没有父窗口
        }}
private:void timerEvent(QTimerEvent *) {g_context.WaitAndUpdateAll();//更新数据//颜色数据if(g_has_image_generator) {ImageMetaData image_map;g_image_generator.GetMetaData(image_map);//为g_image_map设置图片,图片的数据来源于外部硬件设备g_image_map->setPixmap(QPixmap::fromImage(QImage(image_map.Data(), image_map.XRes(),image_map.YRes(), QImage::Format_RGB888)));}//深度数据
        DepthMetaData depth_map;g_depth_generator.GetMetaData(depth_map);XnDepthPixel max_depth_value = depth_map.ZRes();QImage depth_img(depth_map.XRes(), depth_map.YRes(), QImage::Format_ARGB32);//格式为ARGB32型的for(unsigned int i = 0; i < depth_map.XRes(); i++)for(unsigned int j = 0; j < depth_map.YRes(); j++){XnDepthPixel depth_value_ij = depth_map(i, j);//获取x,y处的坐标值if(depth_value_ij == 0) {depth_img.setPixel(i, j, qRgba(0, 0, 0, 0));}//如果捕捉不到深度信息,则将其设置为0else {float fscale = 1.0f*depth_value_ij/max_depth_value;//当前深度的比例因子depth_img.setPixel(i, j, qRgba(255*(1-fscale), 0, 255*fscale, 255*(1-fscale)));}}g_depth_map->setPixmap(QPixmap::fromImage(depth_img));}
};int  main(int argc, char **argv)
{QApplication app(argc, argv);g_status = g_context.Init();//context初始化if(g_status != XN_STATUS_OK) {QMessageBox::critical(NULL, "Context Initial Error!", xnGetStatusString(g_status));return -1;}// g_context.SetGlobalMirror(true);//设置全局镜像,就像照镜子一样,与设置为false时的2张图片镜像XnMapOutputMode xmode;//定义图像的输出模式xmode.nXRes = 640;//x方向分辨率xmode.nYRes = 480;//y方向分辨率xmode.nFPS = 30;//帧率//设置颜色节点属性g_status = g_image_generator.Create(g_context);if(g_status != XN_STATUS_OK) {QMessageBox::critical(NULL, "Image map create failed", xnGetStatusString(g_status));g_has_image_generator = false;}if( g_has_image_generator ) {g_status = g_image_generator.SetMapOutputMode(xmode);if(g_status != XN_STATUS_OK) {QMessageBox::critical(NULL, "Image map output mode error!", xnGetStatusString(g_status));return -1;}}//设置深度节点属性g_status = g_depth_generator.Create(g_context);if(g_status != XN_STATUS_OK) {QMessageBox::critical(NULL, "Depth map create failed", xnGetStatusString(g_status));return -1;}g_status = g_depth_generator.SetMapOutputMode(xmode);if(g_status != XN_STATUS_OK) {QMessageBox::critical(NULL, "Depth map output mode error!", xnGetStatusString(g_status));return -1;}if(g_has_image_generator)//视觉校正,否则深度图和颜色图感应到的区域不能一一对应;//g_depth_generator.GetAlternativeViewPointCap().SetViewPoint(g_image_generator);//Qt场景设置
    QGraphicsScene scene;g_image_map = scene.addPixmap(QPixmap());g_image_map->setZValue(1);//设置为z方向上的第1层g_depth_map = scene.addPixmap(QPixmap());g_depth_map->setZValue(2);//设置为z方向上的第2层//Qt视图创建QGraphicsView view(&scene);view.resize(660, 500);//设置定时器,每隔一段时间读取kinect的颜色信息和深度信息
    CTimer timer;timer.start();view.show();return app.exec();
}

  总结:通过本次实验,了解了怎样使用OpenNI来显示kinect的颜色图像和深度图像了。

  参考资料:http://kheresy.wordpress.com/index_of_openni_and_kinect/comment-page-5/

  附录:实验工程code下载。

Kinect+OpenNI学习笔记之2(获取kinect的颜色图像和深度图像)相关推荐

  1. Kinect+OpenNI学习笔记之6(获取人体骨架并在Qt中显示)

    前言 MS的kinec SDK和OpenNI都提供了人体骨骼跟踪的算法,人体骨骼跟踪算法在kinect人体行为识别中非常重要,该识别过程通常被用来作为行为识别的第一步, 比如说,通过定位人体中的骨骼支 ...

  2. Kinect+OpenNI学习笔记之14(关于Kinect的深度信息)

    前言 由于最近要研究kinect采集到的深度信息的一些统计特征,所以必须先对kinect深度信息做进一步的了解.这些了解包括kinect的深 度值精度,深度值的具体代表的距离是指哪个距离以及kinec ...

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

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

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

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

  5. Kinect开发学习笔记之(六)带游戏者ID的深度数据的提取

    Kinect开发学习笔记之(六)带游戏者ID的深度数据的提取 zouxy09@qq.com http://blog.csdn.net/zouxy09 我的Kinect开发平台是: Win7x86 + ...

  6. Kinect开发学习笔记之(四)提取颜色数据并用OpenCV显示

    Kinect开发学习笔记之(四)提取颜色数据并用OpenCV显示 zouxy09@qq.com http://blog.csdn.net/zouxy09 我的Kinect开发平台是: Win7 x86 ...

  7. Kinect+OpenNI学习笔记之12(简单手势所表示的数字的识别)

    引自:http://www.cnblogs.com/tornadomeet/archive/2012/11/04/2753185.html 前言 这篇文章是本人玩kinect时做的一个小实验,即不采用 ...

  8. Kinect+OpenNI学习笔记之11(OpenNI驱动kinect手势相关的类的设计)

    前言 本文所设计的类主要是和人体的手部打交道的,与人体的检测,姿势校正,骨架跟踪没有关系,所以本次类的设计中是在前面的OpenNI+Kinect系列博文基础上去掉那些与手势无关的驱动,较小代码量负担. ...

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

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

最新文章

  1. MindSpore后端运行类
  2. 计算机ppt2003考试试题,计算机模块PPT2003试题及答案.doc
  3. 2020年有寓意的领证日期_2020年有意义谐音的领证日子 容易记住的领证日期
  4. 圆柱体积怎么算立方公式_【六年级数学微课】巧算圆锥的体积
  5. 北大核刊最新版2020_爱尔兰地图(2020版)
  6. Hi3559AHi3519AHi3556A规格对比
  7. ​我敢说,这是最全的常用设计模式汇总
  8. 双向链表逆置c语言,【C++】实现双向链表的所有操作,包括逆置双链表(三种方法)...
  9. mysql8.0 tar安装_CentOS7安装MySQL8.0 tar包
  10. Linux应急响应入门--入侵排查(全面)
  11. 微软《我的世界》PC Java版销量超过3000万
  12. 使用oracle sql profile固定执行计划
  13. Xshell中文乱码问题
  14. 视频教程-Dubbo入门视频课程-Java
  15. AG-DST论文笔记
  16. 禁用/开启 Windows系统3D加速
  17. 数据沼泽_数据湖:只是一片沼泽,没有数据治理和目录
  18. python实现选择题自动答题_答题辅助python代码实现
  19. 使用快启动PE修复win10系统引导
  20. linux基本命令整理——鸟哥linux私房菜第五章

热门文章

  1. 【原创】使用Ultra Librarian为Altium Designer 09生成元器件库
  2. linux vim命令,linux之vim命令
  3. python编程狮app_Python编程狮官方app下载_Python编程狮安卓app下载 v1.0.8 - 创意手游...
  4. 最好浏览器_Windows最好的浏览器!只有你想不到,没有它做不到
  5. python与c 交互原理_PYTHON 与C相互交互调用实例解析
  6. Android Realm数据库
  7. Apache ActiveMQ
  8. java数组_Java数组
  9. java反射用法示例_Java反射示例教程
  10. java java se_Java SE 9:尝试资源改进