前回奥行き情報を(一応)推定する事ができたので、そろそろ 3D にしてみようと思う。
本日のターゲットは、このどうしようもない写真。

これを、Kinect で適当に 3 次元復元して俯瞰したら、こうなった。

※ ちなみにぼくの隣は博士様の席なのだ。
理論自体はほとんどそのままなのだが、前のソースは数値計算の精度的にアレだったり座標系の置き方的にアレだったりしたので、ほんのわずかながら改良を加えた。
ちなみに、依然として視点操作ができない。この辺はダメなままである。あと、毎度の事ながら、OpenCV 2.0 以外のバージョンではうまくビルドできない可能性があるので注意。もしダメそうだったらリンクするライブラリとかインクルードするヘッダファイルとかをいじってみてね。
- #include<cv.h>
- #include<highgui.h>
- #include<XnCppWrapper.h>
- #include<GL/glut.h>
- #include<limits.h>
- #pragma comment(lib,"cv200.lib")
- #pragma comment(lib,"cxcore200.lib")
- #pragma comment(lib,"highgui200.lib")
- #pragma comment(lib,"C:/Program files/OpenNI/Lib/openNI.lib")
- #pragma comment(lib, "glut32.lib")
- const int IMAGE_WIDTH = 640;
- const int IMAGE_HEIGHT = 480;
- const char* SAMPLE_XML_PATH =
- "C:/Program Files/OpenNI/Data/SamplesConfig.xml";
- // グローバル変数。使い過ぎよくない。
- xn::Context context;
- xn::EnumerationErrors errors;
- xn::DepthGenerator depth;
- xn::ImageGenerator image;
- xn::DepthMetaData depthMD;
- xn::ImageMetaData imageMD;
- cv::Ptr<IplImage> iplimage, ipldepth;
- // Kinectカメラの内部パラメータ
- const double f = 526.37013657;
- const double cx = 313.68782938;
- const double cy = 259.01834898;
- // ==================
- // 暇になったら再描画
- // ==================
- void idle() {
- glutPostRedisplay();
- }
- void display() {
- context.WaitAnyUpdateAll();
- // 深度・画像メタデータ取得
- depth.GetMetaData(depthMD);
- image.GetMetaData(imageMD);
- // 深度データの座標ををカメラに合わせる
- depth.GetAlternativeViewPointCap().SetViewPoint(image);
- // ============================
- // IplImage構造体にデータを格納
- // ============================
- iplimage->imageData = (char *)imageMD.WritableData();
- ipldepth->imageData = (char *)depthMD.WritableData();
- // 画像を反転
- cvFlip(iplimage, iplimage, 1);
- cvFlip(ipldepth, ipldepth, 1);
- glClear(GL_COLOR_BUFFER_BIT);
- glPointSize(1);
- glBegin(GL_POINTS);
- // 点の色は白
- glColor3d(1.0, 1.0, 1.0);
- // 点を打っていく
- for(int y = 0; y < IMAGE_HEIGHT; y++) {
- // ピクセルデータへのポインタ
- short* pDepthImgData = (short*)(
- ipldepth->imageData + y * ipldepth->widthStep
- );
- /* 点群にRGB画像のテクスチャを貼りたいとき用
- unsigned char* pCameraImgData = (unsigned char*)(
- iplimage->imageData + y * iplimage->widthStep
- );
- */
- for(int x = 0; x < IMAGE_WIDTH; x++) {
- // 画素(x, y)に対応する深度データ取得
- int d =
- (int)pDepthImgData[ipldepth->nChannels * x];
- if (d == 0) continue;
- // 3次元位置の推定
- double X = (x - cx)/f;
- double Y = (y - cy)/f;
- double Z = 1;
- // 3次元点を求める
- X *= (double)d;
- Y *= (double)d;
- Z *= (double)d;
- /* ↓これを書くと、点に画像データの色がつく
- double R =
- pCameraImgData
- [iplimage->nChannels*x+0]/255.0;
- double G =
- pCameraImgData
- [iplimage->nChannels*x+1]/255.0;
- double B =
- pCameraImgData
- [iplimage->nChannels*x+2]/255.0;
- glColor3d(R, G, B);
- */
- // 座標を指定して点をプロット
- glVertex3d(X, Y, Z);
- }
- }
- glEnd();
- glFlush();
- }
- void resize(int w, int h) {
- glViewport(0, 0, w, h);
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- gluPerspective(45.0, (double)w / h,
- 1.0, INT_MAX);
- // 俯瞰視点(てきとうです)
- gluLookAt(
- 0, -5000, 1950,
- 0, 0, 2000,
- 0, 0, 1
- );
- }
- void init() {
- glClearColor(0.0, 0.0, 0.0, 1.0);
- }
- int main(int argc, char** argv) {
- // OpenNI関連のいろいろ
- context.InitFromXmlFile(SAMPLE_XML_PATH);
- context.FindExistingNode(XN_NODE_TYPE_DEPTH,depth);
- context.FindExistingNode(XN_NODE_TYPE_IMAGE,image);
- // OpenCV関連のいろいろ
- iplimage = cvCreateImage(
- cvSize(IMAGE_WIDTH,IMAGE_HEIGHT),IPL_DEPTH_8U, 3
- );
- ipldepth = cvCreateImage(
- cvSize(IMAGE_WIDTH,IMAGE_HEIGHT),IPL_DEPTH_16S,1
- );
- // OpenGL関連のいろいろ
- glutInitWindowSize(640, 480);
- glutInit(&argc, argv);
- glutInitDisplayMode(GLUT_RGBA);
- glutCreateWindow("T");
- glutIdleFunc(idle);
- glutDisplayFunc(display);
- glutReshapeFunc(resize);
- init();
- glutMainLoop();
- return 0;
- }
ふぅ…。
もはやこのシリーズは自分の中で備忘録的な位置づけになってしまったので、ソースコードが解りにくいのは仕様。あしからず。
2011/04/25 Kinectプチハック(エピソード4)
返信削除ですが、追加のインクルードファイル、ライブラリファイル、依存ファイルの一覧を教えてください。
コメントありがとうございます。
削除だいぶ前に書いた記事ですのであまり自信はありませんが、使用したライブラリは以下の通りであったと記憶しています。
・ GLUT 3.7
・ OpenCV 2.0
・ OpenNI 1.0.0.23
・ Nite 1.3.0.17
このうち、特に OpenNI の導入には苦戦しました。こちらの解説が参考になると思います。
また、OpenCV の最新版(2.3)ではライブラリの構成が変わっているため、2.0 以外をお使いになる場合はソースコードを修正する必要があるかと思われます。
各々の依存しているヘッダファイルや静的リンクライブラリ(拡張子が .lib のファイル)は、ソースコード中で明示的に書いてある通りです。
【ヘッダ】
・GL/glut.h // GLUT
・cv.h // OpenCV
・highgui.h // OpenCV
・XnCppWrapper.h // OpenNI
【静的リンクライブラリ】
・glut32.lib // GLUT
・cv200.lib // OpenCV
・cxcore200.lib // OpenCV
・highgui200.lib // OpenCV
・openNI.lib // OpenNI
GNです、コメントを書いてくれてありがとうございます。
返信削除実はまた質問があります。
CMakeとMPI_CXXをご存知ですか?
御存じなら1つ教えてほしいのですが、MPI_CXXをwindowsにインストールする方法を知っていたら教えてくれないでしょうか?
コメントありがとうございます。
削除申し訳ありませんが、私の知識不足ゆえお役に立つことができません。
なお、Open MPI 1.5.4 の Windows 向けインストーラパッケージには、mpicxx.exe という名前の(恐らく Windows 向け)バイナリが含まれていると思うのですが、詳しい事は分かりません。
コメントありがとうございます。
削除たーせるさんのコメント通りにプログラムを作成します。
windows7 32bitとPCL All-One.exeを用いてkinect動画に法線ベクトルを表示するソースコードを作成したいのです。
返信削除また、以下の2つの機能も必要としています。
①法線ベクトルの数を増やす
②入力画像を領域分け(背景と物体を分ける)する
上記の条件を満たすソースコードの作成を教えてください。
お願いします。
コメントありがとうございます。
削除申し訳ございませんが、本文と無関係なご質問にはお答えしかねます。
ご了承ください。
OpenNIを勉強している初心者なのですが質問があります。
返信削除3次元における深度を取得したいのですが、
画素(x, y)に対応する深度データ取得
int d = (int)pDepthImgData[ipldepth->nChannels * x];
で取得できる値は3次元点のKinectからの直線距離のような気がするのですがこの値は深度になりますか?
間違っていたらすいません。
またKinectの焦点距離の取得の方法も知っていたら教えてもらえないでしょうか?