昨天验证了Kinect是可以用的,今天做了第一个实验。参考的是小斤同学的文章
http://blog.csdn.net/chenxin_130/article/details/6696187
http://blog.csdn.net/yangtrees/article/details/8989650
本实验使用C++编写,小斤同学使用了opencv1.0的函数库,这个实验一个困难的地方就是将OpenNI中的深度数据和彩色图像数据保存到OpenCV的数据中。
这一部分我参照了 开启Kinect & 格式转换Mat 这篇文章,终于找到了解决方法,这里列举下其中的两种方法。
首先看Mat的构造函数
C++: Mat::Mat()
C++: Mat::Mat(int rows, int cols, int type)
C++: Mat::Mat(Size size, int type)
C++: Mat::Mat(int rows, int cols, int type, const Scalar& s)
C++: Mat::Mat(Size size, int type, const Scalar& s)
C++: Mat::Mat(const Mat& m)
C++: Mat::Mat(int rows, int cols, int type, void* data, size_t step=AUTO_STEP)
C++: Mat::Mat(Size size, int type, void* data, size_t step=AUTO_STEP)
C++: Mat::Mat(const Mat& m, const Range& rowRange, const Range& colRange=Range::all() )
C++: Mat::Mat(const Mat& m, const Rect& roi)
C++: Mat::Mat(const CvMat* m, bool copyData=false)
C++: Mat::Mat(const IplImage* img, bool copyData=false)
C++: template<typename T, int n> explicit Mat::Mat(const Vec<T, n>& vec, bool copyData=true)
C++: template<typename T, int m, int n> explicit Mat::Mat(const Matx<T, m, n>& vec, bool copyData=true)
C++: template<typename T> explicit Mat::Mat(const vector<T>& vec, bool copyData=false)
C++: Mat::Mat(int ndims, const int* sizes, int type)
C++: Mat::Mat(int ndims, const int* sizes, int type, const Scalar& s)
C++: Mat::Mat(int ndims, const int* sizes, int type, void* data, const size_t* steps=0)
C++: Mat::Mat(const Mat& m, const Range* ranges)
使用
Mat(int rows, int cols, int type, void* data, size_t step=AUTO_STEP)
方法新声明一个图像矩阵并用利用指针传递深度信息和图像信息。
depthGenerator.GetMetaData(depthMD);
imageGenerator.GetMetaData(imageMD);
if(depthMD.Data() != NULL)
{
//convert ImageMetaDate to Mat
uchar *imageMDPointer = (uchar *)imageMD.Data();
Mat imageRGB(480, 640, CV_8UC3, imageMDPointer);//Mat(int rows, int cols, int type, void* data, size_t step=AUTO_STEP);
cvtColor(imageRGB, imageShow, CV_RGB2BGR);
//convert DepthMetaData to Mat
unsigned short *depthMDPointer = (unsigned short *)depthMD.Data();
Mat imgDepth(480, 640, CV_16UC1, depthMDPointer);
convertScaleAbs(imgDepth, depthShow, 255/4096.0); //将16深度位数据转换为8位数据,以便用灰度图像显示。
normalize(depthShow, depthShow, 255, 0, NORM_MINMAX );//归一化 0~255
//output
imshow("Image", imageShow);
imshow("Depth", depthShow);
}
第二种方法
通过指针将深度数据和图像数据一个一个赋值到指定的Mat中去。
Mat rgbMat3(480,640,CV_8UC3);
Mat rgbMatShow3;
uchar *rgb_p;
uchar *src_p;
src_p = (uchar*) imageMD.Data();
for (int y=0; y<480; y++)
{
rgb_p = rgbMat3.ptr<uchar>(y);//这里特别
for (int x=0; x<640; x++)
{
*rgb_p++ =(uchar) *src_p++;
*rgb_p++ =(uchar) *src_p++;
*rgb_p++ =(uchar) *src_p++;
}
}
cvtColor(rgbMat3,rgbMatShow3,CV_RGB2BGR);
imshow("testColorMat3",rgbMatShow3);
Mat depthMat3(480,640,CV_16SC1);
Mat depthMatShow3(480,640,CV_8UC1);
UINT16* depthSrc_p;
uchar* depth3_p;
depthSrc_p = (UINT16*)depthMD.Data();
for (int y=0; y<480; y++)
{
depth3_p = depthMatShow3.ptr<uchar>(y);
for (int x=0; x<640; x++)
{
depth3_p[x]= (uchar)((*depthSrc_p)*255/4096);
depthSrc_p++;
}
}
//convertScaleAbs(depthMat3,depthMatShow3,255/4096.0);//这一步很重要;
normalize(depthMatShow3,depthMatShow3,255,0,CV_MINMAX);
imshow("testDepthMat3",depthMatShow3);
本实验的源码如下
#include "stdafx.h"
#include "opencv2/opencv.hpp"
#include "XnCppWrapper.h"
using namespace cv;
using namespace std;
void checkOpenNIError(XnStatus res, string status)
{
if( res != XN_STATUS_OK)
{
cerr << status << "Error: "<<xnGetStatusString(res) <<endl;
}
}
int main(int argc, char **argv)
{
XnStatus result = XN_STATUS_OK;
xn::DepthMetaData depthMD;
xn::ImageMetaData imageMD;
//Mat imgDepth16u(480, 640, CV_16UC1);
//Mat imgBGR8u(480, 640, CV_8UC3);//Mat(nrows, ncols, type)
Mat depthShow(480, 640, CV_8UC1);
Mat imageShow(480, 640, CV_8UC3);
char key = 0;
namedWindow("Depth", WINDOW_AUTOSIZE);
namedWindow("Image", WINDOW_AUTOSIZE);
xn::Context context;
result = context.Init();
checkOpenNIError(result, "initialize context");
xn::DepthGenerator depthGenerator;
result = depthGenerator.Create(context);
checkOpenNIError(result, "Create depth generator");
xn::ImageGenerator imageGenerator;
result = imageGenerator.Create(context);
checkOpenNIError(result, "Create image generator");
XnMapOutputMode mapMode;
mapMode.nXRes = 640;
mapMode.nYRes = 480;
mapMode.nFPS = 30;
result = depthGenerator.SetMapOutputMode(mapMode);
result = imageGenerator.SetMapOutputMode(mapMode);
// correct view port
depthGenerator.GetAlternativeViewPointCap().SetViewPoint(imageGenerator);
//read data
result = context.StartGeneratingAll();
result = context.WaitNoneUpdateAll();
while ( (key != 27) && !(result = context.WaitNoneUpdateAll()) )
{
//get meta data
depthGenerator.GetMetaData(depthMD);
imageGenerator.GetMetaData(imageMD);
if(depthMD.Data() != NULL)
{
//convert ImageMetaDate to Mat
uchar *imageMDPointer = (uchar *)imageMD.Data();
Mat imageRGB(480, 640, CV_8UC3, imageMDPointer);//Mat(int rows, int cols, int type, void* data, size_t step=AUTO_STEP);
cvtColor(imageRGB, imageShow, CV_RGB2BGR);
//convert DepthMetaData to Mat
unsigned short *depthMDPointer = (unsigned short *)depthMD.Data();
Mat imgDepth(480, 640, CV_16UC1, depthMDPointer);
convertScaleAbs(imgDepth, depthShow, 255/4096.0);
normalize(depthShow, depthShow, 255, 0, NORM_MINMAX );
//output
imshow("Image", imageShow);
imshow("Depth", depthShow);
}
key=cvWaitKey(20);
}
context.StopGeneratingAll();
context.Release();
return 0;
}