PR

Kinectを使ったバーチャル試着室で着せ替えシミュレーション

2012年8月31日(金)
薬師寺 国安

コントロールの配置

ツールボックスからデザイン画面上にListBoxコントロール1個、KinectColorViwerコントロールを1個配置します。次に 要素を配置し、その子要素として、Imageコントロールを1個、KinectSensorChooserコントロールを1個配置します。

次に、KinectColorViewerを選択し、プロパティの[その他]パネルにあるKinectの「データバインドの適用」を選択します。ElementNameにKinectSensorChooser1を指定し、「パス」にKinectを指定します(図2)。

図2:KinectColorViewerのKinectプロパティから「データバインドの適用」を設定する(クリックで拡大)

書き出されるXAMLをリスト2のように編集します。レイアウトは図3になります。

リスト2 書き出され編集されたXAMLコード(MainWindow.xaml)

  • (1)要素のWindowStateにMaximizedを指定して全画面表示とします。
  • (2)プロパティ要素内に、KeyがListBoxTemplateという名前の要素を配置します。中に要素を配置しMarginプロパティに10を指定して余白を設けます。要素内に要素を配置し、Width、Height、Sourceプロパティにデータをバインドします。ここで指定する名称はVBコード内で定義されたプロパティ名です。
  • (3)KinectColorViewerのKinectプロパティにデータバインドが適用されています。
  • (4)ListBoxのItemTemplateプロパティで(1)で定義したListBoxTemplateを参照します。
<Window x:Class="MainWindow"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" WindowState="Maximized"
  Title="MainWindow" Height="1026" Width="976" xmlns:my="clr-namespace:Microsoft.Samples.Kinect.WpfViewers;assembly=Microsoft.Samples.Kinect.WpfViewers"> ■(1)
  <Window.Resources> ■(2)
    <DataTemplate x:Key="ListBoxTemplate">  ■(2)
      <StackPanel Margin="10"> ■(1)
        <Image Source="{Binding 画像名}" Width="{Binding 幅}" Height="{Binding 高さ}" Stretch="Fill"/> ■(2)
      </StackPanel> ■(2)
    </DataTemplate> ■(2)
  </Window.Resources> ■(2)
  <Canvas>
    <ListBox Height="884" HorizontalAlignment="Left" Margin="685,0,0,0" Name="ListBox1" VerticalAlignment="Top" Width="226" ItemTemplate="{StaticResource ListBoxTemplate}"/> ■(4)
    <my:KinectColorViewer Height="480" HorizontalAlignment="Left" Name="KinectColorViewer1" VerticalAlignment="Top" Width="640" Kinect="{Binding ElementName=KinectSensorChooser1, Path=Kinect}" /> ■(3)
    <Canvas x:Name="ImageArea" Width="640" Height="480" Margin="0,0,310,60">
      <Image Height="95" HorizontalAlignment="Left"  Name="fashionImage" Stretch="Fill" VerticalAlignment="Top" Width="81" />
      <my:KinectSensorChooser Height="142" Name="KinectSensorChooser1" Width="175" Canvas.Left="444" Canvas.Top="320" />
    </Canvas>
  </Canvas>
</Window>
図3:各種コントロールがレイアウトされた(クリックで拡大)

次に、ソリューションエクスプローラー内のMainWindow.xamlを展開して表示される、MainWindow.xaml.vbをダブルクリックしてリスト3のコードを記述します。

ロジックコードを記述する

リスト3 (MainWindow.xaml.vb)

Option Strict On

Imports Microsoft.Kinect

音声認識用のオーディオ形式を表すクラスが含まれる、Microsoft.Speech.AudioFormat名前空間をインポートします。

Imports Microsoft.Speech.AudioFormat

音声認識を実装するためのクラスが含まれる、Microsoft.Speech.Recognition名前空間をインポートします。

Imports Microsoft.Speech.Recognition

Imports Coding4Fun.Kinect.Wpf
Imports System.Windows.Media.Imaging
Imports System.IO

Fashionクラス内にString型の「画像名」「幅」「高さ」プロパティを定義しています。XAMLコード内でのバインディングに使用されています。

