SOL9 Sample: YoloObjectDetector

SOL9 2.0 Samples

1 Screenshot









2 Source code

/*
 * YoloObjectDetector.cpp 
 * Copyright (c) 2019 Antillia.com TOSHIYUKI ARAI. ALL RIGHTS RESERVED. 
 */


//2019/05/22 

//Simple example to use Detector class of yolo_v2_class.hpp
  
/*
struct bbox_t {
    unsigned int x, y, w, h;       // (x,y) - top-left corner, (w, h) - width & height of bounded box
    float prob;                    // confidence - probability that the object was found correctly
    unsigned int obj_id;           // class of object - from range [0, classes-1]
    unsigned int track_id;         // tracking id for video (0 - untracked, 1 - inf - tracked object)
    unsigned int frames_counter;   // counter of frames on which the object was detected
    float x_3d, y_3d, z_3d;        // center of object (in Meters) if ZED 3D Camera is used
};

struct image_t {
    int h;                        // height
    int w;                        // width
    int c;                        // number of chanels (3 - for RGB)
    float *data;                  // pointer to the image data
};
  */
  
#define _CONSOLE_

#include <sol/ModuleFileName.h>
#include <sol/DropFiles.h>

#include <sol/ListView.h>
#include <sol/StringList.h>

#include <sol/Profile.h>
#include <sol/StringT.h>
#include <sol/opencv/OpenCVObject.h>
#include <sol/opencv/OpenCVApplicationView.h>
#include <sol/opencv/OpenCVNamedWindow.h>
#include <sol/PushButton.h>
#include <sol/FileDialog.h>
#include <vector>

#include <yolo_v2_class.hpp>

#include "Resource.h"

namespace SOL {

class MainView :public OpenCVApplicationView {

private:
  ////////////////////////////////////////////////////////////////////////////////////////
  //Inner class starts.
  class SimpleView :public OpenCVNamedWindow {
  private:
    StringT<char>  filePath;
    int            loadFlag;
    cv::Mat        image;
    
    void display()
    {
      show(image);
    }
    
  public:
    SimpleView(View* parent, const char* name, Args& args)
    :OpenCVNamedWindow(parent, name, args)
    {
      try {
      const char* filename = (const char*)args.get(XmNimageFileName);
      int imageLoadingFlag = (int)args.get(XmNimageLoadingFlag);
      
      loadImage(filename, imageLoadingFlag); //"..\\images\\WafukuMannequin.png");
      } catch (Exception& ex) {
        caught(ex);
      }
    }
    
    ~SimpleView()
    {
    }
     
    void loadImage(const char* filename, int flag=CV_LOAD_IMAGE_COLOR)
    {
      try {
        filePath = filename;
        loadFlag = flag;
        image    = readImage(filename, flag);
        refresh();
      } catch (Exception& ex) {
        caught(ex);
      }
    }
    
    void reload()
    {
      try {
        image    = readImage((const char*)filePath, loadFlag);
        refresh();
      } catch (Exception& ex) {
        caught(ex);
      }
    }

    void draw_named_rectangles(std::vector<bbox_t>& boxes, std::vector<std::string>& class_names)  
    {
      try {
       
          for (int i = 0; i < boxes.size(); i++){
            unsigned int id = boxes[i].obj_id;
            std::string name= class_names[id];
            char number[10];
            sprintf(number, "%d", i);
            Scalar color(0, 0, 255);
            //Sorry, the following shows a very ugly number string.
            //putText(image, number, Point(boxes[i].x, boxes[i].y),  FONT_HERSHEY_COMPLEX_SMALL, 0.6, color, 0.2, LINE_AA);
            putText(image, number, Point(boxes[i].x, boxes[i].y),  FONT_HERSHEY_SCRIPT_SIMPLEX, 0.5, color, 0.1, LINE_AA);
            rectangle(image, Point(boxes[i].x,                 boxes[i].y), 
                               Point (boxes[i].x + boxes[i].w,    boxes[i].y + boxes[i].h),
                                   color, 1);
          }
        refresh();
      } catch (Exception& ex) {
        caught(ex);
      }
    }
  
    void writeImage(const char* filename)
    {
      OpenCVNamedWindow::writeImage(filename, image);
    }
  };
  //Inner class endss
  ////////////////////////////////////////////////////////////////////////////////////////

  StringT<char>           imageFile;
  StringT<char>           savedImageFile;
  SmartPtr<Detector>      detector;
  
  SmartPtr<SimpleView>    view;
  SmartPtr<ListView>      listv;

  SmartPtr<PushButton>    reloadButton;
  SmartPtr<PushButton>    detectButton;
  String                  selectedFolder;
  std::string             cfg_filename;
  std::string             coco_filename;
  std::string             weight_filename;
  std::vector<std::string>       class_names;
  FileDialog              filedlg;
  Profile                 profile;

 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)
  {
    if (view && listv && detectButton  && reloadButton) {
      view            -> reshape(         0,  40,  w-310, h-45);
      reloadButton    -> reshape(10,       4,     80,   28);
      detectButton    -> reshape(100 + 10, 4,     80,   28);
      listv           -> reshape(w-305,  40, 300, h-45);
    }
  }

  void open(Action& action)
  {
    Args ar;
    
    char dir[MAX_PATH] = {0};
    //Restore previously select folder from a registry(profile of this application) for fileDialog
    if (profile.getFileFolder(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);
    }
  }

  
  void reload(Action& action)
  {
    if (view) {
      view ->reload(); 
    }
  }
  

