プロジェクトの作成(Windows Phoneアプリケーション)

プロジェクトの作成(Windows Phoneアプリケーション)

VS 2010のメニューから[ファイル(F)/新規作成(N)/プロジェクト(P)]と選択します。次に、「インストールされたテンプレート」から「Silverlight for Windows Phone」を選択し、右に表示される項目から「Windows Phone アプリケーション」を選択して、「名前(N)」に任意のプロジェクト名を指定します。ここでは「KINECT_WindowsPhone_Skeleton」という名前を付けています(図6)。Windows Phone OSのバージョンは7.1を選択します。

図6:Windows Phoneアプリケーションを選択する(クリックで拡大)

参照の追加

VS2010のメニューから「プロジェクト(P)/参照の追加(R)」と選択して、各種コンポーネントを追加しておきます。今回追加するのは、Coding4Fun.Kinect.KinectService.CommonとCoding4Fun.Kinect.KinectService.PhoneClientの2つです。「.NET」タブ内に表示されていないDLLファイルは「参照」タブからDLLファイルを指定します。

Coding4Fun.Kinect.KinectService.Common.dlとCoding4Fun.Kinect.KinectService.PhoneClient.dllは、kinectservice.zipを解凍したフォルダの、\KinectService\Phone Client\フォルダ内に存在しますので、これを指定してください。

コントロールの配置

ツールボックスからデザイン画面上にCanvasコントロールを1個、その子要素として、Imageを1個、Ellipseを10個配置します。次にCanvasの外にTextBlockを2個とButtonコントロールを1個配置します。書き出されるXAMLコードはリスト1、レイアウトは図7のようになります。EllipseのNameに指定している名前はリスト1を参照してください。

リスト1 (MainPage.xaml)

(1)x:NameがSkeletonという

要素を配置しています。
(2)要素の子要素としてNameがImage1という要素を配置しています。HeightとWidthの値は 要素のHeightとWidthの値と同じにしておきます。各人間の身体の部位をNameにした10個の要素を配置し、WidthとHeightに15を指定して直径15ピクセルの円を描いています。Fillには各円の色を指定しています。
(3)addressTextBoxには、図4で表示されるIPアドレスを入力します。
<phone:PhoneApplicationPage 
  x:Class="KINECT_WindowsPhone_Skeleton.MainPage"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
  xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
  xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768"
  FontFamily="{StaticResource PhoneFontFamilyNormal}"
  FontSize="{StaticResource PhoneFontSizeNormal}"
  Foreground="{StaticResource PhoneForegroundBrush}"
  SupportedOrientations="Portrait" Orientation="Portrait"
  shell:SystemTray.IsVisible="True">
 
  <!--LayoutRoot は、全てのページ コンテンツが配置されるルート グリッドです-->
  <Grid x:Name="LayoutRoot" Background="Transparent">
    <Canvas x:Name="Skeleton" Width="448" Height="336" Margin="12,108,20,324"> ■(1)
      <Image Height="336" Name="Image1" Stretch="Fill" Width="448" Canvas.Left="0" Canvas.Top="0" /> ■(1)
      <Ellipse Canvas.Left="0" Canvas.Top="0" Height="15" Name="headEllipse" Stroke="Black" Width="15" Fill="Orange" /> ■(2)
      <Ellipse Canvas.Left="15" Canvas.Top="0" Height="15" Name="rightEllipse" Stroke="Black" Width="15" Fill="SlateGray" /> ■(2)
      <Ellipse Canvas.Left="30" Canvas.Top="0" Height="15" Name="leftEllipse" Stroke="Black" Width="15" Fill="SpringGreen" /> ■(2)
      <Ellipse Canvas.Left="45" Canvas.Top="0" Height="15" Name="hipCenterEllipse" Stroke="Black" Width="15" Fill="Red" /> ■(2)
      <Ellipse Canvas.Left="60" Canvas.Top="0" Height="15" Name="ElbowRightEllipse" Stroke="Black" Width="15" Fill="Beige" /> ■(2)
      <Ellipse Canvas.Left="75" Canvas.Top="0" Height="15" Name="ElbowLeftEllipse" Stroke="Black" Width="15" Fill="Firebrick" /> ■(2)
      <Ellipse Canvas.Left="90" Canvas.Top="0" Height="15" Name="shoulderRightEllipse" Stroke="Black" Width="15" Fill="Bisque" /> ■(2)
      <Ellipse Canvas.Left="105" Canvas.Top="0" Height="15" Name="shoulderLeftEllipse" Stroke="Black" Width="15" Fill="Chartreuse" /> ■(2)
      <Ellipse Canvas.Left="120" Canvas.Top="0" Height="15" Name="HipRightEllipse" Stroke="Black" Width="15" Fill="Moccasin" /> ■(2)
      <Ellipse Canvas.Left="135" Canvas.Top="0" Height="15" Name="HipLeftEllipse" Stroke="Black" Width="15" Fill="MediumOrchid" /> ■(2)
    </Canvas> ■(1)
    <TextBlock Height="47" HorizontalAlignment="Left" Margin="15,487,0,0" Name="TextBlock1" Text="Address" VerticalAlignment="Top" Width="87" />
    <TextBox Height="74" HorizontalAlignment="Left" Margin="87,473,0,0" Name="addressTextBox"  VerticalAlignment="Top" Width="293" /> ■(3)
    <Button Content="OK" Height="74" HorizontalAlignment="Left" Margin="372,473,0,0" Name="okButton" VerticalAlignment="Top" Width="90" />
  </Grid>
