開始之前,讓我們自己開始再熟練熟練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;
}
但我們使用OpenNI和Kinect更多的是爲了研究開發之用,其中用到最多的是OpenCV(OpenGL、QT也很多,只是本人用的最多的是OpenCV),下面就結合OPenNI 2和OpenCV 2.4.3開始我的第一個程序:利用OpenCV函數顯示深度圖像和彩色圖像。直接上代碼:
// YeOpenNI2SimpleUsingOpenCV.cpp : 定義控制檯應用程序的入口點。
//
#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;
}
顯示效果圖:
這個是在原有的程序上做了添加,主要添加了:
1. 深度圖像和彩色圖像的視頻模式的設置:streamDepth.setVideoMode( mModeDepth);和streamColor.setVideoMode( mModeColor);
視頻模式VideoMode類主要包括了:get/set像素格式、get/set分辨率(座標x和y值)、以及每秒多少幀圖像等。其中像素格式主要包括以下幾種:
enum PixelFormat {
PIXEL_FORMAT_DEPTH_1_MM = 100, PIXEL_FORMAT_DEPTH_100_UM = 101, PIXEL_FORMAT_SHIFT_9_2 = 102, PIXEL_FORMAT_SHIFT_9_3 = 103,
PIXEL_FORMAT_RGB888 = 200, PIXEL_FORMAT_YUV422 = 201, PIXEL_FORMAT_GRAY8 = 202, PIXEL_FORMAT_GRAY16 = 203,
PIXEL_FORMAT_JPEG = 204
}
主要分成兩類:深度像素格式和彩色圖像格式。具體是什麼含義,我想利用OpenCV常用圖像格式知識,自己多嘗試使用對照,發現它們的不同之處和特別之處。
2. 設置彩色圖像視頻與深度視頻的視覺校正,但我們從上面的彩色圖像和深度圖像可以看出來,它們通過“校正”之後還是存在着一定的偏差,對於這個問題目前已有人做了修改,但官方還是沒有做具體的說明和糾正。在OPenNI 2的架構中,要進行視覺的校正,是直接調用Device提供的setImageRegistrationMode(ImageRegistrationMode mode) 函數來進行視覺校正的設置。但目前的OpenNI 2裏,只提供IMAGE_REGISTRATION_OFF = 0(不用校正)和 IMAGE_REGISTRATION_DEPTH_TO_COLOR = 1(把深度映射到彩色圖像的位置上)這兩種模式可以使用。根據目前的OpenNI 2已經不是隻針對Kinect一種感應器了,針對不同的感應器,不一定都要支持視覺校正的功能,所以在設定前,最好先判斷使用的感應器是否支持“視覺校正”功能,借用官方的話說:“It is a good practice to first check if the mode is supported by calling isImageRegistrationModeSupported(). ”其中ImageRegistrationMode枚舉如下:
enum ImageRegistrationMode { IMAGE_REGISTRATION_OFF = 0, IMAGE_REGISTRATION_DEPTH_TO_COLOR = 1 }
3. 讀取深度圖像信息和彩色圖像信息,然後相應的轉換爲OpenCV格式,並顯示:
// 讀取數據流
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 );
這個主要就是OpenCV的圖像格式和顯示有關的知識了,此處省去N個字。。。
總結:知道了如何獲取深度和彩色圖像信息+OpenCV常用圖像轉換函數和圖像格式,我想這個程序就很好寫,並且很明瞭易懂了。
原文鏈接地址:
https://www.cnblogs.com/yemeishu/archive/2013/01/11/2856859.html