2011/04/25

Kinectプチハック(エピソード4)

【ミッション: Kinectで立体復元に挑戦しよう】

前回奥行き情報を(一応)推定する事ができたので、そろそろ 3D にしてみようと思う。

本日のターゲットは、このどうしようもない写真。


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

机上の本や PC はもちろん、部屋の隅っこの柱やパイプなどの凹凸がくっきり浮き出ている事が確認できる。

※ ちなみにぼくの隣は博士様の席なのだ。いないけど。



理論自体はほとんどそのままなのだが、前のソースは数値計算の精度的にアレだったり座標系の置き方的にアレだったりしたので、ほんのわずかながら改良を加えた。

ちなみに、依然として視点操作ができない。この辺はダメなままである。あと、毎度の事ながら、OpenCV 2.0 以外のバージョンではうまくビルドできない可能性があるので注意。もしダメそうだったらリンクするライブラリとかインクルードするヘッダファイルとかをいじってみてね。

  1. #include<cv.h>  
  2. #include<highgui.h>  
  3. #include<XnCppWrapper.h>  
  4.   
  5. #include<GL/glut.h>  
  6. #include<limits.h>  
  7.   
  8. #pragma comment(lib,"cv200.lib")  
  9. #pragma comment(lib,"cxcore200.lib")  
  10. #pragma comment(lib,"highgui200.lib")  
  11. #pragma comment(lib,"C:/Program files/OpenNI/Lib/openNI.lib")  
  12.   
  13. #pragma comment(lib, "glut32.lib")  
  14.   
  15. const int IMAGE_WIDTH  = 640;  
  16. const int IMAGE_HEIGHT = 480;  
  17.   
  18. const char* SAMPLE_XML_PATH =   
  19.     "C:/Program Files/OpenNI/Data/SamplesConfig.xml";  
  20.   
  21. // グローバル変数。使い過ぎよくない。  
  22. xn::Context context;  
  23. xn::EnumerationErrors errors;  
  24. xn::DepthGenerator depth;    
  25. xn::ImageGenerator image;  
  26. xn::DepthMetaData depthMD;  
  27. xn::ImageMetaData imageMD;  
  28.   
  29. cv::Ptr<IplImage> iplimage, ipldepth;  
  30.   
  31. // Kinectカメラの内部パラメータ  
  32. const double f  = 526.37013657;  
  33. const double cx = 313.68782938;  
  34. const double cy = 259.01834898;  
  35.   
  36.   
  37. // ==================  
  38. // 暇になったら再描画  
  39. // ==================  
  40. void idle() {  
  41.     glutPostRedisplay();  
  42. }  
  43.   
  44. void display() {  
  45.     context.WaitAnyUpdateAll();  
  46.   
  47.     // 深度・画像メタデータ取得  
  48.     depth.GetMetaData(depthMD);  
  49.     image.GetMetaData(imageMD);  
  50.           
  51.     // 深度データの座標ををカメラに合わせる  
  52.     depth.GetAlternativeViewPointCap().SetViewPoint(image);  
  53.   
  54.     // ============================  
  55.     // IplImage構造体にデータを格納  
  56.     // ============================  
  57.     iplimage->imageData = (char *)imageMD.WritableData();  
  58.     ipldepth->imageData = (char *)depthMD.WritableData();  
  59.   
  60.     // 画像を反転  
  61.     cvFlip(iplimage, iplimage, 1);  
  62.     cvFlip(ipldepth, ipldepth, 1);  
  63.   
  64.     glClear(GL_COLOR_BUFFER_BIT);  
  65.     glPointSize(1);  
  66.     glBegin(GL_POINTS);  
  67.   
  68.     // 点の色は白  
  69.     glColor3d(1.0, 1.0, 1.0);  
  70.   
  71.     // 点を打っていく  
  72.     for(int y = 0; y < IMAGE_HEIGHT; y++) {  
  73.         // ピクセルデータへのポインタ  
  74.         short* pDepthImgData = (short*)(  
  75.             ipldepth->imageData + y * ipldepth->widthStep  
  76.         );  
  77.           
  78.         /* 点群にRGB画像のテクスチャを貼りたいとき用 
  79.           unsigned char* pCameraImgData = (unsigned char*)( 
  80.               iplimage->imageData + y * iplimage->widthStep 
  81.           ); 
  82.         */  
  83.   
  84.         for(int x = 0; x < IMAGE_WIDTH; x++) {  
  85.             // 画素(x, y)に対応する深度データ取得  
  86.             int d =   
  87.                 (int)pDepthImgData[ipldepth->nChannels * x];  
  88.             if (d == 0) continue;  
  89.   
  90.             // 3次元位置の推定  
  91.             double X = (x - cx)/f;  
  92.             double Y = (y - cy)/f;  
  93.             double Z =          1;  
  94.   
  95.             // 3次元点を求める  
  96.             X *= (double)d;  
  97.             Y *= (double)d;  
  98.             Z *= (double)d;  
  99.   
  100.             /* ↓これを書くと、点に画像データの色がつく 
  101.               double R =  
  102.                   pCameraImgData 
  103.                       [iplimage->nChannels*x+0]/255.0; 
  104.               double G = 
  105.                   pCameraImgData 
  106.                       [iplimage->nChannels*x+1]/255.0; 
  107.               double B =  
  108.                   pCameraImgData 
  109.                       [iplimage->nChannels*x+2]/255.0; 
  110.               glColor3d(R, G, B); 
  111.             */  
  112.   
  113.             // 座標を指定して点をプロット  
  114.             glVertex3d(X, Y, Z);  
  115.         }  
  116.     }  
  117.     glEnd();  
  118.     glFlush();  
  119. }  
  120.   
  121. void resize(int w, int h) {  
  122.     glViewport(0, 0, w, h);  
  123.     glMatrixMode(GL_PROJECTION);  
  124.     glLoadIdentity();  
  125.     gluPerspective(45.0, (double)w / h,   
  126.                     1.0, INT_MAX);  
  127.   
  128.     // 俯瞰視点(てきとうです)  
  129.     gluLookAt(  
  130.         0, -5000, 1950,   
  131.         0,     0, 2000,   
  132.         0,     0,    1  
  133.     );  
  134. }  
  135.   
  136. void init() {  
  137.     glClearColor(0.0, 0.0, 0.0, 1.0);  
  138. }  
  139.   
  140. int main(int argc, char** argv) {  
  141.   
  142.     // OpenNI関連のいろいろ  
  143.     context.InitFromXmlFile(SAMPLE_XML_PATH);  
  144.     context.FindExistingNode(XN_NODE_TYPE_DEPTH,depth);   
  145.     context.FindExistingNode(XN_NODE_TYPE_IMAGE,image);  
  146.       
  147.     // OpenCV関連のいろいろ  
  148.     iplimage = cvCreateImage(  
  149.         cvSize(IMAGE_WIDTH,IMAGE_HEIGHT),IPL_DEPTH_8U, 3  
  150.     );  
  151.     ipldepth = cvCreateImage(  
  152.         cvSize(IMAGE_WIDTH,IMAGE_HEIGHT),IPL_DEPTH_16S,1  
  153.     );  
  154.   
  155.     // OpenGL関連のいろいろ  
  156.     glutInitWindowSize(640, 480);  
  157.     glutInit(&argc, argv);  
  158.     glutInitDisplayMode(GLUT_RGBA);  
  159.     glutCreateWindow("T");  
  160.     glutIdleFunc(idle);  
  161.     glutDisplayFunc(display);  
  162.     glutReshapeFunc(resize);  
  163.     init();  
  164.     glutMainLoop();  
  165.     return 0;  
  166. }  

