SOL9 Sample: SolFeatureDetector

SOL9 2.0 Samples

1 Screenshot







2 Source code

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


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

#define _CONSOLE_
#include <sol/Pair.h>
#include <sol/ModuleFileName.h>
#include <sol/DropFiles.h>
#include <sol/Label.h>
#include <sol/ComboBox.h>
#include <sol/ComboBoxColorChooser.h>
#include <sol/PushButton.h>

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


namespace SOL {

class MainView :public OpenCVApplicationView {
private:
  typedef enum {
      /* AgastFeatureDetector */   DETECTOR_AGAST,
      /* AKAZEFeatureDetector */   DETECTOR_AKAZE,
      /* BRISKFeatureDetector */   DETECTOR_BRISK,
      /* FastFeatureDetector  */   DETECTOR_FAST,
      /* GFTTDetector         */   DETECTOR_GFTT,
      /* KAZEFeatureDetector  */   DETECTOR_KAZE,
      /* MSERFeatureDetector  */   DETECTOR_MSER,
      /* ORBFeatureDetector   */   DETECTOR_ORB,
  } DETECTOR;
  
private:
  ////////////////////////////////////////////////////////////////////////////////////////
  //Inner classes start.
  class OriginalImageView :public OpenCVImageView {
  private:
    cv::Mat originalImage;
    
    //This is a mandatory method, because in parent class it's declared
    //as a pure virtual function.
    cv::Mat& getMat()
    {
      return originalImage;
    }
    
    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)
    {
      try {
        originalImage = readImage(filename, imageLoadingFlag);
        refresh();
      } catch (Exception& ex) {
        caught(ex);
      }
    }
  };
  
  class DetectedImageView :public OpenCVImageView {
  private:
    cv::Mat originalImage;
    cv::Mat detectedImage;
    
    cv::Mat& getMat()
    {
      return detectedImage;
    }
    
    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)
    {
      try {
        originalImage = readImage(filename, imageLoadingFlag);
        detectedImage  = originalImage;
        refresh();
      } catch (Exception& ex) {
        caught(ex);
      }
    }
    
    void clear()
    {
      cv::Mat image = originalImage.clone();
      detectedImage = image;
      refresh();
    }
    
