SOL9 Sample: SimpleBlobDetector

SOL9 2.0 Samples

1 Screenshot


2 Source code

/*
 * SimpleBlobDetector.cpp 
 * Copyright (c) 2015 Antillia.com TOSHIYUKI ARAI. ALL RIGHTS RESERVED. 
 */


//2017/12/01 Added save, saveAs methods to MainView.

#define _CONSOLE_

#include <sol/StringT.h>
#include <sol/LabeledTrackBar.h>

#include <sol/opencv/OpenCVApplicationView.h>
#include <sol/opencv/OpenCVImageView.h>
#include <sol/FileDialog.h>

namespace SOL {

class MainView :public OpenCVApplicationView {

private:
  ///////////////////////////////////////////////
  //Inner classes start.
  class OriginalImageView: public OpenCVImageView {
  private:
    cv::Mat originalImage; 
    
    cv::Mat& getMat()
    {
      return originalImage;
    }
    
    virtual void display()
    {
       show(originalImage);
    }
 
  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);

        loadImage(filename, imageLoadingFlag);
 
      } catch (SOL::Exception ex) {
        caught(ex);
      }
    } 

    ~OriginalImageView()
    {
    }
    
    void loadImage(const char* filename, 
              int imageLoadingFlag= CV_LOAD_IMAGE_COLOR)
    {
      originalImage = readImage(filename, imageLoadingFlag);
      refresh();
    }    

  };

  class DetectedImageView: public OpenCVImageView {
  private:
    cv::Mat originalImage; 
    cv::Mat grayScaleImage; 
    cv::Mat detectedImage; 

    cv::Mat& getMat()
    {
      return detectedImage;
    }
    
    //The scaled image is displayed on this image view.
    virtual void display()
    {
       show(detectedImage);
    }
 
  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);

        loadImage(filename, imageLoadingFlag);

      } catch (SOL::Exception ex) {
        caught(ex);
      }
    } 

    ~DetectedImageView()
    {
    }
    
    void loadImage(const char* filename, 
                     int imageLoadingFlag= CV_LOAD_IMAGE_COLOR)
    {
      originalImage = readImage(filename, imageLoadingFlag);
      cv::cvtColor(originalImage, grayScaleImage, cv::COLOR_BGR2GRAY);
      detectedImage  = grayScaleImage.clone();
      refresh();
    }    

    void detect(int minDist, int minArea, 
            int maxArea)
    {
      try {
        cv::SimpleBlobDetector::Params params;

        params.thresholdStep = 10.0;
        params.minThreshold = 50.0;
        params.maxThreshold = 220.0;
 
        params.filterByArea = true;
        params.minArea = minArea;
        params.maxArea = maxArea;

        params.filterByColor = true;
        params.blobColor     = 0;

        params.filterByCircularity = true;
        params.minCircularity = 0.5;

        params.filterByConvexity = true;
        params.minConvexity = 0.8;
 
        params.filterByInertia = true;
        params.minInertiaRatio = 0.1;
 
        params.minRepeatability = 2.0;
        params.minDistBetweenBlobs= 5.0;
        params.minDistBetweenBlobs= (double)minDist;

 
        Ptr<SimpleBlobDetector> detector = SimpleBlobDetector::create(params);
        std::vector<KeyPoint> keypoints;
 
        detector->detect(grayScaleImage, keypoints);
        
        drawKeypoints(grayScaleImage, keypoints, 
              detectedImage, CV_RGB(255, 0, 0), 
              DrawMatchesFlags::DRAW_RICH_KEYPOINTS );

 
        refresh();
        
      } catch (cv::Exception& ex) {
      }
    }
  };
  //Inner classes end.
    
private:

  StringT<char>                imageFile;
  StringT<char>                savedImageFile;
  
  int                          imageLoadingFlag;

  SmartPtr<OriginalImageView>  originalImage;
  SmartPtr<DetectedImageView>   detectedImage;

  static const int          TEMPLATE_WINDOW_SIZE_MAX = 31;
  int                       minAreaSize;  //7
  SmartPtr<LabeledTrackBar> minAreaSizeTrackBar;
 
  static const int          SEARCH_WINDOW_SIZE_MAX = 31;
  int                       maxAreaSize;  //21
  SmartPtr<LabeledTrackBar> maxAreaSizeTrackBar;

  static const int          H_PARAMETER_MAX = 31;
  int                       minDistBetweenBlobs;  //3
  SmartPtr<LabeledTrackBar> minDistBetweenBlobsTrackBar;

  FileDialog                filedlg;

