Kinect ハック on Mac OS X:(3) デモプログラム glview

過去2回、OpenKinectについて書きました(第1回(サンプルの実行)第2回(APIの概要))。今回はデモプログラムであるglviewについて調べてみます。

ポイントは、(1)OpenKinectのAPIをどのように使っているか、(2)OpenGL(GLUT)をどのように使っているか の2点だと思います。今回の目次はこのようになります。
  • main関数の処理内容
  • 描画処理 (gl_threadfunc関数, DrawGLScene関数)の処理内容
  • カメラからの情報取得コールバック関数(depth_cb関数, rgb_cb関数)の処理内容
  • ユーザ入力を受ける関数 (keyPressed関数) の処理内容

main関数の処理内容

main関数の処理の流れは、次のようになっています。(各種APIは第2回(APIの概要)を参照して下さい)
  1. t_gamma配列(※)の事前計算  (※深度カメラからの情報を距離情報に直すときに利用)
  2. コンテキストの作成 (freenect_init関数)
  3. ログレベルの設定 (freenect_set_log_level関数)
  4. 利用するデバイスの決定 (freenect_set_log_level関数):
    プログラム起動時の引数が渡されていれば、その番号のデバイスを利用します。渡されていなければ0番(最初の)デバイスを利用します。もし利用可能なデバイスがなければ、終了します。
  5. デバイスのオープン (freenect_open_device関数)
  6. 種々の設定
    • 傾きの設定 (freenect_set_tilt_degs関数):
      初期設定では0度(==freenect_angle)
    • LEDの設定 (freenect_set_led関数):
      初期設定では赤(==LED_RED)
    • カメラの情報を受け取るコールバック関数の設定(freenect_set_depth_callback関数, freenect_set_rgb_callback関数):
      それぞれdepth_cb関数とrgb_cb関数を設定
    • カメラの情報を受け取る際のフォーマットの指定 (freenect_set_rgb_format関数, freenect_set_depth_format)
    • : それぞれRGB、11bitを指定
  7. 新規スレッドにてgl_threadfunc関数(後に説明)を実行
  8. カメラ情報取得開始 (freenect_start_depth関数, freenect_start_rgb関数)
  9. 正常に処理が行われている間、加速度情報をコンソールに表示 (freenect_get_raw_accel関数, freenect_get_mks_accel関数)
  10. カメラ情報取得終了 (freenect_stop_depth関数, freenect_stop_rgb関数)

描画処理 (gl_threadfunc関数, DrawGLScene関数)の処理内容

描画処理の初期化を行う関数が、gl_threadfunc関数です。main関数から呼ばれ、次の処理を行います。
  1. ウィンドウの作成
  2. 描画関数を設定(DrawGLScene関数)
  3. キー押し下げ時の処理関数の設定(keyPressed関数)
  4. 描画の開始。
gl_threadfunc関数で設定した描画関数(DrawGLScene関数)は、何度も実行され、カメラから取得した情報をOpenGLのウィンドウに表示します。カメラから取得できる深度とRGBはともに、幅640×高さ480の形になっています。その情報は、gl_depth_back配列, gl_rgb_back配列に入っており(カメラからの情報取得用のコールバック(depth_cb関数, rgb_cb関数)で設定されます)、その情報を一旦コピーしてから(gl_depth_front配列, gl_rgb_back配列)、ウィンドウに表示します (※)。深度情報はウィンドウ左側0<x<640の領域に、RGB情報はウィンドウ右側の640<x<1280の領域に描画されます。

※ このようにback(カメラからの取得用)、front(描画用)の2つの分けている理由は、処理速度を上げるため。もし一つの配列を使ってデータをやりとりすると、カメラから情報を取得できても、描画が完全に終わるまでは取得した情報を書き込めず、パフォーマンスが低下します。

カメラからの情報取得コールバック関数(depth_cb関数, rgb_cb関数)の処理内容

カメラからの取得できる情報には、深度情報とRGB情報があります。それらはOpenKinectから定期的に呼ばれるコールバック関数で受け取ることができます。

まず、RGB情報について(rgb_cb関数)は、引数として渡された領域(変数rgb)を、gl_rgb_back配列にそのままコピー(memcpy)しています。(前述の通り、書きこまれたgl_rgb_back配列の情報は、描画処理(DrawGLScene関数)内でgl_rgb_front配列にコピーされた上で描画されます)

次に、深度情報について(depth_cb関数)ですが、RGB情報と比べて処理が多少複雑です。というのは、RGBの場合はそのまま表示すれば良かったのですが、深度情報の場合は、(1)深度情報を距離に直す (2)視覚化するために深度情報を色情報に変換(※)する ためです。処理内容は次の通りです。
(※ カメラから近い順に、白→赤→黄→緑→水色→青→黒 と段階的に変化するようにします)
  1. ピクセルの数(FREENECT_FRAME_PIX == 640×480)だけループし、それぞれについて次の処理を行います。
    1. ピクセルの深度の値(depth[i])を距離に補正し、変数pvalに格納します。(main関数であらかじめ計算しておいたt_gamma配列を利用します)
    2. 補正した値pvalを、下位8ビットと上位のビットに分離します。下位の値(0〜255)は変数lbに格納します。
    3. 上位のビットの値に応じて、色分けをします。
      • 上位ビット値=0 (0〜255)の場合:下位ビットの値に応じて白(pval=0)→赤(pval=255)に段階的に変化
      • 上位ビット値=1 (256〜511)の場合:同様に赤(pval=256)→黄(pval=511) に段階的に変化
      • 上位ビット値=2 の場合:黄→緑 に段階的に変化
      • 上位ビット値=3 の場合:緑→水色 に段階的に変化
      • 上位ビット値=4 の場合:水色→青 に段階的に変化
      • 上位ビット値=5 の場合:青→黒 に段階的に変化
      • 上位ビット値>5 の場合:黒(一色)

ユーザ入力を受ける関数 (keyPressed関数) の処理内容

この関数は、OpenGLに登録され、表示しているウィンドウ上でキー入力があった場合に実行されます。
  • 'w', 's', 'x'が押された場合、Kinectの傾きをそれぞれ1度上昇、水平、1度下降とします (関数の最後で、freenect_set_tilt_degs関数を呼び出します)。
  • '0'〜'6'が押された場合、数字の値に応じてLEDを点滅させます。0:無灯、1:緑、2:赤、3:黄(※)、4:黄点滅(※)、5:緑点滅、6:赤と黄(※)を交互に点滅。(※:黄色は、実際のところは橙色のようです)


今回は、前回調べたAPIをもとに、サンプルプログラムの挙動を把握しました。次回は、深度情報と色情報をもとに、データを立体的に表示するプログラムを作ってみたいと思います。

コメント なし: