Kinect v2を使った「じゃんけんゲーム」を作る

2014年12月16日(火)
薬師寺 国安

XMLファイルの作成(Jyanken.xml)

VS2013メニューの[プロジェクト]ー[新しい項目の追加]を選択して、表示される画面から「データ」を指定し、表示される項目から「XMLファイル」を選択します。名前には「Jyanken.xml」と指定し、最後に「追加」ボタンをクリックします(図6)。

「XMLファイル」を選択する

図6:「XMLファイル」を選択する(クリックで拡大)

するとXMLエディターが起動しますので、リスト2のXMLを記述します。

リスト2 Jyanken.xml

<?xml version="1.0" encoding="utf-8" ?>
<じゃんけん>
  <画像名>グー.png</画像名>
  <画像名>チョキ.png</画像名>
  <画像名>パー.png</画像名>
</じゃんけん>

追加したXMLファイルを選択してプロパティを表示します。「ビルドアクション」に「コンテンツ」、「出力ディレクトリーコピー」に「常にコピーする」と指定して下さい(図7)。この設定を忘れるとエラーになりますので、注意してください。

XMLファイルのプロパティを設定した

図7:XMLファイルのプロパティを設定した

プログラムコード

次に、ソリューションエクスプローラー内のMainWindow.xamlを展開して表示されるMainWindow.xam.vbに、リスト3以降のコードを記述します。かなり分量が多いですが、がんばって下さい。

名前空間の読み込み

リスト3(MainWindow.xaml.vbの一部)

Imports System.ComponentModel   (1)
Imports Microsoft.Kinect   (2)
Imports Microsoft.Speech.AudioFormat   (3)
Imports Microsoft.Speech.Recognition   (4)
Imports KinectSensor_KinectAudioStream   (5)
Imports System.IO
Public Class MainWindow
  1. コンポーネントやコントロールの実行時動作、およびデザイン時動作を実装するためのクラスが用意されているSystem.ComponentModel名前空間を読み込みます。
  2. Kinectを扱うためのクラスが含まれるMicrosoft.Kinect名前空間を読み込みます。
  3. 音声認識用のオーディオ形式を表すクラスが含まれるMicrosoft.Speech.AudioFormat名前空間を読み込みます。
  4. 音声認識を実装するためのクラスが含まれるMicrosoft.Speech.Recognition名前空間を読み込みます。
  5. オーディオストリームのクラスを提供するKinectSensor_KinectAudioStream名前空間を読み込みます。これは、ソリューションエクスプローラー内のDLLフォルダーに配置したKinectAudioStreamを、参照設定に追加したものです。

メンバー変数の宣言

