2
votes

I have two different windows, one will to display streams on a image and calculate a user's skeleton head position (window A), and another is display a 3D visual model that will use the skeleton data to zoom and translate(animation)(window B).

However, my problem is how can I suppose to pass and keep updating these skeleton head position data from window A to window B? I am using WPF and M'soft Kinect SDK. My another question is that how can I display a control like a button or a menu on the visual model as for my case the model is filled up the whole screen.

  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;

        }

Edit


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

I can't get the HeadPosition.Text update with the data.What actually happened?

kinect changed event handler at window 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
What is ht.GetHeadPoistion doing? Directly accessing the skeleton.Joints[JointType.Head].Position object will get you the same stuff -- without the weirdness of using out parameters. - Nicholas Pappas
Yes..I changed back to access it directly. At first i thought I can pass the value around from the GetHeadPosition. - user1884304

2 Answers

2
votes

You can do this in one of many different ways. It all depends on how you want to seperate the code in your program.

Option 1: Public Event Handlers

You could set up public event handlers in Window B that subscribe to the SkeletonFrameReady event from the KinectSensor. For example, in the class that sets up your KinectSensor you might have something like:

WindowB windowB = new WindowB();

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

    sensor.SkeletonFrameReady += windowB.OnSkeletonFrameReady;

    // some more setup code
}

Then in your WindowB class you would have the event callback:

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

Option 2: Pass the Sensor

You could set up your window(s) to accept a reference to the KinectSensor. When you open the second window from your main class, just pass the sensor in:

WindowB windowB = new WindowB(sensor);

With your constructor of WindowB taking a KinectSensor and then setting up the callback from above:

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

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

Notice this allows your callback to be private.

Option 3: Using a Framework Messenger

You could also use a framework messenger, such as MVVM Light. MVVM Light provides a lightweight messenger system that allows you to easily pass objects around from one view to the the next. While this is more useful in a MVVM structured program that doesn't mean you can't use it outside one.

You can broadcast the entire SkeletonFrameReadyEventArgs out from your main classes SkeletonFrameReady callback:

private void OnSkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
{
    Messenger.Default.Send<SkeletonFrameReadyEventArgs>(e);

    // do more stuff
}

Then you just need to subscribe to it from you 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
}

Or you could just send the individual Skeleton, fromo your main class:

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

Your WindowB would then register, as shown above, on a SkeletonFrame instead of the event args. The callback would do what it needs to do with the SkeletonFrame object.

What's Best?

Up to you. There are several other ways you could ultimately do this. These are the first three I thought of. They will all accomplish the same thing -- you just want to use the one your are most comfortable with for your program style.

Maximizing the Window

To maximize the window, you can place a button in your XAML and setup a callback to toggle between the Maximized and Normal window state.

XAML:

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

Code Behind:

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

  _isMaxed = !_isMaxed;
}
0
votes
  1. You can pass the Skeleton to your second window (e.g. in constructor) and use its OnHeadPositionChanged-Event.

  2. Just add the control in the xaml and set fix positions, like Margin="0,10,0,10", or use a Canvas as parent and set the position through Canvas.Top="0" Canvas.Left="20".