OZ++ Sample: ObjectDetector



/******************************************************************************  *  * 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.  *  *  *  ObjectDetector.cpp  *  *****************************************************************************/ //2017/5/20 Modified to use OpenCVScrolledImage instead of OpenCVImageView //         to reduce excessive screen flickering on a window resizing. //2019/01/03 #include <opencv2/stitching.hpp> #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; }