本例是使用opencv函数调用openni的图像。
通常在使用xtion或kinect时总是只在openni下使用,为
了能在opencv环境下使用xtion搜索了相关资源,通过
实验,总结如下(在ubuntu14.04,qt下):
方案一:
OpenNI 2与OpenCV结合的第一个程序
开始之前,让我们自己开始再熟练熟练OpenNI 2的基本使用,主要包括以下几个步骤:
1. 初始化OpenNI环境: openni::OpenNI::initialize();
2. 声明并打开Device设备: openni::Device devAnyDevice; devAnyDevice.open( openni::ANY_DEVICE );
3. 创建并打开深度数据流:openni::VideoStream streamDepth; streamDepth.create( devAnyDevice, openni::SENSOR_DEPTH ); streamDepth.start();
4. 读取数据流信息并保存在VideoFrameRef中:openni::VideoFrameRef frameDepth;streamDepth.readFrame( &frameDepth );
5. 获取深度(或颜色等)数据,开始我们自己的开发之旅: const openni::DepthPixel* pDepth = (const openni::DepthPixel*)frameDepth.getData();
6. 当结束使用数据时,首先关闭、销毁数据流:streamDepth.destroy();
7. 接着关闭设备: devAnyDevice.close();
8. 最后关闭OpenNI: openni::OpenNI::shutdown();
#include <iostream>
#include "OpenNI.h"
int main( int argc, char** argv )
{
// 初始化OpenNI环境
openni::OpenNI::initialize();
// 声明并打开Device设备,我用的是Kinect。
openni::Device devAnyDevice;
devAnyDevice.open( openni::ANY_DEVICE );
// 创建并打开深度数据流
openni::VideoStream streamDepth;
streamDepth.create( devAnyDevice, openni::SENSOR_DEPTH );
streamDepth.start();
// 同样的创建并打开彩色图像数据流
openni::VideoStream streamColor;
streamColor.create( devAnyDevice, openni::SENSOR_COLOR );
streamColor.start();
// 循环读取数据流信息并保存在VideoFrameRef中
openni::VideoFrameRef frameDepth;
openni::VideoFrameRef frameColor;
for( int i = 0; i < 1000; ++ i )
{
// 读取数据流
streamDepth.readFrame( &frameDepth );
streamColor.readFrame( &frameColor );
// 获取data array
const openni::DepthPixel* pDepth
= (const openni::DepthPixel*)frameDepth.getData();
const openni::RGB888Pixel* pColor
= (const openni::RGB888Pixel*)frameColor.getData();
// 显示深度信息和对应的彩色R、G、B数值
int idx = frameDepth.getWidth() * ( frameDepth.getHeight() + 1 ) / 2;
std::cout << pDepth[idx] << "( "
<< (int)pColor[idx].r << ","
<< (int)pColor[idx].g << ","
<< (int)pColor[idx].b << ")"
<< std::endl;
}
// 关闭数据流
streamDepth.destroy();
streamColor.destroy();
// 关闭设备
devAnyDevice.close();
// 最后关闭OpenNI
openni::OpenNI::shutdown();
return 0;
}
案列:利用OpenCV函数显示深度图像和彩色图像。直接上代码:
#include "stdafx.h"
#include <iostream>
#include "OpenNI.h"
// 载入OpenCV头文件
#include "opencv2/opencv.hpp"
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace std;
using namespace openni;
using namespace cv;
int main( int argc, char** argv )
{
// 初始化OpenNI环境
OpenNI::initialize();
// 声明并打开Device设备,我用的是Kinect。
Device devAnyDevice;
devAnyDevice.open(ANY_DEVICE );
// 创建深度数据流
VideoStream streamDepth;
streamDepth.create( devAnyDevice, SENSOR_DEPTH );
// 创建彩色图像数据流
VideoStream streamColor;
streamColor.create( devAnyDevice, SENSOR_COLOR );
// 设置深度图像视频模式
VideoMode mModeDepth;
// 分辨率大小
mModeDepth.setResolution( 640, 480 );
// 每秒30帧
mModeDepth.setFps( 30 );
// 像素格式
mModeDepth.setPixelFormat( PIXEL_FORMAT_DEPTH_1_MM );
streamDepth.setVideoMode( mModeDepth);
// 同样的设置彩色图像视频模式
VideoMode mModeColor;
mModeColor.setResolution( 640, 480 );
mModeColor.setFps( 30 );
mModeColor.setPixelFormat( PIXEL_FORMAT_RGB888 );
streamColor.setVideoMode( mModeColor);
// 图像模式注册
if( devAnyDevice.isImageRegistrationModeSupported(
IMAGE_REGISTRATION_DEPTH_TO_COLOR ) )
{
devAnyDevice.setImageRegistrationMode( IMAGE_REGISTRATION_DEPTH_TO_COLOR );
}
// 打开深度和图像数据流
streamDepth.start();
streamColor.start();
// 创建OpenCV图像窗口
namedWindow( "Depth Image", CV_WINDOW_AUTOSIZE );
namedWindow( "Color Image", CV_WINDOW_AUTOSIZE );
// 获得最大深度值
int iMaxDepth = streamDepth.getMaxPixelValue();
// 循环读取数据流信息并保存在VideoFrameRef中
VideoFrameRef frameDepth;
VideoFrameRef frameColor;
while( true )
{
// 读取数据流
streamDepth.readFrame( &frameDepth );
streamColor.readFrame( &frameColor );
// 将深度数据转换成OpenCV格式
const cv::Mat mImageDepth( frameDepth.getHeight(), frameDepth.getWidth(), CV_16UC1, (void*)frameDepth.getData());
// 为了让深度图像显示的更加明显一些,将CV_16UC1 ==> CV_8U格式
cv::Mat mScaledDepth;
mImageDepth.convertTo( mScaledDepth, CV_8U, 255.0 / iMaxDepth );
// 显示出深度图像
cv::imshow( "Depth Image", mScaledDepth );
// 同样的将彩色图像数据转化成OpenCV格式
const cv::Mat mImageRGB(frameColor.getHeight(), frameColor.getWidth(), CV_8UC3, (void*)frameColor.getData());
// 首先将RGB格式转换为BGR格式
cv::Mat cImageBGR;
cv::cvtColor( mImageRGB, cImageBGR, CV_RGB2BGR );
// 然后显示彩色图像
cv::imshow( "Color Image", cImageBGR );
// 终止快捷键
if( cv::waitKey(1) == 'q')
break;
}
// 关闭数据流
streamDepth.destroy();
streamColor.destroy();
// 关闭设备
devAnyDevice.close();
// 最后关闭OpenNI
openni::OpenNI::shutdown();
return 0;
}
注:在做此实验中,由于自身opencv和openni2的环境部署问题,出现一系列包导入路径问题:
INCLUDEPATH += /usr/include\ /usr/include/opencv\ /usr/include/opencv2\ /usr/include/openni2\#需加
LIBS += /usr/lib/x86_64-linux-gnu/libopencv_highgui.so.2.4\ /usr/lib/x86_64-linux-gnu/libopencv_core.so \ /usr/lib/x86_64-linux-gnu/libopencv_imgproc.so\ /usr/lib/x86_64-linux-gnu/libopencv_video.so\ /usr/lib/x86_64-linux-gnu/libopencv_objdetect.so\ /usr/lib/libOpenNI2.so#需加
方案二:此处不在解释,直接上代码,ps:由于用到openni1中的函数,实验没有完成:
OpenNI获取的图像结合OpenCV显示
copenni.cpp:
#include <XnCppWrapper.h>
#include <QtGui/QtGui>
#include <iostream>
using namespace xn;
using namespace std;
class COpenNI
{
public:
~COpenNI() {
context.Release();//释放空间
}
bool Initial() {
//初始化
status = context.Init();
if(CheckError("Context initial failed!")) {
return false;
}
context.SetGlobalMirror(true);//设置镜像
//产生图片node
status = image_generator.Create(context);
if(CheckError("Create image generator error!")) {
return false;
}
//产生深度node
status = depth_generator.Create(context);
if(CheckError("Create depth generator error!")) {
return false;
}
//视角校正
status = depth_generator.GetAlternativeViewPointCap().SetViewPoint(image_generator);
if(CheckError("Can't set the alternative view point on depth generator")) {
return false;
}
return true;
}
bool Start() {
status = context.StartGeneratingAll();
if(CheckError("Start generating error!")) {
return false;
}
return true;
}
bool UpdateData() {
status = context.WaitNoneUpdateAll();
if(CheckError("Update date error!")) {
return false;
}
//获取数据
image_generator.GetMetaData(image_metadata);
depth_generator.GetMetaData(depth_metadata);
return true;
}
public:
DepthMetaData depth_metadata;
ImageMetaData image_metadata;
private:
//该函数返回真代表出现了错误,返回假代表正确
bool CheckError(const char* error) {
if(status != XN_STATUS_OK ) {
QMessageBox::critical(NULL, error, xnGetStatusString(status));
cerr << error << ": " << xnGetStatusString( status ) << endl;
return true;
}
return false;
}
private:
XnStatus status;
Context context;
DepthGenerator depth_generator;
ImageGenerator image_generator;
};
main.cpp:
#include <QCoreApplication>
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <opencv2/core/core.hpp>
#include "copenni.cpp"
#include <iostream>
using namespace cv;
using namespace xn;
int main (int argc, char **argv)
{
COpenNI openni;
if(!openni.Initial())
return 1;
namedWindow("color image", CV_WINDOW_AUTOSIZE);
namedWindow("color edge detect", CV_WINDOW_AUTOSIZE);
namedWindow("depth image", CV_WINDOW_AUTOSIZE);
namedWindow("depth edge detect", CV_WINDOW_AUTOSIZE);
if(!openni.Start())
return 1;
while(1) {
if(!openni.UpdateData()) {
return 1;
}
/*获取并显示色彩图像*/
Mat color_image_src(openni.image_metadata.YRes(), openni.image_metadata.XRes(),
CV_8UC3, (char *)openni.image_metadata.Data());
Mat color_image;
cvtColor(color_image_src, color_image, CV_RGB2BGR);
imshow("color image", color_image);
/*对色彩图像进行canny边缘检测并显示*/
Mat color_image_gray, color_image_edge;
cvtColor(color_image_src, color_image_gray, CV_RGB2GRAY);//因为在进行边缘检测的时候只能使用灰度图像
Canny(color_image_gray, color_image_edge, 5, 100);
imshow("color edge detect", color_image_edge);
/*获取并显示深度图像*/
Mat depth_image_src(openni.depth_metadata.YRes(), openni.depth_metadata.XRes(),
CV_16UC1, (char *)openni.depth_metadata.Data());//因为kinect获取到的深度图像实际上是无符号的16位数据
Mat depth_image, depth_image_edge;
depth_image_src.convertTo(depth_image, CV_8U, 255.0/8000);
imshow("depth image", depth_image);
/*计算深度图像的canny边缘并显示*/
Canny(depth_image, depth_image_edge, 5, 100);
imshow("depth edge detect", depth_image_edge);
waitKey(30);
}
}
参考:
Kinect+OpenNI学习笔记之4(OpenNI获取的图像结合OpenCV显示)
OpenNI 2与OpenCV结合的第一个程序
使用opencv显示openni获取的图像
Kinect开发教程二:OpenNI读取深度图像与彩色图像并显示
附录:openni库
OpenNI