OZ++ Sample: BoundingBoxDetector








/******************************************************************************  *  * Copyright (c) 2018 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.  *  *  *  BoudingBoxDetector.cpp  *  *****************************************************************************/ // #include <es++/gtkmm-3.0/Application.h> #include <es++/gtkmm-3.0/Label.h> #include <es++/gtkmm-3.0/LabeledTrackBar.h> #include <es++/gtkmm-3.0/FileOpenDialog.h> #include <es++/opencv-3.0/OpenCVMainView.h> #include <es++/opencv-3.0/OpenCVScrolledImageView.h> #include <es++/opencv-3.0/OpenCVScaleComboBox.h> using namespace Gtk; namespace Es { class MainView :public Es::OpenCVMainView { private:   ///////////////////////////////////////////////////////    //Inner classes start.   class OriginalImageView :public Es::OpenCVScrolledImageView {   public:     OriginalImageView()     {     }         void rescale(int scaling_ratio)     {       OpenCVScrolledImageView::scaleImage(scaling_ratio);     }   };   class DetectedImageView :public Es::OpenCVScrolledImageView {   private:     cv::Mat edgePreserved;     cv::Mat cannyEdgedImage;         cv::Mat gray_image;     cv::Mat detected_image;     public:     DetectedImageView()     {     }     void loadImage(const std::string& filename,          int imageLoadingFlag= CV_LOAD_IMAGE_COLOR,                 int scaling_ratio=100)     {       OpenCVScrolledImageView::loadImage(filename, imageLoadingFlag,                                 scaling_ratio);         cv::Mat& original_image = getOriginalImage();       detected_image = original_image.clone();       detected_image.create( original_image.size(), original_image.type() );       cv::cvtColor( original_image, gray_image, COLOR_BGR2GRAY );       scaleImage(gray_image, scaling_ratio);     }         void applyEdgePreservedFilter(double sigmaColor, double sigmaSpace,                             cv::Mat& image, cv::Mat& filtered )     {       //const int SIGMA_SPACE = 160;       //const int SIGMA_COLOR = 70;              try {         int flag = RECURS_FILTER ; //NORMCONV_FILTER is very slow;         cv::edgePreservingFilter(             image,              filtered,              flag,             sigmaSpace,        //(double)SIGMA_SPACE,              sigmaColor/100.0f); //(double)SIGMA_COLOR/100.0f);              } catch (cv::Exception& ex) {         ; //Ignore       }     }     void detect(int sigmacolor, int sigmaspace, int threshold1, int threshold2, int scaling_ratio)     {       threshold1 = (threshold1/2)*2 + 1;       threshold2 = (threshold2/2)*2 + 1;       Mat threshold_output;       std::vector<vector<Point> > contours;       std::vector<Vec4i> hierarchy;              cv::Mat& original_image = getOriginalImage();       //1 Apply EdgePreservedFilter to originalImage.       applyEdgePreservedFilter((double)sigmacolor, (double)sigmaspace,                  original_image, edgePreserved);           //2 Convert it to grayImage.       cv::cvtColor(edgePreserved, gray_image, COLOR_BGR2GRAY );                //3 Apply Canny edge detector to the grayImage.       cv::Canny(gray_image, cannyEdgedImage, threshold1, threshold2);              //4 Find contours from the detectedImage.       cv::findContours(cannyEdgedImage, contours,             hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );       std::vector<std::vector<cv::Point> > contours_poly( contours.size() );       std::vector<cv::Rect> boundRect( contours.size() );         //5 Get approximate polygonal coordinates from the contours, and       // bounding rectangles from the contours_polygons.       for( int i = 0; i < contours.size(); i++ ) {          cv::approxPolyDP(cv::Mat(contours[i]), contours_poly[i], 3, true );         boundRect[i] = boundingRect( Mat(contours_poly[i]) );       }              detected_image = original_image.clone();              //6 Find minimum x and y, and maximum w and h from the boundRect array.       int width  = detected_image.size().width;       int height = detected_image.size().height;       int x = width, y = height, w = 0, h = 0;       int sx = width, sy = height, ex = 0, ey = 0;       //       for( int i = 0; i< contours.size(); i++ )  {         int xx = boundRect[i].x;         int yy = boundRect[i].y;         int ww = boundRect[i].width;         int hh = boundRect[i].height;         int area = ww * hh;         int MIN_AREA = 10;         int MIN_X    = 10;         int MIN_Y    = 10;                 if (area > MIN_AREA) {           if (xx < sx && xx > MIN_X)             sx = xx;           if (yy < sy && yy > MIN_Y)             sy = yy;                      if (xx > ex)              ex = xx;           if (yy > ey)             ey = yy;         }       }              int endx = x + w;       if (endx >= width)        endx = width;       int endy = y + h;       if (endy >= height)        endy = height;       int eex = sx + ex;       int eey = sy + ey;       if (eex > width)         eex = width - 4;       if (eey > height)         eey = height- 4;       //7 Draw a rectangle having a start Point(sx, sy) and end Point(ex, ey) on the contourImage.       cv::rectangle(detected_image, Point(sx, sy), Point(ex, ey), CV_RGB(255, 0, 0), 2, 8, 0 );                     scaleImage(detected_image, scaling_ratio);     }      void rescale(int scaling_ratio)     {       OpenCVScrolledImageView::scaleImage(detected_image, scaling_ratio);     }   };   // Inner classes end.   ///////////////////////////////////////////////////////    Es::Label              filepath;   Es::HorizontalLayout   horiz_layout;   Es::VerticalLayout     control_pane;   OriginalImageView      original_image;   DetectedImageView       detected_image;   int                    loading_flag;   Es::OpenCVScaleComboBox scale_combobox;   Es::LabeledTrackBar     sigmacolor_trackbar;   int                     sigmacolor;   Es::LabeledTrackBar     sigmaspace_trackbar;   int                     sigmaspace;   Es::LabeledTrackBar     threshold1_trackbar;   int                     threshold1;     Es::LabeledTrackBar     threshold2_trackbar;   int                     threshold2;     int                     scaling_ratio;  //Percentage.   static const int        CONTROLPANE_WIDTH = 180;   std::string             filename;     Es::FileOpenDialog      file_dialog; public:   //////////////////////////////////////////////   //Constructor   //   MainView(Es::Application& applet,            std::string&      name,           Es::Args&         args)   :OpenCVMainView(applet, name, args)   ,scaling_ratio(100)  //100%   ,file_dialog(*this, Es::FileOpenDialog::IMAGE_FILES)   {     int w = (int)args.get(XmNwidth);     int h = (int)args.get(XmNheight);     int ratio = (int)args.get(XmNscalingRatio);     scaling_ratio = OpenCVImageView::validateScale(ratio);     Es::MainLayout& main_layout = get_main_layout();     main_layout.pack_start(filepath, FALSE, FALSE, 0);     main_layout.pack_start(horiz_layout);     filename = "../../images/SuperCar2.png";     filepath.set_label(filename);     int ww = (w - CONTROLPANE_WIDTH)/2;     filepath.set_size_request(w, 30);     original_image.set_size_request(ww, h);     detected_image.set_size_request(ww, h);     control_pane.set_size_request( CONTROLPANE_WIDTH, h);     horiz_layout.pack_start(original_image);     horiz_layout.pack_start(detected_image);     horiz_layout.pack_start(control_pane, FALSE, FALSE, 0);     scale_combobox.set_selection(scaling_ratio);     sigmacolor = 160;     sigmacolor_trackbar.set_label("SigmaColor: [0, 200]");     sigmacolor_trackbar.configure_adjuster((double)sigmacolor, 0.0f, 200.0f);     sigmacolor_trackbar.set_value_changed_callback(             sigc::mem_fun(*this, &MainView::sigmacolor_value_changed) );     sigmaspace = 40;     sigmaspace_trackbar.set_label("SigmaColor: [0, 100]");     sigmaspace_trackbar.configure_adjuster((double)sigmaspace, 0.0f, 100.0f);     sigmaspace_trackbar.set_value_changed_callback(             sigc::mem_fun(*this, &MainView::sigmaspace_value_changed) );     threshold1 = 50;     threshold1_trackbar.set_label("Threshold1: [0, 300]");     threshold1_trackbar.configure_adjuster((double)threshold1, 0.0f, 300.0f);     threshold1_trackbar.set_value_changed_callback(             sigc::mem_fun(*this, &MainView::threshold1_value_changed) );     threshold2 = 100;     threshold2_trackbar.set_label("Threshold2: [0, 300]");     threshold2_trackbar.configure_adjuster((double)threshold2, 0.0f, 300.0f);     threshold2_trackbar.set_value_changed_callback(             sigc::mem_fun(*this, &MainView::threshold2_value_changed) );     control_pane.set_spacing(20);     control_pane.pack_start(scale_combobox, Gtk::PACK_SHRINK);     control_pane.pack_start(sigmacolor_trackbar, Gtk::PACK_SHRINK);     control_pane.pack_start(sigmaspace_trackbar, Gtk::PACK_SHRINK);     control_pane.pack_start(threshold1_trackbar, Gtk::PACK_SHRINK);     control_pane.pack_start(threshold2_trackbar, Gtk::PACK_SHRINK);     scale_combobox.set_changed_callback(              sigc::mem_fun(*this, &MainView::scale_changed) );     loading_flag = IMREAD_COLOR;     original_image.loadImage(filename, loading_flag, scaling_ratio);     detected_image.loadImage(filename, loading_flag, scaling_ratio);     detected_image.detect(sigmacolor, sigmaspace, threshold1, threshold2, scaling_ratio);     show_all();   }   void scale_changed()   {     std::string scale = scale_combobox.get_active_text();     printf("scale_changed %s\n", scale.c_str());     scaling_ratio = scale_combobox.get_selection();     original_image.rescale(scaling_ratio);     detected_image.rescale(scaling_ratio);   }   void sigmacolor_value_changed()   {     sigmacolor = (int)sigmacolor_trackbar.get_value();     detected_image.detect(sigmacolor, sigmaspace, threshold1, threshold2, scaling_ratio);   }   void sigmaspace_value_changed()   {     sigmaspace = (int)sigmaspace_trackbar.get_value();     detected_image.detect(sigmacolor, sigmaspace, threshold1, threshold2, scaling_ratio);   }   void threshold1_value_changed()   {     threshold1 = (int)threshold1_trackbar.get_value();          detected_image.detect(sigmacolor, sigmaspace, threshold1, threshold2, scaling_ratio);   }   void threshold2_value_changed()   {     threshold2 = (int)threshold2_trackbar.get_value();          detected_image.detect(sigmacolor, sigmaspace, threshold1, threshold2, scaling_ratio);   }   void file_open()   {     int rc = file_dialog.popup();     if (rc == Gtk::RESPONSE_OK) {       const std::string filename = file_dialog.get_filename();       filepath.set_label(filename);       original_image.loadImage(filename, loading_flag, scaling_ratio);       detected_image.loadImage(filename, loading_flag, scaling_ratio);       detected_image.detect(sigmacolor, sigmaspace, threshold1, threshold2, scaling_ratio);     }   } }; } int main(int argc, char** argv) {   Es::Environment env;   try {     std::string name = argv[0];     Es::Application applet(argc, argv);     Es::Args args;     args.set(XmNx, 20);     args.set(XmNy, 40);     args.set(XmNwidth, 900);     args.set(XmNheight, 400);     args.set(XmNscalingRatio, 60); //60%     Es::MainView mainv(applet, name, args);     mainv.show();     applet.run(mainv);   } catch (Es::Exception& ex) {     caught(ex);   } catch (...) {     printf("Get exception \n");   }   return 0; }