1
votes

I've been having some serious trouble getting skeleton tracking working properly for Kinect For Windows, using SDK v1.5 and VS2012. I'm building on the source code from https://github.com/EvilClosetMonkey/Fizbin.Kinect.Gestures , but the tracking goes completely astray when there's multiple people on the screen. I've then gone on to look at the code here ( http://social.msdn.microsoft.com/Forums/en-US/kinectsdknuiapi/thread/459012d7-d51e-460d-aa6a-a1b80c27626c/ ), and I've attempted to integrate the "AppChoosesSkeletons" functionality (code below):

using System.Windows;
using System.Windows.Data;
using Microsoft.Kinect;
using Microsoft.Kinect.Toolkit;
using Microsoft.Samples.Kinect.WpfViewers;
using System.Diagnostics;
using System.ComponentModel;
using System.Linq;
using System;

namespace Fizbin.Kinect.Gestures.Demo
{
public partial class MainWindow : Window, INotifyPropertyChanged
{
    private readonly KinectSensorChooser sensorChooser = new KinectSensorChooser();

    private Skeleton[] skeletons = new Skeleton[0];

    // skeleton gesture recognizer
    private GestureController gestureController;

    public MainWindow()
    {
        DataContext = this;

        InitializeComponent();

        // initialize the Kinect sensor manager
        KinectSensorManager = new KinectSensorManager();
        KinectSensorManager.KinectSensorChanged += this.KinectSensorChanged;

        // locate an available sensor
        sensorChooser.Start();

        // bind chooser's sensor value to the local sensor manager
        var kinectSensorBinding = new Binding("Kinect") { Source = this.sensorChooser };
        BindingOperations.SetBinding(this.KinectSensorManager, KinectSensorManager.KinectSensorProperty, kinectSensorBinding);
    }

    #region Kinect Discovery & Setup

    private void KinectSensorChanged(object sender, KinectSensorManagerEventArgs<KinectSensor> args)
    {
        if (null != args.OldValue)
            UninitializeKinectServices(args.OldValue);

        if (null != args.NewValue)
            InitializeKinectServices(KinectSensorManager, args.NewValue);
    }

    /// <summary>
    /// Kinect enabled apps should customize which Kinect services it initializes here.
    /// </summary>
    /// <param name="kinectSensorManager"></param>
    /// <param name="sensor"></param>
    private void InitializeKinectServices(KinectSensorManager kinectSensorManager, KinectSensor sensor)
    {
        // Application should enable all streams first.

        // configure the color stream
        kinectSensorManager.ColorFormat = ColorImageFormat.RgbResolution640x480Fps30;
        kinectSensorManager.ColorStreamEnabled = true;

        // configure the depth stream
        kinectSensorManager.DepthStreamEnabled = true;

        kinectSensorManager.TransformSmoothParameters =
            new TransformSmoothParameters
            {
                Smoothing = 0.5f,
                Correction = 0.5f,
                Prediction = 0.5f,
                JitterRadius = 0.05f,
                MaxDeviationRadius = 0.04f
            };

        // configure the skeleton stream
        sensor.SkeletonFrameReady += FramesReady;
        kinectSensorManager.SkeletonStreamEnabled = true;
        sensor.SkeletonStream.TrackingMode = SkeletonTrackingMode.Seated;
        // initialize the gesture recognizer
        gestureController = new GestureController();
        gestureController.GestureRecognized += OnGestureRecognized;

        kinectSensorManager.KinectSensorEnabled = true;

        if (!kinectSensorManager.KinectSensorAppConflict)
        {
            // addition configuration, as needed
        }
    }

    /// <summary>
    /// Kinect enabled apps should uninitialize all Kinect services that were initialized in InitializeKinectServices() here.
    /// </summary>
    /// <param name="sensor"></param>
    private void UninitializeKinectServices(KinectSensor sensor)
    {

    }

    #endregion Kinect Discovery & Setup

    #region Properties

    public static readonly DependencyProperty KinectSensorManagerProperty =
        DependencyProperty.Register(
            "KinectSensorManager",
            typeof(KinectSensorManager),
            typeof(MainWindow),
            new PropertyMetadata(null));

    public KinectSensorManager KinectSensorManager
    {
        get { return (KinectSensorManager)GetValue(KinectSensorManagerProperty); }
        set { SetValue(KinectSensorManagerProperty, value); }
    }

    /// <summary>
    /// Gets or sets the last recognized gesture.
    /// </summary>
    private string _gesture;
    public String Gesture
    {
        get { return _gesture; }

        private set
        {
            if (_gesture == value)
                return;

            _gesture = value;

            Debug.WriteLine("Gesture = " + _gesture);

            if (this.PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs("Gesture"));
        }
    }

    #endregion Properties

    #region Events

    /// <summary>
    /// Event implementing INotifyPropertyChanged interface.
    /// </summary>
    public event PropertyChangedEventHandler PropertyChanged;

    #endregion Events

    #region Event Handlers

    /// <summary>
    ///
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e">Gesture event arguments.</param>
    private void OnGestureRecognized(object sender, GestureEventArgs e)
    {
        Debug.WriteLine(e.GestureType);

        switch (e.GestureType)
        {
            case GestureType.Menu:
                Gesture = "Menu";
                break;
            case GestureType.WaveRight:
                Gesture = "Wave Right";
                break;
            case GestureType.WaveLeft:
                Gesture = "Wave Left";
                break;
            case GestureType.JoinedHands:
                Gesture = "Joined Hands";
                break;
            case GestureType.SwipeLeft:
                Gesture = "Swipe Left";
                break;
            case GestureType.SwipeRight:
                Gesture = "Swipe Right";
                break;
            case GestureType.ZoomIn:
                Gesture = "Zoom In";
                break;
            case GestureType.ZoomOut:
                Gesture = "Zoom Out";
                break;

            default:
                break;
        }
    }

