violetasdev / bodytrackingdepth_course

Course material for the "Body tracking with depth cameras" course
14 stars 4 forks source link

skeleton data #32

Closed hediiieh closed 6 months ago

hediiieh commented 2 years ago

hi, i wanted to thank you for these awsome courses. they helped me alot. im fairly new to this topic and i was wondering, is there a way to record the skeleton data from tutorial 5? or using kinect studio is the only option?

violetasdev commented 2 years ago

Hi @hediiieh

I am happy the course helped you!

There is a way to extract the skeleton joints and import them into a text file by coding it, no need to use Kinect Studio. Once you have the data imported, you can use Unity, for example, for the visualization.

The steps include:

  1. Create the data structure with the requirements you need from the body and the scene
  2. Generate the body data
  3. Use this object to save the body data
  4. Use the StreamWriter object to import your data to the file

As I read that you are new to this topic, that might not sound very clear. Like you, others might need it, so thank you for your question! I will work on a new tutorial with this functionality (hopefully in the following weeks) to be available and published here, with the hope of helping others.

hediiieh commented 2 years ago

hi, your tutorials are really awesome, specially for folks like me starting from zero. I recommend them to everyone. so thanks again You see, I love to record the skeleton data for image processing and machine learning purposes. the only way I found for recording data was with Kinect studio. I'll def look into what you said and your new tutorial would be very much appreciated.

violetasdev commented 6 months ago

Define first a timer if you need to save the data regularly:

public MainWindow()
        {
            // Initialize the sensor
            this.kinectSensor = KinectSensor.GetDefault();
            this.multiSourceFrameReader = this.kinectSensor.OpenMultiSourceFrameReader(FrameSourceTypes.Body | FrameSourceTypes.Color);
            this.multiSourceFrameReader.MultiSourceFrameArrived += this.Reader_MultiSourceFrameArrived;
            SetupCurrentDisplay(DEFAULT_DISPLAYFRAMETYPE);

            this.kinectSensor.Open();

            InitializeComponent();

            saveTimer = new Timer(3600000); // Set the interval to 3600000 milliseconds (1 hour, adjust as required)
            saveTimer.Elapsed += OnTimedEvent;
            saveTimer.AutoReset = true;
            saveTimer.Enabled = true;
        }

Now you need to store the skeleton data that is received by the sensor:

        private void Reader_MultiSourceFrameArrived(object sender, MultiSourceFrameArrivedEventArgs e)
        {

            MultiSourceFrame multiSourceFrame = e.FrameReference.AcquireFrame();
            BodyFrame bodyFrame = multiSourceFrame.BodyFrameReference.AcquireFrame();

            using (bodyFrame) {
                if (bodyFrame != null)
                {

                    //Get the number the bodies in the scene
                    bodies = new Body[bodyFrame.BodyFrameSource.BodyCount];
                    bodyFrame.GetAndRefreshBodyData(bodies);
                    // Save skeleton data to file
                    StoreSkeletonData(bodies);  // Save data to a file

Store the skeleton joints and any other data you require. In this example, I add for each sample the timestamp and the body ID:

        private void StoreSkeletonData(Body[] bodies)
        {
            var timestamp = DateTime.Now;
            var skeletonData = bodies.Where(b => b.IsTracked).Select(body => new
            {
                Timestamp = timestamp,
                BodyId = body.TrackingId,
                Joints = body.Joints.ToDictionary(j => j.Key.ToString(), j => new
                {
                    X = j.Value.Position.X,
                    Y = j.Value.Position.Y,
                    Z = j.Value.Position.Z,
                    TrackingState = j.Value.TrackingState.ToString()
                })
            }).ToList();

            periodicDataStorage.AddRange(skeletonData);
        }

        private void SaveSkeletonData()
        {

            if (periodicDataStorage.Any())
            {
                var json = JsonConvert.SerializeObject(periodicDataStorage, Json.Formatting.Indented);
                string filePath = $@"C:\temp\skeletonData_{DateTime.Now:_yyyyMMdd_HHmmss}.json";

            // Ensure the directory exists
            string directoryPath = System.IO.Path.GetDirectoryName(filePath);
            if (!Directory.Exists(directoryPath))
            {
                Directory.CreateDirectory(directoryPath);
            }

            // Write the JSON string to the file
            File.WriteAllText(filePath, json);

                periodicDataStorage.Clear();  // Clear the stored data after saving
            }    
        }

Finally, ensure that when closing the app, you save to a file any leftover data:

    private void Window_Closed(object sender, EventArgs e)
        {
            if (saveTimer != null)
            {
                saveTimer.Stop();
                saveTimer.Dispose();
            }
    ( rest of your code)
}