OpenNI--读取两个kinect的数据

#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 

http://blog.csdn.net/chenli2010/article/details/6948228

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值