Deep Insider の Tutor コーナー
>>  Deep Insider は本サイトからスピンオフした姉妹サイトです。よろしく! 
新型Kinect for Windows v2 Developer Previewプログラミング入門(2)

新型Kinect for Windows v2 Developer Previewプログラミング入門(2)

Kinectプログラマー向け速報第2弾。SDKの相違点から新型Kinectの実力を探る

2013年12月25日

Kinect for Windows v2 Developer Preview向けのSDKは、以前のv1とどこが異なるのか? その主要な差異を示しながら、v2での基本的なプログラミング方法を紹介する。

初音玲(Microsoft MVP for Visual Basic)
  • このエントリーをはてなブックマークに追加

 前回は、「Kinect for Windows v2 Developer Preview」のシステム構成やセンサー類の変更点を紹介した。いよいよ今回はプログラミング面での主要な変更点を説明する。

注意事項

 本稿で検証に使用したKinect for Windows v2 Developer Previewのソフトウェアやハードウェア、APIは暫定的なものであり、正式版では変更される可能性がある。

 また、本稿は早期提供プログラムの参加規約で公表が許可されている事項について実際に確認した結果に基づき記載していることもあらかじめご了承いただきたい。

Kinect for Windows SDK v2 Developer Previewとは

 本稿のサンプルコードで使用する「Kinect for Windows SDK v2 Developer Preview」(以下、KinectSDK2プレビュー版)は、2014年に一般発売が予定されている新型のKinect用の早期提供版SDKだ。そのため、クラスやメンバーは今後、変更される可能性があるだけでなく、名前は予約されているが実装されていない部分もまだある。

 しかし、すでに主要機能は実装済みであるし、クラス構成もかなり洗練されているので、今後大きく変わることもないと想定される。従って、今からKinectSDK2プレビュー版の開発内容について把握しておくことは無駄にはならないだろう。むしろ、ここで得たノウハウが、新型Kinectの一般販売時には技術的アドバンテージになるはずだ。

 KinectSDK2プレビュー版のシステム要件を調べてみると、デバイス側と多少相違がある。筆者が特に注目したのは、「Supported Operating Systems and Architectures(サポートしているOSとアーキテクチャ)」の欄で、KinectSDK2プレビュー版には「Windows 8/Windows 8.1/Windows Embedded Standard 8/Windows Surface/Windows Surface 2」と記載されている部分だ。現状、WindowsストアアプリのプロジェクトでKinectSDK2プレビュー版を参照設定できないが、この記載を考慮すると、今後、何らかの解決が図られるのかもしれない。

KinectSDK2プレビュー版の基本的な使用方法

 現行のKinectSDK1と新しいKinectSDK2プレビュー版の音声以外のデータ処理を比較したのが下の図である。

図1.1 SDKでのデータ処理比較

 KinectSDK1と比較してKinectSDK2プレビュー版ではSDKから取り出すフレーム(Frame)の種類が増え、より柔軟に処理できるようになっている。例えば、赤外線画像データはKinectSDK1でもv1.6から「ColorFrame」のモードを切り替えることで取得できるが、KinectSDK2プレビュー版ではColorFrame(=カラーフレーム)とInfraredFrame(=赤外線フレーム)が別々のフレームに分けられたので、カラー画像と赤外線画像の両方を同時に取得できるようになった。

 またKinectSDK1でも、SkeletonFrameの距離データにPlayerIndexを含まない形式がv1.6から利用可能になったが、KinectSDK2プレビュー版では、PlayerIndexを含まない距離データはDepthFrameに、PlayerIndexはBodyIndexFrameにとそれぞれ別のフレームになり、同様に同時に取得できるようになった。

画像系データ取得の手順

 骨格データ以外のデータの取得手順をまとめたのが次の図である。

図1.2 画像系データ取得の手順

 KinectSDK1では、どのフレームを処理するかを、対応するStreamクラスのEnableメソッドを実行して指定する。一方、KinectSDK2プレビュー版は「Stream」という考え方が隠ぺいされており、処理したいフレームに対応するFrameSourceクラスのオブジェクトが用意されているので、このオブジェクトに対してOpenReaderメソッドを実行することになる。

 また、データの発生イベントについても、KinectSDK1ではKinectSensorクラスのイベントとしてデータ発生イベントがあるが、KinectSDK2プレビュー版ではOpenReaderメソッドで得られるおのおののフレームに対応するReaderクラスのイベントとしてデータ発生イベントがあるので、どのフレームに対するイベントなのかが分かりやすいし、フレームごとに処理したいときなども非常に見通しがよいコードが記述できる。

