3.3.27 ObjectDetector

The following ObjectDetector is a simple example to detect faces, eyes, and bodies by using CascadeClassifier class of OpenCV. In OpenCV 4.8.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 "opencv/data/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 open dialog which can be popped up by clicking [...] button.
    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 ObjectDetector 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.




    //
    //ObjectDetector.cpp
    //Copyright (c) 2017 Antillia.com TOSHIYUKI ARAI. ALL RIGHTS RESERVED.
    
    #include <oz++/motif/Label.h>
    #include <oz++/motif/TextField.h>
    #include <oz++/motif/PushButton.h>
    #include <oz++/motif/RowColumn.h>
    #include <oz++/motif/FileDropdownComboBox.h>
    #include <oz++/motif/FileOpenDialog.h>
    #include <oz++/motif/FolderOpenDialog.h>
    #include <oz++/opencv/OpenCVMainView.h>
    #include <oz++/opencv/OpenCVImageView.h>
    #include <oz++/opencv/OpenCVScrolledImageView.h>
    #include <oz++/opencv/OpenCVScaleComboBox.h>
    #include <opencv2/objdetect/objdetect.hpp>
    
    namespace OZ {
    
    class MainView : public OpenCVMainView {
    
    private:
      //////////////////////////////////////////////
      //Inner class starts.
    
      class SimpleView  :public OpenCVScrolledImageView {
      private:
        cv::Mat originalImage;
        cv::Mat scaledImage;
    
        void display()
        {
          show(scaledImage);
        }
    
      public:
        SimpleView(View* parent, const char* name, Args& args)
        :OpenCVScrolledImageView(parent, name, args)
        {
          const char* filename = "";
          int   loadingFlag    = 1;
          int   scalingRatio   = 100;
    
          if (args.has(XmNimageFileName)) {
            filename = (const char*)args.get(XmNimageFileName);
          }
    
          if (args.has(XmNimageLoadingFlag)) {
            loadingFlag = (int)args.get(XmNimageLoadingFlag); 
          }
          if (args.has(XmNimageScalingRatio)) {
            scalingRatio = (int)args.get(XmNimageScalingRatio); 
          }
    
          loadImage(filename, loadingFlag, scalingRatio);
        }
    
        void loadImage(const char* filename, int loadingFlag, int scalingRatio)
        {
          originalImage = readImage(filename, loadingFlag);
          scaleImage(originalImage, scaledImage, scalingRatio); 
        }
    
        void rescale(int scalingRatio)
        {
          scaledImage.release();
          scaleImage(originalImage, scaledImage, scalingRatio); 
        }
     
        void clear(int scalingRatio)
        {
          rescale(scalingRatio); 
        }
    
        void detect(const char* path, int scalingRatio)
        {
          try {
            CascadeClassifier classifier;
            classifier.load(path);
          
            cv::vector<Rect> faces;
           classifier.detectMultiScale(originalImage, 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(originalImage, 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);
            }
            scaleImage(originalImage, scaledImage, scalingRatio); 
          } catch (Exception& ex) {
            caught(ex);
          }
        }
      };
      //Inner class ends.
      //////////////////////////////////////////////
    
      //SmartPtr<BulletinBoard>   bboard;
        SmartPtr<TextField>       filePath;
        SmartPtr<Label>            classifierLabel;
        SmartPtr<FileDropdownComboBox> classifierComboBox;
        SmartPtr<PushButton>      folderButton;
        StringT<char>            classifierFolder;
    
        SmartPtr<SimpleView>     view;
    
      SmartPtr<RowColumn>      controlPane;
        SmartPtr<OpenCVScaleComboBox>  scaleComboBox;
        SmartPtr<PushButton>   reloadButton;
        SmartPtr<PushButton>   detectButton;
    
      SmartPtr<FileOpenDialog> fileDialog;
      SmartPtr<FolderOpenDialog>  folderDialog;
    
      StringT<char>            imageFileName;
      int                      imageLoadingFlag;
      int                      imageScalingRatio;
    
      void fileOpen(Action& action)
      {
        fileDialog->popup();
      }
    
      void updateLabel(const char* filename)
      {
         CompoundString cs(filename);
         filePath->set(XmNlabelString, cs);    
         filePath->setString(filename);//, cs);    
      }
    
      void scaleChanged(Action& action)
      {
        int val = scaleComboBox->getScale();
    
        if (val > 0 && imageScalingRatio != val) {
          imageScalingRatio = val;
          view -> rescale(imageScalingRatio); 
        }
      }  
    
      void showFolderBrowser(Action& action)
      {
        folderDialog->popup();
      }
    
      void ok(Action& action)
      {
        try {  
          const char* filename = fileDialog->getFileName();
          imageFileName = filename;
          printf("filename: %s\n", filename);
          fileDialog->popdown();
          view->invalidate();
          view->loadImage(filename, 
            imageLoadingFlag, imageScalingRatio);
    
          updateLabel(filename);
    
          resize(width(), height());
          //flush();
        } catch (OZ::Exception& ex) {
           caught(ex);
        } 
      }
    
      void selectFolder(Action& action)
      {
        classifierFolder = folderDialog->getFolderName();
        printf("selectFolder %s\n", (const char*)classifierFolder);
       
        folderDialog->popdown();
        classifierComboBox->listupFiles((const char*)classifierFolder, "*.xml");
    
      }
    
      void reload(Action& action)
      {
         view -> loadImage(imageFileName,
                           imageLoadingFlag,
                           imageScalingRatio);
      }
    
      void detect(Action& action)
      {
        XmString xms;
        classifierComboBox->get(XmNselectedItem, (XtArgVal)&xms);
        CompoundString cs(xms);
        char* item = NULL;
        cs.get(&item);
        if (item != NULL) {
          char classifierxml[PATH_MAX];
          sprintf(classifierxml, "%s/%s", (const char*)classifierFolder,
               item); 
          printf("detect xml=%s\n", classifierxml);
          view -> detect(classifierxml, imageScalingRatio); 
        }
        XtFree(item);
      }
    
      void resize(Dimension w, Dimension h)
      {
        int CP_WIDTH = 160;
        int ww =  w-CP_WIDTH;
        static  int LH = 0;
        if (LH == 0) {
          LH = filePath->height();
        }
    
        static  int CH = 0;
        if (CH == 0) {
          CH = classifierComboBox->height();
        }
        static const int CL_WIDTH = 100;
        static const int FB_WIDTH = 60;
        if (filePath && classifierComboBox && view  && controlPane ) {
          BulletinBoard* bboard = getBulletinBoard();
          //bboard->unmap();
          //bboard->unmanage();
    
          int lh = LH;
          int ch = CH;
          int m = 2; 
          filePath              -> reshape(m, m, w, lh+m);
          classifierLabel    -> reshape(m, lh+2*m, CL_WIDTH, CH); 
          classifierComboBox -> reshape(2*m+CL_WIDTH, lh+2*m, w-CL_WIDTH-FB_WIDTH-4*m, CH);
          folderButton       -> reshape(w - FB_WIDTH, lh+2*m+m, FB_WIDTH-m, LH);
    
          view               -> reshape(m, lh+2*m + ch+2*m, ww-2*m, 
                        h - lh - ch -4*m-ch);
          Window cw = controlPane->getWindow();
          controlPane        -> reshape(ww-1, lh+2*m + ch+2*m, CP_WIDTH+1, 
                        h - lh - ch-4*m);
    
          //controlPane -> unmap();
          //controlPane -> map();
    
          //bboard->manage();
          //bboard->map();
        }
      }
    
    public:
      MainView(OpenCVApplication& applet, const char* name, Args& args)
      :OpenCVMainView(applet, name, args)
      {
        BulletinBoard* bboard = getBulletinBoard();
    
        try {
          Args ar;
          ar.reset();
    
          imageFileName     = "../images/WafukuMannequin.png";
    
          imageLoadingFlag  = CV_LOAD_IMAGE_COLOR;
          imageScalingRatio = 100;
    
          //1 Create a filePath to display a filename.
          ar.set(XmNalignment,  XmALIGNMENT_BEGINNING);
          filePath = new TextField(bboard, "", ar);
          filePath -> setEditable(False);
          updateLabel(imageFileName);
    
          CompoundString classifiercs("Classifier");
          ar.reset();
          ar.set(XmNalignment,  XmALIGNMENT_BEGINNING);
          ar.set(XmNlabelString, classifiercs);
          classifierLabel = new Label(bboard, "", ar);
    
          CompoundString foldercs("...");
          ar.reset();
          ar.set(XmNlabelString, foldercs);
          folderButton = new PushButton(bboard, "", ar);
          folderButton -> addCallback(XmNactivateCallback, this,
            (Callback)&MainView::showFolderBrowser, NULL);
    
          ar.reset();
          classifierComboBox = new FileDropdownComboBox(bboard, "", ar);
    
          //2 Create a simpleview.
          ar.reset();
          ar.set(XmNimageFileName,    imageFileName);
          ar.set(XmNimageLoadingFlag, imageLoadingFlag);
          ar.set(XmNimageScalingRatio, imageScalingRatio);
          view = new SimpleView(bboard, "", ar);
    
          //3 Create a controlPane.
          ar.reset();
          controlPane = new RowColumn(bboard, "", ar);
    
          //4 Create a scaleComboBox.
          const char* defaultScale = "100%";
          ar.reset();
          CompoundString scaler("Scale");
          ar.set(XmNlabelString, scaler);
          ar.set(XmNdefaultScale, defaultScale);
          scaleComboBox = new OpenCVScaleComboBox(controlPane, "", ar);
          scaleComboBox->addCallback(XmNselectionCallback, this,
            (Callback)&MainView::scaleChanged, NULL);
    
          CompoundString reloadcs("Reload");
          ar.reset();
          ar.set(XmNlabelString, reloadcs);
          reloadButton = new PushButton(controlPane, "", ar);
          reloadButton -> addCallback(XmNactivateCallback, this,
            (Callback)&MainView::reload, NULL);
    
          CompoundString detectcs("Detect");
          ar.reset();
          ar.set(XmNlabelString, detectcs);
          detectButton = new PushButton(controlPane, "", ar);
          detectButton -> addCallback(XmNactivateCallback, this,
            (Callback)&MainView::detect, NULL);
    
          const char* home = getenv("HOME");
    
          //5 Create a fileOpendialog
          ar.reset();
          ar.set(XmNrootFolderName, home);
          fileDialog = new FileOpenDialog(this, "FileOpenDialog", ar);
          fileDialog  -> getOkButton()
                      -> addCallback(XmNactivateCallback, this,
                              (Callback)&MainView::ok, NULL);  
    
          //5 Create a folderOpenDialog
          ar.reset();
          ar.set(XmNrootFolderName, home);
          folderDialog = new FolderOpenDialog(this, "FolderOpenDialog", ar);
          folderDialog  -> getOkButton()
                      -> addCallback(XmNactivateCallback, this,
                              (Callback)&MainView::selectFolder, NULL);  
        } catch (OZ::Exception& ex) {
          caught(ex);
        }
      }
    
      ~MainView()
      {
      }
    };
    
    }
    
    //
    int main(int argc, char** argv)
    {
      try {
        const char*  appclass = argv[0];
    
        OpenCVApplication applet(appclass, argc, argv);
    
        Args args;
        args.set(XmNwidth,  800);
        args.set(XmNheight, 460);
        MainView view(applet, argv[0], args);
        view.realize();
    
        applet.run();
      } catch (OZ::Exception& ex) {
        caught(ex);
      }
      return 0;
    }
    
    



    Last modified: 1 June 2017

     Last modified: 1 June 2017

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