Kinect开发(2)-景深数据获取
上一节讲了OpenNI2开发Kinect的基本框架,但是,具体的数据流获取并没有详细介绍,本篇文章开始介绍数据流的获取与处理。采用OpenCV进行图像的处理与显示。
获取景深数据有2种方式,一种是轮询,另外一种是设置一个Listener,当有新的数据帧到达时,会通知该Listener。下面分别实现这两种方式。
先上代码,注:为了更清晰的展示主要过程,对于一些错误及异常都没有进行判断,代码写的比较简陋。
方式一:轮询
1 #include <iostream> 2 using namespace std; 3 4 #include <OpenNI.h> 5 #pragma comment(lib, "openni2.lib") 6 7 #include <opencv/cv.h> 8 #include <opencv/highgui.h> 9 #pragma comment(lib, "opencv_core244.lib") 10 #pragma comment(lib, "opencv_highgui244.lib") 11 12 int main() 13 { 14 openni::Status rc = openni::STATUS_OK; 15 openni::Device device; 16 openni::VideoStream depthStream; 17 openni::VideoFrameRef frame; 18 IplImage* img = NULL; 19 char* pImgData = NULL; 20 //初始化设备驱动 21 openni::OpenNI::initialize(); 22 //打开设备 23 device.open(openni::ANY_DEVICE); 24 //接收景深传感器的数据 25 depthStream.create(device, openni::SENSOR_DEPTH); 26 depthStream.start(); 27 cvNamedWindow("wnd", CV_WINDOW_AUTOSIZE); 28 while (true) 29 { 30 depthStream.readFrame(&frame); 31 if (frame.isValid()) 32 { 33 openni::DepthPixel* pData = (openni::DepthPixel*)frame.getData(); 34 if (!pImgData) 35 { 36 pImgData = new char[frame.getHeight()*frame.getWidth()]; 37 } 38 if (!img) 39 { 40 img = cvCreateImage(cvSize(frame.getWidth(), frame.getHeight()),8, 1); 41 } 42 for (int row=0; row!=frame.getHeight(); ++row) 43 { 44 for (int col=0; col!=frame.getWidth(); ++col) 45 { 46 pImgData[row*frame.getWidth() + col] = (char)pData[row*frame.getWidth()+col]%256; 47 } 48 } 49 img->imageData = pImgData; 50 cvShowImage("wnd", img); 51 char c = cvWaitKey(30); 52 if (c == 27) 53 { 54 cvReleaseImage(&img); 55 delete[] pImgData; 56 cvDestroyWindow("wnd"); 57 break; 58 } 59 } 60 } 61 depthStream.stop(); 62 depthStream.destroy(); 63 device.close(); 64 openni::OpenNI::shutdown(); 65 return 0; 66 }
首先进行驱动、设备的初始化,由于上一节中已经介绍过,不再进行赘述。
27:初始化一个OpenCV的窗口,用于显示处理之后的深度数据。
30:从VideoStream中读取景深数据的数据帧。数据帧是openni::VideoFrameRef类型,该对象保存着本帧数据的宽高、时间戳、帧计数等信息。
31:判断该数据帧是否有效。
33:获取到该帧的数据,注意,OpenNI是用2个字节来表示一个景深数据,也就是DepthPixel其实就是uint16_t类型。
34-41:根据该帧的信息,分配OpenCV需要用到的结构。
42-48:这里只是进行一个简单的处理,对每个深度数据取256的模,以便进行区分。
49-50:把处理后的数据在窗口中显示出来。
方式二:事件
1 #include <conio.h> 2 #include <iostream> 3 using namespace std; 4 5 #include <OpenNI.h> 6 #pragma comment(lib, "openni2.lib") 7 8 #include <opencv/cv.h> 9 #include <opencv/highgui.h> 10 #pragma comment(lib, "opencv_core244.lib") 11 #pragma comment(lib, "opencv_highgui244.lib") 12 13 class NewDepthFrameListener 14 : public openni::VideoStream::NewFrameListener 15 { 16 public: 17 NewDepthFrameListener():m_pImg(nullptr), m_pImgData(nullptr) {}; 18 ~NewDepthFrameListener() 19 { 20 if (m_pImg) 21 { 22 cvReleaseImage(&m_pImg); 23 m_pImg = nullptr; 24 } 25 if (m_pImgData) 26 { 27 delete[] m_pImgData; 28 m_pImgData = nullptr; 29 } 30 } 31 32 public: 33 virtual void onNewFrame(openni::VideoStream& stream) 34 { 35 openni::VideoFrameRef frame; 36 stream.readFrame(&frame); 37 if (frame.isValid()) 38 { 39 const openni::DepthPixel* pData = (openni::DepthPixel*)frame.getData(); 40 if (!m_pImgData) 41 { 42 m_pImgData = new char[frame.getWidth()*frame.getHeight()]; 43 } 44 if (!m_pImg) 45 { 46 m_pImg = cvCreateImage(cvSize(frame.getWidth(), frame.getHeight()), 8, 1); 47 } 48 for (int row=0; row!=frame.getHeight(); ++row) 49 { 50 for (int col=0; col!=frame.getWidth(); ++col) 51 { 52 m_pImgData[row*frame.getWidth() + col] = (char)pData[row*frame.getWidth()+col]%256; 53 } 54 } 55 m_pImg->imageData = m_pImgData; 56 cvShowImage("wnd", m_pImg); 57 frame.release(); 58 } 59 } 60 61 private: 62 char* m_pImgData; 63 IplImage* m_pImg; 64 }; 65 66 int main() 67 { 68 openni::Status rc = openni::STATUS_OK; 69 openni::Device device; 70 openni::VideoStream depthStream; 71 openni::VideoFrameRef frame; 72 NewDepthFrameListener listener; 73 IplImage* img = NULL; 74 char* pImgData = NULL; 75 //初始化设备驱动 76 openni::OpenNI::initialize(); 77 //打开设备 78 device.open(openni::ANY_DEVICE); 79 //接收景深传感器的数据 80 depthStream.create(device, openni::SENSOR_DEPTH); 81 depthStream.start(); 82 depthStream.addNewFrameListener(&listener); 83 cvNamedWindow("wnd", CV_WINDOW_AUTOSIZE); 84 while (true) 85 { 86 if (cvWaitKey(30) == 27) 87 { 88 break; 89 } 90 } 91 cvDestroyWindow("wnd"); 92 depthStream.stop(); 93 depthStream.destroy(); 94 device.close(); 95 openni::OpenNI::shutdown(); 96 return 0; 97 }
代码比较简单,就不再进行说明。
最后的效果如下图: