Azure Kineck SDK - Hello world (for dummies)

Dopo qualche giorno di attesa sono arrivati in BitForFun i due Azure Kinect DK che abbiamo ordinato.


Per chi non lo conoscesse, l' Azure Kinect SDK è un kit di sviluppo e include diversi sensori come una telecamera di profondità, una camera RGB, giroscopio, accelerometro, un array di microfoni e altro.

Da tecnico, la prima cosa che ho notato è (per via della giovane uscita) la mancanza di documentazione per chi vuole svilupparci con Visual Studio e C#.

Questo Hello world per l'Azure Kinect ha l'obbiettivo primario di evidenziare quanto sia semplice (economicamente e tecnicamente) eseguire il Body Tracking.

L'obiettivo secondario è mostrare dei cerchi colorati in corrispondenza delle mani e seguirne i movimenti :)

In realtà esiste un wrapper C# ma è scarsamente documentato.

Facendo riferimento alll' SDK in C++ però è semplice venirne a capo anche con C#.


Senza dilungarmi, ecco quanto annunciato nell'introduzione.

Creare una nuova applicazione WPF:

New project WPF netcore

Io l'ho nominata "Azure Kinect Hello World".

Aggiungere i pacchetti NuGet relativi al Kinect:

1) Microsoft.Azure.Kinect.Sensor

2) Microsoft.Azure.Kinect.BodyTracking

3) WriteableBitmapEx

Nuget references

Nota: appena aggiunti i pacchetti, VS2019 darà il seguente errore "Azure Kinect only supports the x86/x64 platform ('AnyCPU' not supported)"

Basta andare in configuration manager e creare una nuova configurazione:

Solution configuration

Project start

L'hello world avrà le seguenzi sezioni:

  1. Configurazione (e calibrazione)
  2. Acquisizione
  3. Visualizzazione

https://github.com/giemma/AzureKinectDkHelloWorld

Ecco il codice C# al completo:

public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            Task.Run(() => Go());
        }

        private async Task Go()
        {
            try
            {
                using (Device device = Device.Open())
                {

                    device.StartCameras(new DeviceConfiguration
                    {
                        CameraFPS = FPS.FPS30,
                        ColorResolution = ColorResolution.R1080p,
                        ColorFormat = ImageFormat.ColorBGRA32,

                        DepthMode = DepthMode.NFOV_2x2Binned,

                        SynchronizedImagesOnly = true
                    });

                    var calibration = device.GetCalibration();
                    Transformation transformation = calibration.CreateTransformation();

                    Tracker tracker = Tracker.Create(calibration, new TrackerConfiguration()
                    {
                        ProcessingMode = TrackerProcessingMode.Gpu,
                        SensorOrientation = SensorOrientation.Default
                    });

                    while (true)
                    {
                        Capture capture1 = device.GetCapture();

                        tracker.EnqueueCapture(capture1);
                        var frame = tracker.PopResult(TimeSpan.Zero, throwOnTimeout: false);
                        if (frame != null)
                        {
                            this.Dispatcher.Invoke(() =>
                            {
                                for (uint i = 0; i < frame.NumberOfBodies; i++)
                                {
                                    var bodyId = frame.GetBodyId(i);
                                    var body = frame.GetBody(i);

                                    var handLeft = body.Skeleton.GetJoint(JointId.HandLeft);
                                    var handRight = body.Skeleton.GetJoint(JointId.HandRight);

                                    var pointLeft = calibration.TransformTo2D(handLeft.Position, CalibrationDeviceType.Depth, CalibrationDeviceType.Color);
                                    var pointRight = calibration.TransformTo2D(handRight.Position, CalibrationDeviceType.Depth, CalibrationDeviceType.Color);

                                    try
                                    {
                                        if (pointLeft.HasValue && pointRight.HasValue)
                                        {
                                            Image1.Source = CreateNewBitmap(capture1.Color,
                                                (int)pointLeft.Value.X, (int)pointLeft.Value.Y,
                                                (int)pointRight.Value.X, (int)pointRight.Value.Y);
                                        }
                                    }
                                    catch { }
                                }
                            });

                        }
                    }
                }
            }
            catch (Exception ex)
            {
            }
        }

        private WriteableBitmap CreateNewBitmap(
            Microsoft.Azure.Kinect.Sensor.Image image,
            int xLeft, int yLeft,
            int xRight, int yRight)
        {

            WriteableBitmap wb = new WriteableBitmap(
                image.WidthPixels + 30,
                image.HeightPixels + 30,
                96,
                96,
                PixelFormats.Bgra32, null);

            var region = new Int32Rect(0, 0, image.WidthPixels, image.HeightPixels);

            unsafe
            {
                using (var pin = image.Memory.Pin())
                {
                    wb.WritePixels(region, (IntPtr)pin.Pointer, (int)image.Size, image.StrideBytes);
                }
            }
            using (wb.GetBitmapContext())
            {
                wb.FillEllipse(xLeft, yLeft, xLeft + 40, yLeft + 40, Colors.Red);
                wb.FillEllipse(xRight, yRight, xRight + 40, yRight + 40, Colors.Blue);
            }

            return wb;
        }
    }
<Image  x:Name="Image1"  Stretch="UniformToFill" />

Termino con il link al sito di Microsoft:

Documentazione su Microsoft.Com