Kinect v2を使った「じゃんけんゲーム」を作る
2014年12月16日(火)

音声認識処理
リスト6 (MainWindow.xaml.vbの一部、リスト5の続き)
01 | Private Sub speechEngine_SpeechRecognized(sender As Object, e As SpeechRecognizedEventArgs) |
02 | messageTextBlock.Text = String.Empty |
03 | Rnd = New Random |
04 | RandomNumber = Rnd.Next(0, 2) (1) |
05 | Const myConfidence As Double = 0.4 (2) |
06 | If e.Result.Confidence >= myConfidence Then |
07 | Select Case e.Result.Text |
08 | Case “じゃんけんぽん” |
09 | computerJankenImage.Source = Nothing |
10 |
11 | JyankenImage = xmldoc.Descendants(“画像名”)(RandomNumber).Value (3) |
12 | computerJankenImage.Source = New BitmapImage(New Uri(“Images/” & JyankenImage, UriKind.Relative)) |
13 | If JyankenImage = “グー.png” AndAlso flagImage = “グー.png” Then (4) |
14 | messageTextBlock.Text = “あいこです” |
15 | ElseIf JyankenImage = “パー.png” AndAlso flagImage = “パー.png” Then |
16 | messageTextBlock.Text = “あいこです” |
17 | ElseIf JyankenImage = “チョキ.png” AndAlso flagImage = “チョキ.png” Then |
18 | messageTextBlock.Text = “あいこです” |
19 | ElseIf JyankenImage = “グー.png” AndAlso flagImage = “パー.png” Then |
20 | messageTextBlock.Text = “あなたの勝です” |
21 | player_Score += 1 |
22 | ElseIf JyankenImage = “パー.png” AndAlso flagImage = “グー.png” Then |
23 | messageTextBlock.Text = “コンピューターの勝です” |
24 | computer_Score += 1 |
25 | ElseIf JyankenImage = “パー.png” AndAlso flagImage = “チョキ.png” Then |
26 | messageTextBlock.Text = “あなたの勝です” |
27 | player_Score += 1 |
28 | ElseIf JyankenImage = “チョキ.png” AndAlso flagImage = “パー.png” Then |
29 | messageTextBlock.Text = “コンピューターの勝です” |
30 | computer_Score += 1 |
31 | ElseIf JyankenImage = “グー.png” AndAlso flagImage = “チョキ.png” Then |
32 | messageTextBlock.Text = “コンピューターの勝です” |
33 | computer_Score += 1 |
34 | ElseIf JyankenImage = “チョキ.png” AndAlso flagImage = “グー.png” Then |
35 | messageTextBlock.Text = “あなたの勝です” |
36 | player_Score += 1 |
37 | End If |
38 | playerScoreTextBlock.Text = “あなたの得点=” & player_Score |
39 | computerScoreTextBlock.Text = “コンピューターの得点=” & computer_Score |
40 | End Select |
41 | End If |
42 | End Sub |
- 0~2までの3つの乱数を発生します。
- Confidenceプロパティで音声認識の信頼度を設定します。-1~1の値で指定し、数字が大きいほど信頼度が高くなります。標準は「0」です。「-1」を指定すると、どんな言葉でも反応してしまう可能生があり、「1」を指定すると、なかなか認識されません。今回は信頼度が「0.4」より大きい場合に言葉を認識するよう指定しています。
以下、プレイヤーが「じゃんけんぽん」とセンサーに向かって発生した場合の処理です。 - 乱数に該当する位置にある「画像名」要素の値を取得します。
- コンピューターが表示する「グー」「チョキ」「パー」のイメージ画像によって条件分岐を行います。JyanlenImageとflagImageの画像を比較して勝ち負けを表示しています。結果をmessageTextBlockに表示し、プレイヤーが勝ったら変数player_Scoreを、コンピューターが勝ったらcomputer_Scoreを1ずつ加算して表示します。
新しいボディフレームの準備ができているときに発生するイベント処理
リスト7 (MainWindow.xaml.vbの一部、リスト6の続き)
01 | Private Sub myBodyFrameReader_FrameArrived(sender As Object, e As BodyFrameArrivedEventArgs) |
02 | Using frame = e.FrameReference.AcquireFrame (1) |
03 | If frame Is Nothing = False Then |
04 | Using myDataContext = myBodyDrawingGroup.Open |
05 | myDataContext.DrawRectangle(Brushes.Black, Nothing, myRect) |
06 | frame.GetAndRefreshBodyData(myBodies) (2) |
07 | For i As Integer = 0 To Me.myBodies.Length - 1 (3) |
08 | If myBodies(i).IsTracked = True Then |
09 | Dim joints As IReadOnlyDictionary(Of JointType, Joint) = myBodies(i).Joints (4) |
10 | Dim points As New Dictionary(Of JointType, Point) (5) |
11 | For Each joint In joints.Keys (6) |
12 | Dim pos = myKinect.CoordinateMapper.MapCameraPointToDepthSpace(joints(joint).Position) (7) |
13 | points(joint) = New Point(pos.X, pos.Y) (8) |
14 | If joint = JointType.HandLeft Then (9) |
15 | DrawHandState(myBodies(i).Joints(JointType.HandLeft), myBodies(i).HandLeftState, myBodies(i).HandLeftConfidence) |
16 | ElseIf joint = JointType.HandRight Then |
17 | DrawHandState(myBodies(i).Joints(JointType.HandRight), myBodies(i).HandRightState, myBodies(i).HandRightConfidence) |
18 | End If |
19 | Next |
20 | End If |
21 | Next |
22 | Me.myBodyDrawingGroup.ClipGeometry = New RectangleGeometry(myRect) (10) |
23 | End Using |
24 | End If |
25 | End Using |
26 | End Sub |
- e.FrameReference.AcquireFrameメソッドで、ボディフレームを取得し、Frameで参照します。
- GetAndRefreshBodyDataメソッドで、更新されたボディデータを取得します。
- ボディデータの中を、反復処理を行います。
- ボディデータが追跡されている場合は、ボディデータの関節を取得し、変数jointsで参照します。
- JointTypeのキーとPointの値で初期化された新しい、Dictionaryのインスタンスである、pointsオブジェクトを作成します。
- 各関節をjoint変数で取得していきます。
- CoordinateMapper.MapCameraPointToDepthSpaceメソッドで、関節の位置を、カメラ空間から距離空間へのポイントにマップし、変数posで参照します。CoordinateMapper.MapCameraPointToDepthSpaceメソッドの書式は下記の通りです。
CoordinateMapper.MapCameraPointToDepthSpace(cameraPoint)
「cameraPoint」にはカメラ空間からマップするポイントCameraSpacePointを指定します。この場合はカメラ空間における関節の位置を指定しています。 - 距離空間にマップされた関節のXとY座標で初期化された、新しいPointのインスタンスpoints(joint)オブジェクトを作成します。
- 関節のタイプが「左手」や「右手」であった場合は、DrawHandStateを実行します。
- DrawingGroup のクリップ領域にmyRectで初期化された2次元の四角形を設定します。
ウインドウが閉じられる場合の処理
リスト8 (MainWindow.xaml.vbの一部、リスト7の続き)
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を閉じ、全ての関連付けから解放します。
カラーフレーム到着時のイベント
リスト9 (MainWindow.xaml.vbの一部、リスト8の続き)
01 | Private Sub myColorFrameReader_FrameArrived(sender As Object, e As ColorFrameArrivedEventArgs) |
02 | Using myColorFrame As ColorFrame = e.FrameReference.AcquireFrame (1) |
03 | If myColorFrame Is Nothing = True Then |
04 | Return |
05 | End If |
06 | myColorFrame.CopyConvertedFrameDataToArray(ColorImagePixelData, ColorImageFormat.Bgra) (2) |
07 | End Using |
08 | colorBitmap.WritePixels(New Int32Rect(0, 0, colorBitmap.PixelWidth, colorBitmap.PixelHeight), ColorImagePixelData, colorBitmap.PixelWidth * BytesPerPixel, 0) (3) |
09 | Image1.Source = colorBitmap (4) |
10 | End Sub |
- e.FrameReference.AcquireFrameメソッドでカラーフレームを取得し、myColorFrameで参照します。
- CopyConvertedFrameDataToArrayメソッドで、フレームから「BGRA形式」のバイト列に変換し、バイト配列に格納します。書式は下記の通りです。
CopyConvertedFrameDataToArray(frameData, colorFomat)
「frameData」には格納する配列、この場合はバイト配列のColorImagePixelDataを指定しています。「colorFormat」には「色の形式」を指定します。ここでは、「Bgra形式」となります。 - colorBitmap(WriteableBitmapクラス)のWritePixelsメソッドで、ビットマップの指定した領域内のピクセルを更新します。書式は下記の通りです。
WritePixels(sourecRect, pixels, stride, offset)
「sourceRect」には「Int32Rect型」を指定します。更新するWriteableBitmapの四角形です。「pixels」にはビットマップの更新に使用する「ピクセル配列」を指定します。この場合は、ColorImagePixelDataのバイト列を指定しています。「stride」にはpixels内の更新領域の「ストライド」を指定します。今回はcolorBitmapのPixelWidthに「4」を乗算した値を指定しています。「ストライド」とは、画像データのX座標横一列あたりに用いられるバイト数を示す値です。例えば、横幅が512ピクセルで、RGBA各色8ビット(32ビットカラー)で表現される画像データのストライドは、
512(ピクセル)×4(バイト)=2048
となります。今回の場合はRGBカラーの解像度が1920×1080(ピクセル)であるため
1920×4=7680
の値が「stride」に適用されることになります。「offset」には入力バッファのオフセットを指定します。今回は「0」を指定しています。 - 「Image1」のSourceプロパティにcolorBitmapオブジェクトを指定します。これでRGBカメラからの画像が表示されます。
プレイヤーの手の形によって条件分岐を行う処理
リスト10 (MainWindow.xaml.vbの一部、リスト9の続き)
01 | Private Sub DrawHandState(joint As Joint, state As HandState, myTrackingConfidence As TrackingConfidence) |
02 |
03 | If myTrackingConfidence <> TrackingConfidence.High Then |
04 | Return |
05 | End If |
06 |
07 | If state = HandState.Open Then |
08 | jankenImage.Source = New BitmapImage(New Uri("Images/パー.png", UriKind.Relative)) |
09 | flagImage = "パー.png" |
10 | ElseIf state = HandState.Closed Then |
11 | jankenImage.Source = New BitmapImage(New Uri("Images/グー.png", UriKind.Relative)) |
12 | flagImage = "グー.png" |
13 | ElseIf state = HandState.Lasso Then |
14 | jankenImage.Source = New BitmapImage(New Uri("Images/チョキ.png", UriKind.Relative)) |
15 | flagImage = "チョキ.png" |
16 | Else |
17 | jankenImage.Source = Nothing |
18 | Exit Sub |
19 | End If |
20 | End Sub |
21 | End Class |
手の形がOpen、つまり「パー」の場合は、ソリューションエクスプローラー内のImagesフォルダーから、「パー.png」をjankenImageのSourceプロパティに指定します。flagImageには「パー.png」を代入します。「グー」、「チョキ」パーについても同じ処理を行います。ここでの値が、speechEngine_SpeechRecognizedイベントの音声認識で使用され、「じゃんけんぽん」と言いながら「グー」「チョキ」「パー」のいずれかをセンサーに向けると、コンピューターとの勝負結果が表示されるようになります。
実行すると動画1のようになります。実際には「じゃんけんぽん」と喋っていますが、動画には音声が入っていませんので、ご了承ください。
動画1:Kinect v2センサーが手の形を認識して、じゃんけんができる
連載バックナンバー
Think ITメルマガ会員登録受付中
Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。
全文検索エンジンによるおすすめ記事
- Kinect v2の音声認識で「仮面」を選んで変身してみる
- Kinect v2を使って、机の上のリンゴをつかんで移動してみる
- Kinect v2のジェスチャーでBing Mapsを未来的に直感操作する
- Kinect v2で実現する打楽器のバーチャル演奏
- Kinect v2のカメラから画像を取り込んで表示する基本プログラム
- Kinectで人体を認識して棒人間を動かすサンプル
- Kinectの音声認識を使ってWebブラウザを操作するサンプル
- 声で選んだアイテムをプレイヤーの身体に装着・連動させるKinectサンプル
- Kinectを使って、自分の手のひらに小さな分身を出現させてみる
- KinectButtonを動的に作成して、ジェスチャーで文字を表示させるサンプル