Public Class FashionInfo
  Property 画像名 As String
  Property 幅 As String
  Property 高さ As String
End Class
Class MainWindow

深度情報が認識可能なプレイヤーの数(6)で初期化された定数メンバ変数、skeletonCountを宣言します。

  Const skeletonCount As Integer = 6

認識可能なプレイヤーの数分の配列を持った、Skeletonクラス型のメンバ配列変数allSkeletonsを宣言しておきます。-1しているのは、添え字は0から始まるためです。

  Dim allSkeletons(skeletonCount - 1) As Skeleton

1個のKinectセンサーを表すメンバ変数kinectを宣言します。

  Dim kinect As KinectSensor

XML要素を表すメンバ変数xmldocを宣言します。

  Dim xmldoc As XElement

音声認識サービスを実行するためのアクセス権を提供するSpeechRecognitionEngineクラス用メンバ変数engineを宣言します。

  Dim engine As SpeechRecognitionEngine

  Dim words As String

ListBox内の項目のインデックスに該当するメンバ変数で、0で初期化しておきます。

  Dim index As Integer = 0

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

XElement.Loadメソッドでbin\Debugフォルダ内のXML文書ファイル(fashion.xml)を読み込みます。FashionInfoクラス型の新しいリストであるmyFashionInfoオブジェクトを作成します。
要素のコレクション内を変数resultで反復処理しながら、以下の処理を繰り返します。

新しいFashionInfoクラスの「画像名」プロパティに、Image/という文字列を連結した要素の値を指定します。「幅」プロパティにはダブル型に変換した、要素の属性”幅”の値を指定します。「高さ」プロパティには、ダブル型に変換した、要素の属性”高さ”の値を指定します。
これらの値の指定されたFashionInfoクラスを、AddメソッドでmyFashionInfoオブジェクトに追加していきます。ListBoxのItemsSourceプロパティにmyFashionInfoオブジェクトを指定します。ListBox内に服の一覧が表示されます。

fashionImageのSourceプロパティに0番目の要素の値を、画像を配置しているImage/というフォルダ名と連結して指定します。Widthプロパティには0番目の要素の属性”幅”を指定し、Heightプロパティには、0番目の要素の属性”高さ”を指定します。fashionImage内にListBoxのインデックスが0番目の画像(先頭の画像)が表示されます。

Kinectセンサーを取得し、Kinectを動作させます。

要素を構成するための代替項目の一覧を表すChoicesクラスのインスタンス、sentenceオブジェクトを作成します。Choiceクラスは、GrammarBuilder オブジェクトからのみ直接使用されます。Addメソッドで、認識させる言葉として「上」「下」「消去」「おわり」という語句をChoicesオブジェクトであるsentenceに追加します。
GrammarBuilderクラスは、単純な入力から複雑な Grammar(構文情報を取得管理するクラス)を構築するためのメカニズムを提供するクラスで、登録された言葉の構文(文法)設定を行い、SpeechRecognitionEngineへと設定します。
Appendメソッドで、登録した言葉を GrammarBuilder オブジェクトとして現在の GrammarBuilder に追加します。音声認識サービスを実行するためのアクセス権を提供する、SpeechRecognitionEngineクラスの新しいインスタンスを作成します。

文法のチェックされた言葉(builder)で初期化された、新しいGrammerクラスのインスタンス、myGrammerオブジェクトを作成します。Grammerクラスは、構文情報を取得および管理するためにランタイムをサポートするクラスです。

SpeechRecognitionEngineクラスのLoadGrammerメソッドで、Grammar によって指定されたとおりに、特定の構文を同期的に読み込みます。

言葉が認識された際には、AddHandlerステートメントで言葉を認識した際に発生するSpeechRecognizedイベントに、イベントハンドラを指定します。

Confidenceプロパティで音声認識の信頼度を設定します。-1が低、0が標準、1が高信頼度となります。-1を指定するとどんな言葉にでも反応する恐れがあります。1を指定するとなかなか認識してくれません。今回は信頼度が0.5より大きい場合に、指定した言葉を認識するよう指定しています。