~コード略~
</phone:PhoneApplicationPage>
図7:各種コントロールがレイアウトされた(クリックで拡大)

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

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

リスト2 (MainPage.xaml.vb)

Option Strict On

KinectServiceに接続するための機能を提供する、2つの名前空間をインポートしておきます。

Imports Coding4Fun.Kinect.KinectService.Common
Imports Coding4Fun.Kinect.KinectService.PhoneClient

Partial Public Class MainPage
  Inherits PhoneApplicationPage
 
  ' コンストラクター
  Public Sub New()
    InitializeComponent()
  End Sub

リスナーに接続するためのクライアントであるSkeletonClientクラス型のメンバ変数_skeletonClientを宣言します。同様にColorClientクラス型のメンバ変数_colorClientを宣言します。

  Dim _skeletonClient As SkeletonClient
  Dim _colorClient As ColorClient

[OK]ボタンがクリックされた時の処理

Address入力ボックスに入力されたIPアドレスを、変数myIPAddressに格納しておきます。IPアドレスが入力されていない場合は、警告メッセージを表示し、処理を抜けます。IPアドレスが入力されていたなら、新しいSkeletonClientのインスタンスとColorClientのインスタンスを作成します。ColorClientが接続されていなかった場合は、ConnectメソッドでIPアドレスとポートを指定して接続します。

SkeletonClientが接続されていなかった場合は、同じくConnectメソッドでIPアドレスとポートを指定して接続します。

AddHandlerステートメントでRGBカメラのフレームが更新された場合のイベントハンドラを追加します。同じく、スケルトンのフレームが更新された場合のイベントハンドラを追加します。

  Private Sub okButton_Click(sender As System.Object, e As System.Windows.RoutedEventArgs) Handles okButton.Click
      Dim myIPAddress As String = addressTextBox.Text
 
    If myIPAddress = String.Empty Then
      MessageBox.Show("Addressを入力してください。")
      Exit Sub
    Else
      _skeletonClient = New SkeletonClient()
      _colorClient = New ColorClient()

If Not _colorClient.IsConnected Then _colorClient.Connect(myIPAddress, 4530) Else _colorClient.Disconnect() End If If Not _skeletonClient.IsConnected Then _skeletonClient.Connect(myIPAddress, 4532) Else _skeletonClient.Disconnect() End If AddHandler _colorClient.ColorFrameReady, AddressOf client_ColorFrameReady AddHandler _skeletonClient.SkeletonFrameReady, AddressOf client_SkeletonFrameReady End If End Sub

RGBカメラのフレームが更新された時に発生するイベント

Image1のSourceプロパティにRGBカメラのフレームをビットマップイメージに変換して表示します。

  Private Sub client_ColorFrameReady(ByVal sender As Object, ByVal e As ColorFrameReadyEventArgs)
    If e.ColorFrame.BitmapImage IsNot Nothing Then
      Image1.Source = e.ColorFrame.BitmapImage
    End If
  End Sub

スケルトンフレームが更新された時に発生するイベント

Skeletonクラス用オブジェクト変数mySkeletonで、スケルトンデータを持つe.SkeletonFrame.Skeletons内で、全ての関節の位置がトラッキングされた状態にある、シーケンスの最初の要素を取得していきます。

