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

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

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

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

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

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

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

リスト2 Jyanken.xml

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

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

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

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

プログラムコード

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

名前空間の読み込み

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

1Imports System.ComponentModel   (1)
2Imports Microsoft.Kinect   (2)
3Imports Microsoft.Speech.AudioFormat   (3)
4Imports Microsoft.Speech.Recognition   (4)
5Imports KinectSensor_KinectAudioStream   (5)
6Imports System.IO
7Public 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の続き)

01Private myKinect As KinectSensor   (1)
02Private myBodyFrameReader As BodyFrameReader   (2)
03Private myColorFrameReader As ColorFrameReader = Nothing   (3)
04Private colorBitmap As WriteableBitmap = Nothing   (4)
05Private BytesPerPixel As Integer = 4   (5)
06Private ColorImagePixelData As Byte()   (6)
07Private Rnd As Random   (7)
08Private RandomNumber As Integer
09Private SpeechEngine As SpeechRecognitionEngine   (8)
10Const SpeechID As String = "SR_MS_ja-JP_Kinect_11.0"  (9)
11Private myKinectAudioStream As KinectAudioStream   (10)
12Private Index As Integer = 0
13Private myBodies As Body()    (11)
14Private myBodyDrawingGroup As New DrawingGroup   (12)
15Private myRect As Rect   (13)
16Private JyankenImage As String
17Private xmldoc As XElement   (14)
18Private flagImage As String
19Private player_Score As Integer = 0
20Private 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の続き)

01Private Sub MainWindow_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
02        myKinect = KinectSensor.GetDefault
03        xmldoc = XElement.Load("Jyanken.xml")   (1)
04 
05        Try
06            If myKinect Is Nothing = False Then
07                Dim myDepthDescription = myKinect.DepthFrameSource.FrameDescription   (2)
08                myKinect.Open()   (3)
09                myBodyFrameReader = myKinect.BodyFrameSource.OpenReader (4)
10                AddHandler myBodyFrameReader.FrameArrived, AddressOf myBodyFrameReader_FrameArrived   (5)
11                myBodies = New Body(myKinect.BodyFrameSource.BodyCount - 1) {} (6)
12                myRect = New Rect(0, 0, myDepthDescription.Width, myDepthDescription.Height)   (7)
13                myColorFrameReader = myKinect.ColorFrameSource.OpenReader
14                AddHandler myColorFrameReader.FrameArrived, AddressOf myColorFrameReader_FrameArrived   (8)
15                Dim myColorFrameDescripton As FrameDescription = myKinect.ColorFrameSource.CreateFrameDescription(ColorImageFormat.Bgra) (9)
16                BytesPerPixel = myColorFrameDescripton.BytesPerPixel  (10)
17                ReDim ColorImagePixelData(myColorFrameDescripton.Width * myColorFrameDescripton.Height * BytesPerPixel – 1)   (11)
18                colorBitmap = New WriteableBitmap(myColorFrameDescripton.Width, myColorFrameDescripton.Height, 96.0, 96.0, PixelFormats.Bgr32, Nothing) (12)
19                Dim myAudioBeamList As IReadOnlyList(Of AudioBeam) = myKinect.AudioSource.AudioBeams   (13)
20                Dim myAudioStream = myAudioBeamList(0).OpenInputStream (14)
21                myKinectAudioStream = New KinectAudioStream(myAudioStream)    (15)
22            End If
23        Catch
24            myKinect.Close()
25            myKinect = Nothing
26        End Try
27        SpeechEngine = New SpeechRecognitionEngine(SpeechID)   (16)
28        Dim myWord As New Choices
29        With myWord
30            .Add(“じゃんけんぽん”)    (17)
31        End With
32 
33        Dim myGrammerBuilder As New GrammarBuilder
34        myGrammerBuilder.Culture = SpeechEngine.RecognizerInfo.Culture
35        myGrammerBuilder.Append(myWord)   (18)
36        Dim myGrammer As New Grammar(myGrammerBuilder)   (19)
37        SpeechEngine.LoadGrammar(myGrammer)   (20)
38 
39        AddHandler SpeechEngine.SpeechRecognized, AddressOf speechEngine_SpeechRecognized   (21)
40        myKinectAudioStream.SpeechActive = True   (22)
41        SpeechEngine.SetInputToAudioStream(myKinectAudioStream, New SpeechAudioFormatInfo(EncodingFormat.Pcm, 16000, 16, 1, 32000, 2, Nothing)) (23)
42        SpeechEngine.RecognizeAsync(RecognizeMode.Multiple)  (24)
43End 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メルマガ会員のサービス内容を見る

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