the glue

やってみたことで忘れそうなこと、役立ちそうなことなどをまとめています。たまに何気ない日常の話もします。

Visual C#でKinectを使う(その2)

前回はKinect SDKをインストールし、実際にプロジェクトを作成、作成したプロジェクト上でKinect SDKが使えるようにしました。

今回は実際に動作するコードを書きながら、大まかな解説をしようかと思います。

今回

Kinectでできること

Kinectには大まかに以下の3つのセンサーがあります。

  • RGBカメラ
    • いわゆる普通のWebカメラと同等
    • 最近のWebカメラに比べるとv1センサーのカメラはあまり性能よろしくない
  • 深度センサー
    • 対象物との距離を測るセンサー
    • ピクセルごとの距離が取得できる
  • デュアルマイク
    • 音の方向や大きさがわかるマイク

これらを使って、

  • 人の検出(最大同時6人)
  • 骨格の検出(最大同時2人) などなどほかにもいろいろなことができます。

コーディングをしましょう

今回はウィンドウに映像を表示するので、前回の内容に則って、コンソールアプリケーションではなくWPFアプリケーションを新規作成しておきましょう。

MainWindow.xaml

<Window x:Class="kinect_test.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="480" Width="640">
    <Grid>
        <Image Name="rgbCamera" Stretch="Uniform" />
    </Grid>
</Window>

カメラの映像を表示するImage部品を作成しましょう。 ここでは、NameはrgbCameraとして指定しています。 ウィンドウサイズの変更に追従するようにStrechも明示しておきましょう。

MainWindows.xaml.cs

KinectSensorインスタンスの取得

Kinectは、KinectSensorクラスから扱うことができます。 まずはKinectを扱うクラスに、KinectSensorクラスのインスタンスを入れる変数を作りましょう。
外部から参照する予定はないので、privateにしておくといいかと思います。

public partial class MainWindow : Window
    {
        // この行を追加
        private KinectSensor kinect;
...
...

次に、イニシャライザでKinectSensorクラスのインスタンスを作成し、作った変数に格納しておきましょう。
Kinectは一台だけ接続されているという前提です。

        public MainWindow()
        {
            // Kinectが接続されているかどうか
            if ( KinectSensor.KinectSensors.Count == 0 ) {
                // 例外を吐いてもいい
                MessageBox.Show("No Kinect Sensors connected");
                Close();
            }
            // 0個目のKinectのKinectSensorインスタンスを取得(つまり1台目)
            kinect = KinectSensor.KinectSensors[0];
...

まず、Kinectが接続されているか(接続されたKinectの数が0ではないか)をチェックしています。 Kinectが接続されていないようならこの時点でダイアログを表示し、アプリケーションを終了するようにしています。
ここで例外を吐くようにするのもいいかと思います。

Kinectが接続されているようなら、一台目のKinectのKinectSensorインスタンスを取得し先ほど作った変数に格納します。
KinectSensorのインスタンスは、KinectSensor.KinectSensorsという配列から取得することができます。
配列の添え字は0からカウントされるので、一台目のKinectインスタンスはKinectSensors[0]から取得できます。

RGBカメラの有効化

有効にする機能を指定しましょう。今回はRGBカメラを使うので、ColorStreamのみを有効にします。
以下を上記のイニシャライザに追記しましょう。

kinect.ColorStream.Enable();

また、先ほど説明した深度センサーと骨格検出はそれぞれ

kinect.DepthStream.Enable();
kinect.SkeletonStream.Enable();

で有効化できます。

RGBカメラの更新にイベントを設定

KinectからRGBカメラの情報を取得したときに実行されるイベントを設定しましょう。 有効化のときと同様、イニシャライザに以下を追記してください。

kinect.ColorFrameReady += new EventHandler<ColorImageFrameReadyEventArgs>(kinect_ColorFrameReady);

深度センサーと骨格検出についても、有効化と同様にColorをDepthやSkeletonに置き換えれば大丈夫ですが、機能に関係なくすべての情報の更新について実行されるイベントを設定することもできます。

kinect.AllFramesReady += new EventHandler<AllFramesReadyEventArgs>(kinect_AllFramesReady);

上記のようにして設定したイベントは、関数としてその処理を書く必要があります。

Kinectの動作開始

ここまで設定したら、イニシャライザの最後に以下を追記してください。

kinect.Start();

これでKinectが動作を開始します。

RGBカメラの更新で実行されるイベント

上記で設定した、KinectからRGBカメラの更新があったときに実行されるイベントを関数として定義する必要があります。
イニシャライザの次の行に以下の関数を追加しましょう。

void kinect_ColorFrameReady( object sender, ColorImageFrameReadyEventArgs e )
{
}

この関数はRGBカメラの更新で実行される関数で、第二引数である e の中に更新されたデータが格納されていると考えてください。
この関数では、

  1. e からRGBカメラが取得した画像データを取り出す
  2. Image部品に表示できる形式に変換する
  3. 先ほどMainWindow.xamlに追加したImage部品に表示する

といった処理を書くことになります。

デフォルトではKinect v1センサーのRGBカメラは30FPSですので、この関数は一秒間に約30回ほど呼び出され、
その都度RGBカメラが取得した画像でウィンドウの表示を更新することになるので、パラパラ漫画のようなイメージで動画を表示することができます。

さて、この関数を埋めればとりあえずKinectのカメラの映像をウィンドウに表示することが可能になるのですが、 Image部品に表示できる形式に変換する のに便利なライブラリがあるので、
今回は長くなってしまいましたので次回そのライブラリの導入の仕方も含めまとめて紹介したいと思います。