認識された音声(speechArgs.Result.Text)を変数wordsに格納します。wordsの内容で条件分岐を行います。

「上」と発声された場合は、メンバ変数indexを1ずつ減算します。ListBoxの選択されたインデックスにindexの値を指定します。fashionImageのSourceプロパティにindex番目の要素の値を、画像を配置しているImage/というフォルダ名と連結して指定します。
Widthプロパティにはindex番目の要素の属性”幅”を指定し、Heightプロパティには、index番目の要素の属性”高さ”を指定します。fashionImage内にListBoxのインデックスがindex番目の画像が表示されます。

「下」と発声された場合は、メンバ変数indexを1ずつ増加します。ListBoxの選択されたインデックスにindexの値を指定します。fashionImageのSourceプロパティにindex番目の要素の値を、画像を配置しているImage/というフォルダ名と連結して指定します。
Widthプロパティにはindex番目の要素の属性”幅”を指定し、Heightプロパティには、index番目の要素の属性”高さ”を指定します。fashionImage内にListBoxのインデックスがindex番目の画像が表示されます。

「消去」と発声された場合は、fashionImageを非表示にします。

「おわり」と発声された場合は、Kinectセンサーを停止し、音声認識も停止して、Environment.Exit(0)でプログラムを終了します。

Kinectの音声インターフェースは、Kinect.AudioSourceで提供されます。Startメソッドで音声入力を開始します。入力ストリームを取得し、SpeechRecognitionEngine クラスのSetInputToDefaultAudioDeviceメソッドで、SpeechRecognitionEngine の現在のインスタンスに、システム既定のオーディオ入力を割り当てます。

認識操作の後に、RecognizeAsync によって開始された認識を終了しないよう、RecognizeMode.Multipleを指定して、RecognizeAsyncメソッドで非同期音声認識を開始します。

スケルトン・トラッキングの移動パラメータを指定するTransformSmoothParametersクラスの各プロパティを設定します。

Smoothingで平滑化の程度を指定します。値は0~1.0の間で、デフォルトは0.5です。値が大きいほど平滑化されます。

Correctionで、平滑化の緩急を指定します。値は0~1.0の間で、デフォルトは0.5です。値が小さいほど、平滑化に緩急を付けるため動作が低下します。

Predictionでスムーズに動作させるために予測されたフレームの数を取得します。
JitterRadiusでジッタ処理の対象にする半径(メートル)を指定します。デフォルトは0.05(5cm)です。

MaxDeviationRadiusで、フィルタされた値と生データとの誤差の許容最大値(メートル)を設定します。デフォルトは0.04(4cm)です。

EnableメソッドにTransformSmoothParametersを指定して、スケルトンを有効にします。

AddHandlerステートメントで、RGBカメラ、距離カメラ、スケルトンのフレームが更新された時に発生する、AllFramesReadyイベントにkinect_AllFramesReadyイベントハンドラを追加します。