サンプルコードのスタイルについて

 KinectSDK1のサンプルコードでは、WriteableBitmapオブジェクト形式のデータをコードビハインド側(MainWindow.xaml.csやMainWindow.xaml.vbなどのファイル)でImageコントロールのSourceプロパティに直接設定していた。

 KinectSDK2プレビュー版に添付されているサンプルプログラムもコードビハインド側にコードが大量に書かれている点は変わらないが、WriteableBitmap化してデータをWPFのImageコントロールのSourceプロパティにBindingして表示するスタイルに変更されている(筆者としては、ここまでやっているならば、コードビハインド側からロジックを別クラスに分離して、次のようなクラス構成でKinectModelクラスにロジックを集約して記述してほしかったと思う)。

図2.1 KinectModelクラスにロジックを集約して記述したクラス構成の例

画像系データ取得のサンプル

 ColorFrame、DepthFrame、InfraredFrame、LongExposureInfraredFrame、BodyIndexFrameは、フレーム上の1ドットあたりの内容が異なるだけで(次の表を参照)、それぞれのデータ取得処理は基本的に同じようなコードになる。

Frame内容
ColorFrame カラー画像値(4bytes/dot)
DepthFrame センサーからの距離(2bytes/dot)
InfraredFrame 赤外線画像値(2bytes/dot)
LongExposureInfraredFrame 赤外線画像値(2bytes/dot)
BodyIndexFrame PlayerIndex(1bytes/dot)
表3.1 フレームデータのデータ形式

 各フレームデータから対応するサイズの配列に転記する方法も、KinectSDK1と同様のものが用意されている。例えばWPFのImageコントロールで表示するためのカラーデータをBitmapオブジェクトにするための流れは次のようになる。

図3.1 カラーデータからBitmapオブジェクトへの変換

 Bitmapオブジェクトを毎回生成すると処理時間がかかるのでWriteableBitmap形式で画面サイズ相当のメモリ領域を確保しておいて、そこを毎回書き換えることでメモリ領域確保時間を削減している。このあたりの考え方はKinectSDK1と同じであるので現行版でのノウハウが活用できる。

カラーデータを表示するには

 KiectSDK2プレビュー版を使った一例として一番シンプルなサンプル「Kinect2ColorSample」を用いて、カラーデータ処理方法を確認する。