リスト4 (MainWindow.xaml.vbの一部、リスト3の続き)

    Private myKinect As KinectSensor   (1)
    Private myBodyFrameReader As BodyFrameReader   (2)
    Private myColorFrameReader As ColorFrameReader = Nothing   (3)
    Private colorBitmap As WriteableBitmap = Nothing   (4)
    Private BytesPerPixel As Integer = 4   (5)
    Private ColorImagePixelData As Byte()   (6)
    Private Rnd As Random   (7)
    Private RandomNumber As Integer
    Private SpeechEngine As SpeechRecognitionEngine   (8)
    Const SpeechID As String = "SR_MS_ja-JP_Kinect_11.0"  (9)
    Private myKinectAudioStream As KinectAudioStream   (10)
    Private Index As Integer = 0
    Private myBodies As Body()    (11)
    Private myBodyDrawingGroup As New DrawingGroup   (12)
    Private myRect As Rect   (13)
    Private JyankenImage As String
    Private xmldoc As XElement   (14)
    Private flagImage As String
    Private player_Score As Integer = 0
    Private computer_Score As Integer = 0
  1. KinectSensorクラスのメンバー変数myKinectを宣言します。
  2. ボディフレームのリーダーを表すBodyFrameReaderクラスのメンバー変数myBodyFrameReaderを宣言します。
  3. カラーフレームリーダーを表すクラスであるColorFrameReader型のメンバー変数myColorFrameReaderを宣言します。
  4. WriteableBitmapクラス型のメンバー変数colorBitmapを宣言します。WriteableBitmapは、書き込みおよび更新が可能なBitmapSource を提供するクラスで、BitmapSourceは単一の一定なピクセルセットを、特定のサイズおよび解像度で表わすクラスを意味します。
  5. Integer型のメンバー変数BytePerPixelを宣言し、「4」で初期化しておきます。この値は、32ビットフルカラーのRGB形式で、各カラーチャネルに割り当てられる「bits per pixel(BPP)」が「8」のため、Bgr32を「8」で除算した「4」バイトを意味します。「青」、「緑」、「赤」では24ビットしか使用されませんが、残りの8ビットは「Alpha(不透明度)」に使用されることが多いです。値を直接指定する代わりに以下のように記述しても同じです。
    CInt(PixelFormats.Bgr32.BitsPerPixel / 8)
  6. バイト型の配列であるメンバー変数ColorImagePixelDataを宣言します。
  7. 乱数を発生させるRandomクラス型のメンバー変数Rndを宣言します。
  8. 音声認識サービスを実行するためのアクセス権を提供するクラスであるSpeechRecognitionEngineクラス用のメンバー変数SpeechEngineを宣言します。
  9. 日本語音声認識エンジンのIDを、メンバー定数として宣言します。
  10. KinectAudioStreamクラス型のメンバー変数myKinectAudioStreamを宣言します。
  11. 単一のボディを表す配列のBody()クラス型のメンバー変数myBodiesを宣言します。
  12. 1つの描画として操作できる描画のコレクションを表す、DrawingGroupのインスタンスmyBodyDrawingDroupメンバー変数を宣言します。
  13. 四角形の幅、高さ、および位置を表すRect構造体のメンバー変数myRectを宣言します。
  14. XMLを表すXElementクラス型のメンバー変数xmldocを宣言します。

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

リスト5 (MainWindow.xaml.vbの一部、リスト4の続き)

Private Sub MainWindow_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
        myKinect = KinectSensor.GetDefault
        xmldoc = XElement.Load("Jyanken.xml")   (1)

        Try
            If myKinect Is Nothing = False Then
                Dim myDepthDescription = myKinect.DepthFrameSource.FrameDescription   (2)
                myKinect.Open()   (3)
                myBodyFrameReader = myKinect.BodyFrameSource.OpenReader (4)
                AddHandler myBodyFrameReader.FrameArrived, AddressOf myBodyFrameReader_FrameArrived   (5)
                myBodies = New Body(myKinect.BodyFrameSource.BodyCount - 1) {} (6)
                myRect = New Rect(0, 0, myDepthDescription.Width, myDepthDescription.Height)   (7)
                myColorFrameReader = myKinect.ColorFrameSource.OpenReader
                AddHandler myColorFrameReader.FrameArrived, AddressOf myColorFrameReader_FrameArrived   (8)
                Dim myColorFrameDescripton As FrameDescription = myKinect.ColorFrameSource.CreateFrameDescription(ColorImageFormat.Bgra) (9)
                BytesPerPixel = myColorFrameDescripton.BytesPerPixel  (10)
                ReDim ColorImagePixelData(myColorFrameDescripton.Width * myColorFrameDescripton.Height * BytesPerPixel – 1)   (11)
                colorBitmap = New WriteableBitmap(myColorFrameDescripton.Width, myColorFrameDescripton.Height, 96.0, 96.0, PixelFormats.Bgr32, Nothing) (12)
                Dim myAudioBeamList As IReadOnlyList(Of AudioBeam) = myKinect.AudioSource.AudioBeams   (13)
                Dim myAudioStream = myAudioBeamList(0).OpenInputStream (14)
                myKinectAudioStream = New KinectAudioStream(myAudioStream)    (15)
            End If
        Catch
            myKinect.Close()
            myKinect = Nothing
        End Try
        SpeechEngine = New SpeechRecognitionEngine(SpeechID)   (16)
        Dim myWord As New Choices
        With myWord
            .Add(“じゃんけんぽん”)    (17)
        End With

        Dim myGrammerBuilder As New GrammarBuilder
        myGrammerBuilder.Culture = SpeechEngine.RecognizerInfo.Culture
        myGrammerBuilder.Append(myWord)   (18)
        Dim myGrammer As New Grammar(myGrammerBuilder)   (19)
        SpeechEngine.LoadGrammar(myGrammer)   (20)

        AddHandler SpeechEngine.SpeechRecognized, AddressOf speechEngine_SpeechRecognized   (21)
        myKinectAudioStream.SpeechActive = True   (22)
        SpeechEngine.SetInputToAudioStream(myKinectAudioStream, New SpeechAudioFormatInfo(EncodingFormat.Pcm, 16000, 16, 1, 32000, 2, Nothing)) (23)
        SpeechEngine.RecognizeAsync(RecognizeMode.Multiple)  (24)
