使用OpenNI2读取oni格式的文件,并将其中的彩色视频,深度视频显示并保存

前几天做人体行为识别的师姐在网上下载了一个以.oni格式保存的数据集,师姐让我帮忙将.oni格式的数据读出并保存为图片序列,以便能用OpenCV/matlab进行处理弄了两三天,终于能完整的将oni文件中的视频数据一帧不少的读出来了,现在将我的方法分享一下。


之前没有接触过OpenNI,这次用到OpenNI是从零开始学的,到今天我也只学了不到4天,有错误的地方还请指教。


首先说一下我对OpenNI2的认识,开始也用过OpenNI1.5但是发现太难,结构不如OpenNI2这种C++风格的清晰,因此,在最初接触了OpenNI几个小时后我就果断的选择了使用OpenNI2,而且OpenNI2的配置也相对比较简单,我用的版本是OpenNI-Windows-x86-2.2,系统是Win7+VS2010。(我的配置是按照这个方法进行的)


由于我仅仅用OpenNI2读取oni格式的数据并保存,下面就只谈与之相关的。(其他的我也不懂)


目前能查到的将oni格式文件中的视频流中每一帧视频都读出来的方法有两种:

一、设置循环。首先读取视频流中的总帧数,然后用这个总帧数设置循环次数每一次读取一帧并保存。

二、设置事件。为视频流添加一个事件,每当视频流更新则读取当前帧并保存。

这两种方法我都用过但是都会出现同样的问题,那就是丢帧,即不能按顺序的一帧不落的将所有帧都读出,究其原因可能是我的电脑太慢了,在视频流下一帧更新之前不能将当前帧读取并保存。


几经挣扎我终于找到的能一帧不落的读完所有帧,那就是要在设置循环的方法中设置视频流的速度,将视频流的速度设置为-1,即只有程序在进行读取视频流的时候视频流才更新,其他时间视频流是不动作的。


另外,程序中的图片显示以及保存都是用的OpenCV,关于OpenCV,网上的资料很多我就不做过多的介绍了,如果有需要还可以用OpenCV将oni文件保存为.avi的视频。


下面在程序以及注释中进行详细的解释


#include <iostream>
#include <OpenNI.h>
#include <opencv2\core\core.hpp>
#include <opencv2\imgproc\imgproc.hpp>
#include <opencv2\highgui\highgui.hpp>

using namespace std;

int main()
{
	//定义oni文件中视频的总帧数以及得到的图片的保存目录
	int total = 0;
	char* imagefile = "D:\\data\\data1";
	
	//初始化OpenNI环境
	openni::OpenNI::initialize();

	//声明设备并打开oni文件
	openni::Device fromonifile;
	fromonifile.open("D:\\USER28_CAL11\\qw\\S13_C11_U26_D3.oni");

	//声明控制对象,这对视频流的控制起到了关键作用
	openni::PlaybackControl* pController = fromonifile.getPlaybackControl();

	//声明视频流对象以及帧对象
	openni::VideoStream streamColor;
	openni::VideoFrameRef frameColor;

	//验证是否有彩色传感器(是否有彩色视频)和建立与设备想关联的视频流
	if(fromonifile.hasSensor(openni::SENSOR_COLOR))
	{		
		if(streamColor.create( fromonifile, openni::SENSOR_COLOR ) == openni::STATUS_OK )
		{
			cout<<"建立视频流成功"<<endl;
		}
		else
		{
			cerr<<"ERROR: 建立视频流没有成功"<<endl;
			system("pause");
			return -1;
		}
	}
	else
	{
		cerr << "ERROR: 该设备没有彩色传感器" << endl;
		system("pause");
		return -1;
	}

	//建立显示窗口
	cv::namedWindow("Image");

	//获取总的视频帧数并将该设备的速度设为-1以便能留出足够的时间对每一帧进行处理、显示和保存
	total = pController->getNumberOfFrames(streamColor);
	pController->setSpeed(-1);

	//开启视频流
	streamColor.start();
	for (int i = 1;i <= total; ++ i)
	{
		//读取视频流的当前帧
		streamColor.readFrame(&frameColor);

		cout<<"当前正在读的帧数是:"<<frameColor.getFrameIndex()<<endl;
		cout<<"当前的循环次数是:  "<<i<<endl;

		//将帧保存到Mat中并且将其转换到BGR模式,因为在OpenCV中图片的模式是BGR
		cv::Mat rgbImg(frameColor.getHeight(), frameColor.getWidth(), CV_8UC3, (void*)frameColor.getData());
		cv::Mat bgrImg;
		cvtColor(rgbImg, bgrImg, CV_RGB2BGR);

		//将每一帧按顺序帧保存到图片目录下
		char imagefullname[255];
		char imagenum[50];
		sprintf(imagenum,"\\%03d.png",i);
		strcpy(imagefullname,imagefile);
		strcat(imagefullname,imagenum);
		cv::imwrite(imagefullname,bgrImg);

		//显示当前帧
		cv::imshow("Image",bgrImg);
		if (cv::waitKey(30) == 27)
		{
			break;
		}
	}

	//销毁显示窗口
	cv::destroyWindow("Image");	

	//关闭视频流
	streamColor.destroy();

	//关闭设备
	fromonifile.close();

	//关闭OpenNI
	openni::OpenNI::shutdown();
	
	return 0;
}

程序运行的截图(数据集是从网上下载的,不要在意视频上那个人,我也不认识)



如果想要读深度数据那么将30和32行的SENSOR_COLOR改成SENSOR_DEPTH

当然由于在OpenNI中的深度数据到OpenCV中要用CV_16UC1来保存并且要想较好的显示还需要下面的转换

const cv::Mat mImageDepth( frame.getHeight(), frame.getWidth(), CV_16UC1, (void*)frame.getData());			
			int iMaxDepth = stream.getMaxPixelValue();
			cv::Mat mScaledDepth;
			mImageDepth.convertTo( mScaledDepth, CV_8U, 255.0 / iMaxDepth );


以上,就是我的一些经验,不免有疏漏,请多多包含。

参考:

http://www.cnblogs.com/yemeishu/archive/2013/01/11/2856859.html

http://blog.csdn.net/chenxin_130/article/details/8580636

http://www.dotblogs.com.tw/v6610688/archive/2014/03/02/openni_oni_format_file_to_avi_opencv.aspx#feedback

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值