【ミッション: Kinectのカメラ映像をIplImageに変換して使おう】
前回のあらすじ:
OpenNI を入れた。
Kinect のカメラ、及び深度データを OpenCV で使うための最小限のソースコードを
この辺で見つけたので、さっそく試してみた。
自分の環境に合わせてじゃっかんソースコードを書き換えたが、概ねそのままである(下記のコードは、Visual Studio と OpenCV 2.0 のコンビネーションじゃないとうまく動かない気がする。特にライブラリのバージョンに注意)。
- #include<cv.h>
- #include<highgui.h>
-
-
-
-
- #include<XnCppWrapper.h>
-
- #pragma comment(lib,"C:/Program files/OpenNI/Lib/openNI.lib")
-
- #define SAMPLE_XML_PATH "C:/Program Files/OpenNI/Data/SamplesConfig.xml"
-
- int main() {
- xn::Context context;
- xn::EnumerationErrors errors;
-
- context.InitFromXmlFile(SAMPLE_XML_PATH);
-
- xn::DepthGenerator depth;
- context.FindExistingNode(XN_NODE_TYPE_DEPTH, depth);
-
- xn::ImageGenerator image;
- context.FindExistingNode(XN_NODE_TYPE_IMAGE, image);
-
- xn::DepthMetaData depthMD;
- xn::ImageMetaData imageMD;
-
- cv::Mat depthshow;
- cv::Mat show;
- int key = 0;
- bool isWarp=false;
- while (key!='q')
- {
-
- context.WaitAnyUpdateAll();
-
- image.GetMetaData(imageMD);
- depth.GetMetaData(depthMD);
-
-
- cv::Mat depth16(480,640,CV_16SC1,(unsigned short*)depthMD.WritableData());
- cv::Mat imni(480,640,CV_8UC3,(uchar*)imageMD.WritableData());
-
-
- cv::cvtColor(imni,show,CV_RGB2BGR);
-
-
- depth16.convertTo(depthshow,CV_8U,-255/4096.0,255);
-
- cv::imshow("depth",depthshow);
- cv::imshow("image",show);
- key = cv::waitKey(33);
- }
- context.Shutdown();
- return 0;
- }
#include<cv.h>
#include<highgui.h>
// ※インクルードパスに
// 「C:\Program files\OpenNI\Include」
// を追加しておこう!
#include<XnCppWrapper.h>
#pragma comment(lib,"C:/Program files/OpenNI/Lib/openNI.lib")
#define SAMPLE_XML_PATH "C:/Program Files/OpenNI/Data/SamplesConfig.xml"
int main() {
xn::Context context;
xn::EnumerationErrors errors;
context.InitFromXmlFile(SAMPLE_XML_PATH);
xn::DepthGenerator depth; // 深度コンテキスト
context.FindExistingNode(XN_NODE_TYPE_DEPTH, depth);
xn::ImageGenerator image; // イメージコンテキスト
context.FindExistingNode(XN_NODE_TYPE_IMAGE, image);
xn::DepthMetaData depthMD;
xn::ImageMetaData imageMD;
cv::Mat depthshow;
cv::Mat show;
int key = 0;
bool isWarp=false;
while (key!='q')
{
// waitとエラー処理
context.WaitAnyUpdateAll();
image.GetMetaData(imageMD);
depth.GetMetaData(depthMD);
// 画像と深度はOpenCVのMatに格納
cv::Mat depth16(480,640,CV_16SC1,(unsigned short*)depthMD.WritableData());
cv::Mat imni(480,640,CV_8UC3,(uchar*)imageMD.WritableData());
// RGB色空間をBGRに変換
cv::cvtColor(imni,show,CV_RGB2BGR);
// 11ビット画像を8ビット画像に変換
depth16.convertTo(depthshow,CV_8U,-255/4096.0,255);
cv::imshow("depth",depthshow);
cv::imshow("image",show);
key = cv::waitKey(33);
}
context.Shutdown();
return 0;
}
これで、Kinect から労せずしてカメラ映像を取得する事ができるようになった。
……と見せかけて、
上記のサンプルコードのままでは(僕にとって)多少問題がある。
この段階で、画像データは OpenCV の汎用行列クラスである
cv::Mat のオブジェクトとして扱えるようになるのだが、
このページの情報によると、
cv::Mat のメンバである
step の値が、4 バイト単位に調整されなくなるという不都合が残っているらしい。
以前書いたような
Windows API との連携を考えた場合、画像の管理には素性がはっきりしている
IplImage 構造体を用いた方が、面倒も少なくて済むだろう。
僕がてきとうに調べた限り、Kinect から取ってきた画像データを直に
IplImage に変換するような先人のソースコードを見つける事はできなかった。
それでも、恐らく需要はあるかも知れないと思い、ちょっと作ってみることに。