End Sub
  1. 最初に、Kinectセンサーを使用可能にします。XElement.Loadメソッドで「Jyanken.xml」を読み込みます。
    Kinectセンサーが使用可能な状態にある場合は、以下の処理を行います。
  2. 距離フレームプロパティの形式を取得し、変数myDepthDescriptionで参照します。
  3. Kinectを動作させます。
  4. BodyFrameSource.OpenReaderで、ボディフレームのソースフレームのリーダーを作成し、変数myBodyFrameReaderで参照します。
  5. myBodyFrameReader.FrameArrivedで、新しいボディフレームの準備ができているときに発生するイベント処理を実行します。
  6. ボディフレームソースのボディの個数を引数に持った、新しいBodyの配列をmyBodiesに格納します。
  7. 距離フレームプロパティのWidthとHeightで初期化された、新しいRectを、変数myRectで参照します。
  8. myColorFrameReader.FrameArrivedでカラーフレーム到着時のイベントを実行します。
  9. カラー画像の情報を作成(BGRAフォーマット)し、変数myColorFrameDescriptonで参照します。
  10. カラーフレームのプロパティBytesPerPixelで、ピクセル データのサイズ (ピクセルあたりのバイト) を取得し、メンバー変数BytesPerPixelに格納します。
  11. 動的配列変数ColorImagePixelDataを確保します。
  12. ピクセル データを格納するビットマップを作成し、変数colorBitmapで参照します。
  13. オーディオビームを取得し、配列変数myAudioBeamListに格納します。
  14. OpenInputStreamで音声入力設定を行い、変数myAudioStreamで参照します。
  15. myAudioStreamで初期化されたKinectAudioStreamのインスタンスである、myKinectAudioStreamオブジェクトを作成します。
  16. 定数メンバー変数SpeechIDで初期化されたSpeechRecognitionEngineのインスタンス、SpeechEngineオブジェクトを作成します。
  17. Choicesクラスは、要素を構成するための代替項目の一覧を表すクラスで、GrammarBuilder オブジェクトからのみ直接使用されます。認識させる言葉をAddメソッドで登録します。ここでは「じゃんけんぽん」と登録しています。
  18. GrammarBuilderクラスは、単純な入力から複雑な Grammar(構文情報を取得管理するクラス)を構築するためのメカニズムを提供するクラスで、登録された言葉の構文(文法)の設定を行います。Appendメソッドで、登録した言葉(myWord)を myGrammarBuilder オブジェクトに追加します。
  19. 文法のチェックされた言葉(myGrammerBuilder)で初期化された、新しいGrammerクラスのインスタンス、myGrammerオブジェクトを作成します。Grammerクラスは、構文情報を取得および管理するためにランタイムをサポートするクラスです。
  20. SpeechRecognitionEngineクラスのLoadGrammerメソッドで、Grammar によって指定されたとおりに、特定の構文を同期的に読み込みます。
  21. SpeechEngine.SpeechRecognizedで音声が認識された時に、音声認識処理を行います。
  22. SpeechActiveプロパティにTrueを指定し、オーディオストリームの変換をアクティブにします。この記述がないと音声が認識されませんので、注意して下さい。
  23. SetInputToAudioStreamメソッドで認識エンジンに入力設定を行います。
  24. 複数の音声認識が可能なように、RecognizeMode.Multipleを指定して、RecognizeAsyncメソッドで非同期音声認識を開始します。
  • Kinect v2を使った「じゃんけんゲーム」を作るサンプル

    『作りながら学ぶKinect v2プログラミング開発』 第2回のサンプルプログラムです。
薬師寺国安事務所

薬師寺国安事務所代表。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メルマガ会員のサービス内容を見る

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