将kinect骨架位置数据传递到另一个窗口

时间:2012-12-07 08:45:08

标签: c# wpf kinect

我有两个不同的窗口,一个用于在图像上显示流并计算用户的骨架头部位置(窗口A),另一个用于显示3D视觉模型,该模型将使用骨架数据进行缩放和平移(动画) (窗口B)。

然而,我的问题是我怎么能想通过并继续将这些骨架头部位置数据从窗口A更新到窗口B?我正在使用WPF和M'soft Kinect SDK。我的另一个问题是,如何在视觉模型上显示像按钮或菜单这样的控件,就像我的情况一样,模型在整个屏幕上都被填满。

  foreach (Skeleton skeleton in skeletons)
    {
        if (skeleton.TrackingState == SkeletonTrackingState.Tracked)
        {

            ht.GetHeadPosition(skeleton, out message, out headPosition);

            this.headPoint.X = headPosition.X;
            this.headPoint.Y = headPosition.Y;
            this.headPoint.Z = headPosition.Z;

            this.StatusTextBlock.Text = message;

        }

修改


  public void newSensor_SkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
    {
        using (SkeletonFrame skeletonFrame = e.OpenSkeletonFrame())
        {
            if (skeletonFrame == null)
                 return;

             GetSkeletons(skeletonFrame, ref skeletons);

             if (skeletons.All(s => s.TrackingState == SkeletonTrackingState.NotTracked))
                 return;

             //skeletonManager.Draw(skeletons);
        }

        foreach (Skeleton skeleton in skeletons)
        {
            if (skeleton.TrackingState == SkeletonTrackingState.Tracked)
            {
                Joint headJoint = skeleton.Joints[JointType.Head];
                Joint hipCenter = skeleton.Joints[JointType.HipCenter];

                headPosition = headJoint.Position;

                this.headPoint.X = headPosition.X;
                this.headPoint.Y = headPosition.Y;
                this.headPoint.Z = headPosition.Z;

                message = string.Format("Head: X:{0:0.0} Y:{1:0.0} Z:{2:0.0}",
                headPoint.X,
                headPoint.Y, headPoint.Z);

                //MessageBox.Show(message);

                this.HeadPosition.Text = message;
            }
        }
    }

我无法使用数据获取HeadPosition.Text更新。实际发生了什么?

kinect在窗口A更改了事件处理程序

    private void sensorChooser_KinectChanged(object sender, KinectChangedEventArgs e)
    {
        KinectSensor oldSensor = (KinectSensor)e.OldSensor;
        StopKinect(oldSensor);

        KinectSensor newSensor = (KinectSensor)e.NewSensor;

        if (newSensor == null)
        {
            return;
        }

        //Register for event and enable Kinect Sensor features you want
        newSensor.DepthFrameReady += newSensor_DepthFrameReady;
        newSensor.SkeletonFrameReady += mw.newSensor_SkeletonFrameReady;

        //newSensor.ColorStream.Enable(ColorImageFormat.RgbResolution640x480Fps30);
        newSensor.DepthStream.Enable(DepthImageFormat.Resolution640x480Fps30);

       ....

        newSensor.SkeletonStream.Enable(parameter);

        StartKinect(newSensor);

    }

XAML_的 _ __ _ __ _ __ _ __ _ __ _ __ _ __ _ __ _ __ _ __ _ __ _ __ _ __ _ __ _ __ _ 的__ _ __ _ __ _ __ _ _

  <Grid x:Name="firstGrid">
    <Viewport3D x:Name="viewPort" Grid.Column="0" Grid.Row="0" ClipToBounds="False" Width="2048" 
    ....
    .....
    </Viewport3D>

    <TextBox x:Name="IndexPosition" HorizontalAlignment="Left" Height="23" Margin="485,2,0,0"   TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="69"/>

    <TextBox x:Name="CameraPosition" HorizontalAlignment="Left" Height="23" Margin="570,2,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="142"/>

    <TextBlock Name="HeadPosition" HorizontalAlignment="Left" Margin="492,23,0,0" Text="Text" VerticalAlignment="Top" Width="182" Height="29" 
               Foreground="Tomato" FontSize="20"/>

2 个答案:

答案 0 :(得分:2)

您可以通过多种方式之一完成此操作。这一切都取决于你想如何分离程序中的代码。

选项1:公共事件处理程序

您可以在Window B中设置订阅来自SkeletonFrameReady的{​​{1}}事件的公共事件处理程序。例如,在设置KinectSensor的类中,您可能会遇到类似的内容:

KinectSensor

然后在你的WindowB windowB = new WindowB(); private void InitializeKinectServices(KinectSensor sensor) { // some setup code sensor.SkeletonFrameReady += windowB.OnSkeletonFrameReady; // some more setup code } 课程中,您将获得事件回调:

WindowB

选项2:传递传感器

您可以设置窗口以接受对public void OnSkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e) { using (SkeletonFrame skeletonFrame = e.OpenSkeletonFrame()) { // do what you need } } 的引用。当您从主类打开第二个窗口时,只需将传感器传递到:

KinectSensor

使用WindowB windowB = new WindowB(sensor); 的构造函数获取WindowB,然后设置上面的回调:

KinectSensor

请注意,这允许您的回调是私有的。

选项3:使用Framework Messenger

您还可以使用框架信使,例如MVVM Light。 MVVM Light提供了一个轻量级的信使系统,允许您轻松地将对象从一个视图传递到下一个视图。虽然这在MVVM结构化程序中更有用,但并不意味着你不能在一个程序之外使用它。

您可以在主要课程public WindowB(KinectSensor sensor) { sensor.SkeletonFrameReady += OnSkeletonFrameReady; } private void OnSkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e) { using (SkeletonFrame skeletonFrame = e.OpenSkeletonFrame()) { // do what you need } } 回调中播放整个SkeletonFrameReadyEventArgs

SkeletonFrameReady

然后您只需要向您订阅private void OnSkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e) { Messenger.Default.Send<SkeletonFrameReadyEventArgs>(e); // do more stuff }

WindowB

或者你可以从你的主要班级发送个人public WindowB() { Messenger.Default.Register<SkeletonFrameReadyEventArgs>(this, OnSkeletonFrameReady); } private void OnSkeletonFrameReady(SkeletonFrameReadyEventArgs e) { // do what you need with the event arg, just as you would in a regular callback }

Skeleton

如上所示,您的private void OnSkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e) { using (SkeletonFrame skeletonFrame = e.OpenSkeletonFrame()) { // do checks for capturing the appropriate skeleton. Messenger.Default.Send<SkeletonFrame>(skeletonFrame); // do more stuff if you need. } } 会在WindowB而不是事件参数上注册。回调将执行它对SkeletonFrame对象所需的操作。

什么是最好的?

由你决定。还有其他几种方法可以最终实现这一目标。这是我想到的前三个。他们都将完成同样的事情 - 你只想使用你最熟悉的程序风格。

最大化窗口

要最大化窗口,您可以在XAML中放置一个按钮并设置回调以在SkeletonFrameMaximized窗口状态之间切换。

XAML:

Normal

代码背后:

<Button Click="MyButton_Click">Click Me</Button>

答案 1 :(得分:0)

  1. 您可以将Skeleton传递到第二个窗口(例如在构造函数中)并使用其OnHeadPositionChanged-Event。

  2. 只需在xaml中添加控件并设置修复位置,例如Margin="0,10,0,10",或使用Canvas作为父级,并通过Canvas.Top="0" Canvas.Left="20"设置位置。