Do you have a project that you are using the Kinect 2.0 Face detection as well as one, or more, of the other feeds from the Kinect? Well I am, and I was having issues with obtaining all the Frames I wanted from the Kinect. Let’s start with a brief, highlevel, overview, I had a need to obtain the data relating to the Color Image, the Body Tracking, and the Face Tracking. Seems very straight forward until I realized that the Face Data was not included in the MultiSourceFrameReader class. That reader only provided me the Color and Body frame data. In order to get the Face data I needed to use a FaceFrameReader. Which required me to listen for the arrival of two frame events.
For example, I was doing something like this.
public MainWindowViewModel() { _kinectSensor = KinectSensor.GetDefault(); const FrameSourceTypes frameTypes = FrameSourceTypes.Color | FrameSourceTypes.Body; MultiSourceFrameReader kinectFrameReader = _kinectSensor.OpenMultiSourceFrameReader( frameTypes ); kinectFrameReader.MultiSourceFrameArrived += OnMultiSourceFrameArrived; const FaceFrameFeatures faceFrameFeatures = FaceFrameFeatures.BoundingBoxInColorSpace | FaceFrameFeatures.RotationOrientation | FaceFrameFeatures.FaceEngagement; faceFrameSource = new FaceFrameSource( _kinectSensor, 0, faceFrameFeatures ); faceFrameReader = faceFrameSources.OpenReader(); faceFrameReader.FrameArrived += OnFaceFrameArrived; _kinectSensor.IsAvailableChanged += OnSensorAvailableChanged; _kinectSensor.Open(); } private void OnMultiSourceFrameArrived( object sender, MultiSourceFrameArrivedEventArgs e ) { //Process Color and Body Frames } private void OnFaceFrameArrived( object sender, FaceFrameArrivedEventArgs e ) { //Process Face frame }
In theory, this should not be a problem because the Kinect is firing off all frames at around 30 per second and, I assume, in unison. However, I was running into the issue that if my processing of the Face data took longer then the 30th of a second I had to process, the color or body data could be at a different point in the cycle. What I was seeing was images that appeared to be striped between two frames. Now I understand that this behavior could be linked of various issues that I am not going to dive into in this post. But what I had noticed was the more processing I tried to pack in to the Face Frame arrival handler, the more frequently I saw bad images. It is worth noting that my actual project will process all six of the faces that the Kinect can track, and when having to iterate through more then one face per frame, the bad, striped, images were occurring more then good images. This lead me to my conclusion (and my solution lead me to write this blog.)
I also did not like the above approach because it forced me to process frames in different places, and possibly on different cycles. So when something wasn’t working I had to determine which Frame was the offender, then go to that processing method. No bueno.
In trouble shooting the poor images, I had the thought “I just want the color and frame that the Face frame using.” Confused? I’ll try to explain. Basically, the Kinect Face tracking is using some conglomeration of the basic Kinect Feeds (Color, Depth, Body) to figure out what is a face, and the features of that face. I know this because if a body is not being tracked, a face is not being tracked. The depth is then use to track if the eyes are open or closed and other intricacies of the face. Anyways, back on track, I had a feeling that the Kinect Face Frame had, at least, some link back to the other frames that were used to determine the state of the face for that 30th of a second. That is when I stumbled upon FaceFrame.BodyFrameReference and FaceFrame.ColorFrameReference (FaceFrame.DepthFrameReference also exsits, it’s just not needed for my purposes). From those references you can get the respective frames.
After my epiphany my code turned into:
public MainWindowViewModel() { _kinectSensor = KinectSensor.GetDefault(); //Multiframe reader stuff was here. //It is now gone. const FaceFrameFeatures faceFrameFeatures = FaceFrameFeatures.BoundingBoxInColorSpace | FaceFrameFeatures.RotationOrientation | FaceFrameFeatures.FaceEngagement; faceFrameSource = new FaceFrameSource( _kinectSensor, 0, faceFrameFeatures ); faceFrameReader = faceFrameSources.OpenReader(); faceFrameReader.FrameArrived += OnFaceFrameArrived; _kinectSensor.IsAvailableChanged += OnSensorAvailableChanged; _kinectSensor.Open(); } private void OnFaceFrameArrived( object sender, FaceFrameArrivedEventArgs e ) { ... var bodyReference = faceFrame.BodyFrameReference; BodyFrame bodyFrame = bodyReference.AcquireFrame(); var colorReference = faceFrame.ColorFrameReference; ColorFrame colorFrame = colorReference.AcquireFrame(); //Process Face frame ... } private void ProcessBodyAndColorFrames( BodyFrame bodyFrame, ColorFrame colorFrame ) { //Process Body and Color Frames ... }
I still have the processing methods split out similarly to how I had them in the first (bad) way, but with this approach I am a little more confident that the Color and Body Frames and I analyzing are the same ones used by the Face processor. I am also more free to split up the processing as I see fit. The color and body are really only lumped together because that is how I was doing it before. In the future they might be split up and done in parallel, who knows.
And with that, the occurrence of bad images appears to be greatly reduced. At least for now. We will see how long it lasts. I still get some bad frames, but I am at least closer to being able to completely blame the Kinect, or poor USB performance, or something other than me (which is my ultimate goal.)
Not a big thing, just something I could not readily find on the web.