頭、左手、右手、腰の中央、左肘、右肘、左肩、右肩、左腰、右腰の関節を取得し、各部位に該当する円を、身体の部位に収まるよう描画するSetEllpisePositionプロシージャを実行します。

  Private Sub client_SkeletonFrameReady(ByVal sender As Object, ByVal e As SkeletonFrameReadyEventArgs)
      Dim mySkeleton As Skeleton = (From s In e.SkeletonFrame.Skeletons Where s.TrackingState = SkeletonTrackingState.Tracked Select s).FirstOrDefault()
    If mySkeleton Is Nothing Then
      Return
    End If
    SetEllipsePosition(headEllipse, mySkeleton.Joints(CInt(JointType.Head)))
    SetEllipsePosition(leftEllipse, mySkeleton.Joints(CInt(JointType.HandLeft)))
    SetEllipsePosition(rightEllipse, mySkeleton.Joints(CInt(JointType.HandRight)))
 
    SetEllipsePosition(hipCenterEllipse, mySkeleton.Joints(CInt(JointType.HipCenter)))
    
    SetEllipsePosition(ElbowLeftEllipse, mySkeleton.Joints(CInt(JointType.ElbowLeft)))
    SetEllipsePosition(ElbowRightEllipse, mySkeleton.Joints(CInt(JointType.ElbowRight)))
 
    SetEllipsePosition(shoulderLeftEllipse, mySkeleton.Joints(CInt(JointType.ShoulderLeft)))
    SetEllipsePosition(shoulderRightEllipse, mySkeleton.Joints(CInt(JointType.ShoulderRight)))
 
    SetEllipsePosition(HipLeftEllipse, mySkeleton.Joints(CInt(JointType.HipLeft)))
    SetEllipsePosition(HipRightEllipse, mySkeleton.Joints(CInt(JointType.HipRight)))    End Sub

各円が身体の関節の位置に納まる処理

Canvas.SetLeftとSetTopプロパティの書式は下記です。

  • Canvas.SetLeft(プロパティ値の書き込み対象の要素,指定した要素のCanvas.Left属性を設定)
  • Canvas.SetTop(プロパティ値の書き込み対象の要素,指定した要素のCanvas.Top属性を設定)

448はImage1のWidth、336はImage1のHeightの値です。円の位置合わせのためにWidthとHeighの半分の値を加算しています。

  Private Sub SetEllipsePosition(myEllipse As Ellipse, myJoint As Joint)
    Canvas.SetLeft(myEllipse, (448 * myJoint.Position.X) + 224)
    Canvas.SetTop(myEllipse, (336 * -myJoint.Position.Y) + 168)
  End Sub
End Class

以上で今回のサンプルは終了です。

人気記事トップ10

人気記事ランキングをもっと見る

企画広告も役立つ情報バッチリ! Sponsored

ClickHouse Cloudが実現した広告運用SaaS「ATOM」のデータ基盤革新、パフォーマンスを向上しながら、運用負荷とコストを削減 11月11日 6:20 AIで開発が加速する時代、品質保証はどう変わる? Tricentisが示すAIエージェント活用の実像 11月9日 6:45 悪用までの猶予が「1分」に迫るフロンティアAI時代に開発と本番を貫く脆弱性管理が必要 10月29日 8:30 欧州CRA対応とSBOM運用。AI生成コードのOSS混入問題の対策とは ――スニペット単位で検出する「FossID」「Insignary Clarity」によるSBOM運用 9月16日 6:40 PostgreSQLからTiDBへ、稼働中SaaSで進める段階的DB移行の実践と再設計への展望 9月7日 6:30 機能安全開発におけるGoogleTestの活用を支援!「Parasoft C/C++test CT」で実現する効率化&AI連携 4月14日 6:30 【CNDW2025】Grafanaが明かす「オブザーバビリティの哲学」ー最小限の労力で実用的なインサイトを得るには 1月23日 6:30 【CNDW2025】プロダクト急増に備える基盤刷新 ーウェルスナビがECSからEKSへの移行で得た知見とは 1月15日 6:30 【CNDW2025】250環境を5人で運用、構築時間は30分に ーKINTOテクノロジーズが語るインフラ基盤組織の作り方 2025年12月18日 6:30 新たな自動化で熱視線! AIエージェントの「推論能力」を支える2つのコンポーネントとは? 2025年11月28日 6:30