ふぅ…。

もはやこのシリーズは自分の中で備忘録的な位置づけになってしまったので、ソースコードが解りにくいのは仕様。あしからず。

8 件のコメント:

  1. 2011/04/25 Kinectプチハック(エピソード4)
    ですが、追加のインクルードファイル、ライブラリファイル、依存ファイルの一覧を教えてください。

    返信削除
    返信
    1. コメントありがとうございます。

      だいぶ前に書いた記事ですのであまり自信はありませんが、使用したライブラリは以下の通りであったと記憶しています。

      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

      削除
  2. GNです、コメントを書いてくれてありがとうございます。

    実はまた質問があります。
    CMakeとMPI_CXXをご存知ですか?
    御存じなら1つ教えてほしいのですが、MPI_CXXをwindowsにインストールする方法を知っていたら教えてくれないでしょうか?

    返信削除
    返信
    1. コメントありがとうございます。

      申し訳ありませんが、私の知識不足ゆえお役に立つことができません。

      なお、Open MPI 1.5.4 の Windows 向けインストーラパッケージには、mpicxx.exe という名前の(恐らく Windows 向け)バイナリが含まれていると思うのですが、詳しい事は分かりません。

      削除
    2. コメントありがとうございます。
      たーせるさんのコメント通りにプログラムを作成します。

      削除
  3. windows7 32bitとPCL All-One.exeを用いてkinect動画に法線ベクトルを表示するソースコードを作成したいのです。

    また、以下の2つの機能も必要としています。
    ①法線ベクトルの数を増やす
    ②入力画像を領域分け(背景と物体を分ける)する

    上記の条件を満たすソースコードの作成を教えてください。
    お願いします。

    返信削除
    返信
    1. コメントありがとうございます。

      申し訳ございませんが、本文と無関係なご質問にはお答えしかねます。

      ご了承ください。

      削除
  4. OpenNIを勉強している初心者なのですが質問があります。
    3次元における深度を取得したいのですが、
    画素(x, y)に対応する深度データ取得
    int d = (int)pDepthImgData[ipldepth->nChannels * x];
    で取得できる値は3次元点のKinectからの直線距離のような気がするのですがこの値は深度になりますか?
    間違っていたらすいません。
    またKinectの焦点距離の取得の方法も知っていたら教えてもらえないでしょうか?

    返信削除

ひとことどうぞφ(・ω・,,)