1. 基於景深資料的使用者互動
到目前為止我們只用了骨骼資料中關節點的X,Y值。然而Kinect產生的關節點資料除了X,Y值外還有一個深度值。基於Kinect的應用程式應該利用好這個深度值。下面的部分將會介紹如何在Kinect應用程式中使用深度值。
除了使用WPF的3D特性外,在布局系統中可以根據深度值來設定可視化元素的尺寸大小來達到某種程式的立體效果。下面的例子使用Canvas.ZIndex屬性來設定元素的層次,手動設定控制項的大小並使用ScaleTransform來根據深度值的改變來進行縮放。使用者介面包括一些圓形,每一個圓代表一定的深度。應用程式跟蹤使用者的手部關節點,以手形圖示顯示,表徵圖會根據使用者手部關節點的深度值來進行縮放,使用者離Kinect越近,手形圖表越大,反之越小。
建立一個新的WPF項目,主介面的XAML如下。主要的版面配置容器為Cnavas容器。它包含5個Ellipses及對應的TextBlock控制項,TextBlock用來對圓形進行說明。這幾個圓形隨機分布在螢幕上,但是圓形的Canvas.ZIndex是確定的。Canvas容器也包含了兩個影像控制,用來代表兩隻手。每一個手部表徵圖都定義了一個ScaleTransform對象。手形圖示是和右手方向一致的,將ScaleTransform的ScaleX設定為-1可以將其反轉,看起來像左手。
<Window x:Class="KinectDepthBasedInteraction.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Depth UI Target" Height="1080" Width="1920" WindowState="Maximized" Background="White"> <Window.Resources> <Style x:Key="TargetLabel" TargetType="TextBlock" > <Setter Property="FontSize" Value="40" /> <Setter Property="Foreground" Value="White"/> <Setter Property="FontWeight" Value="Bold" /> <Setter Property="IsHitTestVisible" Value="False" /> </Style> </Window.Resources> <Viewbox> <Grid x:Name="LayoutRoot" Width="1920" Height="1280"> <Image x:Name="DepthImage"/> <StackPanel HorizontalAlignment="Left" VerticalAlignment="Top"> <TextBlock x:Name="DebugLeftHand" Style="{StaticResource TargetLabel}" Foreground="Black" /> <TextBlock x:Name="DebugRightHand" Style="{StaticResource TargetLabel}" Foreground="Black" /> </StackPanel> <Canvas> <Ellipse x:Name="Target3" Fill="Orange" Height="200" Width="200" Canvas.Left="776" Canvas.Top="162" Canvas.ZIndex="1040" /> <TextBlock Text="3" Canvas.Left="860" Canvas.Top="206" Panel.ZIndex="1040" Style="{StaticResource TargetLabel}" /> <Ellipse x:Name="Target4" Fill="Purple" Height="150" Width="150" Canvas.Left="732" Canvas.Top="320" Canvas.ZIndex="940" /> <TextBlock Text="4" Canvas.Left="840" Canvas.Top="372" Panel.ZIndex="940" Style="{StaticResource TargetLabel}" /> <Ellipse x:Name="Target5" Fill="Green" Height="120" Width="120" Canvas.Left="880" Canvas.Top="592" Canvas.ZIndex="840" /> <TextBlock Text="5" Canvas.Left="908" Canvas.Top="590" Panel.ZIndex="840" Style="{StaticResource TargetLabel}" /> <Ellipse x:Name="Target6" Fill="Blue" Height="100" Width="100" Canvas.Left="352" Canvas.Top="544" Canvas.ZIndex="740" /> <TextBlock Text="6" Canvas.Left="368" Canvas.Top="582" Panel.ZIndex="740" Style="{StaticResource TargetLabel}" /> <Ellipse x:Name="Target7" Fill="Red" Height="85" Width="85" Canvas.Left="378" Canvas.Top="192" Canvas.ZIndex="640" /> <TextBlock Text="7" Canvas.Left="422" Canvas.Top="226" Panel.ZIndex="640" Style="{StaticResource TargetLabel}" /> <Image x:Name="LeftHandElement" Source="Images/hand.png" Width="80" Height="80" RenderTransformOrigin="0.5,0.5"> <Image.RenderTransform> <ScaleTransform x:Name="LeftHandScaleTransform" ScaleX="1" CenterY="-1" /> </Image.RenderTransform> </Image> <Image x:Name="RightHandElement" Source="Images/hand.png" Width="80" Height="80" RenderTransformOrigin="0.5,0.5"> <Image.RenderTransform> <ScaleTransform x:Name="RightHandScaleTransform" CenterY="1" ScaleX="1" /> </Image.RenderTransform> </Image> </Canvas> </Grid> </Viewbox></Window
不同顏色的圓形代表不同的深度,例如名為Target3的元素代表距離為3英尺。Target3的長寬比Target7要大,這簡單的通過縮放可以實現。在我們的執行個體程式中,我們將其大小進行寫入程式碼,實際的程式中,應該根據特定要求可以進行縮放。Canvas容器會根據子項目的Canvas.ZIndex的值對元素在垂直於電腦螢幕的方向上進行排列,例如最上面的元素,其Canvas.ZIndex最大。如果兩個元素有相同的ZIndex值,那麼會根據其在XAML中聲明的順序進行顯示,在XAML中,後面聲明的元素在之前聲明的元素的前面。對於Canvas的所有子項目,ZIndex值越大,離螢幕越近,越小離螢幕越遠。將深度值取反剛好能達到想要的效果。這意味這我們不能直接使用深度值來給ZIndex來賦值,而要對它進行一點轉換。Kinect能夠產生的最大深度值為13.4英尺,相應的,我們將Canvas.Zindex的取值範圍設定為0-1340,將深度值乘以100能獲得更好的精度。因此Target5的Canvas.ZIndex設定為840(13.5-5=8.4*100=840)。