Thursday, July 14, 2011

Camera Face Detection in C# Using Emgu CV (OpenCV in .NET) and WPF

Face Detection
Hi there, this is a new tutorial category in my blog. It's Computer Vision. In this chance, I'd like to show you something cool. It's how to perform Face Detection using your camera / Webcam. You'll see how your application can detect faces from a captured image. Curious about it? Let's take a look how to do that.

This what you need to follow this tutorial:
  1. Microsoft Visual Studio 2010. Or if you don't have one, you can use 2008 version
  2. Emgu CV (OpenCV in .NET). You can download the latest version in this link: http://www.emgu.com/wiki/index.php/Main_Page and follow the installation instruction
  3. Basic Knowledge of C# Programming
  4. Familiar in WPF Development
After you've got what you need, it's time to rock!

1. First thing you should do is installing Emgu CV. Your installation path should be like C:\Emgu\emgucv-windows-x86 2.2.1.1150. And you can see inside C:\Emgu\emgucv-windows-x86 2.2.1.1150\bin some DLLs and sample programs. You can see a simple face detection app Example.FaceDetection.exe and you'll see something like the first picture in this post.
Emgu CV Installation Path

2. Next, let's open your Visual Studio and create a new WPF Project. Add some references and make sure it'll look like the picture below:
References

3. Now, copy code below to make our user experience. Put this code in your MainWindow.xaml file
<Window x:Class="WpfFaceDetectionTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="600" Width="800" Loaded="Window_Loaded">
    <Grid>
        <Image Name="image1" Stretch="Fill" />
    </Grid>
</Window>

4. Next, let's code it! Open your MainWindow.xaml.cs and add this code on top
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
using Emgu.CV.Structure;
using Emgu.CV;
using System.Runtime.InteropServices;

5. Initialize two objects Capture and HaarCascade. Those are important class in this tutorial, so you have to make it. And we also need DispatcherTimer to capture the picture every millisecond.
        private Capture capture;
        private HaarCascade haarCascade;
        DispatcherTimer timer;

        public MainWindow()
        {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            capture = new Capture();
            haarCascade = new HaarCascade(@"haarcascade_frontalface_alt_tree.xml");
            timer = new DispatcherTimer();
            timer.Tick += new EventHandler(timer_Tick);
            timer.Interval = new TimeSpan(0, 0, 0, 0, 1);
            timer.Start();
        }

6. This last part is the routine. What this code will do is capture image every millisecond, and then convert it to gray frame. After converted, faces will be detected. Each detected faces will be marked by black rectangular.
        void timer_Tick(object sender, EventArgs e)
        {
            Image<Bgr,Byte> currentFrame = capture.QueryFrame();

            if (currentFrame != null)
            {
                Image<Gray, Byte> grayFrame = currentFrame.Convert<Gray, Byte>();
                    
                var detectedFaces = grayFrame.DetectHaarCascade(haarCascade)[0];
                    
                foreach (var face in detectedFaces)
                    currentFrame.Draw(face.rect, new Bgr(0, double.MaxValue, 0), 3);
                    
                image1.Source = ToBitmapSource(currentFrame);
            }
            
        }

7. Finally, this additional code is needed to convert plain Bitmap Class to BitmapSource so WPF can read it as an image and view it on image1
        [DllImport("gdi32")]
        private static extern int DeleteObject(IntPtr o);

        public static BitmapSource ToBitmapSource(IImage image)
        {
            using (System.Drawing.Bitmap source = image.Bitmap)
            {
                IntPtr ptr = source.GetHbitmap(); //obtain the Hbitmap

                BitmapSource bs = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
                    ptr,
                    IntPtr.Zero,
                    Int32Rect.Empty,
                    System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());

                DeleteObject(ptr); //release the HBitmap
                return bs;
            }
        }

8. Here is the result of our work:
Single Face Detected
Two Faces Detected

Okay, I think that's all I can do in this post. See you to my next post. Keep blogging and fighting ^^

Note: If you can't run your project, just build it and make sure all opencv_xxxx.dll files and haarcascade_frontalface_alt_tree.xml in the same directory with your executable file. You can find those files inside C:\Emgu\emgucv-windows-x86 2.2.1.1150\bin


References:
http://friism.com/webcam-face-detection-in-c-using-emgu-cv
http://www.emgu.com/wiki/index.php/Main_Page

20 comments:

  1. can u give me another link to download emgu as above link is not working

    ReplyDelete
  2. @hfgh:
    The link is fine. Maybe it was under maintenance :)

    ReplyDelete
    Replies
    1. The Code won't work all it's giving me is a white window!

      Delete
    2. is that so? can you explain the details of your problem?

      Delete
  3. Hi:
    Am following your code, but hitting a problem
    in Capture.cs - would you be able to suggest a solution?:

    line 105: "Emgu.CV.CvInvoke threw an exception"

    also, no doubt related, "MainWindow" crashes and has to be closed using Task Manager...

    Setup:
    1) I have downloaded your code to desktop and have opened in MSVisual Studio C# 2010 Express.

    2) Have refreshed references to Emgu.CV, Emgu.CV.UI, Emgu.Util

    3) Have ensured that opencv_xxxx.dll files and haarcascade_frontalface_alt_tree.xml are in the bin folder of the execution directory...

    4) Hoping to capture image from built-in video cam on lenovo x200...

    Many thanks

    ReplyDelete
  4. @gettingstarted:
    Not sure what's the problem source. Maybe this thread can help to solve your problem:
    The type initializer for 'Emgu.CV.CvInvoke' threw an exception

    ReplyDelete
  5. Hi Junian.
    My son is building an master project in social communications area. He shows some photos during a random time. His experiment consist in calculate how many time the observer remains looking the photo.
    We think about start the time when the observer come in front of the picture (by webcam) and when he left, we calculate the time. Is it possible?

    ReplyDelete
  6. Hi Perceptra,
    It's possible. You can do that based on your description. Or, if you want to be better, you can also use face recognition.

    Good luck for your son's project. Hope this will help you and your son :)

    ReplyDelete
  7. Hiii!
    This is done in the WPF ? and how the performance of the video? i have an awful low FPS ! and i dunno why((

    ReplyDelete
    Replies
    1. yes, it's done with wpf,
      unfortunately i've got a low FPS too, because this code just plain straight

      Delete
    2. but the same code in WinForms work perfectly... it's very strange...

      Delete
    3. actually, it also can be done in winform... you just need to change the GUI from WPF to WinForm

      Delete
  8. hey, thanks for the tutorial. It's awesome :)

    ReplyDelete
  9. Hi All,

    I am getting the same problem with the slow frame rate in WPF.

    I have a functioning version in WinForms but I need this in WPF.

    I am stuck at the line

    var detectedFaces = grayFrame.DetectHaarCascade(haarCascade)[0];

    Removing this step means it doesn't detect the face and the frame rate speeds up to normal.

    I have used both haarcascade_frontalface_alt_tree and haarcascade_frontalface_default.

    ReplyDelete
  10. I was wondering if you could extend this solution to recognizing faces also? that'd be very helpfull to me! :)

    ReplyDelete
  11. It showed a blank window !! what's the problem ,please???

    ReplyDelete
  12. The type initializer for 'Emgu.CV.CvInvoke' threw an exception

    how can I fix this please ???

    ReplyDelete
  13. copy-paste article dumbass

    ReplyDelete

Please leave your comment here

Back to top