#include<cv.h>
#include<highgui.h>
#include<XnCppWrapper.h>
#include<string>
#include<vector>
#include<iostream>
using namespace std;
void check(XnStatus result, string step)
{
if(result != XN_STATUS_OK)
cerr<<step<<" error: "<<xnGetStatusString(result)<<endl;
return;
}
int main(int argc,char* argv[])
{
XnStatus isError = XN_STATUS_OK;
// initialze context
xn::Context context;
isError = context.Init();
check(isError,"Initialize context");
// set map output mode
XnMapOutputMode mode;
mode.nXRes = 640;
mode.nYRes = 480;
mode.nFPS = 30;
//***********************devices enumaration part begin*********************//
xn::NodeInfoList device_node_info_list;
cout<<"devices:"<<endl;
isError = context.EnumerateProductionTrees(XN_NODE_TYPE_DEVICE,NULL,device_node_info_list);
// EnumerateProductionTrees函数的第一个参数为XnProductionNodeType类型,其实就是typedef了的int类型。
// 而XN_NODE_TYPE系列为枚举成员,利用enum类型和int类型本质上相同的特点,很容易列举出所有node的类型。
if((isError != XN_STATUS_OK) && (device_node_info_list.Begin() != device_node_info_list.End()))
{
cout<<"Enumerating device failed. Reason: "<<xnGetStatusString(isError)<<endl;
return isError;
}
for(xn::NodeInfoList::Iterator nodeIt = device_node_info_list.Begin();
nodeIt != device_node_info_list.End();nodeIt++)
{
xn::NodeInfo info = *nodeIt; // 这里先构造一个临时对象,然后调用复制构造函数
XnProductionNodeDescription description = info.GetDescription();
cout<<" device: vendor "<<description.strVendor<<" name "<<description.strName<<endl;
}
//**********************devices enumaration part end*************************//
//*******************depth nodes enumaration part begin**********************//
xn::NodeInfoList depth_node_info_list;
xn::DepthGenerator depthGen;
vector<xn::DepthGenerator> nDepthGen;
cout<<"depth nodes:"<<endl;
isError = context.EnumerateProductionTrees(XN_NODE_TYPE_DEPTH,NULL,depth_node_info_list);
if((isError != XN_STATUS_OK) && (depth_node_info_list.Begin() != depth_node_info_list.End()))
{
cout<<"Enumerating depth generators failed. Reason: "<<xnGetStatusString(isError)<<endl;
return isError;
}
for(xn::NodeInfoList::Iterator nodeIt = depth_node_info_list.Begin();
nodeIt != depth_node_info_list.End();nodeIt++)
{
xn::NodeInfo info = *nodeIt;
XnProductionNodeDescription description = info.GetDescription();
cout<<" depth: vendor "<<description.strVendor<<" name "<<description.strName<<endl;
context.CreateProductionTree(info);
info.GetInstance(depthGen);
depthGen.SetMapOutputMode(mode);
nDepthGen.push_back(depthGen);
}
//*******************depth nodes enumaration part end**********************//
//********************image nodes enumatation part begin*******************//
xn::NodeInfoList image_node_info_list;
xn::ImageGenerator imageGen;
vector<xn::ImageGenerator> nImageGen;
cout<<"image nodes: "<<endl;
isError = context.EnumerateProductionTrees(XN_NODE_TYPE_IMAGE,NULL,image_node_info_list);
if((isError != XN_STATUS_OK) && (image_node_info_list.Begin() != image_node_info_list.End()))
{
cout<<"Enumerating image generators failed.Reason: "<<xnGetStatusString(isError)<<endl;
}
for(xn::NodeInfoList::Iterator nodeIt = image_node_info_list.Begin();
nodeIt != image_node_info_list.End();nodeIt++)
{
xn::NodeInfo info = *nodeIt;
XnProductionNodeDescription description = info.GetDescription();
cout<<" image: vendor "<<description.strVendor<<" name "<<description.strName<<endl;
context.CreateProductionTree(info);
info.GetInstance(imageGen);
imageGen.SetMapOutputMode(mode);
nImageGen.push_back(imageGen);
}
//********************image nodes enumatation part end*******************//
// name window to show depth and image
char nameOfWindow[80];
vector<string> depthWindow;
vector<string> imageWindow;
for(int i=0;i<nDepthGen.size();i++)
{
sprintf(nameOfWindow,"depth%d",i);
cvNamedWindow(nameOfWindow);
depthWindow.push_back(nameOfWindow);
}
for(int i=0;i<nImageGen.size();i++)
{
sprintf(nameOfWindow,"image%d",i);
cvNamedWindow(nameOfWindow,CV_WINDOW_AUTOSIZE);
imageWindow.push_back(nameOfWindow);
}
// name window end
// if there are two kinects, view point can be set like this:
nDepthGen[0].GetAlternativeViewPointCap().SetViewPoint(nImageGen[1]);
nDepthGen[1].GetAlternativeViewPointCap().SetViewPoint(nImageGen[0]);
/********* 为什么这样不行?
for(int i=0;i<nDepthGen.size();i++)
{
nDepthGen[i].GetAlternativeViewPointCap().SetViewPoint(nImageGen[i]);
}
***********/
//************************generating data begain*************************//
IplImage* depth = cvCreateImage(cvSize(640,480),IPL_DEPTH_16S,1);
IplImage* image = cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,3);
IplImage* depthShow = cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);
IplImage* imageShow = cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,3);
xn::DepthMetaData depthMD;
xn::ImageMetaData imageMD;
isError = context.StartGeneratingAll();
while(true)
{
if(context.WaitAndUpdateAll() != XN_STATUS_OK) break;
for(int i=0;i<nDepthGen.size();i++)
{
nDepthGen[i].GetMetaData(depthMD);
memcpy(depth->imageData,depthMD.Data(),640*480*2);
cvConvertScale(depth,depthShow,255.0/4096.0);
cvShowImage(depthWindow[i].data(),depthShow);
}
for(int i=0;i<nImageGen.size();i++)
{
nImageGen[i].GetMetaData(imageMD);
memcpy(image->imageData,imageMD.Data(),640*480*3);
cvCvtColor(image,imageShow,CV_RGB2BGR);
cvShowImage(imageWindow[i].data(),imageShow);
}
if(cvWaitKey(10) == 27) break;
}
cvReleaseImage(&depth);
cvReleaseImage(&image);
cvReleaseImage(&depthShow);
cvReleaseImage(&imageShow);
cvDestroyAllWindows();
context.StopGeneratingAll();
context.Shutdown();
return 0;
}
通过枚举所有的depth node和image node来对每一个camera创建一个generator,然后就是传统的生成meta data转化成image然后输出了。没想到openNI还自带了一个Iterator来帮助循环,想的挺周到的,可惜刚接触还没用习惯。下面进行几点说明:
1. 程序的devices enumaration部分是用来枚举所有设备并输出相关信息的,写具体的应用程序时可以省略。
2. 程序的depth nodes enumaration部分枚举所有能用的depth相机,对每一个相机在context中添加一个depthGenerator,并设置output mode。程序创建了一个vector容 器, 所有的depthGenerator放入其中,以供后面生成数据使用。
3. 程序的image nodes enumatation部分同上。
4. 程序的name window部分创建显示图像的窗口,可以省略。在省略的情况下,显示图像时传一个字符串形式的window name给cvShowImage,opencv会自动创建一个窗 口,最后用cvDestroyAllWindows()来一次性关闭所有窗口。
5. 在两个kinect的情况下,每一个kinect所产生的depth图像和rgb图像因视点不一样而不能匹配,这时需要改变一个图像的视点。openNI只允许将depth图像的视点转变到rgb图 像上。我想当然的认为depthGenerator和imageGenerator会按角标一一对应,故而试图用循环来改变depth图像的视点到rgb图像上,没想到在我的电脑上depthGenerator[0] 对应的是imageGenerator[1],而depthGenerator[1]对应的却是imageGenerator[0]。奇之怪也!似乎系统在找depth node的时候是随机找的。于是乎只能用枚举的方法改正 视点了。如果有多个kinect,可以在depth nodes enumaration部分增加一个query,从而找到depth与image之间的对应。(偶没试过,后面有时间的话试一下)。
6. 这一部分就是标准的读取数据然后输出了。
注:连多个kinect时,必须确保每一个kinect都连在不同的USB中心,也就是说,不能将多个kinect连在同一个USB集线器中。
附:名古屋工业大学高手代码:http://nma.web.nitech.ac.jp/fukushima/openni/SampleMultiKinect.cpp
#include <opencv2/opencv.hpp>
using namespace cv;
#include <XnCppWrapper.h>
#pragma comment(lib,"C:/Program files/OpenNI/Lib/openNI.lib")
#define CHECK_RC(rc, what) \
if (rc != XN_STATUS_OK) \
{ \
printf("%s failed: %s\n", what, xnGetStatusString(rc)); \
return rc; \
}
using namespace xn;
//Multi Kinect Test
#define NUM_KINECT 2
int main()
{
XnStatus nRetVal = XN_STATUS_OK;
Context context;
nRetVal = context.Init();
CHECK_RC(nRetVal, "Initialize context");
XnMapOutputMode mapMode;
mapMode.nXRes = 640;
mapMode.nYRes = 480;
mapMode.nFPS = 30;
xn::NodeInfoList device_node_info_list;
// enumerate all devices
printf("devices:\n");
nRetVal = context.EnumerateProductionTrees(XN_NODE_TYPE_DEVICE, NULL,
device_node_info_list);
if (nRetVal != XN_STATUS_OK && device_node_info_list.Begin () !=
device_node_info_list.End ()) {
printf("enumerating devices failed. Reason: %s", xnGetStatusString
(nRetVal));
return -1;
}
for (xn::NodeInfoList::Iterator nodeIt = device_node_info_list.Begin
(); nodeIt != device_node_info_list.End (); ++nodeIt) {
const xn::NodeInfo& info = *nodeIt;
const XnProductionNodeDescription& description =
info.GetDescription();
printf("device: vendor %s name %s, instance %s\n",
description.strVendor, description.strName, info.GetInstanceName());
}
printf("image nodes:\n");
ImageGenerator im_multi[NUM_KINECT];
ImageMetaData imMD;
xn::NodeInfoList image_node_info_list;
vector<NodeInfo> mImageNodes;
nRetVal = context.EnumerateProductionTrees(XN_NODE_TYPE_IMAGE, NULL,
image_node_info_list, NULL);
for (xn::NodeInfoList::Iterator nodeIt =
image_node_info_list.Begin(); nodeIt != image_node_info_list.End(); ++nodeIt)
{
const xn::NodeInfo& info = *nodeIt;
const XnProductionNodeDescription& description = info.GetDescription();
printf("creation info %s\n",info.GetCreationInfo());
printf("image: vendor-%s ,name-%s, instance %s\n",
description.strVendor, description.strName, info.GetInstanceName());
printf("Version %d.%d\n",description.Version.nMajor,description.Version.nMinor);
//XN_NODE_TYPE_DEPTH = 2,
//XN_NODE_TYPE_IMAGE = 3,
//XN_NODE_TYPE_AUDIO = 4,
//XN_NODE_TYPE_IR = 5,
printf("Type %d\n",description.Type);
mImageNodes.push_back(info);
}
【1】 for(int i=0;i<NUM_KINECT;i++)
{
context.CreateProductionTree(mImageNodes[i]);
mImageNodes[i].GetInstance(im_multi[i]);
nRetVal = im_multi[i].SetMapOutputMode(mapMode);
}
printf("depth nodes:\n");
DepthGenerator dp_multi[NUM_KINECT];
DepthMetaData dpMD;
xn::NodeInfoList depth_node_info_list;
vector<NodeInfo> mDepthNodes;
// enumerate depth nodes:
nRetVal = context.EnumerateProductionTrees(XN_NODE_TYPE_DEPTH, NULL,
depth_node_info_list, NULL);
for (xn::NodeInfoList::Iterator nodeIt =
depth_node_info_list.Begin(); nodeIt != depth_node_info_list.End(); ++nodeIt)
{
const xn::NodeInfo& info = *nodeIt;
const XnProductionNodeDescription& description = info.GetDescription();
printf("creation info %s\n",info.GetCreationInfo());
printf("depth: vendor-%s ,name-%s, instance %s\n",
description.strVendor, description.strName, info.GetInstanceName());
printf("Version %d.%d\n",description.Version.nMajor,description.Version.nMinor);
//XN_NODE_TYPE_DEPTH = 2,
//XN_NODE_TYPE_IMAGE = 3,
//XN_NODE_TYPE_AUDIO = 4,
//XN_NODE_TYPE_IR = 5,
printf("Type %d\n",description.Type);
mDepthNodes.push_back(info);
}
【2】
for(int i=0;i<NUM_KINECT;i++)
{
context.CreateProductionTree(mDepthNodes[i]);
mDepthNodes[i].GetInstance(dp_multi[i]);
nRetVal = dp_multi[i].SetMapOutputMode(mapMode);
}
nRetVal = context.StartGeneratingAll();
int key = 0;
while(key!='q')
{
context.WaitAnyUpdateAll();//wait and error processing
for(int i=0;i<NUM_KINECT;i++)
{
im_multi[i].GetMetaData(imMD);
Mat imMat(480,640,CV_8UC3,(unsigned char*)imMD.WritableData());
char name[64];
sprintf(name,"Image %d",i);
cvtColor(imMat,imMat,CV_RGB2BGR);
imshow(name, imMat);
}
for(int i=0;i<NUM_KINECT;i++)
{
dp_multi[i].GetMetaData(dpMD);
Mat dp16(480,640,CV_16SC1,(unsigned short*)dpMD.WritableData());
Mat dpMat;
dp16.convertTo(dpMat,CV_8U,1.0/16.0);
char name[64];
sprintf(name,"Depth %d",i);
imshow(name, dpMat);
}
key = waitKey(1);
}
cvDestroyAllWindows();
}
一个group google上的一个讨论帖,有较高的参考价值:http://groups.google.com/group/openni-dev/browse_thread/thread/72f5f6ac787bdee7