Kinectを使って、画面上の赤い輪をくぐるサンプル

2012年8月23日(木)
薬師寺 国安

ロジックコードを記述する

Option Strict On
Imports Microsoft.Kinect

Class MainWindow

一個のKinectセンサーを表すKinectSensorクラスのメンバ変数Kinectを宣言しておきます。

  Dim Kinect As KinectSensor

整数四角形の幅、高さ、および位置を表すInt32Rect構造体のメンバ変数myScreenImageRectを宣言します。領域の指定に使用されます。

  Dim myScreenImageRect As Int32Rect

Short型の配列メンバ変数myDepthPixelDataとByte型の配列メンバ変数myColorPixelDataを宣言しておきます。
※深度情報は、1ピクセルあたり2バイトのshort型。画像情報はフルカラーなので1ピクセルあたり4バイトのbyte型です。

  Dim myDepthPixelData As Short()

  Dim myColorPixelData As Byte()

ピクセル深度を格納するためのDouble型のメンバ変数myDepthを宣言しておきます。

  Private myDepth As Double

WriteableBitmapクラス型のHuman_Image1_Bitmap(楕円の輪より背面に来るプレイヤー)、Human_Image2_Bitmap(楕円の輪より前面に来るプレイヤー)、Room_Bitmap(一番奥に位置する部屋(背景))プロパティを定義しておきます。WriteableBitmapクラスは、書き込みおよび更新が可能なBitmapSourceを提供するクラスです。ここで定義したプロパティをImageコントロールのSourceプロパティにバインドしています。

  Property Human_Image1_Bitmap As WriteableBitmap
  Property Human_Image2_Bitmap As WriteableBitmap
  Property Room_Bitmap As WriteableBitmap

ウィンドウが読み込まれた時の処理

ピクセル深度の値を2400(2m40cm)で初期化しておきます。Kinectセンサーを取得し、ビットマップデータを初期化し、プレイヤーの画層(レイヤー)を初期化するinit_kinectプロシージャを実行します。

構成ツリーのオブジェクトがレンダリングされる直前に発生する、CompositionTarget.Renderingイベントにイベントハンドラを指定します。イベントハンドラ内では以下の処理を行います。

OpenNextFrame(100)メソッドで、KinectからRGBデータの次のフレームを開きます。次のフレームがなかった場合のタイムアウトを100ミリセコンドと指定しています。同様に、Kinectから深度データの次のフレームを開きます。次のフレームがなかった場合のタイムアウトを100ミリセコンドと指定しています。
背景を描画し距離データを取得するRenderScreenプロシージャを実行します。引数として、Kinectのストリーミング用RGBデータのバッファと深度データのバッファを含んでいる、colorFrameとdepthFrameを渡しています。DataContextプロパティにMainWindow自身のインスタンスを指定します。この処理を行わないとプレイヤーが表示されませんので注意してください。

  Private Sub MainWindow_Loaded(sender As Object, e As System.Windows.RoutedEventArgs) Handles Me.Loaded
 
    myDepth = 2400
    init_kinect()
    AddHandler CompositionTarget.Rendering, Sub(renderSender As Object, renderArgs As EventArgs)
      Using colorFrame As ColorImageFrame = Kinect.ColorStream.OpenNextFrame(100)
        Using depthFrame As DepthImageFrame = Kinect.DepthStream.OpenNextFrame(100)
          RenderScreen(colorFrame, depthFrame)
        End Using
      End Using
            End Sub
    DataContext = Me
  End Sub

Kinectデバイスを取得し、ビットマップデータを初期化し、プレイヤーの画層(レイヤー)を初期化する処理

Kinectセンサーを取得します。DepthStream.Enableメソッドで距離カメラの表示サイズを640×480、1秒あたり30フレームで、動作を開始します。同様にColorStream.Enableメソッドで、RDBカメラを、RGBフォーマット、表示サイズ640×480、1秒あたり30フレームで、動作を開始します。プレイヤーおよびスケルトンの認識も開始します。

骨格生成を行う場合は、深度センサー(距離カメラ)を有効にする必要があります。Dim depthStream As DepthImageStream = Kinect.DepthStreamで、距離カメラの処理を行うクラスのインスタンスを取得します。Short配列変数myDepthPixelDataに距離カメラのピクセルデータのバイト長分の配列を作成します。640×480の表示サイズの場合は、myDepthPixelData=New Short(307200-1){}分の配列を確保することになります。-1しているのは配列のインデックスは0から始まるためです。

バイト配列変数myColorPixelDataにRGBカメラのピクセルデータのバイト長分の配列を作成します。

WriteableBitmapクラス型のRoom_Bitmapを下記の書式で初期化します。

