OZ++ Sample: HOGPeopleDetector




/******************************************************************************  *  * Copyright (c) 2019 Antillia.com TOSHIYUKI ARAI. ALL RIGHTS RESERVED.  *  * Redistribution and use in source and binary forms, with or without  * modification, are permitted provided that the following conditions  * are met:  * 1. Redistributions of source code must retain the above copyright  *    notice, this list of conditions, and the following disclaimer.  *  * 2. The name of the author may not be used to endorse or promote products  *    derived from this software without specific prior written permission.  *  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  *  *  *  HOGPeopleDetector.cpp  *  *****************************************************************************/ //2018/04/10 //On cv::HOGDescriptor Struct, see:  https://docs.opencv.org/3.4.1/d5/d33/structcv_1_1HOGDescriptor.html /* //Constructor cv::HOGDescriptor::HOGDescriptor ( Size  _winSize, //Detection window size. Align to block size and block stride. Default value is Size(64,128).    Size  _blockSize,                                //Block size in pixels. Align to cell size. Default value is Size(16,16).    Size  _blockStride,                              //Block stride. It must be a multiple of cell size. Default value is Size(8,8).    Size  _cellSize,                                 //Cell size. Default value is Size(8,8).    int  _nbins,                                     //Number of bins used in the calculation of histogram of gradients. Default value is 9.    int  _derivAperture = 1,                         //not documented ?   double  _winSigma = -1,     int  _histogramNormType = HOGDescriptor::L2Hys,  //histogramNormType    double  _L2HysThreshold = 0.2,                   //L2-Hys normalization method shrinkage.    bool  _gammaCorrection = false,                  //Flag to specify whether the gamma correction preprocessing is required or not.    int  _nlevels = HOGDescriptor::DEFAULT_NLEVELS,  //Maximum number of detection window increases. Default value is 64.    bool  _signedGradient = false                    //Indicates signed gradient will be used or not.   )   ////////////////////////////////////////////////////// Please note the following attributes. Public Attributes  Size  blockSize    Block size in pixels. Align to cell size. Default value is Size(16,16). More... Size  blockStride    Block stride. It must be a multiple of cell size. Default value is Size(8,8). More... Size  cellSize    Cell size. Default value is Size(8,8). More... int  derivAperture    not documented More... float  free_coef    not documented More... bool  gammaCorrection    Flag to specify whether the gamma correction preprocessing is required or not. More... int  histogramNormType    histogramNormType More... double  L2HysThreshold    L2-Hys normalization method shrinkage. More... int  nbins    Number of bins used in the calculation of histogram of gradients. Default value is 9. More... int  nlevels    Maximum number of detection window increases. Default value is 64. More... UMat  oclSvmDetector    coefficients for the linear SVM classifier used when OpenCL is enabled More... bool  signedGradient    Indicates signed gradient will be used or not. More... std::vector< float >  svmDetector    coefficients for the linear SVM classifier. More... double  winSigma    Gaussian smoothing window parameter. More... Size  winSize    Detection window size. Align to block size and block stri  */ /* train_HOG.cpp See also: https://docs.opencv.org/3.4.1/d5/d77/train_HOG_8cpp-example.html#a34 */ //2019/01/03 #include <opencv2/stitching.hpp> #include <oz++/motif/Label.h> #include <oz++/motif/RowColumn.h> #include <oz++/motif/LabeledComboBox.h> #include <oz++/motif/LabeledTrackBar.h> #include <oz++/opencv/OpenCVScaleComboBox.h> #include <oz++/opencv/OpenCVMainView.h> #include <oz++/opencv/OpenCVImageView.h> #include <oz++/motif/FileOpenDialog.h> #include <opencv2/objdetect.hpp> #include <opencv2/features2d/features2d.hpp> namespace OZ { class MainView :public OpenCVMainView { private:    typedef enum {     DEFAULT      = 0,     DAIMLER      = 1,     USER_DEFINED = 2   } HOG_TYPE;      private:   ///////////////////////////////////////////////   //Inner classes start.   class OriginalImageView: public OpenCVImageView {   private:     cv::Mat originalImage;      cv::Mat scaledImage;          virtual void display()     {        show(scaledImage);     }     public:     OriginalImageView(View* parent, const char* name, Args& args)     :OpenCVImageView(parent, name, args)     {       try {         const char* filename = (const char*)args.get(XmNimageFileName);         int imageLoadingFlag = args.get(XmNimageLoadingFlag);         int scalingRatio = (int)args.get(XmNimageScalingRatio);         loadImage(filename, imageLoadingFlag, scalingRatio);         } catch (OZ::Exception ex) {         caught(ex);       }     }      ~OriginalImageView()     {     }          void loadImage(const char* filename,          int imageLoadingFlag= CV_LOAD_IMAGE_COLOR,                 int scalingRatio=100)     {       originalImage = readImage(filename, imageLoadingFlag);       scaleImage(originalImage, scaledImage, scalingRatio);     }         void rescale(int scalingRatio)     {       scaledImage.release();       scaleImage(originalImage, scaledImage, scalingRatio);     }   };   class DetectedImageView: public OpenCVImageView {   private:     cv::Mat originalImage;      cv::Mat grayImage;      cv::Mat detectedImage;      cv::Mat scaledImage;     //The scale image is displayed on this image view.     virtual void display()     {        show(scaledImage);     }     public:     DetectedImageView(View* parent, const char* name, Args& args)     :OpenCVImageView(parent, name, args)     {       try {         const char* filename = (const char*)args.get(XmNimageFileName);         int imageLoadingFlag = args.get(XmNimageLoadingFlag);         int scalingRatio = (int)args.get(XmNimageScalingRatio);         loadImage(filename, imageLoadingFlag, scalingRatio);       } catch (OZ::Exception ex) {         caught(ex);       }     }      ~DetectedImageView()     {     }          void loadImage(const char* filename,          int imageLoadingFlag= CV_LOAD_IMAGE_COLOR,                 int scalingRatio=100)     {       originalImage = readImage(filename, imageLoadingFlag);       detectedImage = originalImage.clone();       detectedImage.create( originalImage.size(), originalImage.type() );       //1 Convert it to a gray image.       cv::cvtColor(originalImage, grayImage, COLOR_BGR2GRAY);                 //2 Apply equalizeHist to the gray image.       cv::equalizeHist(grayImage, grayImage);                scaleImage(detectedImage, scaledImage, scalingRatio);     }         void rescale(int scalingRatio)     {       scaledImage.release();       scaleImage(detectedImage, scaledImage, scalingRatio);     }     void clear(int scalingRatio)     {       cv::Mat image = originalImage.clone();       detectedImage = image;       scaleImage(detectedImage, scaledImage, scalingRatio);       refresh();     }     void detect(HOG_TYPE descriptor,int scalingRatio)     {       detectedImage  = originalImage.clone();       //Please refer the method size_t HOGDescriptor::getDescriptorSize() const in opencv-3.4.1/module/objdetect/src/hog.cpp       //Note the following restrictions on blockSize, winSize, blockStride and cellSize:       // (blockSize.width % cellSize.width == 0 &&       //  blockSize.height % cellSize.height == 0);       //((winSize.width - blockSize.width) % blockStride.width == 0 &&        // (winSize.height - blockSize.height) % blockStride.height == 0)               cv::HOGDescriptor hog ;          switch(descriptor) {       case DEFAULT:         hog.winSize     = cv::Size(64,128);         hog.blockSize   = cv::Size(16, 16);         hog.blockStride = cv::Size( 8,  8);         hog.cellSize    = cv::Size( 8,  8);         hog.nbins       = 9;         hog.setSVMDetector(cv::HOGDescriptor::getDefaultPeopleDetector());          break;                case DAIMLER:         hog.winSize     = cv::Size(48, 96);         hog.blockSize   = cv::Size(16, 16);         hog.blockStride = cv::Size( 8,  8);         hog.cellSize    = cv::Size( 8,  8);         hog.nbins       = 9;         hog.setSVMDetector(cv::HOGDescriptor::getDaimlerPeopleDetector());          break;                case USER_DEFINED:         hog.winSize     = cv::Size(32,64);         hog.blockSize   = cv::Size( 8, 8);         hog.blockStride = cv::Size( 4, 4);         hog.cellSize    = cv::Size( 4, 4);         hog.nbins       = 9;         hog.setSVMDetector(cv::HOGDescriptor::getDefaultPeopleDetector());          break;       }          std::vector<cv::Rect> people;       hog.detectMultiScale(grayImage, people);              for (std::vector<cv::Rect>::const_iterator it = people.begin();                           it != people.end(); ++it) {         cv::Rect r = *it;         cv::rectangle(detectedImage, r.tl(), r.br(), CV_RGB(255, 0, 0), 3);       }       scaleImage(detectedImage, scaledImage, scalingRatio);     }   };   //Inner classes end.      private:   StringT<char>                 imageFile;   int                           imageLoadingFlag;   int                           imageScalingRatio; //percentage    SmartPtr<Label>               label;   SmartPtr<OriginalImageView>   originalImage;   SmartPtr<DetectedImageView>   detectedImage;   SmartPtr<RowColumn>           controlPane;   SmartPtr<OpenCVScaleComboBox> scaleComboBox;   HOG_TYPE                    descriptorIndex;   SmartPtr<LabeledComboBox>     descriptorComboBox;   SmartPtr<PushButton>          clearButton;   SmartPtr<PushButton>          detectButton;      SmartPtr<FileOpenDialog>      fileDialog; public:   void scaleChanged(Action& action)   {     int val = scaleComboBox->getScale();     if (val > 0 && imageScalingRatio != val) {       imageScalingRatio = val;       originalImage -> rescale(imageScalingRatio);        detectedImage -> rescale(imageScalingRatio);      }   }     void cancel(Action& action)   {     fileDialog->popdown();   }   void fileOpen(Action& action)   {     fileDialog->popup();   }   void updateLabel(const char* filename)   {      CompoundString cs(filename);      label->set(XmNlabelString, cs);       }   void ok(Action& action)   {     try {         imageFile  = fileDialog->getFileName();       const char* filename = (const char*)imageFile;       printf("filename: %s\n", filename);       fileDialog->popdown();            originalImage->invalidate();       originalImage->loadImage(filename,          imageLoadingFlag, imageScalingRatio);       originalImage->invalidate();       detectedImage ->loadImage(filename,          imageLoadingFlag, imageScalingRatio);        detectedImage->detect(descriptorIndex, imageScalingRatio);       updateLabel(filename);       resize(width(), height());       flush();     } catch (OZ::Exception& ex) {        caught(ex);     }    }   void resize(Dimension w, Dimension h)   {     int CP_WIDTH = 200;     int LB_HEIGHT = 30;     int ww =  w-CP_WIDTH;     int hh = h - LB_HEIGHT;     if (label && originalImage && detectedImage && controlPane       ) {       label        -> reshape(0, 0, w, LB_HEIGHT);        originalImage-> reshape(0, LB_HEIGHT, ww/2, hh);       detectedImage -> reshape(ww/2, LB_HEIGHT, ww/2-1, hh);             controlPane  -> reshape(ww-1, LB_HEIGHT, CP_WIDTH+1, hh);       //The following two lines are a workaround to erase garbage.       controlPane -> unmap();       controlPane -> map();     }     flush();   }   void descriptorChanged(Action& event)   {     descriptorIndex = (HOG_TYPE)descriptorComboBox -> getSelectedPosition();          detectedImage -> detect(descriptorIndex,                                  imageScalingRatio);   }   void clear(Action& event)   {     detectedImage -> clear(imageScalingRatio);   }   void detect(Action& event)   {     detectedImage -> detect(descriptorIndex,                                 imageScalingRatio);   } public:   MainView(OpenCVApplication& applet, const char* name, Args& args)   :OpenCVMainView(applet, name, args)    {     BulletinBoard* bboard = getBulletinBoard();     imageFile = "../images/Pedestrian8.png";     imageLoadingFlag = CV_LOAD_IMAGE_COLOR;     imageScalingRatio = 60; //%     try {       Args ar;       CompoundString fileNamecs(imageFile);       ar.set(XmNlabelString, fileNamecs);        ar.set(XmNalignment, XmALIGNMENT_BEGINNING);        label = new Label(bboard, "", ar);       ar.reset();       ar.set(XmNimageFileName, imageFile);       ar.set(XmNimageLoadingFlag, imageLoadingFlag);       ar.set(XmNimageScalingRatio, imageScalingRatio);       originalImage = new OriginalImageView(bboard, "", ar);       ar.reset();       ar.set(XmNimageFileName, imageFile);       ar.set(XmNimageLoadingFlag, imageLoadingFlag);       ar.set(XmNimageScalingRatio, imageScalingRatio);       detectedImage   = new DetectedImageView(bboard, "", ar);       ar.reset();       controlPane = new RowColumn(bboard, "", ar);       const char* defaultScale = "60%";       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);       const char* methods[] = {       "Default",       "Diamler",       "UserDefined",       };       CompoundStringList csl(methods, CountOf(methods));       descriptorIndex = DEFAULT;       CompoundString descriptor("Descriptor");       ar.reset();       ar.set(XmNlabelString, descriptor);       ar.set(XmNitems, csl);       ar.set(XmNselectedPosition, descriptorIndex);       ar.set(XmNitemCount, CountOf(methods));       descriptorComboBox = new LabeledComboBox(controlPane, "", ar);       descriptorComboBox -> addCallback(XmNselectionCallback, this,         (Callback)&MainView::descriptorChanged, NULL);             ar.reset();       clearButton = new PushButton(controlPane, "Clear", ar);       clearButton->addCallback(XmNactivateCallback, this,                  (Callback)&MainView::clear, NULL);       ar.reset();       detectButton = new PushButton(controlPane, "Detect", ar);       detectButton->addCallback(XmNactivateCallback, this,                  (Callback)&MainView::detect, NULL);       detectedImage->detect(descriptorIndex, imageScalingRatio);       ar.reset();       fileDialog = new FileOpenDialog(this, "FileOpenDialog", ar);       fileDialog  -> getOkButton()                   -> addCallback(XmNactivateCallback, this,                           (Callback)&MainView::ok, NULL);        sendConfigureEvent();      } 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,  900);     args.set(XmNheight, 380);     MainView view(applet, argv[0], args);     view.realize();     applet.run();        } catch (OZ::Exception& ex) {     caught(ex);   }   return 0; }