public:

  void minAreaSizeScrolled(Action& action)
  {
    minAreaSize = minAreaSizeTrackBar->getPosition();
    detectedImage -> detect(minDistBetweenBlobs, minAreaSize, 
          maxAreaSize);
  }
  
  void maxAreaSizeScrolled(Action& action)
  {
    maxAreaSize = maxAreaSizeTrackBar->getPosition();
    detectedImage -> detect(minDistBetweenBlobs, minAreaSize, 
          maxAreaSize);
  }

  void minDistBetweenBlobsScrolled(Action& action)
  {
    minDistBetweenBlobs = minDistBetweenBlobsTrackBar->getPosition();
    detectedImage -> detect(minDistBetweenBlobs, minAreaSize, 
          maxAreaSize);
  }

  void updateCaption()
  {
    char caption[1024];
    sprintf_s(caption, CountOf(caption), "%s - %s", (const char*)imageFile, 
      getAppName());
    setText(caption);
  }
  

  void openFile(const char* filename)
  {
    try {  
      imageFile  = filename;
    
      //originalImage->invalidate();
      originalImage->loadImage(filename, imageLoadingFlag);

      //originalImage->invalidate();
      detectedImage ->loadImage(filename, imageLoadingFlag); 

      detectedImage -> detect(minDistBetweenBlobs, minAreaSize, 
                    maxAreaSize);

      updateCaption();
      
    } catch (SOL::Exception& ex) {
       caught(ex);
    } 
  }

  void resize(int w, int h)
  {
    int CP_WIDTH = 260;
    int ww =  w-CP_WIDTH;
    
    if (originalImage && detectedImage && minDistBetweenBlobsTrackBar &&
        minAreaSizeTrackBar && maxAreaSizeTrackBar) {
          
      originalImage-> reshape(0,      0, ww/2,   h);
      detectedImage -> reshape(ww/2,  0, ww/2-1, h);
      minDistBetweenBlobsTrackBar -> reshape(ww+1, 0, CP_WIDTH-2, 50);
      minAreaSizeTrackBar        -> reshape(ww+1, 60, CP_WIDTH-2, 50);
      maxAreaSizeTrackBar        -> reshape(ww+1, 120, CP_WIDTH-2, 50);
    }
  }

  void open(Action& action)
  {
    Args ar;
    
    char dir[MAX_PATH] = { 0 };
    if (restoreFileFolder(dir, CountOf(dir))) {
      ar.set(XmNdirectory, dir);
      filedlg.setValues(ar);
    }
    
    try {    
      if(filedlg.open()) {
    
        const char* filename = filedlg.getFileName();
        saveFileFolder(filename);
  
        openFile(filename);
      }
    } catch (Exception& ex) {
      caught(ex);
    }
  }  
  
public:
  MainView(OpenCVApplication& applet, const char* name, Args& args)
  :OpenCVApplicationView(applet, name, args) 
  {
    imageFile        = "../images/cat.jpg";
    imageLoadingFlag = CV_LOAD_IMAGE_COLOR;

    try {
      Args ar;
      ar.reset();
      ar.set(XmNimageFileName, (const char*)imageFile);
      ar.set(XmNimageLoadingFlag, imageLoadingFlag);

      originalImage = new OriginalImageView(this, "", ar);

      ar.reset();
      ar.set(XmNimageFileName, (const char*)imageFile);
      ar.set(XmNimageLoadingFlag, imageLoadingFlag);

      detectedImage   = new DetectedImageView(this, "", ar);
      
      //3 Create a minDistBetweenBlobsTrackBar.
      minDistBetweenBlobs    = 9;
      ar.reset();
      ar.set(XmNminimum, 5);
      ar.set(XmNmaximum, 100);
      ar.set(XmNposition, minDistBetweenBlobs);
      minDistBetweenBlobsTrackBar = new LabeledTrackBar(this, "MinDistanceBetweenBlob", ar);
      minDistBetweenBlobsTrackBar -> addCallback(XmNtrackBarScrollCallback, this,
        (Callback)&MainView::minDistBetweenBlobsScrolled, NULL);


      //4 Create a minAreaSizeTrackBar.
      minAreaSize    = 15;
      ar.reset();
      ar.set(XmNminimum, 1);
      ar.set(XmNmaximum, 100);
      ar.set(XmNposition, minAreaSize);
      minAreaSizeTrackBar = new LabeledTrackBar(this, "MinArea", ar);
      minAreaSizeTrackBar -> addCallback(XmNtrackBarScrollCallback, this,
        (Callback)&MainView::minAreaSizeScrolled, NULL);
            
      //5 Create a maxAreaSizeTrackBar.
      maxAreaSize    = 130;
      ar.reset();
      ar.set(XmNminimum, 100);
      ar.set(XmNmaximum, 2000);
      ar.set(XmNposition, maxAreaSize);
    
      maxAreaSizeTrackBar = new LabeledTrackBar(this, "MaxArea", ar);
      maxAreaSizeTrackBar -> addCallback(XmNtrackBarScrollCallback, this,
        (Callback)&MainView::maxAreaSizeScrolled, NULL);

      detectedImage -> detect(minDistBetweenBlobs, minAreaSize, 
            maxAreaSize);
      
       updateCaption();  

      ar.reset();
      ar.set(XmNfilter, FileDialog::getImageFilesFilter());
      filedlg.create(this, "OpenFile", ar);
      
      postResizeRequest(); 
      
    } catch(SOL::Exception& ex) {
      caught(ex);
    }
  }

  ~MainView()
  {
  }
  
  //2017/12/01
  void save(Action& action)
  {
    try {
      if (!savedImageFile.isEmpty()) {
        //Write detected image into the filename.
        detectedImage->writeImage(savedImageFile);
      } else {
        saveAs(action);
      }
    } catch (Exception& ex) {
      caught(ex);
    }
  }
  
  //2017/12/01
  void saveAs(Action& action)
  {
    Args ar;
    
    char dir[MAX_PATH] = { 0 };
    if (restoreFileFolder(dir, CountOf(dir))) {
      ar.set(XmNdirectory, dir);
      filedlg.setValues(ar);
    }
    
    try {    
      if(filedlg.save()) {
    
        const char* filename = filedlg.getFileName();
        saveFileFolder(filename);
        
        //Write detected image into the filename.
        detectedImage->writeImage(filename);
        savedImageFile = filename;
      }
    } catch (Exception& ex) {
      caught(ex);
    }
  }  

};

}

//
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,  940);
    args.set(XmNheight, 380);
    MainView view(applet, name, args);
    view.realize();

    applet.run();

  } catch (SOL::Exception& ex) {
    caught(ex);
  }
}


Last modified: 2 Dec. 2017

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