kaorun55氏の「KINECT SDK Beta2 でスケルトンデータを扱う( C# + WPF ) のVB版になります。
いつもと同じようにXAMLソースから
--------------------------------------------------------------------------------
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="521" Width="661">
<Grid>
<Image Height="480" Name="Image1" Width="640" />
</Grid>
</Window>
--------------------------------------------------------------------------------
特別なところはありません。Imageコントロールが1つだけです。
メインソースです。
--------------------------------------------------------------------------------
Imports System.Threading
Imports System.Windows.Threading
Imports System.Windows.Media
Imports Microsoft.Research.Kinect.Nui
Class MainWindow
Inherits Window
Private readerThread As Thread
Private shouldRun As Boolean
Private kinect As Runtime
Private usercolor() As Color = {Color.FromRgb(0, 0, 0), Colors.Red, Colors.Green, Colors.Blue, Colors.Yellow, Colors.Magenta, Colors.Pink}
Public Sub New()
' この呼び出しはデザイナーで必要です。
InitializeComponent()
' InitializeComponent() 呼び出しの後で初期化を追加します。
If Runtime.Kinects.Count > 0 Then
''KINECT初期化
kinect = Runtime.Kinects(0)
kinect.Initialize(RuntimeOptions.UseColor Or RuntimeOptions.UseDepthAndPlayerIndex Or RuntimeOptions.UseSkeletalTracking)
kinect.VideoStream.Open(ImageStreamType.Video, 2, ImageResolution.Resolution640x480, ImageType.Color)
kinect.DepthStream.Open(ImageStreamType.Depth, 2, ImageResolution.Resolution320x240, ImageType.DepthAndPlayerIndex)
''スレッドの開始
shouldRun = True
readerThread = New Thread(New ThreadStart(AddressOf RenderThread))
readerThread.Start()
End If
End Sub
Sub RenderThread()
While (shouldRun)
''タイムアウトは100ms
Dim video As ImageFrame = kinect.VideoStream.GetNextFrame(100)
Dim depth As ImageFrame = kinect.DepthStream.GetNextFrame(100)
Dim skeleton As SkeletonFrame = kinect.SkeletonEngine.GetNextFrame(100)
''メインスレッドにイメージデータの書き込みを指示
Me.Dispatcher.BeginInvoke(DispatcherPriority.Background, New Action(
Sub()
Dim drawingVisual As New DrawingVisual
Using drawingContext As DrawingContext = drawingVisual.RenderOpen()
drawingContext.DrawImage(DrawPixels(kinect, video, depth), New Rect(0, 0, video.Image.Width, video.Image.Height))
''骨格の部位ごとに座標を求める
For Each s In skeleton.Skeletons
If s.TrackingState = SkeletonTrackingState.Tracked Then
For Each j In s.Joints
Dim point As Point = GetVideoPoint(j)
'円を描く
drawingContext.DrawEllipse(New SolidColorBrush(Colors.Red), New Pen(Brushes.Red, 1), New Point(point.X, point.Y), 5, 5)
Next
End If
Next
End Using
'描画可能なビットマップを作る
Dim bitmap As RenderTargetBitmap = New RenderTargetBitmap(video.Image.Width, video.Image.Height, 96, 96, PixelFormats.Default)
bitmap.Render(drawingVisual)
Image1.Source = bitmap
End Sub
))
End While
End Sub
Function DrawPixels(ByVal kinect As Runtime, ByVal video As ImageFrame, ByVal depth As ImageFrame) As WriteableBitmap
Dim x, y, index As Integer
Dim playerIndex, distance As Integer
Dim videoX, videoY, videoIndex As Integer
Dim byte0, byte1 As Byte
'ピクセルごとのユーザーID
For y = 0 To depth.Image.Height - 1
For x = 0 To depth.Image.Width - 1
index = (x + (y * depth.Image.Width)) * 2
byte0 = depth.Image.Bits(index)
byte1 = depth.Image.Bits(index + 1)
'ユーザーIDと距離
playerIndex = byte0 And &H7
distance = byte1 << 5 Or byte0 >> 3
If playerIndex <> 0 Then
videoX = 0
videoY = 0
''深度データの座標からカラーデータの座標へ変換
kinect.NuiCamera.GetColorPixelCoordinatesFromDepthPixel(ImageResolution.Resolution640x480, New ImageViewArea(), x, y, 0, videoX, videoY)
videoIndex = (videoX + (videoY * video.Image.Width)) * video.Image.BytesPerPixel
videoIndex = Math.Min(videoX, video.Image.Bits.Length - video.Image.BytesPerPixel)
video.Image.Bits(videoIndex) = usercolor(playerIndex).R
video.Image.Bits(videoIndex + 1) = usercolor(playerIndex).G
video.Image.Bits(videoIndex + 2) = usercolor(playerIndex).B
End If
Next
Next
'バイト列をビットマップに展開
'描画可能なビットマップを作る
Dim bitmap As WriteableBitmap = New WriteableBitmap(video.Image.Width, video.Image.Height, 96, 96, PixelFormats.Bgr32, Nothing)
bitmap.WritePixels(New Int32Rect(0, 0, video.Image.Width, video.Image.Height), video.Image.Bits, video.Image.Width * video.Image.BytesPerPixel, 0)
Return bitmap
End Function
Function GetVideoPoint(ByVal joint As Joint) As Point
Dim kinect As Runtime = Runtime.Kinects(0)
Dim depthX, depthY As Single
Dim videoX, videoY As Integer
depthX = 0
depthY = 0
''骨格データ(ベクタ座標)から深度データの座標へ変換
kinect.SkeletonEngine.SkeletonToDepthImage(joint.Position, depthX, depthY)
depthX = Math.Min(depthX * kinect.DepthStream.Width, kinect.DepthStream.Width)
depthY = Math.Min(depthY * kinect.DepthStream.Height, kinect.DepthStream.Height)
videoX = 0
videoY = 0
''深度データの座標をカラーデータの座標に変換
kinect.NuiCamera.GetColorPixelCoordinatesFromDepthPixel(ImageResolution.Resolution640x480, New ImageViewArea(), CInt(depthX), CInt(depthY), 0, videoX, videoY)
Return New Point(Math.Min(videoX, kinect.VideoStream.Width), Math.Min(videoY, kinect.VideoStream.Height))
End Function
Private Sub Window_Unloaded(sender As System.Object, e As System.Windows.RoutedEventArgs) Handles MyBase.Unloaded
shouldRun = False
End Sub
End Class
--------------------------------------------------------------------------------
Skeletonの座標データはKINECTを中心にXYZの3D座標になります。
XYは-1~1までの単精度浮動小数になるのでこれを2Dの座標に変換しなければいけないのですが、手順としてSkeleton座標>Depth(深度)座標>Video(カラー)座標の順番に変換しています。
Skeleton>Depthの変換はSkeletonToDepthImageで変換します。
Depth>Videoの変換はGetColorPixelCoordinatesFromDepthPixelを使って変換しています。
変換した座標をもとにShapeを描画すればVideo,Depthのイメージに骨格情報を重ねて表示できます。
0 件のコメント:
コメントを投稿