Enableメソッドで、RGBカメラ、距離カメラを有効にします。

  Private Sub MainWindow_Loaded(sender As Object, e As System.Windows.RoutedEventArgs) Handles Me.Loaded
    xmldoc = XElement.Load("fashion.xml")
 
    Dim myFashionInfo As New List(Of FashionInfo)
  
    For Each result In From c In xmldoc.Descendants("画像名") Select c
      With myFashionInfo
        .Add(New FashionInfo With {.画像名 = "Image/" & result.Value,
                                   .幅 = CStr(CInt(result.Attribute("幅").Value) / 2),
                                   .高さ = CStr(CInt(result.Attribute("高さ").Value) / 2)})
      End With
    Next
    ListBox1.ItemsSource = myFashionInfo
    ListBox1.SelectedIndex = 0
    fashionImage.Visibility = Windows.Visibility.Visible
    fashionImage.Source = New BitmapImage(New Uri("Image/" & xmldoc.Descendants("画像名")(index).Value, UriKind.Relative))
    fashionImage.Width = CDbl(xmldoc.Descendants("画像名")(index).Attribute("幅").Value)
    fashionImage.Height = CDbl(xmldoc.Descendants("画像名")(index).Attribute("高さ").Value)
 
    If KinectSensor.KinectSensors.Count = 0 Then
      MessageBox.Show("Kinectを接続してください")
      Exit Sub
    Else
      kinect = KinectSensor.KinectSensors(0)
      kinect.Start()
      Dim sentence As Choices = New Choices
      With sentence
        .Add("上")
        .Add("下")
        .Add("消去")
        .Add("おわり")
      End With
 
      Dim builder As GrammarBuilder = New GrammarBuilder
      builder.Append(sentence)
      Dim myGrammer As Grammar = New Grammar(builder)
      engine = New SpeechRecognitionEngine()
      engine.LoadGrammar(myGrammer)
 
      AddHandler engine.SpeechRecognized, Sub(speechSender As Object, speechArgs As SpeechRecognizedEventArgs)
 
            words = speechArgs.Result.Text
            Dim myConfidence = speechArgs.Result.Confidence
            If myConfidence > 0.5 Then
              Select Case words
                Case "上"
                  If index <= 0 Then
                    index = 0
                  Else
                    index = index - 1
                  End If
                  ListBox1.SelectedIndex = index
                fashionImage.Visibility = Windows.Visibility.Visible
                fashionImage.Source = New BitmapImage(New Uri("Image/" & xmldoc.Descendants("画像名")(index).Value, UriKind.Relative))
                fashionImage.Width = CDbl(xmldoc.Descendants("画像名")(index).Attribute("幅").Value)
                fashionImage.Height = CDbl(xmldoc.Descendants("画像名")(index).Attribute("高さ").Value)
                  Case "下"
                    If index >= ListBox1.Items.Count - 1 Then
                       index = ListBox1.Items.Count - 1
                    Else
                       index = index + 1
                    End If
                    ListBox1.SelectedIndex = index
                    fashionImage.Visibility = Windows.Visibility.Visible
                fashionImage.Source = New BitmapImage(New Uri("Image/" & xmldoc.Descendants("画像名")(index).Value, UriKind.Relative))
                fashionImage.Width = CDbl(xmldoc.Descendants("画像名")(index).Attribute("幅").Value)
                fashionImage.Height = CDbl(xmldoc.Descendants("画像名")(index).Attribute("高さ").Value)
                  Case "消去"
                    fashionImage.Visibility = Windows.Visibility.Collapsed
                  Case "おわり"
                    If kinect Is Nothing = False Then
                      If kinect.IsRunning = True Then
                         kinect.Stop()
                         kinect.Dispose()
                         engine.RecognizeAsyncStop()
                      End If
                    End If
                      Environment.Exit(0)
                      End Select
            End If
              End Sub

            Dim audio As KinectAudioSource = kinect.AudioSource
            Using s As Stream = audio.Start()
            engine.SetInputToDefaultAudioDevice()
            engine.RecognizeAsync(RecognizeMode.Multiple)
      End Using
    End If
 
    Dim myParam As New TransformSmoothParameters
    With myParam
        .Smoothing = 0.75F 'スムージングの量を取得
        .Correction = 0.0F '補正の量を取得
        .Prediction = 0.0F '予測されたフレームの数を取得。
        .JitterRadius = 0.05F '取得またはジッタ低減 (メートル) に半径を設定。
        .MaxDeviationRadius = 0.4F 'フィルタの位置がrawデータから逸脱できる最大半径を取得
    End With
    kinect.SkeletonStream.Enable(myParam)

 
    AddHandler kinect.AllFramesReady, AddressOf kinect_AllFramesReady
    kinect.ColorStream.Enable(ColorImageFormat.RgbResolution640x480Fps30)
    kinect.DepthStream.Enable(DepthImageFormat.Resolution640x480Fps30)
  End Sub
Think IT会員限定特典
  • Kinectを使ったバーチャル試着室を作るサンプル

薬師寺国安事務所

薬師寺国安事務所代表。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のWebサイトにログインすることでさまざまな限定特典を入手できるようになります。

Think IT会員サービスの概要とメリットをチェック

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