3.3.33 CustomYoloObjectDetector

As you know, the latest YOLOv3 has a C++ Detetor class implementation (darknet-master/include/Detector.h).
You can also define your own Detector C++ class based on C APIs of detector.c, image.c, etc. in darknet-master/src folders.
If you try to use the C APIs in the folder with std::list and std::data classes, however, you encounter some data-type ambiguity problem on struct list in list.h, and data in data.h files.

In order to be able C APIs in darknet-master/src with C++ std library without causing data-type ambiguity problem, we have changed original source files in darknet-master/src folder by defining USE_STD macro in the following way:

For example, the list.h can be rewritten by using USE_STD macro.

#ifndef LIST_H
#define LIST_H

typedef struct node{
    void *val;
    struct node *next;
    struct node *prev;
} node;

#ifdef USE_STD
typedef struct ylist{
    int size;
    node *front;
    node *back;
} ylist;
#else
typedef struct list{
    int size;
    node *front;
    node *back;
} list;
#endif

#ifdef __cplusplus
extern "C" {
#endif

#ifdef USE_STD
ylist *make_list();
int list_find(ylist *l, void *val);
void list_insert(ylist *, void *);
void **list_to_array(ylist *l);
void free_list(ylist *l);
void free_list_contents(ylist *l);
void free_list_contents_kvp(ylist *l);
#else
list *make_list();
int list_find(list *l, void *val);
void list_insert(list *, void *);
void **list_to_array(list *l);
void free_list(list *l);
void free_list_contents(list *l);
void free_list_contents_kvp(list *l);
#endif

#ifdef __cplusplus
}
#endif
#endif



Furthermore, we have removed -fvisibility=hidden option of Makefiel in darknet-master folder, and added D_GLIBCXX_USE_CXX11_ABI macro to compilation option in the following way.

$(CPP) -std=c++11 -D_GLIBCXX_USE_CXX11_ABI=0 $(COMMON) $(CFLAGS) -c $< -o $@

For detail, please check the simple extension code darknet-master-to-use-std to the original darknet-master/src.

In this example, we have used the following classes.

ConfigParser

Detector3

OpenCVScrolledImageView

DetectedObjectList


The following CustomYoloObjectDetector is a simple example to use the Detector3 class.











//
//CustomYoloObjectDetector.cpp
//Copyright (c) 2019 Antillia.com TOSHIYUKI ARAI. ALL RIGHTS RESERVED.
//
//2019/06/09

#include <opencv2/stitching.hpp>
#include <oz++/motif/Label.h>
#include <oz++/motif/RowColumn.h>
#include <oz++/motif/LabeledComboBox.h>
#include <oz++/motif/LabeledTrackBar.h>
#include <oz++/motif/DropdownScaler.h>

#include <oz++/opencv/OpenCVMainView.h>
#include <oz++/opencv/OpenCVScrolledImageView.h>
#include <oz++/motif/FileOpenDialog.h>
#include <oz++/motif/ScrolledTableView.h>
#include <oz++/ConfigParser.h>

#include <oz++/yolov3/Detector3.h>
#include <oz++/yolov3/DetectedObjectList.h>

namespace OZ {

class MainView :public OpenCVMainView {
   
private:
  ///////////////////////////////////////////////

  class DetectedImageView: public OpenCVScrolledImageView {
  private:
    cv::Mat originalImage; 
    cv::Mat scaledImage;
    
    virtual void display()
    {
       show(scaledImage);
    }
 
