2

我有两个不同的窗口,一个将在图像上显示流并计算用户的骨架头部位置(窗口 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"/>
4

2 回答 2

2

您可以通过多种不同方式中的一种来执行此操作。这完全取决于您希望如何分隔程序中的代码。

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

您可以设置公共事件处理程序Window BSkeletonFrameReadyKinectSensor. 例如,在设置你的类中,KinectSensor你可能有类似的东西:

WindowB windowB = new WindowB();

private void InitializeKinectServices(KinectSensor sensor)
{
    // some setup code

    sensor.SkeletonFrameReady += windowB.OnSkeletonFrameReady;

    // some more setup code
}

然后在您的WindowB班级中,您将获得事件回调:

public void OnSkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
{
    using (SkeletonFrame skeletonFrame = e.OpenSkeletonFrame())
    {
        // do what you need
    }
}

选项 2:通过传感器

您可以设置您的窗口以接受对KinectSensor. 当您从主类打开第二个窗口时,只需将传感器传入:

WindowB windowB = new WindowB(sensor);

使用您的构造函数,WindowB然后KinectSensor从上面设置回调:

public WindowB(KinectSensor sensor) {
    sensor.SkeletonFrameReady += OnSkeletonFrameReady;
}

private void OnSkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
{
    using (SkeletonFrame skeletonFrame = e.OpenSkeletonFrame())
    {
        // do what you need
    }
}

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

选项 3:使用框架 Messenger

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

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.
    }
}

然后,您将在 a而不是事件 argsWindowB上注册,如上所示。SkeletonFrame回调会做它需要对SkeletonFrame对象做的事情。

什么是最好的?

由你决定。还有其他几种方法可以最终做到这一点。这是我想到的前三个。它们都将完成相同的事情——您只想使用最适合您的程序风格的那个。

最大化窗口

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

XAML:

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

代码背后:

bool _isMaxed = false;
public void MyButton_Click(object sender, RoutedEventArgs e)
{
  if (_isMaxed)
      this.WindowState = WindowState.Normal;
  else
      this.WindowState = WindowState.Maximized;

  _isMaxed = !_isMaxed;
}
于 2012-12-07T17:34:29.703 回答
0
  1. 您可以将骨架传递给您的第二个窗口(例如在构造函数中)并使用其 OnHeadPositionChanged-Event。

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

于 2012-12-07T09:35:29.493 回答