変数宣言部

 内部的に使用する変数は以下のとおりである(VBとC#のコードを併記)。

Visual Basic
Private WithEvents Kinect As KinectSensor     ……1
Private WithEvents Reader As ColorFrameReader ……2

Private ColorImagePixelData As Byte()         ……3
Private ColorImageBitmap As WriteableBitmap   ……4
Private ColorImageBitmapRect As Int32Rect     ……5
Private ColorImageStride As Integer           ……6
リスト2.1 変数宣言部(Visual Basic .NET)
  • 1Kinectデバイスとの接続用変数を宣言。
  • 2カラーデータ用のFrameRreader変数をHandles句でイベントが拾えるようにWithEvents付きで宣言。
  • 3カラーデータ用のフレームをBGRA(青/緑/赤/アルファ値)形式に変換したものを格納する変数を宣言。
  • 4画面に表示するためのWriteableBitmap変数を宣言。
  • 5WriteableBitmapを書き換える領域を指定する変数を宣言。
  • 6WriteableBitmapを書き換えるときの1行分のバイト数を格納する変数を宣言。
C#
private KinectSensor Kinect;              ……1
private ColorFrameReader Reader;          ……2

private byte[] ColorImagePixelData;       ……3
private WriteableBitmap ColorImageBitmap; ……4
private Int32Rect ColorImageBitmapRect;   ……5
private int ColorImageStride;             ……6
リスト2.2 変数宣言部(C#)
  • 1Kinectデバイスとの接続用変数を宣言。
  • 2カラーデータ用のFrameRreader変数を宣言。
  • 3カラーデータ用のフレームをBGRA(青/緑/赤/アルファ値)形式に変換したものを格納する変数を宣言。
  • 4画面に表示するためのWriteableBitmap変数を宣言。
  • 55WriteableBitmapを書き換える領域を指定する変数を宣言。
  • 66WriteableBitmapを書き換えるときの1行分のバイト数を格納する変数を宣言。

 12がKinectSDK2プレビュー版での変更点だ。

 その他の変数はKinectSDK1でもよく使われる変数で、カラーデータを表示するのに必要なメモリ領域はクラス共通変数として宣言しておき、事前に初期化しておくことで、カラーデータ発生イベント時に変数領域を毎回確保する必要がなくなるため処理速度の向上が期待できる。

センサー接続と初期化

 初期化の主な処理は、WriteableBitmap変数などカラーデータを処理するためのメモリ領域の確保だ(次のVB/C#コード)。

Visual Basic
Private Sub DiscoverKinectSensor()
  Me.Kinect = KinectSensor.KinectSensors.FirstOrDefault(
    Function(x)
      Return x.Status = KinectStatus.Connected                   ……1
    End Function)
  If Me.Kinect IsNot Nothing Then
    Dim colorDesc = Me.Kinect.ColorFrameSource.FrameDescription  ……2

    Me.Kinect.Open()                                 3
    Me.Reader = Me.Kinect.ColorFrameSource.OpenReader            ……4
    Me.ColorImageBitmap = New WriteableBitmap(colorDesc.Width,   ……5
                          colorDesc.Height,
                          96.0,
                          96.0,
                          PixelFormats.Bgr32,
                          Nothing)
    Me.ColorImageStride = colorDesc.Width * Me.BytesPerPixel     ……6
    ReDim Me.ColorImagePixelData(Me.ColorImageStride * colorDesc.Height - 1)  ……7
    Me.ColorImageBitmapRect = New Int32Rect(0,                   ……8
                        0,
                        colorDesc.Width,
                        colorDesc.Height)
  End If
End Sub
リスト2.3 初期化(Visual Basic .NET)
  • 1接続されている1番目のKinect2センサーを取得する。
  • 2カラーデータの各種情報(解像度など)を取得する。
  • 3Kinect2センサーをオンにする。
  • 4カラーデータ用のフレーム取得を開始する。
  • 5カラーデータの解像度に合わせてWriteableBitmapの領域を確保する。
  • 6バイト配列をWriteableBitmapにマッピングするときの1行のバイト数を計算する。
  • 7カラーデータの解像度×4bytesの大きさでフレームを受け取るバイト配列領域を確保する。
  • 8カラーデータの解像度に合わせてWriteableBitmapの書き換え領域を確保する。
C#
private void DiscoverKinectSensor()
{
  this.Kinect = KinectSensor.KinectSensors.FirstOrDefault((x) =>
  {
    return x.Status == KinectStatus.Connected;                     ……1
  });
  if (this.Kinect != null)
  {
    var colorDesc = this.Kinect.ColorFrameSource.FrameDescription; ……2

    this.Kinect.Open();                                            ……3
    this.Reader = this.Kinect.ColorFrameSource.OpenReader();       ……4
    this.Reader.FrameArrived += this.Reader_FrameArrived; /* */    ……4'
    this.ColorImageBitmap = new WriteableBitmap(colorDesc.Width,   ……5
      colorDesc.Height,
      96.0,
      96.0,
      PixelFormats.Bgr32,
      null);
    this.ColorImageStride = colorDesc.Width * colorDesc.BytesPerPixel;       ……6
    this.ColorImagePixelData = new byte[colorDesc.Width * colorDesc.Height]; ……7
    this.ColorImageBitmapRect = new Int32Rect(0,                   ……8
          0,
          colorDesc.Width,
          colorDesc.Height);
  }
}
リスト2.4 初期化(C#)
  • 1接続されている1番目のKinect2センサーを取得する。
  • 2カラーデータの各種情報(解像度など)を取得する。
  • 3Kinect2センサーをオンにする。
  • 4カラーデータ用のフレーム取得を開始する。
  • 4'C#ではWithEventsがないのでOpenReader後にイベントハンドラー登録する。
  • 5カラーデータの解像度に合わせてWriteableBitmapの領域を確保する。
  • 6バイト配列をWriteableBitmapにマッピングするときの1行のバイト数を計算する。
  • 7カラーデータの解像度×4bytesの大きさでフレームを受け取るバイト配列領域を確保する。
  • 8カラーデータの解像度に合わせてWriteableBitmapの書き換え領域を確保する。

 KinectSDK2プレビュー版では、ColorFrameSourceクラスにフレームデータの詳細情報用の各種プロパティが用意されており、KinectSDK1よりも解像度などのデータをハードコーディングする必要がないように工夫されている。

カラーデータ処理

 KinectSDK2プレビュー版がカラーデータを取得できるとReaderオブジェクトのFrameArrivedイベントが発生するので、イベントプロシージャ内でWriteableBitmapへの転記処理を行う。

 この部分は、大まかな流れこそKinectSDK1と同様だが、クラスやメソッド・プロパティの名称や構造が異なるのでKinectSDK2プレビュー版にするには順次書き換えが必要な箇所だ(次のVB/C#コード)。

Visual Basic
Private Sub Reader_FrameArrived(sender As Object,
                e As ColorFrameArrivedEventArgs) Handles Reader.FrameArrived
  Dim frameReference = e.FrameReference()                         ……1

  Using frame As ColorFrame = frameReference.AcquireFrame         ……2
    If frame IsNot Nothing Then
      frame.CopyConvertedFrameDataToArray(Me.ColorImagePixelData, ……3
                        ColorImageFormat.Bgra)
      Me.ColorImageBitmap.WritePixels(Me.ColorImageBitmapRect,    ……4
                      Me.ColorImagePixelData,
                      Me.ColorImageStride,
                      0)
      Me.ColorImageElement = Me.ColorImageBitmap                  ……5
    End If
  End Using
End Sub
リスト2.5 カラーデータ処理(Visual Basic .NET)
  • 1フレーム情報を取得する。
  • 2AcquireFrameメソッドでフレームを取得する。
  • 3フレームからBGRA形式のバイト列に変更し、バイト配列に格納する。
  • 4配列でWriteableBitmapを書き換える。
  • 5画面に表示するために公開プロパティに設定する。
C#
private void Reader_FrameArrived(object sender, ColorFrameArrivedEventArgs e)
{
  var frameReference = e.FrameReference;                    ……1

  using(ColorFrame frame = frameReference.AcquireFrame())   ……2
  {
    if (frame != null)
    {
      frame.CopyConvertedFrameDataToArray(                  ……3
            this.ColorImagePixelData,
            ColorImageFormat.Bgra);
      this.ColorImageBitmap.WritePixels(                    ……4
            this.ColorImageBitmapRect,
            this.ColorImagePixelData,
            this.ColorImageStride,
            0);
      this.ColorImageElement = this.ColorImageBitmap;       ……5
    }
  }
}
リスト2.6 カラーデータ処理(C#)
  • 1フレーム情報を取得する。
  • 2AcquireFrameメソッドでフレームを取得する。
  • 3フレームからBGRA形式のバイト列に変更し、バイト配列に格納する。
  • 4バイト配列でWriteableBitmapを書き換える。
  • 5画面に表示するために公開プロパティに設定する。

 KinectModelクラスの処理内容は以上だ。あとはMainViewModelクラス経由でWPF上のImageコントロールにWriteableBitmapの最新の内容が随時表示され続ける。次の画像は、実際にサンプルを動かして表示されている結果だ。

図3.2 Kinect2ColorSampleの動作結果

まとめ

 カラーデータ、距離データ、赤外線データの処理方法は、v1とv2で解像度の違いはあるが基本的な構成は同一だ。また実際に動作させてみると、KinectSDK1と比べるとKinectSDK2プレビュー版では解像度が高いために非常に鮮明である。また、距離データからPlayerIndexが外れているので、距離を取得したいときにPlayerIndex分を除かなくてもよいのは非常に便利だ。

 このようにKinectSDK2プレビュー版でのデータの扱いは、KinectSDK1を踏襲しつつ使いやすい形に整理し直されている。過去のプログラムがそのまま動かないといえば動かないが、実際に過去に作成したKinectアプリをKinectSDK2プレビュー版に作り直してみると、修正は機械的かつ軽微であり、新形式への乗り換えはたやすかったのでそれほど心配する必要はない。

 次回は、KinectSDK2プレビュー版で関節ポイントが追加され、手のひら開閉検出も可能になった骨格データについて確認する。

※以下では、本稿の前後を合わせて5回分(第1回~第5回)のみ表示しています。
 連載の全タイトルを参照するには、[この記事の連載 INDEX]を参照してください。

新型Kinect for Windows v2 Developer Previewプログラミング入門(2)
1. 日本最速レビュー。開発者目線で調査する「Kinect for Windows v2」限定開発者プレビュー版

2014年に一般発売が予定されている新型Kinectを早くも先行レビュー。ハードウェアスペックや、新しくなったソフトウェア構成、センサー類の進化について紹介する。

新型Kinect for Windows v2 Developer Previewプログラミング入門(2)
2. 【現在、表示中】≫ Kinectプログラマー向け速報第2弾。SDKの相違点から新型Kinectの実力を探る

Kinect for Windows v2 Developer Preview向けのSDKは、以前のv1とどこが異なるのか? その主要な差異を示しながら、v2での基本的なプログラミング方法を紹介する。

新型Kinect for Windows v2 Developer Previewプログラミング入門(2)
3. 新型Kinectの骨格データに関する新機能とは?

KinectSDK2プレビュー版の距離データと骨格データに関する主要な変更点を解説。手の開閉が判定できるようになり、グー、チョキ、パーも判別可能に。

新型Kinect for Windows v2 Developer Previewプログラミング入門(2)
4. 世界最速・最新情報、March SDK Update(Kinect for Windows v2 Developer Preview)の内容に迫る!

本日、SDKの3月更新版が提供された。その更新点として「Kinectファームウェアの更新」「Kinect Serviceの変更は特になし」「Kinect Studioの提供」について紹介。

新型Kinect for Windows v2 Developer Previewプログラミング入門(2)
5. Windowsストアアプリ対応に、Unityサポートも ― 最新April SDK Update(Kinect for Windows v2 Developer Preview)の新機能

4月30日に提供が開始された「April SDK Update」の内容を解説。Windowsストアアプリ対応/Unityサポート/サービス・スピンダウン機能/Audio APIなどの新機能を紹介する。

サイトからのお知らせ

Twitterでつぶやこう!