    void FramesReady(object sender, AllFramesReadyEventArgs e, KinectSensor sensor)
    {
        Skeleton skeleton = FindSkeleton(e);
        if (skeleton != null)
        {
            gestureController.UpdateAllGestures(skeleton);
        }
    }

    private int CurrentTrackingId = 0;

    Skeleton FindSkeleton(AllFramesReadyEventArgs e)
    {
        Skeleton skeleton = null;

        using (SkeletonFrame SFrame = e.OpenSkeletonFrame())
        {
            if (SFrame == null)
            {
                return null;
            }

            if (skeletons == null)
            {
                skeletons = new Skeleton[SFrame.SkeletonArrayLength];
            }

            SFrame.CopySkeletonDataTo(skeletons);

            if (CurrentTrackingId != 0)
            {
                // We've been tracking someone; see if they're still here

                skeleton =
                    (from s in skeletons
                     where s.TrackingState == SkeletonTrackingState.Tracked &&
                           s.Joints[JointType.Head].TrackingState == JointTrackingState.Tracked &&
                           s.TrackingId == CurrentTrackingId
                     select s).FirstOrDefault();

                if (skeleton == null)
                {
                    CurrentTrackingId = 0;
                    sensor.SkeletonStream.AppChoosesSkeletons = false;
                }
            }
            else
            {
                // Try to find someone new

                skeleton =
                    (from s in skeletons
                     where s.TrackingState == SkeletonTrackingState.Tracked &&
                           s.Joints[JointType.Head].TrackingState == JointTrackingState.Tracked
                     select s).FirstOrDefault();

                if (skeleton != null)
                {
                    CurrentTrackingId = skeleton.TrackingId;
                    sensor.SkeletonStream.AppChoosesSkeletons = true;
                    sensor.SkeletonStream.ChooseSkeletons(CurrentTrackingId);
                }
            }
        }

        return skeleton;
    }

    #endregion Event Handlers

   }
}

However, I'm getting errors from VS2012 about:

1) No overload for 'FramesReady' matches delegate 'System.EventHandler'

2) 'sensor' not existing (most likely due to it not being imported, but from what I've tried, passing the sensor across methods causes more errors)

If anyone can help with this, or even point me in the right direction towards solving this, that would be great! To reiterate, the main goal is to have the Kinect lock onto the first person it finds, and maintain that lock with multiple people moving around in the line of sight.

1

1 Answers

1
votes

If you are planning you continue to use the KinectSensorManager you can use the KinectSkeletonChooser to help you pick out the skeleton you want. This helper function is also included in the KinectWpfViewers project. You will not need to add any additional code to the code behind in order to use it.

Easiest way to get it going is to just add it to your XAML. Updating the demo code that comes with the Except on Tuesdays' library, it would look like th:

<Window x:Class="Fizbin.Kinect.Gestures.Demo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:kv="clr-namespace:Microsoft.Samples.Kinect.WpfViewers;assembly=Microsoft.Samples.Kinect.WpfViewers"
        Title="MainWindow" Height="350" Width="525">
    <Grid>        
        <Grid HorizontalAlignment="Right" VerticalAlignment="Bottom" Width="320" Height="240">
            <kv:KinectSkeletonChooser KinectSensorManager="{Binding KinectSensorManager}" SkeletonChooserMode="Sticky1Player" />
            <kv:KinectDepthViewer x:Name="DepthViewer" KinectSensorManager="{Binding KinectSensorManager}" />
            <Canvas>
                <kv:KinectSkeletonViewer
                                    KinectSensorManager="{Binding KinectSensorManager}"
                                    Width="{Binding ElementName=DepthViewer, Path=ActualWidth}"
                                    Height="{Binding ElementName=DepthViewer, Path=ActualHeight}"
                                    ShowBones="True" ShowJoints="True" ShowCenter="True" ImageType="Depth" />
            </Canvas>
        </Grid>

        <TextBlock Text="{Binding Gesture}" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="48" FontWeight="Bold" Margin="-2,0,0,0"/>
        <TextBlock Text="{Binding Gesture}" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="48" FontWeight="Bold" Margin="2,0,0,0"/>
        <TextBlock Text="{Binding Gesture}" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="48" FontWeight="Bold" Margin="0,-2,0,0"/>
        <TextBlock Text="{Binding Gesture}" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="48" FontWeight="Bold" Margin="0,2,0,0"/>
        <TextBlock Text="{Binding Gesture}" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="48" FontWeight="Bold" Foreground="White"/>

    </Grid>
</Window>

Note the new KinectSkeletonChooser tag on line 8.

Other options available can be see in the SkeletonChooserMode enum:

public enum SkeletonChooserMode
{
    /// <summary>
    /// Use system default tracking
    /// </summary>
    DefaultSystemTracking,

    /// <summary>
    /// Track the player nearest to the sensor
    /// </summary>
    Closest1Player,

    /// <summary>
    /// Track the two players nearest to the sensor
    /// </summary>
    Closest2Player,

    /// <summary>
    /// Track one player based on id
    /// </summary>
    Sticky1Player,

    /// <summary>
    /// Track two players based on id
    /// </summary>
    Sticky2Player,

    /// <summary>
    /// Track one player based on most activity
    /// </summary>
    MostActive1Player,

    /// <summary>
    /// Track two players based on most activity
    /// </summary>
    MostActive2Player
}