  void detect(Action& action)
  {
    std::string filename((const char*)imageFile);
    printf("filename %s\n", (const char*)imageFile);
    
    std::vector<bbox_t> boxes = detector->detect(filename);
    size_t len = boxes.size();
    listv->clear();
    std::string csv_filename = filename + ".csv";

    for (size_t i = 0; i<len; i++) {
      view->draw_named_rectangles(boxes, class_names);

      unsigned int obj_id = boxes[i].obj_id;
      std::string name= class_names[obj_id];

      char index[10], score[10];
      sprintf(index, "%d", i);

      sprintf(score, "%.2f", boxes[i].prob);
      char x[10], y[10], w[10], h[10];
      sprintf(x, "%3d", boxes[i].x);
      sprintf(y, "%3d", boxes[i].y);
      sprintf(w, "%3d", boxes[i].w);
      sprintf(h, "%3d", boxes[i].h);

      
      StringList item;
      item.add(index);
      item.add(name.c_str());
      item.add(score);
      item.add(x);
      item.add(y);
      item.add(w);
      item.add(h);
      listv->insertLine(i, &item);
    }
  }

  
  void openFile(const char* filename)
  {
    try {
      listv-> clear();
      
      view -> loadImage(filename, CV_LOAD_IMAGE_COLOR);
      imageFile = filename;
      const char* fname = strrchr(filename, '\\');
      if (fname) {
        fname++;
      }
      imageFile = fname;
      updateCaption();
  
      savedImageFile = "";
      
    } 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);
      }
    }    
  }

  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 load_class_names(std::string& filename)
  {
    FILE* fp = fopen(filename.c_str(), "r");
    if (fp) {
      char buffer[256] = {0};
      while( fgets(buffer, sizeof(buffer), fp) != NULL ){
        buffer[strlen(buffer)-1] = '\0';
        //printf("%s\n", buffer);
        std::string class_name(buffer);
        class_names.push_back(class_name);
      }
      fclose(fp); 
    }
  }

  const char** getListViewHeader(int& number)
  {
    static const char* LISTVIEW_HEADER[] = {"id ", "object ", "score", "  x ", "  y ", "  w ", "  h "};
    number = CountOf(LISTVIEW_HEADER);
    return LISTVIEW_HEADER;
  }

  void readIniFile()
  {
    // Read some configuration file names from ini file.
    char buffer[256] = { 0 };
    
    imageFile = "..\\..\\images\\PoliceCar.jpg";
    const char* inifile = ".\\YoloObjectDetector.ini";
    GetPrivateProfileString("CFG_FILE",    "filename", "", buffer, sizeof(buffer), inifile);
    cfg_filename    = buffer;
    printf("CFG_FILE:%s\n", buffer);
    
    GetPrivateProfileString("WEIGHT_FILE", "filename", "", buffer, sizeof(buffer), inifile);
    weight_filename = buffer;
    printf("WEIGHT_FILE:%s\n", buffer);
    
    GetPrivateProfileString("COCO_FILE",   "filename", "", buffer, sizeof(buffer), inifile);
    coco_filename   = buffer;
    printf("COCO_FILE:%s\n", buffer);
    
  }

  
public:
  MainView(OpenCVApplication& applet, const char* name, Args& args)
  :OpenCVApplicationView(applet, name, args)
  {
    
    try {
      readIniFile();

      detector = new Detector(cfg_filename, weight_filename);

      load_class_names(coco_filename);

      Args ar;
      ar.reset();
      ar.set(XmNimageFileName,  imageFile);
      ar.set(XmNimageLoadingFlag, CV_LOAD_IMAGE_COLOR);
      view = new SimpleView(this, "cvwindow", ar); 
      view -> addCallback(XmNdropCallback, this,
        (Callback)&MainView::dropFiles, NULL);
      
      ar.reset();
      ar.set(XmNexStyle, (LONG_PTR)WS_EX_CLIENTEDGE);
      ar.set(XmNstyle, (LONG_PTR)LVS_REPORT);

      listv = new ListView(this, "objects", ar);

      StringList header;
      int number = 0;
      const char** strings = getListViewHeader(number);
      for (int i = 0; i<number; i++) {
        header.add(strings[i]); 
      }
      
      listv->clear();
      listv->setColumn(&header);
       
      ar.reset();
      reloadButton = new PushButton(this, "Reload", ar);
      reloadButton -> addCallback(XmNactivateCallback, this, 
          (Callback)&MainView::reload, NULL); 

      ar.reset();
      detectButton = new PushButton(this, "Detect", ar);
      detectButton -> addCallback(XmNactivateCallback, this, 
          (Callback)&MainView::detect, NULL); 
    
      ar.reset();
      ar.set(XmNfilter, FileDialog::getImageFilesFilter());
      filedlg.create(this, "OpenFile", ar);
    
      addCallback(XmNmenuCallback, IDM_OPEN, this,
          (Callback)&MainView::open, NULL);
      addCallback(XmNmenuCallback, IDM_EXIT, this,
          (Callback)&MainView::confirm, NULL);

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

  ~MainView()
  {
  }
  

  void save(Action& action)
  {
    try {
      if (!savedImageFile.isEmpty()) {
        //Write detected image into the filename.
        view->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.
        view->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,  1000);
    args.set(XmNheight, 500);
    MainView view(applet, name, args);
    view.realize();

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


Last modified: 22 May 2019

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