  public:
    DetectedImageView(View* parent, const char* name, Args& args)
    :OpenCVScrolledImageView(parent, name, args)
    {
      try {
        const char* filename = (const char*)args.get(XmNimageFileName);
        int imageLoadingFlag = args.get(XmNimageLoadingFlag);
        int scalingRatio = (int)args.get(XmNimageScalingRatio);

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

    ~DetectedImageView()
    {
    }
    
    void loadImage(const char* filename, 
        int imageLoadingFlag= CV_LOAD_IMAGE_COLOR,
                int scalingRatio=100)
    {
      originalImage = readImage(filename, imageLoadingFlag);
      scaleImage(originalImage, scaledImage, scalingRatio);
      refresh();
    }    

    void setImage(cv::Mat& image, int scalingRatio=100 )
    {
      originalImage = image;
      rescale(scalingRatio);
    }
 
    void rescale(int scalingRatio)
    {
      scaledImage.release();
      scaleImage(originalImage, scaledImage, scalingRatio);
    }
  };
    
private:

  std::string         imageFile;
  std::string         csv_filename;

  int                 imageLoadingFlag = CV_LOAD_IMAGE_COLOR;
  int                 imageScalingRatio =80; //percentage 

  ConfigParser        parser;

  SmartPtr<Detector3> detector;
  std::string         darknet_root;

  std::string         cfg_filename;
  std::string         coco_filename;
  std::string         weight_filename;

  SmartPtr<DetectedImageView>   detectedImage;
  SmartPtr<Form>                controlPane;
  SmartPtr<DetectedObjectList>  objectList;

  SmartPtr<RowColumn>        topPane;
  SmartPtr<Label>            label;
  SmartPtr<DropdownScaler>   scaleComboBox;
  SmartPtr<PushButton>       reloadButton;
  SmartPtr<PushButton>       detectButton;
 
  SmartPtr<FileOpenDialog>   fileDialog;

public:
  void cancel(Action& action)
  {
    fileDialog->popdown();
  }

  void fileOpen(Action& action)
  {
    fileDialog->popup();
  }

  void scaleChanged(Action& action)
  {
    int val = scaleComboBox->getScale();
    if (val > 0 && imageScalingRatio != val) {
      imageScalingRatio = val;
      detectedImage -> rescale(imageScalingRatio); 
    }
  }  

  void updateTitle(const char* filename)
  {
     std::string appname = getAppName();
     std::string title = filename;
     title += std::string(" - ");
     title += appname; 
     setTitle(title.c_str());
  }

  void ok(Action& action)
  {
    try {  
      imageFile  = fileDialog->getFileName();
      const char* filename = (const char*)imageFile.c_str();
 
      printf("filename: %s\n", filename);
      fileDialog->popdown();
    
      detectedImage ->loadImage(filename, imageLoadingFlag, imageScalingRatio);
      detectedImage->unmap();
      detectedImage->map();

      csv_filename = createCSVFilename(imageFile);
      //resize(width(), height());
      updateTitle(filename);

      flush();
    } catch (OZ::Exception& ex) {
       caught(ex);
    } 
  }

  void resize(Dimension w, Dimension h)
  {
    int CP_WIDTH = 330;
    int LB_HEIGHT = 30;
    int ww =  w-CP_WIDTH;
    int hh = h - LB_HEIGHT;
    
    if (topPane && detectButton && detectedImage && controlPane ) {
      detectButton->get(XmNheight, LB_HEIGHT);
      hh = h - LB_HEIGHT -15;
      detectedImage -> reshape(0, LB_HEIGHT+5, ww-2, hh-30);
     
      controlPane  -> reshape(ww+1, LB_HEIGHT+5, CP_WIDTH-4, hh-30);
    }
    flush();
  }

  void reload(Action& event)
  {
    detectedImage -> loadImage(imageFile.c_str(),
                imageLoadingFlag,
                imageScalingRatio);
  }

  std::string createCSVFilename(std::string& filename)
  {
    std::string csv_fname = filename;
    auto pos = filename.rfind("/");
    if (pos != std::string::npos) { 
      std::string nameonly= filename.substr(pos+1);
      csv_fname = std::string("./") + nameonly + std::string(".csv"); 
      printf("csv_filename %s\n", csv_fname.c_str());
    }
    return csv_fname;
  }

  void detect(Action& event)
  {
    image timage = detector->detect_image(imageFile.c_str(), csv_filename.c_str());

    cv::Mat mat = detector->image_to_mat(timage);
    cv::Mat mbgr;
    cv::cvtColor(mat, mbgr, cv::COLOR_RGB2BGR);
    free_image(timage);
    detectedImage->setImage(mbgr, imageScalingRatio);
    TableView* tablev = objectList->getTableView();
    tablev->removeAllItems();
    tablev->readCSVFile(csv_filename);
  }


public:
  MainView(OpenCVApplication& applet, const char* name, Args& args)
  :OpenCVMainView(applet, name, args) 
  {
    imageScalingRatio = 80;

    char defaultScale[20] = {0};
    sprintf(defaultScale, "%d%%", imageScalingRatio);
    printf("%s¥n", defaultScale);

    imageLoadingFlag = CV_LOAD_IMAGE_COLOR;

    std::string config = "./CustomYoloObjectDetector.ini";

    parser.parse(config);

    darknet_root    = parser.getString("DARKNET_ROOT", "filename");

    cfg_filename    = parser.getString("CFG_FILE", "filename");
    coco_filename   = parser.getString("COCO_FILE", "filename");
    weight_filename = parser.getString("WEIGHT_FILE", "filename");

    BulletinBoard* bboard = getBulletinBoard();
    imageFile = "../../images/JRShinjukuStation.2.jpg";
    csv_filename = createCSVFilename(imageFile);

    // Create a instance oF OZ::Detector3.
    detector = new OZ::Detector3(darknet_root, cfg_filename, weight_filename, coco_filename);

    try {
      Args ar;
      ar.set(XmNx, 0);
      ar.set(XmNy, 0);
      ar.set(XmNmarginHeight, 1);
      ar.set(XmNmarginWidth, 1);
      ar.set(XmNorientation, XmHORIZONTAL);
      ar.set(XmNspacing, 20);
      topPane = new RowColumn(bboard, "", ar);

      ar.reset();
      label = new Label(topPane, "Scale", ar);
      ar.reset();
      ar.set(XmNdefaultScale, defaultScale);
      scaleComboBox = new DropdownScaler(topPane, "", ar);
      scaleComboBox->addCallback(XmNselectionCallback, this,
        (Callback)&MainView::scaleChanged, NULL);

      ar.set(XmNx, 0);
      ar.set(XmNy, 0);
      ar.set(XmNalignment, XmALIGNMENT_BEGINNING); 
      reloadButton = new PushButton(topPane, " Reload ", ar);
      reloadButton->addCallback(XmNactivateCallback, this,
                 (Callback)&MainView::reload, NULL);

      ar.reset(); 
      ar.set(XmNx, 120);
      ar.set(XmNy, 0);
      ar.set(XmNalignment, XmALIGNMENT_BEGINNING); 
      detectButton = new PushButton(topPane, " Detect ", ar);
      detectButton->addCallback(XmNactivateCallback, this,
                 (Callback)&MainView::detect, NULL);

      updateTitle((const char*)imageFile.c_str());


      ar.reset();
      ar.set(XmNimageFileName, imageFile.c_str());
      ar.set(XmNimageLoadingFlag, imageLoadingFlag);
      ar.set(XmNimageScalingRatio, imageScalingRatio);

      detectedImage   = new DetectedImageView(bboard, "", ar);

      ar.reset();
      controlPane = new Form(bboard, "", ar);

      ar.reset();

      objectList = new DetectedObjectList(controlPane, "objectlist", ar);

      ar.reset();
      fileDialog = new FileOpenDialog(this, "FileOpenDialog", ar);
      fileDialog  -> getOkButton()
                  -> addCallback(XmNactivateCallback, this,
                          (Callback)&MainView::ok, NULL); 
      sendConfigureEvent(); 
    } 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,  1000);
    args.set(XmNheight, 480);
    MainView view(applet, appclass, args);
    view.realize();

    applet.run();
    
  } catch (OZ::Exception& ex) {
    caught(ex);
  }
  return 0;
}



 Last modified: 13 Jun. 2019

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