Portfolio


Thursday, May 5, 2011

EmgCV Haar Classifiers Face and Facial Parts Detection

Hello folks..
after so many days of absence; im back with another emguCV project... Its about using haar classifier or commonly known as Haar Cascades in emguCV.

Those who doesn't kn ow much about haar classifiers well Essentially it's a variation on a visual Neural Network recognizer that breaks up the image into pieces that contain a specific feature (nose, mouth, etc) to improve accuracy over a full image neural network that might be confused by the object of interest's orientation or position within the image.

To know more about haar classifiers; follow that link after all who wants to get into all these definitions and bla bla bla ... :P at least I don't.. :P lets do some practical work man..!!!

I've borken the whole project in following steps

  • emguCv
  • Set Variables
  • Haar Cascade Files
  • Capute Video

1. emguCV

EmguCV is an openCV wrapper for .Net enviornment; right now, its only available for C#. You can download it from emguCV website. After downloading, include emguCV.dll in your project reference and add following references in your form

 using Emgu.CV;  
 using Emgu.Util;  
 using Emgu.CV.Structure;  
 using Emgu.CV.CvEnum;  
 using Emgu.CV.UI;  


2. Set Variables

Now set the private variables that we'll use throughout the project

   public partial class frmCapture : Form  
   {  
     private Capture cap; // used to caprute image from device  
     private HaarCascade haar, LEye, REeye, Mouth, Nose, hand; //haar classifiers for different parts  
     private Bitmap bmp, leftE, rightE, faceCrop, Mouthb; //bitmaps  
     private Bitmap facee; //bitmap of face  
     private Image<Gray, byte> MouthImg, LeyeImg, ReyeImg, Noseb; //cropped areas of face  
     private Rectangle CropArea;   
     public frmCapture()  
     {  
       InitializeComponent();  
     }  

3. Haar Cascade Files

You have to load haar cascade files now; they're nothing but simple xml files but pretty long having data about every facial part

 private void frmCapture_Load(object sender, EventArgs e)  
     {  
       cap = new Capture(0);  // device captutre; 0 is for default device
       haar = new HaarCascade("haarcascade_frontalface_alt.xml");   //haar cascade for face
       LEye = new HaarCascade("ojoI.xml");     //haar cascade for left eye
       REeye = new HaarCascade("ojoD.xml");     //haar cascade for right eye
       Mouth = new HaarCascade("Mouth.xml");     //haar cascade for mouth
       Nose = new HaarCascade("Nariz.xml");     //haar cascade for nose
       hand = new HaarCascade("A_gest.xml");     //haar cascade for hand
     }  

4. Capture Video

For video capturing; im using conventional technique of placing my code in timer control's timer_tick function

  //I've used timer control for continious detection.  
     private void timer1_Tick(object sender, EventArgs e)  
     {  
       //use "using" for better memory performance.  
       using (Image<Bgr, byte> nextframe = cap.QueryFrame()) //cap.QueryFrame() automatically detects default capture device.  
       {  
         if (nextframe != null)  
         {  
           Image<Gray, byte> grayframe = nextframe.Convert<Gray, byte>();  
           grayframe._EqualizeHist();  
           //Detect Face  
           var faces = grayframe.DetectHaarCascade(haar, 1.4, 4, HAAR_DETECTION_TYPE.DO_CANNY_PRUNING | HAAR_DETECTION_TYPE.FIND_BIGGEST_OBJECT, new Size(nextframe.Width / 8, nextframe.Height / 8))[0];   
           var nose = grayframe.DetectHaarCascade(Nose, 1.4, 4, HAAR_DETECTION_TYPE.DO_CANNY_PRUNING, new Size(nextframe.Width / 24, nextframe.Height / 12))[0];  
           var hands = grayframe.DetectHaarCascade(hand, 1.4, 4, HAAR_DETECTION_TYPE.DO_CANNY_PRUNING, new Size(24,24))[0];  
           facee = new Bitmap(nextframe.Width, nextframe.Height);  
           facee = nextframe.ToBitmap();  
           foreach (var han in hands)  
           {  
             nextframe.Draw(han.rect, new Bgr(0, 10, 10), 3);  
           }  
           foreach (var face in faces)  
           {  
             nextframe.Draw(face.rect, new Bgr(0, double.MaxValue, 0), 3);  
             CropArea = new Rectangle(face.rect.X, face.rect.Y, face.rect.Width, face.rect.Height); //Crop face from image  
             faceCrop = facee.Clone(CropArea, facee.PixelFormat);  
           }  
           if (faceCrop != null)  
           {  
             Image<Bgr, byte> facePic = new Image<Bgr, byte>(faceCrop);  
             Image<Gray, byte> grayframeface = facePic.Convert<Gray, byte>();  
             //Detect Mouth  
             // it is detected from lower part of cropped face image  
             CropArea = new Rectangle(0, faceCrop.Height/2, faceCrop.Width, faceCrop.Height / 2);  
             bmp = new Bitmap(faceCrop.Width, faceCrop.Height / 2);  
             bmp = faceCrop.Clone(CropArea, faceCrop.PixelFormat);  
             Image<Bgr, byte> mouthpic = new Image<Bgr, byte>(bmp);  
             Image<Gray, byte> grayframemouth = mouthpic.Convert<Gray, byte>();  
             var mouth = grayframemouth.DetectHaarCascade(Mouth, 1.4, 4, HAAR_DETECTION_TYPE.SCALE_IMAGE | HAAR_DETECTION_TYPE.FIND_BIGGEST_OBJECT, new Size(grayframemouth.Width / 4, grayframemouth.Height / 4))[0];  
             foreach (var mou in mouth)  
             {  
                 grayframemouth.Draw(mou.rect,new Gray(), 2);  
                 CropArea = new Rectangle(mou.rect.X, mou.rect.Y, mou.rect.Width, mou.rect.Height);  
                 MouthImg = grayframemouth.Copy(CropArea);  
             }  
             //Detect Right Eye  
             // It is detected from upper right cropped part of face cropped image  
             CropArea = new Rectangle(0, 0, faceCrop.Width / 2, faceCrop.Height / 2);  
             bmp = new Bitmap(faceCrop.Width / 2, faceCrop.Height / 2);  
             bmp = faceCrop.Clone(CropArea, faceCrop.PixelFormat);  
             Image<Bgr, byte> ReyePic = new Image<Bgr, byte>(bmp);  
             Image<Gray, byte> greyreyepic = ReyePic.Convert<Gray, byte>();  
             var righteye = greyreyepic.DetectHaarCascade(REeye, 1.4, 4, HAAR_DETECTION_TYPE.DO_CANNY_PRUNING, new Size(ReyePic.Width/8,ReyePic.Height/8))[0];  
             foreach (var eyer in righteye)  
             {  
                 greyreyepic.Draw(eyer.rect, new Gray(), 2);  
                 CropArea = new Rectangle(eyer.rect.X, eyer.rect.Y, eyer.rect.Width, eyer.rect.Height);  
                 // greyreyepic.ROI = CropArea;  
                 ReyeImg = greyreyepic.Copy(CropArea);  
             }  
             //Detect Left Eye  
             CropArea = new Rectangle(faceCrop.Width / 2, 0, faceCrop.Width / 2, faceCrop.Height / 2);  
             bmp = new Bitmap(faceCrop.Width / 2, faceCrop.Height / 2);  
             bmp = faceCrop.Clone(CropArea, faceCrop.PixelFormat);  
             Image<Bgr,byte> LeyePic = new Image<Bgr, byte>(bmp);  
             Image<Gray, byte> greyleyepic = LeyePic.Convert<Gray, byte>();  
             var lefteye = greyleyepic.DetectHaarCascade(LEye, 1.4, 4, HAAR_DETECTION_TYPE.DO_CANNY_PRUNING, new Size(greyleyepic.Width / 8, greyleyepic.Height / 8))[0];  
           foreach (var eyel in lefteye)  
           {  
             greyreyepic.Draw(eyel.rect, new Gray(), 2);  
             CropArea = new Rectangle(eyel.rect.X, eyel.rect.Y, eyel.rect.Width, eyel.rect.Height);  
            //  greyleyepic.ROI = CropArea;  
             LeyeImg = greyleyepic.Copy(CropArea);  
           }  
             //Detect Nose  
           foreach (var nou in nose)  
           {  
             nextframe.Draw(nou.rect,new Bgr(Color.Black), 2);  
           }  
          MainVideo.Image = nextframe.ToBitmap(); ;  
          if (grayframeface != null)  
          {  
            piccropface.Image = grayframeface.ToBitmap();  
          }  
          bmp.Dispose();  
          if (grayframemouth != null)  
          {  
            cropmouth.Image = grayframemouth.ToBitmap();  
          }  
          if (greyreyepic != null)  
          {  
            piccropreye.Image = greyreyepic.ToBitmap();  
          }  
          if (greyleyepic != null)  
          {  
            piccropleye.Image = greyleyepic.ToBitmap();  
          }  
          if (MouthImg != null)  
          {  
            // picmouth.Image = Mouthb;  
            picmouth.Image = MouthImg.ToBitmap();  
          }  
          if (ReyeImg != null)  
          {  
            //   picrighteye.Image = rightE;  
            picrighteye.Image = ReyeImg.ToBitmap();  
          }  
          if (LeyeImg != null)  
          {  
            //  piclefteye.Image = leftE;  
            piclefteye.Image = LeyeImg.ToBitmap();  
          }  
          if (Noseb != null)  
          {  
            picnose.Image = Noseb.ToBitmap();  
          }  
         }  
         }  
       }  
 }  

Now let me tell you guys how the code actually work.. Al tough the code is self explanatory but still few things has to be discussed. First we capture and image from camera,convert it into gray scale and equalize histogram for better performance. Now see the code below

 var faces = grayframe.DetectHaarCascade(haar, 1.4, 4, HAAR_DETECTION_TYPE.DO_CANNY_PRUNING | HAAR_DETECTION_TYPE.FIND_BIGGEST_OBJECT, new Size(nextframe.Width / 8, nextframe.Height / 8))[0];   

The above code loads haar classifiers from our xml file and matches the gray scale image with it. We can also pass our properties like expected width & height of our face in image that'll make out face detection more precise and faster. We do similar things for nose, mouth and eyes..

To make visible the part of image where a face is detected; we draw a rectangle on that part of image with the code below

 foreach (var face in faces)  
           {  
             nextframe.Draw(face.rect, new Bgr(0, double.MaxValue, 0), 3);  
             CropArea = new Rectangle(face.rect.X, face.rect.Y, face.rect.Width, face.rect.Height); //Crop face from image  
             faceCrop = facee.Clone(CropArea, facee.PixelFormat);  
           }  

After we've find the face; we crop it from image and perform the haar classifier matching for nose, eyes and mouth on that part.. Father, we've also divide our face cropped image in three parts; upper left part will specifically detect for left eye; upper right part will detect for right eye while the whole lower part will be used to detect mouth.. This'll make our code run faster..



5. Screen Mockup





Last but not the least.. haar classifiers are best for working with static images. They doesn't give good result with live pattern matching
. So if your'e working with static images; it'll work like magic, but for live videos etc i'd prefer CAMSHIFT technique.. Your guys can check out my blog on CAMSHIFT here.


Don't forget to comment.. Suggestions are most welcome :)

Jazak Allah..

16 comments:

  1. Assalamu Alaikum Wahab!
    great work you've got going on here! i started implementing t but realized that i dont have those hand/eye/nose xml files that you have used ... :( where do i get those?

    by the way, im Mahvish from rawalpindi, a software engineering student. im working on my final year project. its related to face detection and recognition. we're developing it in c# and currently using EmguCV ourselves, also using the Viola Jones classifier.

    but we we're currently stuck in one place: the xml file that comes with the emgucv package wont detect faces from the classroom photos we've taken. so should we train our own xml? and have you worked in Aforge.NET? will that library work better? and could you possibly help us regarding face "recognition" from database too?

    i can mail you the details if you can help :)

    P.S: i've started my own website that gives basic tutorials for beginners in EmguCV, they might be helpful to people so hope you can link to them, and may i link to your tutorial too?

    http://fewtutorials.bravesites.com/

    Thanks for listening and thanks for the work!!! looking fowrward to ur xml files too ^_^

    ReplyDelete
  2. This comment has been removed by the author.

    ReplyDelete
  3. ok ok, i got the xmls and here's something for all:

    DOWNLOAD THIS PROJECT's DEMO I MADE:
    http://www.megaupload.com/?d=SOZ2UB1N

    i built this application based on what you have told here, and added following to your work:

    >> enhanced the functionality : added a browse button to extract face features from any .bmp or .jpg (*This works for a single face per frame/image.)

    >>filled in the missing code: now you can see the cropped nose too

    accept is as my thanks to you Mr. Wahab :)


    **--please drop by at http://fewtutorials.bravesites.com/ to support me.

    ReplyDelete
  4. Hey mahvish.. thanks for having such an interest in my work.. :) well i've checked out your site but didn't find any way to help you out.. :) so it'll be better if u gimme ur email id or something like i can contact you.. you can catch me on wahabkotwal@yahoo.com

    ReplyDelete
  5. OH MY GOD..... IM SO SORRY FOR WHAT I MAILED YOU EARLIER!!!! I TOTALLY MISUNDERSTOOD the mail.

    you probably wouldn't wanna reply anymore, but please know that i'm GRAVELY sorry coz something like that had happened to me before too... really really sorry :(

    ReplyDelete
  6. Hey great post....

    but where can I find the haar cascade files???

    can u mail it to me (prasadith@gmail.com) or point me in the right direction???

    I mainly need the classifiers for the hand...

    Thankx in advance...

    ReplyDelete
  7. Hi,

    Can you help me out...?

    I want to create my own haar classifier....
    Please mail me at rstanmoy@gmail.com about the total system of making haar classifier....

    It will be a great help of you as am working in my thesis about this...

    ReplyDelete
  8. This comment has been removed by the author.

    ReplyDelete
  9. This comment has been removed by the author.

    ReplyDelete
    Replies
    1. i need your code i am working on emotion detection using emgucv and haar cascade classifier i am totaly stuck on this phase...

      Delete
  10. Hi Wahab! can you please give me the mouth xml file? I am done with face and eye detection but can't find xml file for mouth detection please help!
    Thank You

    ReplyDelete
  11. hello Wahab!! hiii how r u?? i am software engineer and now my project is how to track only hand if body parts comes den i need only hand...only from my body want track hand or finger...please help me out....m very stuck in this thing...i was resourcing but didn't get properly... i want to use haar classifier...if you giv ur email - id....i can explain my real time project i am sure i l get much help..because already i read your articles carefully and m sure this one is the best...because i said you 15 days i was resourcing so....

    ReplyDelete
  12. do u know how to crop multiple face and display it

    ReplyDelete
  13. hellow wahab ,i am working on detection of ear , nose and mouth from the sideview of a face and i am unable to find any haar xml files for it all i could find are in front face
    could you help me out in this

    ReplyDelete
  14. my email id is mehroz.pak@gmail.com
    if you find or know anything mail me as soon as possible , i will be waiting

    ReplyDelete