Kinect + Emgu

Sorry about the inactivity but having and a daytime job and girlfriend sometimes leaves us without time.

Started to play with Computer Vision and Kinect, didn’t done a big thing but I was completly unaware of how CV works and after reading a while about it I hear that Emgu is a great wrapper for openCV library.
In fact you can do some face detection without any worries at all.
So let’s do a hands-on on this library
For this example you need
and to make things even more easier Coding4Fun Kinect Toolkit
This last one is great for helping to pass the kinect raw data to bitmaps
I strongly recommend to read the Emgu documentation before using it… it may be tricky
So let’s start by creating a new windows project, after that it’s time to add the references.
Add the Microsoft.Research.Kinect reference that can be found on the .NET references and then the Coding4Fun dll, and all the dlls needed for Emgu.
references
As you can see Emgu as lots of references and on the bin folder you should add the unmanaged libraries like
cvextern.dll, opencv_calib3d220 and so on… As I said before check the Emgu documentation to know what to do…
On the design view I added a EmguCV.UI.ImageBox and called it imageBox1.
On the code I added
using Emgu.CV;
using Emgu.CV.UI;
using Emgu.CV.Structure;
using Emgu.Util;
using Emgu.CV.CvEnum;
using Microsoft.Research.Kinect.Nui;
using Coding4Fun.Kinect.WinForm;
This is all the using you will need to a simple a Face Detection.
To make this work we will need 3 objects
Kinect.Nui.Runtime,
Emgu.CV.Image
and since the face detection will use the HaarCascade Algorithm we will use the HaarCascade object provided by Emgu
HaarCascade algorith need an xml file from where it will learn the patterns to recognize a face, there are a lot of files for face detection over the internet and you can create your own following this guide as an example (there are lot’s of other guides covering this topic)
so
haar = new HaarCascade("haarcascade_frontalface_alt_tree.xml");

will populate the the haarCascade object with that file.

Then it’s time to initialize the kinect. For now I will only need the RGB camera so I will use the RuntimeOption.UseColor.
We also need to create the event VideoFrameReady in order to get the frames we are working with and finally open the VideoStream.
For those who are not familiar with VideoStream.Open, it will support 4 parameters, the ImageStreamType, poolSize (the minimun value is 2, this will work as a backbuffer for storing data in memory), the ImageResolution and finaly the ImageType:
kinect.Initialize(RuntimeOptions.UseColor);
kinect.VideoFrameReady += new EventHandler(kinect_VideoFrameReady);
kinect.VideoStream.Open(ImageStreamType.Video, 2, ImageResolution.Resolution640x480, ImageType.Color);
and this is it… the complete constructor should look like this:
public Form1()
{
      InitializeComponent();
      haar = new HaarCascade("haarcascade_frontalface_alt_tree.xml");
      kinect.Initialize(RuntimeOptions.UseColor);
      kinect.VideoFrameReady += new EventHandler(kinect_VideoFrameReady);
      kinect.VideoStream.Open(ImageStreamType.Video, 2, ImageResolution.Resolution640x480, ImageType.Color);
}
Now when there is a VideoFrameReady the event will be fired and call kinect_VideoFrameReady method. it will receive the sender and an ImageFrameReadyEventArgs where you can find the image data generated by the sdk
The first task will be convert the captured image to a bitmap and convert it again to a Emgu image so it can be processed
 Image kinImage = new Image(e.ImageFrame.ToBitmap());
this does the trick!
then using the Emgu colored image we will process that nasty face detection
So we will convert the the Colored Emgu Image to a Grayscale one (better for image processing):
Image grayframe = nextFrame.Convert();
and then we will retrieve all the faces detected on that frame using the haarCascade:
 grayframe.DetectHaarCascade(
                                    haar, 1.4, 4,
                                    HAAR_DETECTION_TYPE.DO_CANNY_PRUNING,
                                    new Size(grayframe.Width / 8, grayframe.Height / 8)
                                    )[0];
and finally for each face detected we will get the face rectangle and draw it over the initial image,
foreach (var face in faces)
{                         
    nextFrame.Draw(face.rect, new Bgr(0, double.MaxValue, 0), 3);                    
}
and finally set the image to the imagebox1.
imageBox1.Image = nextFrame;
for the lazy ones here is who like to copy paste without understanding the code (can’t figure why they do it) here it goees:
void kinect_VideoFrameReady(object sender, ImageFrameReadyEventArgs e)
      {
            Image kinImage = new Image(e.ImageFrame.ToBitmap());
            using (Image; nextFrame = kinImage)
            {
                if (nextFrame != null)
                {
                    // there's only one channel (greyscale), hence the zero index
                    Image grayframe = nextFrame.Convert();
                    var faces =
                            grayframe.DetectHaarCascade(
                                    haar, 1.4, 4,
                                    HAAR_DETECTION_TYPE.DO_CANNY_PRUNING,
                                    new Size(grayframe.Width / 14, grayframe.Height / 14)
                                    )[0];
                    foreach (var face in faces)
                    {
                        nextFrame.Draw(face.rect, new Bgr(0, double.MaxValue, 0), 3);
                    }
                    imageBox1.Image = nextFrame;
                }
            }
        }
So as you can see easy code 😀
you can download the .cs file with all the code needed to do it
Here is a small demo of how it works, i’m sorry about the low framerate (my capture software sucks) and bad light conditions but it’s already 2am and my girlfriend is sleeping next to me so it’s better to don’t have more light.
But it’s nice too see that it still can detect my face in such bad lightning conditions :)
with good lightning, the detection occurs flawlessly

Leave a Reply

Your email address will not be published. Required fields are marked *