Kinect v2で実現する打楽器のバーチャル演奏
2014年12月22日(月)

カラーフレーム到着時のイベント
リスト5:(MainWindow.xaml.vbの一部、リスト4の続き)
01 | Private Sub myColorFrameReader_FrameArrived(sender As Object, e As ColorFrameArrivedEventArgs) |
02 | Dim colorFrameProcessed As Boolean = False |
03 | Using myColorFrame As ColorFrame = e.FrameReference.AcquireFrame (1) |
04 | If myColorFrame Is Nothing = False Then |
05 | Dim myColorFrameDescription As FrameDescription = myColorFrame.FrameDescription (2) |
06 | If myColorFrameDescription.Width = colorBitmap.PixelWidth AndAlso myColorFrameDescription.Height = colorBitmap.PixelHeight Then |
07 | If myColorFrame.RawColorImageFormat = ColorImageFormat.Bgra Then (3) |
08 | myColorFrame.CopyRawFrameDataToArray(ColorImagePixelData) |
09 | Else |
10 | myColorFrame.CopyConvertedFrameDataToArray(ColorImagePixelData, ColorImageFormat.Bgra) |
11 | End If |
12 | colorFrameProcessed = True (4) |
13 | End If |
14 | End If |
15 | End Using |
16 | If colorFrameProcessed = True Then |
17 | colorBitmap.WritePixels(New Int32Rect(0, 0, colorBitmap.PixelWidth, colorBitmap.PixelHeight), ColorImagePixelData, colorBitmap.PixelWidth * BytesPerPixel, 0) (5) |
18 | roomImage.Source = colorBitmap (6) |
19 | End If |
20 | End Sub |
- e.FrameReference.AcquireFrameメソッドでカラーフレームを取得し、myColorFrameで参照します。
- myColorFrameにデータがあった場合、KinectSensor から、イメージフレームのプロパティを取得し、変数myColorFrameDescriptionで参照します。
取得したプロパティの幅と高さが、colorBitmapのPixelWidth、PixelHeightと同じであった場合、以下の処理を実行します。 - カラーフレームデータの形式がBgraであった場合は、CopyRawFrameDataToArrayメソッドで、Raw フレームのデータ指定された配列(ColorImagePixelData)にコピーします。
そうでない場合は、CopyConvertedFrameDataToArrayメソッドで、フレームから「BGRA形式」のバイト列に変換し、バイト配列に格納します。書式は下記の通りです。
CopyConvertedFrameDataToArray(frameData,colorFomat)
「frameData」には格納する配列、この場合はバイト配列のColorImagePixelDataを指定しています。「colorFormat」には色の形式を指定します。この場合は「Bgra形式」を指定しています。 - Boolean型で宣言していた変数colorFrameProcessedをTrueで初期化します。
- 変数colorFrameProcessed変数がTrueであった場合は、colorBitmap(WriteableBitmapクラス)のWritePixelsメソッドで、ビットマップの指定した領域内のピクセルを更新します。書式は下記の通りです。
WritePixels(sourecRect,pixels,stride,offset)
「sourceRect」には更新するWriteableBitmapの四角形を表す「Int32Rect型」を指定します。「pixels」にはビットマップの更新に使用する「ピクセル配列」を指定します。この場合は、ColorImagePixelDataのバイト列を指定しています。「stride」にはpixels内の更新領域の「ストライド」を指定します。今回はcolorBitmapのPixelWidthにメンバー変数BytesPerPixel(値は4)の4をかけた値を指定しています。「ストライド」とは、画像データのX座標横一列あたりに用いられるバイト数を示す値です。「offset」には入力バッファのオフセットを指定します。今回は「0」を指定しています。 - roomImageのSourceプロパティにcolorBitmapオブジェクトを指定します。これでRGBカメラからの画像が表示されます。
プレイヤーの手の形によって条件分岐を行う処理
リスト6:(MainWindow.xaml.vbの一部、リスト5の続き)
01 | Private Sub DrawHandState(joint As Joint, state As HandState, myTrackingConfidence As TrackingConfidence) |
02 | If myTrackingConfidence <> TrackingConfidence.High Then |
03 | Return |
04 | End If |
05 | If state = HandState.Open Then |
06 | Index = 0 (1) |
07 | ElseIf state = HandState.Closed Then |
08 | If point.X > Image1.GetValue(Canvas.LeftProperty) And point.X < Image1.GetValue(Canvas.LeftProperty) + Image1.Width AndAlso point.Y > Image1.GetValue(Canvas.TopProperty) And point.Y < Image1.GetValue(Canvas.TopProperty) + Image1.Height Then |
09 | Index = 1 |
10 | End If |
11 | If point.X > Image2.GetValue(Canvas.LeftProperty) And point.X < Image2.GetValue(Canvas.LeftProperty) + Image2.Width AndAlso point.Y > Image2.GetValue(Canvas.TopProperty) And point.Y < Image2.GetValue(Canvas.TopProperty) + Image2.Height Then |
12 | Index = 2 |
13 | End If |
14 | End If |
15 | End Sub |
手がパーの状態なら、Indexの値を0で初期化します。手がグーの状態の場合は、まず太鼓とドラムの位置を取得します。太鼓の位置を取得できたらIndexを1に、ドラムの位置が取得できたらIndexを2に初期化します。
リスト8で、ここで取得したIndexの値で条件分岐を行い、Indexが1で太鼓、Indexが2でドラムの音が鳴るようにしています。
ウインドウが閉じられる場合の処理
リスト7:(MainWindow.xaml.vbの一部、リスト6の続き)
1 | Private Sub MainWindow_Closing(sender As Object, e As CancelEventArgs) Handles Me.Closing |
2 | If myKinect Is Nothing = False Then |
3 | myKinect.Close() |
4 | myKinect = Nothing |
5 | End If |
6 | End Sub |
Kinectが動作している場合はKinectを閉じ、全ての関連付けから解放します。
関節の位置に透明の円を表示する処理
リスト8:(MainWindow.xaml.vbの一部、リスト7の続き)
01 | Private Sub DrawEllipse(myJoint As Joint, R As Integer, myBrush As Brush) |
02 | Dim myEllipse = New Ellipse |
03 | With myEllipse (1) |
04 | .Width = R |
05 | .Height = R |
06 | .Fill = myBrush |
07 | End With |
08 | point = myKinect.CoordinateMapper.MapCameraPointToDepthSpace(myJoint.Position) (2) |
09 | If point.X < 0 OrElse point.Y < 0 Then |
10 | Return |
11 | End If |
12 | Canvas.SetLeft(myEllipse, point.X - (R / 2)) (3) |
13 | Canvas.SetTop(myEllipse, point.Y - (R / 2)) |
14 | If myJoint.JointType = JointType.HandRight Then |
15 | 'TextBlock1.Text = Index |
16 | Select Case Index |
17 | Case 1 |
18 | MediaElement1.Play() |
19 | Case 2 |
20 | MediaElement2.Play() |
21 | End Select |
22 | End If |
23 | CanvasBody.Children.Add(myEllipse) |
24 | End Sub |
- 透明な半径10pixelの円を作成します。半径は呼び出し時に引数で指定しています。
- CoordinateMapper.MapCameraPointToDepthSpaceメソッドで、関節の位置を、カメラ空間から距離空間へのポイントにマップし、メンバー変数pointで参照します。
- SetLeftとSetTopメソッドに透明な円を指定し、XとY軸に描きます。
- メンバー変数Indexが1の場合はMediaElement1(太鼓)、2の場合はMediaElement2(ドラム)を再生します。
音の再生が終わった時の処理
リスト9:(MainWindow.xaml.vbの一部、リスト8の続き)
1 | Private Sub MediaElement1_MediaEnded(sender As Object, e As RoutedEventArgs) Handles MediaElement1.MediaEnded |
2 | MediaElement1.Close() |
3 | End Sub |
4 |
5 | Private Sub MediaElement2_MediaEnded(sender As Object, e As RoutedEventArgs) Handles MediaElement2.MediaEnded |
6 | MediaElement2.Close() |
7 | End Sub |
8 | End Class |
実際に動かしてみた様子を動画に示します。
連載バックナンバー
Think ITメルマガ会員登録受付中
Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。
全文検索エンジンによるおすすめ記事
- Kinect v2を使って、机の上のリンゴをつかんで移動してみる
- Kinect v2の音声認識で「仮面」を選んで変身してみる
- Kinect v2のジェスチャーでBing Mapsを未来的に直感操作する
- Kinect v2のカメラから画像を取り込んで表示する基本プログラム
- Kinect v2を使った「じゃんけんゲーム」を作る
- Kinectで手の動きに合わせてモニタ上の画像を動かすサンプル
- Kinect v2のIRセンサーから赤外線画像を読み込む
- Kinectで人体を認識して棒人間を動かすサンプル
- 声で選んだアイテムをプレイヤーの身体に装着・連動させるKinectサンプル
- Kinect v2の深度センサーから取り込んだ画像を表示する