Kinect v2を使った「じゃんけんゲーム」を作る
2014年12月16日(火)
音声認識処理
Private Sub speechEngine_SpeechRecognized(sender As Object, e As SpeechRecognizedEventArgs) messageTextBlock.Text = String.Empty Rnd = New Random RandomNumber = Rnd.Next(0, 2) (1) Const myConfidence As Double = 0.4 (2) If e.Result.Confidence >= myConfidence Then Select Case e.Result.Text Case “じゃんけんぽん” computerJankenImage.Source = Nothing JyankenImage = xmldoc.Descendants(“画像名”)(RandomNumber).Value (3) computerJankenImage.Source = New BitmapImage(New Uri(“Images/” & JyankenImage, UriKind.Relative)) If JyankenImage = “グー.png” AndAlso flagImage = “グー.png” Then (4) messageTextBlock.Text = “あいこです” ElseIf JyankenImage = “パー.png” AndAlso flagImage = “パー.png” Then messageTextBlock.Text = “あいこです” ElseIf JyankenImage = “チョキ.png” AndAlso flagImage = “チョキ.png” Then messageTextBlock.Text = “あいこです” ElseIf JyankenImage = “グー.png” AndAlso flagImage = “パー.png” Then messageTextBlock.Text = “あなたの勝です” player_Score += 1 ElseIf JyankenImage = “パー.png” AndAlso flagImage = “グー.png” Then messageTextBlock.Text = “コンピューターの勝です” computer_Score += 1 ElseIf JyankenImage = “パー.png” AndAlso flagImage = “チョキ.png” Then messageTextBlock.Text = “あなたの勝です” player_Score += 1 ElseIf JyankenImage = “チョキ.png” AndAlso flagImage = “パー.png” Then messageTextBlock.Text = “コンピューターの勝です” computer_Score += 1 ElseIf JyankenImage = “グー.png” AndAlso flagImage = “チョキ.png” Then messageTextBlock.Text = “コンピューターの勝です” computer_Score += 1 ElseIf JyankenImage = “チョキ.png” AndAlso flagImage = “グー.png” Then messageTextBlock.Text = “あなたの勝です” player_Score += 1 End If playerScoreTextBlock.Text = “あなたの得点=” & player_Score computerScoreTextBlock.Text = “コンピューターの得点=” & computer_Score End Select End If End Sub
- 0~2までの3つの乱数を発生します。
- Confidenceプロパティで音声認識の信頼度を設定します。-1~1の値で指定し、数字が大きいほど信頼度が高くなります。標準は「0」です。「-1」を指定すると、どんな言葉でも反応してしまう可能生があり、「1」を指定すると、なかなか認識されません。今回は信頼度が「0.4」より大きい場合に言葉を認識するよう指定しています。
以下、プレイヤーが「じゃんけんぽん」とセンサーに向かって発生した場合の処理です。 - 乱数に該当する位置にある「画像名」要素の値を取得します。
- コンピューターが表示する「グー」「チョキ」「パー」のイメージ画像によって条件分岐を行います。JyanlenImageとflagImageの画像を比較して勝ち負けを表示しています。結果をmessageTextBlockに表示し、プレイヤーが勝ったら変数player_Scoreを、コンピューターが勝ったらcomputer_Scoreを1ずつ加算して表示します。
新しいボディフレームの準備ができているときに発生するイベント処理
Private Sub myBodyFrameReader_FrameArrived(sender As Object, e As BodyFrameArrivedEventArgs) Using frame = e.FrameReference.AcquireFrame (1) If frame Is Nothing = False Then Using myDataContext = myBodyDrawingGroup.Open myDataContext.DrawRectangle(Brushes.Black, Nothing, myRect) frame.GetAndRefreshBodyData(myBodies) (2) For i As Integer = 0 To Me.myBodies.Length - 1 (3) If myBodies(i).IsTracked = True Then Dim joints As IReadOnlyDictionary(Of JointType, Joint) = myBodies(i).Joints (4) Dim points As New Dictionary(Of JointType, Point) (5) For Each joint In joints.Keys (6) Dim pos = myKinect.CoordinateMapper.MapCameraPointToDepthSpace(joints(joint).Position) (7) points(joint) = New Point(pos.X, pos.Y) (8) If joint = JointType.HandLeft Then (9) DrawHandState(myBodies(i).Joints(JointType.HandLeft), myBodies(i).HandLeftState, myBodies(i).HandLeftConfidence) ElseIf joint = JointType.HandRight Then DrawHandState(myBodies(i).Joints(JointType.HandRight), myBodies(i).HandRightState, myBodies(i).HandRightConfidence) End If Next End If Next Me.myBodyDrawingGroup.ClipGeometry = New RectangleGeometry(myRect) (10) End Using End If End Using 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次元の四角形を設定します。
ウインドウが閉じられる場合の処理
Private Sub MainWindow_Closing(sender As Object, e As CancelEventArgs) Handles Me.Closing If myKinect Is Nothing = False Then myKinect.Close() myKinect = Nothing End If End Sub
Kinectが動作している場合は、Kinectを閉じ、全ての関連付けから解放します。
カラーフレーム到着時のイベント
Private Sub myColorFrameReader_FrameArrived(sender As Object, e As ColorFrameArrivedEventArgs) Using myColorFrame As ColorFrame = e.FrameReference.AcquireFrame (1) If myColorFrame Is Nothing = True Then Return End If myColorFrame.CopyConvertedFrameDataToArray(ColorImagePixelData, ColorImageFormat.Bgra) (2) End Using colorBitmap.WritePixels(New Int32Rect(0, 0, colorBitmap.PixelWidth, colorBitmap.PixelHeight), ColorImagePixelData, colorBitmap.PixelWidth * BytesPerPixel, 0) (3) Image1.Source = colorBitmap (4) 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カメラからの画像が表示されます。
プレイヤーの手の形によって条件分岐を行う処理
Private Sub DrawHandState(joint As Joint, state As HandState, myTrackingConfidence As TrackingConfidence) If myTrackingConfidence <> TrackingConfidence.High Then Return End If If state = HandState.Open Then jankenImage.Source = New BitmapImage(New Uri("Images/パー.png", UriKind.Relative)) flagImage = "パー.png" ElseIf state = HandState.Closed Then jankenImage.Source = New BitmapImage(New Uri("Images/グー.png", UriKind.Relative)) flagImage = "グー.png" ElseIf state = HandState.Lasso Then jankenImage.Source = New BitmapImage(New Uri("Images/チョキ.png", UriKind.Relative)) flagImage = "チョキ.png" Else jankenImage.Source = Nothing Exit Sub End If End Sub End Class
手の形がOpen、つまり「パー」の場合は、ソリューションエクスプローラー内のImagesフォルダーから、「パー.png」をjankenImageのSourceプロパティに指定します。flagImageには「パー.png」を代入します。「グー」、「チョキ」パーについても同じ処理を行います。ここでの値が、speechEngine_SpeechRecognizedイベントの音声認識で使用され、「じゃんけんぽん」と言いながら「グー」「チョキ」「パー」のいずれかをセンサーに向けると、コンピューターとの勝負結果が表示されるようになります。
実行すると動画1のようになります。実際には「じゃんけんぽん」と喋っていますが、動画には音声が入っていませんので、ご了承ください。
連載バックナンバー
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を動的に作成して、ジェスチャーで文字を表示させるサンプル