ポイントは、(1)OpenKinectのAPIをどのように使っているか、(2)OpenGL(GLUT)をどのように使っているか の2点だと思います。今回の目次はこのようになります。
- main関数の処理内容
- 描画処理 (gl_threadfunc関数, DrawGLScene関数)の処理内容
- カメラからの情報取得コールバック関数(depth_cb関数, rgb_cb関数)の処理内容
- ユーザ入力を受ける関数 (keyPressed関数) の処理内容
main関数の処理内容
main関数の処理の流れは、次のようになっています。(各種APIは第2回(APIの概要)を参照して下さい)- t_gamma配列(※)の事前計算 (※深度カメラからの情報を距離情報に直すときに利用)
- コンテキストの作成 (freenect_init関数)
- ログレベルの設定 (freenect_set_log_level関数)
- 利用するデバイスの決定 (freenect_set_log_level関数):
プログラム起動時の引数が渡されていれば、その番号のデバイスを利用します。渡されていなければ0番(最初の)デバイスを利用します。もし利用可能なデバイスがなければ、終了します。 - デバイスのオープン (freenect_open_device関数)
- 種々の設定:
- 傾きの設定 (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を指定
- 傾きの設定 (freenect_set_tilt_degs関数):
- 新規スレッドにてgl_threadfunc関数(後に説明)を実行
- カメラ情報取得開始 (freenect_start_depth関数, freenect_start_rgb関数)
- 正常に処理が行われている間、加速度情報をコンソールに表示 (freenect_get_raw_accel関数, freenect_get_mks_accel関数)
- カメラ情報取得終了 (freenect_stop_depth関数, freenect_stop_rgb関数)
描画処理 (gl_threadfunc関数, DrawGLScene関数)の処理内容
描画処理の初期化を行う関数が、gl_threadfunc関数です。main関数から呼ばれ、次の処理を行います。- ウィンドウの作成
- 描画関数を設定(DrawGLScene関数)
- キー押し下げ時の処理関数の設定(keyPressed関数)
- 描画の開始。
※ このように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)視覚化するために深度情報を色情報に変換(※)する ためです。処理内容は次の通りです。
(※ カメラから近い順に、白→赤→黄→緑→水色→青→黒 と段階的に変化するようにします)
- ピクセルの数(FREENECT_FRAME_PIX == 640×480)だけループし、それぞれについて次の処理を行います。
- ピクセルの深度の値(depth[i])を距離に補正し、変数pvalに格納します。(main関数であらかじめ計算しておいたt_gamma配列を利用します)
- 補正した値pvalを、下位8ビットと上位のビットに分離します。下位の値(0〜255)は変数lbに格納します。
- 上位のビットの値に応じて、色分けをします。
- 上位ビット値=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をもとに、サンプルプログラムの挙動を把握しました。次回は、深度情報と色情報をもとに、データを立体的に表示するプログラムを作ってみたいと思います。