4.23 How to detect faces in an image in OpenCV?

The following SolObjectDetector is a simple example to detect faces, eyes, and bodies by using CascadeClassifier class of OpenCV. In the latest OpenCV3.2.0, the following two types of cascade classifiers are available:

  • Harr Feature-based Cascade Classifier

  • LBP(Local binary pattern) Cascade Classifier

  • For example, you can find folders including these classifier files under the folder "C:\opencv3.2\build\etc".

    You need the following operations to use this program.

    1 Select a folder which contains Harr or LBP cascade classifiers by using a folder selection dialog.
    2 Select a cascade classifier xml file in a combobox.
    3 Open a target image file by using a file open dialog which can be popped up by Open menu item.
    4 Click Detect pushbutton.

    This SolObjectDetector is a simple and elementary GUI tool, but may be useful to evaluate characteristics of cascade classifiers for various images. Of course, this is far from simple in comparison with OpenCV HighGUI system, which you can start to use by learning only three APIs: cv::readimage, cvNamedWindow and cv::showImage.

    Selection of a cascade classifier xml file in a combobox.


    In this program, we use detectMultiScale method of cv::CascadeClassifier class to detect faces from cv::Mat image by using a seleccted classifier xml file path in the following way. See detect method of SimpleView.
     
       CascadeClassifier classifier;
       classifier.load(path);
       cv::vector faces;
       classifier.detectMultiScale(image, faces, 1.1, 3, 0, cv::Size(20,20));
    

    Face detection of a cat.



    Face and eyes detection of a mannequin.


    Eyes detection of a Nioh.


    
    /*
     * SolObjectDetector.cpp 
     * Copyright (c) 2017 Antillia.com TOSHIYUKI ARAI. ALL RIGHTS RESERVED. 
     */
    
    //2017/04/10
    
    #define _CONSOLE_
    
    #include <sol/ModuleFileName.h>
    #include <sol/FolderBrowser.h>
    #include <sol/Label.h>
    #include <sol/ComboBox.h>
    #include <sol/Profile.h>
    #include <sol/StringT.h>
    #include <sol/opencv/OpenCVObject.h>
    #include <sol/opencv/OpenCVApplicationView.h>
    #include <sol/opencv/OpenCVImageView.h>
    #include <sol/PushButton.h>
    #include <sol/FileDialog.h>
    #include <vector>
    #include "Resource.h"
    
    namespace SOL {
    
    class MainView :public OpenCVApplicationView {
    
    private:
      ////////////////////////////////////////////////////////////////////////////////////////
      //Inner class starts.
      class SimpleView :public OpenCVImageView {
      private:
        StringT<char>  filePath;
        int            loadFlag;
        cv::Mat        image;
    
        cv::Mat& getMat()
        {
          return image;
        }
        
        void display()
        {
          show(image);
        }
        
      public:
        SimpleView(View* parent, const char* name, Args& args)
        :OpenCVImageView(parent, name, args)
        {
          try {
            const char* filename = (const char*)args.get(XmNimageFileName);
            int imageLoadingFlag = (int)args.get(XmNimageLoadingFlag);
          
            loadImage(filename, imageLoadingFlag); //"..\\images\\WafukuMannequin.png");
          } catch (Exception& ex) {
            caught(ex);
          }
        }
        
        ~SimpleView()
        {
        }
         
        void loadImage(const char* filename, int flag=CV_LOAD_IMAGE_COLOR)
        {
          try {
            filePath = filename;
            loadFlag = flag;
            image    = readImage(filename, flag);
            
            postResizeRequest();
            
            refresh();
          } catch (Exception& ex) {
            caught(ex);
          }
        }
        
        void reload()
        {
          try {
            image    = readImage((const char*)filePath, loadFlag);
            postResizeRequest();
            refresh();
          } catch (Exception& ex) {
            caught(ex);
          }
        }
    
        void detect(const char* path)
        {
          try {
            CascadeClassifier classifier;
              classifier.load(path);
          
              cv::vector<Rect> faces;
              classifier.detectMultiScale(image, faces, 1.1, 3, 0, cv::Size(20,20));
            if (faces.size() == 0) {
              MessageBox(NULL, "Not detected by detectMultiScale.", 
                  "DetectOperation", MB_OK|MB_ICONINFORMATION); 
            }
              for (int i = 0; i < faces.size(); i++){
                  rectangle(image, Point(faces[i].x,                 faces[i].y), 
                                   Point(faces[i].x + faces[i].width, faces[i].y + faces[i].height),
                                   Scalar(0, 200, 0), 3, CV_AA);
              }
            refresh();
          } catch (Exception& ex) {
            caught(ex);
          }
        }
          
      };
      //Inner class endss
      ////////////////////////////////////////////////////////////////////////////////////////
      
      StringT<char>           imageFile;
      SmartPtr<SimpleView>    view;
      
      SmartPtr<Label>         label;
      SmartPtr<ComboBox>      comboBox;
      
      SmartPtr<FolderBrowser> folderBrowser;
      SmartPtr<PushButton>    classifierButton;
      SmartPtr<PushButton>    reloadButton;
      SmartPtr<PushButton>    detectButton;
      String                  selectedFolder;
    
      FileDialog              filedlg;
    
     void updateCaption()
      {
        char caption[MAX_PATH];
        sprintf_s(caption, CountOf(caption), "%s - %s", 
              (const char*)imageFile, 
              getAppName()); 
        setText(caption);
      }
      
      void resize(int w, int h)
      {
        if (label && comboBox && view && reloadButton && detectButton) {
          classifierButton-> reshape(  w-100+10,   4,     80,   28);
          label           -> reshape(         0,   4,    100,   28);
          comboBox        -> reshape(        90,   4,  w-190,  120);
          view            -> reshape(         0,  40,  w-100, h-45);
    
          reloadButton    -> reshape(w-100 + 10,  80,     80,   28);
          detectButton    -> reshape(w-100 + 10, 140,     80,    28);      
        }
      }
    
      void open(Action& action)
      {
        Args ar;
        
        char dir[MAX_PATH] = {0};
        //Restore previously select folder from a registry(profile of this application) for fileDialog
        if (restoreFileFolder(dir, CountOf(dir))) {
          ar.set(XmNdirectory, dir);
          filedlg.setValues(ar);
        }
        
        try {    
          if(filedlg.open()) {
            const char* filename = filedlg.getFileName();
            saveFileFolder(filename);
    
            view -> loadImage(filename, CV_LOAD_IMAGE_COLOR);
            imageFile = filename;
            const char* fname = strrchr(filename, '\\');
            if (fname) {
              fname++;
            }
            imageFile = fname;
            updateCaption();
          }
        } catch (Exception& ex) {
          caught(ex);
        }
      }
      
      void classifierFolder(Action& action)
      {
        if (folderBrowser->show(selectedFolder)) {        
          char pattern[MAX_PATH];
          sprintf_s(pattern, sizeof(pattern), "%s\\*.xml", (const char*)selectedFolder);
          comboBox->clear();
    
          comboBox->findFiles(pattern);
          comboBox->setCurSel(0);
        }
      }
    
      void reload(Action& action)
      {
        if (view) {
          view ->reload(); 
        }
      }
    
      void detect(Action& action)
      {
        try {
          char path[MAX_PATH];
          String filterName  = comboBox->getCurrentSelection();
        
          sprintf_s(path, sizeof(path), "%s\\%s", 
                  (const char*)selectedFolder, (const char*)filterName);
          if (view) {
            view->detect(path);
          }
        } catch (Exception& ex) {
          caught(ex);
        }
      }
    
      void confirm(Action& action)
      {
        int rc = MessageBox(NULL, "Are you sure to close this window?", "Confirmation", 
                    MB_OKCANCEL|MB_ICONEXCLAMATION);
        if (rc == IDOK) {
          exit(action);
        }
      }
      
    public:
      MainView(OpenCVApplication& applet, const char* name, Args& args)
      :OpenCVApplicationView(applet, name, args)
      {
        try {
          imageFile = "..\\images\\WafukuMannequin.png";
          Args ar;
          label = new Label(this, "Classifier", ar);
          
          ar.reset();
          classifierButton = new PushButton(this, "...", ar);
          classifierButton -> addCallback(XmNactivateCallback, this, 
            (Callback)&MainView::classifierFolder, NULL); 
    
          ar.reset();
          ar.set(XmNstyle, CBS_SORT|CBS_DROPDOWNLIST);
          comboBox = new ComboBox(this, "", ar);
        
          ar.reset();
          ar.set(XmNimageFileName,  imageFile);
          ar.set(XmNimageLoadingFlag, CV_LOAD_IMAGE_COLOR);
          view = new SimpleView(this, "cvwindow", ar); 
    
          addCallback(XmNmenuCallback, IDM_FILTER, this,
            (Callback)&MainView::classifierFolder, NULL);
        
          ar.reset();
          reloadButton = new PushButton(this, "Reload", ar);
          reloadButton -> addCallback(XmNactivateCallback, this, 
              (Callback)&MainView::reload, NULL); 
    
          ar.reset();
          detectButton = new PushButton(this, "Detect", ar);
          detectButton -> addCallback(XmNactivateCallback, this, 
              (Callback)&MainView::detect, NULL); 
        
          ar.reset();
          ar.set(XmNstartingDirectory, "C:\\dev\\opencv3.2");
          folderBrowser = new FolderBrowser(this, "FolderBrowser", ar);
    
          ar.reset();
          ar.set(XmNfilter, FileDialog::getImageFilesFilter());
          filedlg.create(this, "OpenFile", ar);
        
          addCallback(XmNmenuCallback, IDM_OPEN, this,
              (Callback)&MainView::open, NULL);
          addCallback(XmNmenuCallback, IDM_EXIT, this,
              (Callback)&MainView::confirm, NULL);
    
          updateCaption();
                
        } catch (Exception& ex) {
          caught(ex);
        }
      }
    
      ~MainView()
      {
      }
    };
    }
    
    //
    void main(int argc, char** argv) 
    
    {
      try {
        ModuleFileName module(argv[0]);
        
        const char*  name = module.getAppName();
        OpenCVApplication applet(name, argc, argv);
    
        Args args;
        args.set(XmNwidth,  700);
        args.set(XmNheight, 500);
        MainView view(applet, name, args);
        view.realize();
    
        applet.run();
        
      } catch (SOL::Exception& ex) {
        caught(ex);
      }
    }
    

    Last modified: 8 Apr. 2017

    Copyright (c) 2017 Antillia.com ALL RIGHTS RESERVED.