New WriteableBitmap(距離カメラのフレーム幅,距離カメラのフレーム高さ, ビットマップの水平値, ビットマップの垂直値,ビットマップのピクセルフォーマット,ビットマップのビットマップパレット)

「ビットマップのピクセルフォーマット」には、PixelFormats.Bgra32を指定します。Bgra32 は、bits per pixel(BPP)が 32 の sRGB 形式です。各カラー チャネル(青、緑、赤、およびアルファ)に割り当てられるbits per pixel(BPP)は 8 です。ここに、Brg32を指定すると背景が透明化されず真っ黒になってしまいますので注意してください。

ここは、Room_Bitmap = New WriteableBitmap(640, 480, 96, 96, PixelFormats.Bgra32, Nothing)
と指定しても同じです。

同様に、Human_Image1_Bitmap、Human_Image2_BitmapについてもWriteableBitmapの書式で初期化しておきます。

IntRect32構造体のmyScreenImageRectを下記の書式で初期化し、領域を指定します。

New IntRect32(新しいInt32Rect のインスタンスの X座標,新しいInt32Rect のインスタンスの Y座標, 四角形の幅を指定した新しい Int32Rect のインスタンスの幅, 四角形の高さを指定した新しい Int32Rect のインスタンスの高さ)

「新しいInt32Rect のインスタンスの X座標」と「新しいInt32Rect のインスタンスの Y座標」には0を指定します。「四角形の幅を指定した新しい Int32Rect のインスタンスの幅」には、Human_Image2_Bitmapオブジェクトの幅を指定し、「Int32Rect のインスタンスの高さ」には、Human_Image2_Bitmapオブジェクトの高さを指定します。

結局は、
myScreenImageRect = New Int32Rect(0, 0, 640, 480)
と指定しても同じことです。

Kinectを動作させます。

Private Sub init_kinect()
    Try
      If KinectSensor.KinectSensors.Count = 0 Then
        MessageBox.Show("Kinectが接続されていません。")
        Exit Sub
      Else
        Kinect = KinectSensor.KinectSensors(0)
      End If
 
      Kinect.DepthStream.Enable(DepthImageFormat.Resolution640x480Fps30)
      Kinect.ColorStream.Enable(ColorImageFormat.RgbResolution640x480Fps30)
      Kinect.SkeletonStream.Enable()
 
      Dim depthStream = Kinect.DepthStream
      myDepthPixelData = New Short(Kinect.DepthStream.FramePixelDataLength - 1) {}
      myColorPixelData = New Byte(Kinect.ColorStream.FramePixelDataLength - 1) {}

 
      Room_Bitmap = New WriteableBitmap(depthStream.FrameWidth, depthStream.FrameHeight, 96, 96, PixelFormats.Bgra32, Nothing)
      Human_Image1_Bitmap = New WriteableBitmap(depthStream.FrameWidth, depthStream.FrameHeight, 96, 96, PixelFormats.Bgra32, Nothing)
      Human_Image2_Bitmap = New WriteableBitmap(depthStream.FrameWidth, depthStream.FrameHeight, 96, 96, PixelFormats.Bgra32, Nothing)
 
      myScreenImageRect = New Int32Rect(0, 0, CInt(Math.Ceiling(Human_Image2_Bitmap.Width)), CInt(Math.Ceiling(Human_Image2_Bitmap.Height)))
      Kinect.Start()
    Catch ex As Exception
      MessageBox.Show(ex.Message)
      Exit Sub
    End Try
  End Sub
  • Kinectで赤い輪をくぐるサンプル

薬師寺国安事務所

薬師寺国安事務所代表。Visual Basic プログラミングと、マイクロソフト系の技術をテーマとした、書籍や記事の執筆を行う。
1950年生まれ。事務系のサラリーマンだった40歳から趣味でプログラミングを始め、1996年より独学でActiveXに取り組む。1997年に薬師寺聖とコラボレーション・ユニット PROJECT KySS を結成。2003年よりフリーになり、PROJECT KySS の活動に本格的に参加、.NETやRIAに関する書籍や記事を多数執筆する傍ら、受託案件のプログラミングも手掛ける。Windows Phoneアプリ開発を経て、現在はWindows ストア アプリを多数公開中

Microsoft MVP for Development Platforms - Client App Dev (Oct 2003-Sep 2012)。Microsoft MVP for Development Platforms - Windows Phone Development(Oct 2012-Sep 2013)。Microsoft MVP for Development Platforms - Client Development(Oct 2013-Sep 2014)。Microsoft MVP for Development Platforms-Windows Platform Development (Oct 2014-Sep 2015)。

連載バックナンバー

Think ITメルマガ会員登録受付中

Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。

Think ITメルマガ会員のサービス内容を見る

他にもこの記事が読まれています