    void detect(DETECTOR detectorIndex, BYTE b, BYTE g, BYTE r)
    {
      cv::Mat image = originalImage.clone();
      detectedImage.release();// = cv::Mat::ones(originalImage.size(), originalImage.type() );
      
      std::vector<cv::KeyPoint> keypoints;
      switch (detectorIndex) {
        case DETECTOR_AGAST: {      
              Ptr<AgastFeatureDetector> detector =  cv::AgastFeatureDetector::create(); 
              detector->detect(image, keypoints);
            }
            break;
        
      case DETECTOR_AKAZE:{
              Ptr<AKAZE> detector =  cv::AKAZE::create();
              detector->detect(image, keypoints);
            }
            break;
        
      case DETECTOR_BRISK: {
              Ptr<BRISK> detector =  cv::BRISK::create();
              detector->detect(image, keypoints);
            }
            break;
        
      case DETECTOR_FAST: {
              Ptr<FastFeatureDetector> detector =  cv::FastFeatureDetector::create();
              detector->detect(image, keypoints);
            }
            break;
        
      case DETECTOR_GFTT:{
              Ptr<GFTTDetector> detector =  cv::GFTTDetector::create();
              detector->detect(image, keypoints);
            }
            break;
        
      case DETECTOR_KAZE:{
              Ptr<KAZE> detector =  cv::KAZE::create();
              detector->detect(image, keypoints);              
            }
            break;
      case DETECTOR_MSER: {
              Ptr<MSER> detector =  cv::MSER::create();
              detector->detect(image, keypoints);
            }
            break;
      case DETECTOR_ORB:{
              Ptr<ORB> detector =  cv::ORB::create();  //use default argments
              detector->detect(image, keypoints);
            }
            break;
      default:
        break;
      } 
      drawKeypoints(image, keypoints, detectedImage, cv::Scalar(b, g, r));
      refresh();
    } 
  };
  //Inner classes end.
  ////////////////////////////////////////////////////////////////////////////////////////
  
  
  StringT<char>                   imageFile;
  StringT<char>                   savedImageFile;
  
  SmartPtr<OriginalImageView>     originalImage;
  SmartPtr<DetectedImageView>     detectedImage;
  
  SmartPtr<Label>                 detectorLabel;
  SmartPtr<ComboBox>              detectorComboBox;
  
  SmartPtr<Label>                 keyPointColorLabel;
  SmartPtr<ComboBoxColorChooser>  keyPointColorChooser;
  
  DETECTOR                        detectorIndex;
  COLORREF                        keyPointColorRGB;
  BYTE                            keyPointColorRed;
  BYTE                            keyPointColorGreen;
  BYTE                            keyPointColorBlue;
  
  SmartPtr<PushButton>            clearButton;
  SmartPtr<PushButton>            detectButton;
  
  FileDialog                      filedlg;

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

  void resize(int w, int h)
  {
    int workw = 170;
    
    if (originalImage && detectedImage) {
      originalImage        -> reshape(2,              2,  (w-workw)/2-1,    h-4);
      detectedImage        -> reshape((w-workw)/2+1,  2,  (w-workw)/2-1,    h-4);
      
      detectorLabel       -> reshape(w - workw+5,  10,  workw-20, 28);
      detectorComboBox    -> reshape(w - workw+5,  35,  workw-20, 120);
      
      keyPointColorLabel   -> reshape(w - workw+5, 80,  workw-20, 28);
      keyPointColorChooser -> reshape(w - workw+5, 105,  workw-20, 180);
      
      clearButton         -> reshape(w - workw+20, 160,  120,      30);
      detectButton         -> reshape(w - workw+20, 210,  120,      30);
      
    }
  }

  const Pair<char*, DETECTOR>* getDetectorsList(int& count)
  {
    static const Pair<char*, DETECTOR> detectors[] = {
      {"AgastFeatureDetector", DETECTOR_AGAST},
      {"AKAZEFeatureDetector", DETECTOR_AKAZE},
      {"BRISKFeatureDetector", DETECTOR_BRISK},
      {"FastFeatureDetector",  DETECTOR_FAST},
      
      {"GFTTDetector",         DETECTOR_GFTT},
      {"KAZEFeatureDetector",  DETECTOR_KAZE},
      {"MSERFeatureDetector",  DETECTOR_MSER},
      {"ORBFeatureDetector",   DETECTOR_ORB},
    };
    
    count = CountOf(detectors);
    return detectors;
  }
  
  void confirm(Action& action)
  {
    int rc = MessageBox(NULL, "Are you sure to close this window?", "Confirmation", 
                MB_OKCANCEL|MB_ICONEXCLAMATION);
    if (rc == IDOK) {
      exit(action);
    }
  }
  
  void   createImageView()
  {  
    imageFile = "..\\images\\Geometry.png";
      
    int  imageLoadingFlag = CV_LOAD_IMAGE_COLOR;
    Args ar;
    ar.set(XmNimageFileName, imageFile);
    ar.set(XmNimageLoadingFlag, imageLoadingFlag);
    originalImage = new OriginalImageView(this, "cvwindow1", ar); 
    originalImage -> addCallback(XmNdropCallback, this,
      (Callback)&MainView::dropFiles, NULL);
    
    ar.reset();
    ar.set(XmNimageFileName, imageFile);
    ar.set(XmNimageLoadingFlag, imageLoadingFlag);
    detectedImage = new DetectedImageView(this, "cvwindow2", ar); 
  }
  
  void detectorChanged(Action& action)
  {
    detectorIndex = (DETECTOR)detectorComboBox->getCurSel();
    //char text[128];
    //sprintf_s(text, CountOf(text), "detector %d", detectorIndex);
    if (detectedImage) {
      detectedImage -> detect(detectorIndex, keyPointColorBlue,  keyPointColorGreen, keyPointColorRed);
    }
  }
  
  void createDetectorInterface()
  {
    Args ar;
    detectorLabel      = new Label(this, "Detector", ar);
    
    ar.reset();
    ar.set(XmNstyle, CBS_DROPDOWNLIST);
    detectorComboBox   = new ComboBox(this, "", ar);
    
    int count = 0;
    const Pair<char*, DETECTOR>* detectors = getDetectorsList(count);

    for (int i =0; i<count; i++) {
      detectorComboBox->addString(detectors[i].first);
    }
    detectorIndex  = DETECTOR_AGAST;
    detectorComboBox -> setCurSel((int)detectorIndex);
    detectorComboBox -> addCallback(XmNselChangeCallback, this,
        (Callback)&MainView::detectorChanged, NULL);
  }
  
  
  long colorChoosed(Event& event)
  {
    //This is not a BGR
    keyPointColorRGB = (COLORREF)event.getLParam();
    keyPointColorRed   = GetRValue(keyPointColorRGB);
    keyPointColorGreen = GetGValue(keyPointColorRGB);
    keyPointColorBlue  = GetBValue(keyPointColorRGB);
    
    if (detectedImage) {
      detectedImage -> detect(detectorIndex, keyPointColorBlue,  keyPointColorGreen, keyPointColorRed);
    }
    return 1;
  }
  
  void createColorSettingInterface()
  {
    Args ar;
    keyPointColorLabel = new Label(this, "KeyPointColor", ar);
    
    ar.reset();
    //ar.set(XmNstyle, CBS_DROPDOWNLIST);
    ar.set(XmNstyle, WS_VISIBLE);
    ar.set(XmNitemHeight, 32);
    ar.set(XmNrgbStep, 0x128);
    //ar.set(XmNrgbStep, 0x20);
    keyPointColorChooser = new ComboBoxColorChooser(this, "", ar);
    keyPointColorChooser -> setCurrentSelection("#FF0000"); //Red
    
    keyPointColorRGB   = RGB(0xff, 00, 00);
    keyPointColorRed   = GetRValue(keyPointColorRGB);
    keyPointColorGreen = GetGValue(keyPointColorRGB);
    keyPointColorBlue  = GetBValue(keyPointColorRGB);
    
    addEventHandler(WM_COMBOBOX_COLORCHOOSER_SELCHANGED, this,
      (Handler)&MainView::colorChoosed, NULL);
  }
  
  void clear(Action& action)
  {
    if (detectedImage) {
      detectedImage -> clear();
    }
  }
  
  void detect(Action& action)
  {
    if (detectedImage) {
      detectedImage -> detect(detectorIndex, keyPointColorBlue,  keyPointColorGreen, keyPointColorRed);
    }
  }
  
  void createOperationInterface()
  {
    Args ar;
    clearButton = new PushButton(this, "Clear", ar);
    clearButton -> addCallback(XmNactivateCallback, this,
      (Callback)&MainView::clear, NULL);
    
    ar.reset();
    detectButton = new PushButton(this, "Detect", ar);
    detectButton -> addCallback(XmNactivateCallback, this,
      (Callback)&MainView::detect, NULL);
  }
    
  void openFile(const char* filename)
  {
    try {
      originalImage -> loadImage(filename);
      detectedImage  -> loadImage(filename);
      const char* fname = strrchr(filename, '\\');
      if (fname) {
        fname++;
      }
      imageFile = fname;

      detectedImage -> detect(detectorIndex, keyPointColorBlue,  keyPointColorGreen, keyPointColorRed);

      updateCaption();  
      
    } catch (Exception& ex) {
      caught(ex);
    }
  }
  
  
  void dropFiles(Action& action)
  {
    char fileName[MAX_PATH] = { 0 };
    DropFiles drop((HDROP)action.getWParam());

    int num = drop.queryFile(0, fileName, CountOf(fileName));
    if(num > 0) {
      if (filedlg.isImageFileName(fileName)) {
        openFile(fileName);
        bringUp();
      } else {        
        bringUp(); //Activate and raise this view
        showErrorDialog("Invalid image filename", fileName,  MB_OK);
      }
    }    
  }
  
public:
  MainView(OpenCVApplication& applet, const char* name, Args& args)
  :OpenCVApplicationView(applet, name, args)
  {
    try {
      createImageView();
      
      createDetectorInterface();

      createColorSettingInterface();

      addCallback(XmNmenuCallback, IDM_EXIT, this,
          (Callback)&MainView::confirm, NULL);

      createOperationInterface();
      
      detectedImage -> detect(detectorIndex, keyPointColorBlue,  keyPointColorGreen, keyPointColorRed);
   
      updateCaption(); 
      
      Args ar;
      ar.reset();
      ar.set(XmNfilter, FileDialog::getImageFilesFilter());
      filedlg.create(this, "OpenFile", ar);

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

  ~MainView()
  {
  }

  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);
    }
  }  
  
  //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,  900);
    args.set(XmNheight, 380);
    args.set(XmNbackground, (LONG_PTR)(COLOR_BTNFACE+1));
    args.set(XmNexStyle, (LONG_PTR)WS_EX_CONTROLPARENT);
  
    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.