kinect体感开发,写了几个小的测试程序,但是在MFC的框架下使用kinect的话,那些初始化和驱动函数来回编写很麻烦,索性就把调用驱动kinect的函数模块封装成了,贴出来供大家学习和参考,我封装的类名为CkOpenNI,包括CkOpenNI.h和CkOpenNI.cpp两个文件,这个类是结合OpenCV建立,OpenCV可以方便的去做一些显示或者其他操作,因为暂时对Kinect的使用还不太充分,所以包括的成员函数并不全,会在以后的使用过程中逐渐增加的,
CkOpenNI.h代码如下:
#pragma once
#include "xntypes.h"
#include <XnCppWrapper.h>
#include "opencv/cv.h"
#include "opencv/highgui.h"
using namespace std;
class CkOpenNI
{
public:
CkOpenNI(void);
~CkOpenNI(void);
void Initial(void);
void ModifyMode(XnMapOutputMode mapMode,int nXRes,int nYRes,int nFPS);
void Start(void);
void UpData(void);
void GetData(IplImage *imgDepth16u,IplImage *imgRGB8u);
void DestoryKinect(void);
// 产生的深度数据变量
xn::DepthMetaData depthMD;
// 彩色图像数据
xn::ImageMetaData imageMD;
// 定义输出图像属性变量
XnMapOutputMode mapMode;
// 状态指示器
XnStatus status;
//获取kinect转换后的变量
IplImage *imgDepth16u;
IplImage *imgRGB8u;
private:
void CheckOpenNIError( XnStatus result, string status );
xn::Context context;
// 生成深度图像的变量
xn::DepthGenerator depthGenerator;
// 生成彩色图像变量
xn::ImageGenerator imageGenerator;
};
CkOpenNI.cpp代码如下:
#include "CkOpenNI.h"
#include "XnCppWrapper.h"
CkOpenNI::CkOpenNI(void)
{
status = XN_STATUS_OK;
}
/*****************初始化差错函数***********************/
void CkOpenNI::CheckOpenNIError( XnStatus result, string status )
{
if( result != XN_STATUS_OK )
cerr << status << " Error: " << xnGetStatusString( result ) << endl;
}
/*****************Kinect初始化************************/
void CkOpenNI::Initial(void)
{
status = context.Init();//初始化获生成器状态
CheckOpenNIError(status,"initialize context");//check kinect
context.SetGlobalMirror(true);//设置镜像
//根据kinect默认的图像属性创建图像
imgDepth16u = cvCreateImage(cvSize(640,480),IPL_DEPTH_16U,1);
imgRGB8u = cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,3);
//产生图像node
status = imageGenerator.Create(context);
CheckOpenNIError(status,"Create image generator");
//产生深度node
status = depthGenerator.Create(context);
CheckOpenNIError(status,"Create depth generator");
//视角矫正
status = depthGenerator.GetAlternativeViewPointCap().SetViewPoint(imageGenerator);
CheckOpenNIError(status,"Adjust the view point");
//return true;
}
/*******************定义输出图像的属性*********************/
void CkOpenNI::ModifyMode(XnMapOutputMode mapMode,int nXRes,int nYRes,int nFPS)
{
//输出图像的宽
mapMode.nXRes = nXRes;
//输出图像的高
mapMode.nYRes = nYRes;
//输出图像的帧率
mapMode.nFPS = nFPS;
//设置输出彩色图像属性
status = imageGenerator.SetMapOutputMode(mapMode);
//设置输出深度图像属性
status = depthGenerator.SetMapOutputMode(mapMode);
}
/*****************数据开始转换***************************/
void CkOpenNI::Start(void)
{
//开始转换
status = context.StartGeneratingAll();
CheckOpenNIError(status,"Start generate all ");
//return true;
}
/*****************数据更新*******************************/
void CkOpenNI::UpData(void)
{
//更新数据
status = context.WaitNoneUpdateAll();
//获得数据
imageGenerator.GetMetaData(imageMD);
depthGenerator.GetMetaData(depthMD);
//return true;
}
/***************获取数据********************************/
void CkOpenNI::GetData(IplImage *depthShow,IplImage *imageShow)
{
//将深度数据复制到imgDepth16U.imageData,图像大小为640*480,2通道
memcpy(imgDepth16u->imageData,depthMD.Data(),640*480*2);
//使用线形变换转换数据,255/4096比例压缩,转换到0-255范围
cvConvertScale(imgDepth16u,depthShow,255/4096.0,0);
memcpy(imgRGB8u->imageData,imageMD.Data(),640*480*3);
//色彩空间转换,将RGB存储方式转换为BGR
cvCvtColor(imgRGB8u,imageShow,CV_RGB2BGR);
}
/****************窗口销毁和释放**************************/
void CkOpenNI::DestoryKinect(void)
{
context.StopGeneratingAll();
context.Shutdown();
context.Release();
//cvReleaseImage(&imgRGB8u);
//cvReleaseImage(&imgDepth16u);
}
CkOpenNI::~CkOpenNI(void)
{
}
备注:由于上一次对内存泄露没有考虑到位,导致在程序运行的过程中内存极具的增加,先将代码重新修改如上,内存泄露的原因,主要是在
void CkOpenNI::GetData(IplImage *depthShow,IplImage *imageShow)
这个方法中,之前是的写法是这样的
void CkOpenNI::GetData(IplImage *depthShow,IplImage *imageShow)
{
IplImage* imgDepth16u = cvCreateImage(cvSize(640,480),IPL_DEPTH_16U,1);
IplImage* imgRGB8u = cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,3);
//根据kinect默认的图像属性创建图像
imgDepth16u = cvCreateImage(cvSize(640,480),IPL_DEPTH_16U,1);
imgRGB8u = cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,3);
//将深度数据复制到imgDepth16U.imageData,图像大小为640*480,2通道
memcpy(imgDepth16u->imageData,depthMD.Data(),640*480*2);
//使用线形变换转换数据,255/4096比例压缩,转换到0-255范围
cvConvertScale(imgDepth16u,depthShow,255/4096.0,0);
memcpy(imgRGB8u->imageData,imageMD.Data(),640*480*3);
//色彩空间转换,将RGB存储方式转换为BGR
cvCvtColor(imgRGB8u,imageShow,CV_RGB2BGR);
}
在这个方法中,局部变量指针
IplImage* imgDepth16u = cvCreateImage(cvSize(640,480),IPL_DEPTH_16U,1);
IplImage* imgRGB8u = cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,3);
由于是调用视频数据流需要定时的更新和获得数据,在每次调用GetData方法时,这两个指针都会被定义和创建内存,而之前的内存并没用得到释放,从而造成内存的泄露,使得内存占用率极具的增高,影响项目的运行,考虑这些问题将以上方法进行修改,将IplImage* imgDepth16u
定义成类的成员变量而不是GetData方法的局部变量,并且在IplImage* imgRGB8u
void CkOpenNI::Initial(void)
方法中创建相应内存,从而避免了在每次更新时都进行内存创建,避免了内存泄露,修改部分的代码如下:
//获取kinect转换后的变量 IplImage *imgDepth16u; IplImage *imgRGB8u;
在void CkOpenNI::Initial(void)中进行初始化:
void CkOpenNI::Initial(void) { status = context.Init();//初始化获生成器状态 CheckOpenNIError(status,"initialize context");//check kinect context.SetGlobalMirror(true);//设置镜像 //根据kinect默认的图像属性创建图像 imgDepth16u = cvCreateImage(cvSize(640,480),IPL_DEPTH_16U,1); imgRGB8u = cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,3); //产生图像node status = imageGenerator.Create(context); CheckOpenNIError(status,"Create image generator"); //产生深度node status = depthGenerator.Create(context); CheckOpenNIError(status,"Create depth generator"); //视角矫正 status = depthGenerator.GetAlternativeViewPointCap().SetViewPoint(imageGenerator); CheckOpenNIError(status,"Adjust the view point"); //return true; }
void CkOpenNI::GetData(IplImage *depthShow,IplImage *imageShow)具体实现如下:
void CkOpenNI::GetData(IplImage *depthShow,IplImage *imageShow) { //将深度数据复制到imgDepth16U.imageData,图像大小为640*480,2通道 memcpy(imgDepth16u->imageData,depthMD.Data(),640*480*2); //使用线形变换转换数据,255/4096比例压缩,转换到0-255范围 cvConvertScale(imgDepth16u,depthShow,255/4096.0,0); memcpy(imgRGB8u->imageData,imageMD.Data(),640*480*3); //色彩空间转换,将RGB存储方式转换为BGR cvCvtColor(imgRGB8u,imageShow,CV_RGB2BGR); }