Difference between revisions of "The protoComponent Example"

From David Vernon's Wiki
Jump to: navigation, search
(protoComponentComputation.cpp)
Line 32: Line 32:
 
   * - computation
 
   * - computation
 
   *
 
   *
   * Functionally, the module just reads an input image from an input port,  
+
   * Functionally, the module  
   * converts it to a binary image based on the supplied threshold,
+
  * - reads a colour image from an input port,
   * and writes it to an output port
+
   * - reads a threshold value from an imput port,
 +
  * - converts it to a binary image based on a supplied threshold,
 +
   * - counts the number of foreground pixels and background pixels,
 +
  * - writes the binary image to an output port,
 +
  * - and writes the pixel statistics and the time to another output port.
 +
  *
 +
  * The purpose of these operations is simply to illustrate how input/ouput is performed. 
 +
  * The image processing itself is trivial and of no importance.
 
   *
 
   *
 
   * The module also reads a configuration file containing the intrinsic
 
   * The module also reads a configuration file containing the intrinsic
Line 40: Line 47:
 
   * techniques.
 
   * techniques.
 
   *
 
   *
   * A complete tutorial for this example is available on the DREAM wiki  
+
   * A complete tutorial on this example is available on the DREAM wiki  
 
   *
 
   *
 
   *  
 
   *  
Line 73: Line 80:
 
   * The value part can be changed to suit your needs; the default values are shown below.  
 
   * The value part can be changed to suit your needs; the default values are shown below.  
 
   *   
 
   *   
   * - \c myInputPort \c /image:i \n     
+
   * - \c imageInputPort \c /image:i \n     
   *  specifies the input port name (this string will be prefixed by \c /protoComponent  
+
   *  specifies the image input port name (this string will be prefixed by \c /protoComponent
 +
  *  or whatever else is specifed by the name parameter
 +
  * 
 +
  * - \c thresholdInputPort \c /threshold:i \n   
 +
  *  specifies the threshold input port name (this string will be prefixed by \c /protoComponent  
 
   *  or whatever else is specifed by the name parameter
 
   *  or whatever else is specifed by the name parameter
 
   *
 
   *
   * - \c myOutputPort \c /image:o \n   
+
   * - \c imageOutputPort \c /image:o \n   
   *  specifies the output port name (this string will be prefixed by \c /protoComponent  
+
   *  specifies the image output port name (this string will be prefixed by \c /protoComponent
 +
  *  or whatever else is specifed by the name parameter
 +
  *
 +
  * - \c statisticsOutputPort \c /statistics:o \n 
 +
  *  specifies the statistics output port name (this string will be prefixed by \c /protoComponent  
 
   *  or whatever else is specifed by the name parameter
 
   *  or whatever else is specifed by the name parameter
 
   *
 
   *
Line 112: Line 127:
 
   *       
 
   *       
 
   *  - \c /protoComponent/image:i \n
 
   *  - \c /protoComponent/image:i \n
 +
  *     
 +
  *  - \c /protoComponent/threshold:i \n
 
   *
 
   *
 
   * <b>Output ports</b>
 
   * <b>Output ports</b>
Line 119: Line 136:
 
   *
 
   *
 
   *  - \c /protoComponent/image:o \n
 
   *  - \c /protoComponent/image:o \n
 +
  *
 +
  *  - \c /protoComponent/statistics:o \n
 
   *
 
   *
 
   * <b>Port types </b>
 
   * <b>Port types </b>
Line 125: Line 144:
 
   * but doesn't say anything about the data transmitted on the ports. This is defined by the following code.  
 
   * but doesn't say anything about the data transmitted on the ports. This is defined by the following code.  
 
   *
 
   *
   * \c BufferedPort<ImageOf<PixelRgb> >  \c myInputPort; \n  
+
   * \c BufferedPort<ImageOf<PixelRgb> >  \c imageIn; \n  
   * \c BufferedPort<ImageOf<PixelRgb> >  \c myOutputPort;      
+
  * \c BufferedPort<VectorOf<int> >      \c thresholdIn; <tt>//int threshold </tt> \n 
 +
   * \c BufferedPort<ImageOf<PixelRgb> >  \c imageOut; \n 
 +
  * \c BufferedPort                      \c statisticsOut; \n     
 +
  *
 +
  * Thus, there are three types of port in use here, all buffered:
 +
  *
 +
  * - image,
 +
  * - vector of int (there will be just one element in the vector in this case), and
 +
  * - a bottle comprising alphanumerics messages.
 +
  *
 
   *
 
   *
 
   * \section in_files_sec Input Data Files
 
   * \section in_files_sec Input Data Files
Line 157: Line 185:
 
   * FP7 Project 611391 co-funded by the European Commission
 
   * FP7 Project 611391 co-funded by the European Commission
 
   *
 
   *
   * Author:  <name of author>, <author institute>
+
   * Author:  David Vernon, University of Skövde
   * Email:  <preferred email address>
+
   * Email:  david.vernon@his.se
 
   * Website: www.dream20202.eu  
 
   * Website: www.dream20202.eu  
 
   *
 
   *
 
   * This program comes with ABSOLUTELY NO WARRANTY  
 
   * This program comes with ABSOLUTELY NO WARRANTY  
 
   */
 
   */
 
 
 
    
 
    
  /*
+
 
 +
  /*  
 
   * Audit Trail
 
   * Audit Trail
 
   * -----------
 
   * -----------
 
   * 20/08/14  First version validated (David Vernon)
 
   * 20/08/14  First version validated (David Vernon)
 +
  * 06/10/14  Additional ports for threshold input and statistic output (David Vernon)
 +
  *
 
   */  
 
   */  
 
    
 
    
Line 184: Line 214:
 
  using namespace yarp::sig;
 
  using namespace yarp::sig;
 
    
 
    
  class ProtoComponentThread : public Thread
+
  class ProtoComponentThread : public Thread {
  {
+
   
 
  private:
 
  private:
 
   
 
   
  /* class variables */
+
    /* class variables */
 
   
 
   
  int     x, y;
+
     bool              debug;
  PixelRgb rgbPixel;
+
    int                x, y;
  ImageOf<PixelRgb> *image;
+
    PixelRgb           rgbPixel;
     
+
    ImageOf<PixelRgb> *image;
  /* thread parameters: they are pointers so that they refer to the original variables in protoComponent */
+
    int              *thresholdValue; 
 +
    VectorOf<int>    *thresholdVector;
 +
    int              numberOfForegroundPixels;
 
   
 
   
  BufferedPort<ImageOf<PixelRgb> > *imagePortIn;
+
    /* thread parameters: they are pointers so that they refer to the original variables in protoComponent */
  BufferedPort<ImageOf<PixelRgb> > *imagePortOut; 
+
  int *thresholdValue;   
+
 
   
 
   
public:
+
    BufferedPort<ImageOf<PixelRgb> > *imagePortIn;
 +
    BufferedPort<VectorOf<int> >    *thresholdPortIn;
 +
    BufferedPort<ImageOf<PixelRgb> > *imagePortOut;
 +
    BufferedPort<Bottle>            *statisticsPortOut;
 +
 
 
   
 
   
   /* class methods */
+
   public:
+
 
  ProtoComponentThread(BufferedPort<ImageOf<PixelRgb> > *imageIn, BufferedPort<ImageOf<PixelRgb> > *imageOut, int *threshold );
+
    /* class methods */
  bool threadInit();     
+
 
  void threadRelease();
+
    ProtoComponentThread(BufferedPort<ImageOf<PixelRgb> > *imageIn,  
  void run();  
+
                          BufferedPort<VectorOf<int> >    *thresholdIn,
 +
                          BufferedPort<ImageOf<PixelRgb> > *imageOut,
 +
                          BufferedPort<Bottle>            *statisticsOut,
 +
                          int *threshold );
 +
    bool threadInit();     
 +
    void threadRelease();
 +
    void run();  
 
  };
 
  };
 
   
 
   
 
   
 
   
  class ProtoComponent:public RFModule
+
  class ProtoComponent:public RFModule {
{
+
  /* module parameters */
+
 
   
 
   
  string moduleName;
+
    /* module parameters */
  string inputPortName;
+
  string outputPortName; 
+
  string handlerPortName;
+
  string cameraConfigFilename;
+
  float  fxLeft,  fyLeft;          // focal length
+
  float  fxRight, fyRight;        // focal length
+
  float  cxLeft,  cyLeft;          // coordinates of the principal point
+
  float  cxRight, cyRight;        // coordinates of the principal point
+
  int    thresholdValue;
+
 
   
 
   
  /* class variables */
+
    string moduleName;
 
+
    string imageInputPortName;
  BufferedPort<ImageOf<PixelRgb> > imageIn;     //example input port
+
    string thresholdInputPortName;
  BufferedPort<ImageOf<PixelRgb> > imageOut;    //example output port
+
    string imageOutputPortName;
  Port handlerPort;     //a port to handle messages
+
    string statisticsOutputPortName; 
 +
    string handlerPortName;
 +
    string cameraConfigFilename;
 +
    float  fxLeft,  fyLeft;         // focal length
 +
    float  fxRight, fyRight;         // focal length
 +
     float  cxLeft,  cyLeft;          // coordinates of the principal point
 +
    float  cxRight, cyRight;         // coordinates of the principal point
 +
    int    thresholdValue;
 
   
 
   
  /* pointer to a new thread to be created and started in configure() and stopped in close() */
+
    /* class variables */
 
   
 
   
  ProtoComponentThread *protoComponentThread;
+
    BufferedPort<ImageOf<PixelRgb> > imageIn;       // example image input port
    
+
    BufferedPort<VectorOf<int> >    thresholdIn;   // example vector input port
 +
    BufferedPort<ImageOf<PixelRgb> > imageOut;      // example image output port
 +
    BufferedPort<Bottle>            statisticsOut; // example bottle output port
 +
    Port handlerPort;                              // a port to handle interactive messages (also uses bottles)
 
   
 
   
public:
+
    /* pointer to a new thread to be created and started in configure() and stopped in close() */
   
+
  bool configure(yarp::os::ResourceFinder &rf); // configure all the module parameters and return true if successful
+
  bool interruptModule();                      // interrupt, e.g., the ports
+
  bool close();                                // close and shut down the module
+
  bool respond(const Bottle& command, Bottle& reply);
+
  double getPeriod();
+
  bool updateModule();
+
};
+
 
   
 
   
==<code>protoComponentMain.cpp</code>==
+
    ProtoComponentThread *protoComponentThread;
 
   
 
   
  /*
+
  public:
  * Copyright (C) 2014 DREAM Consortium
+
  * FP7 Project 611391 co-funded by the European Commission
+
  *
+
  * Author: <name of author>, <author institute>
+
  * Email:  <preferred email address>
+
  * Website: www.dream20202.eu
+
  *
+
  * This program comes with ABSOLUTELY NO WARRANTY
+
  */
+
 
    
 
    
+
    bool configure(yarp::os::ResourceFinder &rf); // configure all the module parameters and return true if successful
/*
+
    bool interruptModule();                       // interrupt, e.g., the ports
  * Audit Trail
+
    bool close();                                 // close and shut down the module
  * -----------
+
    bool respond(const Bottle& command, Bottle& reply);
  * 20/08/14  First version validated (David Vernon)
+
    double getPeriod();
  */
+
    bool updateModule();
 
+
  };
#include "protoComponent.h"
+
 
+
int main(int argc, char * argv[])
+
{
+
  /* initialize yarp network */
+
 
+
  Network yarp;
+
 
+
  /* create your module */
+
 
+
  ProtoComponent protoComponent;
+
 
+
  /* prepare and configure the resource finder */
+
 
+
  ResourceFinder rf;
+
  rf.setVerbose(true);
+
  rf.setDefaultConfigFile("protoComponent.ini");         // can be overridden by --from parameter
+
  rf.setDefaultContext("protoComponent/configuration");   // can be overridden by --context parameter
+
  rf.configure("DREAM_ROOT", argc, argv);                 // environment variable with root of configuration path
+
 
+
  /* run the module: runModule() calls configure first and, if successful, it then runs */
+
 
+
  protoComponent.runModule(rf);
+
 
+
  return 0;
+
  }
+
  
 +
 +
==<code>protoComponentConfiguration.cpp</code>==
  
==<code>protoComponentConfiguration.cpp</code>==
 
 
 
  /*  
 
  /*  
 
   * Copyright (C) 2014 DREAM Consortium
 
   * Copyright (C) 2014 DREAM Consortium
 
   * FP7 Project 611391 co-funded by the European Commission
 
   * FP7 Project 611391 co-funded by the European Commission
 
   *
 
   *
   * Author:  <name of author>, <author institute>
+
   * Author:  David Vernon, University of Skövde
   * Email:  <preferred email address>
+
   * Email:  david.vernon@his.se
   * Website: www.dream20202.eu  
+
   * Website: www.dream20202.eu
 
   *
 
   *
 
   * This program comes with ABSOLUTELY NO WARRANTY  
 
   * This program comes with ABSOLUTELY NO WARRANTY  
 
   */
 
   */
 +
 
 
    
 
    
 
 
  /*
 
  /*
 
   * Audit Trail
 
   * Audit Trail
 
   * -----------
 
   * -----------
 
   * 20/08/14  First version validated (David Vernon)
 
   * 20/08/14  First version validated (David Vernon)
 +
  * 06/10/14  Additional ports for threshold input and statistic output (David Vernon)
 +
  *
 
   */  
 
   */  
 
   
 
   
 
  #include "protoComponent.h"
 
  #include "protoComponent.h"
 
   
 
   
 
+
 
  /*  
 
  /*  
 
   * Configure method ... use it to do component coordination,  
 
   * Configure method ... use it to do component coordination,  
Line 337: Line 335:
 
     * specifically the port names which are dependent on the module name
 
     * specifically the port names which are dependent on the module name
 
     */
 
     */
   
+
 
 
     setName(moduleName.c_str());
 
     setName(moduleName.c_str());
 
+
 
     /* now, get the rest of the parameters */
 
     /* now, get the rest of the parameters */
 
   
 
   
 
     /* get the name of the input and output ports, automatically prefixing the module name by using getName() */
 
     /* get the name of the input and output ports, automatically prefixing the module name by using getName() */
 
   
 
   
     inputPortName        = "/";
+
     imageInputPortName    =     "/";
     inputPortName        += getName(
+
     imageInputPortName  +=     getName(
                            rf.check("protoInputPort",  
+
                                rf.check("imageInputPort",  
                            Value("/image:i"),
+
                                Value("/image:i"),
                            "Input image port (string)").asString()
+
                                "Input image port (string)").asString()
                            );
+
                                );
 
      
 
      
     outputPortName        = "/";
+
     thresholdInputPortName =     "/";
     outputPortName      += getName(
+
     thresholdInputPortName +=   getName(
                            rf.check("protoOutputPort",  
+
                                rf.check("thresholdInputPort",  
                            Value("/image:o"),
+
                                Value("/threshold:i"),
                            "Output image port (string)").asString()
+
                                "Threshold input port (string)").asString()
                            );
+
                                );
 +
 +
    imageOutputPortName  =      "/";
 +
    imageOutputPortName  +=      getName(
 +
                                rf.check("imageOutputPort",
 +
                                Value("/image:o"),
 +
                                "Output image port (string)").asString()
 +
                                );
 +
 +
    statisticsOutputPortName  = "/";
 +
    statisticsOutputPortName  += getName(
 +
                                rf.check("statisticsOutputPort",
 +
                                Value("/statistics:o"),
 +
                                "Output image port (string)").asString()
 +
                                );
 
   
 
   
 
   
 
   
Line 395: Line 407:
 
     /* open ports  */  
 
     /* open ports  */  
 
          
 
          
     if (!imageIn.open(inputPortName.c_str())) {
+
     if (!imageIn.open(imageInputPortName.c_str())) {
       cout << getName() << ": unable to open port " << inputPortName << endl;
+
       cout << getName() << ": unable to open port " << imageInputPortName << endl;
 
       return false;  // unable to open; let RFModule know so that it won't run
 
       return false;  // unable to open; let RFModule know so that it won't run
 
     }
 
     }
 
   
 
   
     if (!imageOut.open(outputPortName.c_str())) {
+
     if (!thresholdIn.open(thresholdInputPortName.c_str())) {
       cout << getName() << ": unable to open port " << outputPortName << endl;
+
       cout << getName() << ": unable to open port " << thresholdInputPortName << endl;
 
       return false;  // unable to open; let RFModule know so that it won't run
 
       return false;  // unable to open; let RFModule know so that it won't run
 
     }
 
     }
 +
 +
 +
    if (!imageOut.open(imageOutputPortName.c_str())) {
 +
      cout << getName() << ": unable to open port " << imageOutputPortName << endl;
 +
      return false;  // unable to open; let RFModule know so that it won't run
 +
    }
 +
 +
    if (!statisticsOut.open(statisticsOutputPortName.c_str())) {
 +
      cout << getName() << ": unable to open port " << statisticsOutputPortName << endl;
 +
      return false;  // unable to open; let RFModule know so that it won't run
 +
    }
 +
 
   
 
   
 
     /*
 
     /*
Line 409: Line 433:
 
     * so that messages received from the port are redirected to the respond method
 
     * so that messages received from the port are redirected to the respond method
 
     */
 
     */
 
+
 
     handlerPortName =  "/";
 
     handlerPortName =  "/";
 
     handlerPortName += getName();        // use getName() rather than a literal  
 
     handlerPortName += getName();        // use getName() rather than a literal  
Line 422: Line 446:
 
     /* create the thread and pass pointers to the module parameters */
 
     /* create the thread and pass pointers to the module parameters */
 
   
 
   
     protoComponentThread = new ProtoComponentThread(&imageIn, &imageOut, &thresholdValue);
+
     protoComponentThread = new ProtoComponentThread(&imageIn, &thresholdIn, &imageOut, &statisticsOut, &thresholdValue);
 
   
 
   
 
     /* now start the thread to do the work */
 
     /* now start the thread to do the work */
 
   
 
   
 
     protoComponentThread->start(); // this calls threadInit() and it if returns true, it then calls run()
 
     protoComponentThread->start(); // this calls threadInit() and it if returns true, it then calls run()
+
 
 
     return true ;      // let the RFModule know everything went well
 
     return true ;      // let the RFModule know everything went well
 
                       // so that it will then run the module
 
                       // so that it will then run the module
Line 435: Line 459:
 
  bool ProtoComponent::interruptModule()
 
  bool ProtoComponent::interruptModule()
 
  {
 
  {
 +
    protoComponentThread->stop();
 +
 
     imageIn.interrupt();
 
     imageIn.interrupt();
 +
    thresholdIn.interrupt();
 
     imageOut.interrupt();
 
     imageOut.interrupt();
 
     handlerPort.interrupt();
 
     handlerPort.interrupt();
 
+
 
     return true;
 
     return true;
 
  }
 
  }
Line 448: Line 475:
 
   
 
   
 
     imageIn.close();
 
     imageIn.close();
 +
    thresholdIn.close();
 
     imageOut.close();
 
     imageOut.close();
 
     handlerPort.close();
 
     handlerPort.close();
 
    protoComponentThread->stop();
 
 
   
 
   
 
     return true;
 
     return true;
  }
+
  }  
 
   
 
   
 
   
 
   
Line 480: Line 506:
 
           thresholdValue = command.get(2).asInt(); // set parameter value
 
           thresholdValue = command.get(2).asInt(); // set parameter value
 
           reply.addString("ok");
 
           reply.addString("ok");
        }
+
      }
 
     }
 
     }
 
     return true;
 
     return true;
 
  }
 
  }
 +
 +
 +
/* Called periodically every getPeriod() seconds */
 
   
 
   
 
/* Called periodically every getPeriod() seconds */
 
 
 
 
  bool ProtoComponent::updateModule()
 
  bool ProtoComponent::updateModule()
 
  {
 
  {
Line 493: Line 519:
 
  }
 
  }
 
   
 
   
+
 
+
 
  double ProtoComponent::getPeriod()
 
  double ProtoComponent::getPeriod()
 
  {
 
  {
 
     /* module periodicity (seconds), called implicitly by protoComponent */
 
     /* module periodicity (seconds), called implicitly by protoComponent */
   
+
   
 
     return 0.1;
 
     return 0.1;
 
  }
 
  }
 +
  
 
==<code>protoComponentComputation.cpp</code>==
 
==<code>protoComponentComputation.cpp</code>==
Line 508: Line 534:
 
   * FP7 Project 611391 co-funded by the European Commission
 
   * FP7 Project 611391 co-funded by the European Commission
 
   *
 
   *
   * Author:  <name of author>, <author institute>
+
   * Author:  David Vernon, University of Skövde
   * Email:  <preferred email address>
+
   * Email:  david.vernon@his.se
 
   * Website: www.dream20202.eu  
 
   * Website: www.dream20202.eu  
 
   *
 
   *
Line 515: Line 541:
 
   */
 
   */
 
   
 
   
+
 
 
  /*
 
  /*
 
   * Audit Trail
 
   * Audit Trail
 
   * -----------
 
   * -----------
 
   * 20/08/14  First version validated (David Vernon)
 
   * 20/08/14  First version validated (David Vernon)
 +
  * 06/10/14  Additional ports for threshold input and statistic output (David Vernon)
 +
  *
 
   */  
 
   */  
 
    
 
    
Line 525: Line 553:
 
  #include "protoComponent.h"
 
  #include "protoComponent.h"
 
   
 
   
  ProtoComponentThread::ProtoComponentThread(BufferedPort<ImageOf<PixelRgb> > *imageIn, BufferedPort<ImageOf<PixelRgb> > *imageOut, int *threshold)
+
  ProtoComponentThread::ProtoComponentThread(BufferedPort<ImageOf<PixelRgb> > *imageIn,  
 +
                                            BufferedPort<VectorOf<int> >    *thresholdIn,
 +
                                            BufferedPort<ImageOf<PixelRgb> > *imageOut,
 +
                                            BufferedPort<Bottle>            *statisticsOut,
 +
                                            int *threshold)
 
  {
 
  {
     imagePortIn   = imageIn;
+
     imagePortIn       = imageIn;
     imagePortOut   = imageOut;
+
     thresholdPortIn   = thresholdIn;
     thresholdValue = threshold;
+
    imagePortOut      = imageOut;
 +
    statisticsPortOut = statisticsOut;
 +
     thresholdValue   = threshold;
 
  }
 
  }
 
   
 
   
Line 535: Line 569:
 
  {
 
  {
 
     /* initialize variables and create data-structures if needed */
 
     /* initialize variables and create data-structures if needed */
 +
 +
    debug = false;
 
   
 
   
 
     return true;
 
     return true;
  }
+
  }  
 
   
 
   
 
  void ProtoComponentThread::run(){
 
  void ProtoComponentThread::run(){
 
+
 
     /*  
 
     /*  
 
     * do some work ....
 
     * do some work ....
Line 547: Line 583:
 
      
 
      
 
     unsigned char value;
 
     unsigned char value;
 +
    double start;
 +
 
 +
    start = yarp::os::Time::now(); // start time
 
   
 
   
 
     while (isStopping() != true) { // the thread continues to run until isStopping() returns true
 
     while (isStopping() != true) { // the thread continues to run until isStopping() returns true
 
+
 
       cout << "protoComponentThread: threshold value is " << *thresholdValue << endl;
+
       if (debug)
 +
          cout << "protoComponentThread: threshold value is " << *thresholdValue << endl;
 
        
 
        
 +
      /* read image ... block until image is received */
 +
 
       do {
 
       do {
 
           image = imagePortIn->read(true);
 
           image = imagePortIn->read(true);
Line 557: Line 599:
 
        
 
        
 
       if (isStopping()) break; // abort this loop to avoid make sure we don't continue and possibly use NULL images  
 
       if (isStopping()) break; // abort this loop to avoid make sure we don't continue and possibly use NULL images  
 +
 +
 +
      /* read threshold ... block if threshold is not received */
 +
      /*
 +
      do {
 +
          thresholdVector = thresholdPortIn->read(false);
 +
      } while ((thresholdVector == NULL) && (isStopping() != true));  // exit loop if shutting down;
 +
      */
 +
 
 +
      /* read threshold ... do not block if threshold is not received */
 +
 +
      thresholdVector = thresholdPortIn->read(false);
 +
   
 +
      if (thresholdVector != NULL) {
 +
            *thresholdValue = (int) (*thresholdVector)[0];
 +
      }
 +
 +
 +
      if (debug)
 +
          cout << "protoComponentThread: threshold value is " << *thresholdValue << endl;
 +
     
 +
 +
      /* write out the binary image */
 
   
 
   
 
       ImageOf<PixelRgb> &binary_image = imagePortOut->prepare();
 
       ImageOf<PixelRgb> &binary_image = imagePortOut->prepare();
 
       binary_image.resize(image->width(),image->height());
 
       binary_image.resize(image->width(),image->height());
 +
 +
      numberOfForegroundPixels = 0;
 
   
 
   
 
       for (x=0; x<image->width(); x++) {
 
       for (x=0; x<image->width(); x++) {
Line 568: Line 635:
 
               if (((rgbPixel.r + rgbPixel.g + rgbPixel.b)/3) > *thresholdValue) {
 
               if (((rgbPixel.r + rgbPixel.g + rgbPixel.b)/3) > *thresholdValue) {
 
                 value = (unsigned char) 255;
 
                 value = (unsigned char) 255;
 +
                numberOfForegroundPixels++;
 
               }
 
               }
 
               else {
 
               else {
Line 580: Line 648:
 
           }
 
           }
 
         }
 
         }
+
       
 
         imagePortOut->write();
 
         imagePortOut->write();
 +
 +
        /* write out the image statistics */
 +
 +
        Bottle &statisticsMessage = statisticsPortOut->prepare();
 +
 +
        statisticsMessage.clear();
 +
 +
        statisticsMessage.addInt((int)(yarp::os::Time::now()-start));
 +
        statisticsMessage.addString("seconds elapsed");
 +
        statisticsMessage.addString(" - foreground pixel count is");
 +
        statisticsMessage.addInt(numberOfForegroundPixels);
 +
        statisticsPortOut->write();
 
     }
 
     }
 
  }
 
  }
Line 588: Line 668:
 
  {
 
  {
 
     /* for example, delete dynamically created data-structures */
 
     /* for example, delete dynamically created data-structures */
 +
}
 +
 +
 +
==<code>protoComponentMain.cpp</code>==
 +
 +
/*
 +
  * Copyright (C) 2014 DREAM Consortium
 +
  * FP7 Project 611391 co-funded by the European Commission
 +
  *
 +
  * Author:  <name of author>, <author institute>
 +
  * Email:  <preferred email address>
 +
  * Website: www.dream20202.eu
 +
  *
 +
  * This program comes with ABSOLUTELY NO WARRANTY
 +
  */
 +
 
 +
 +
/*
 +
  * Audit Trail
 +
  * -----------
 +
  * 20/08/14  First version validated (David Vernon)
 +
  */
 +
 
 +
#include "protoComponent.h"
 +
 
 +
int main(int argc, char * argv[])
 +
{
 +
  /* initialize yarp network */
 +
 
 +
  Network yarp;
 +
 
 +
  /* create your module */
 +
 
 +
  ProtoComponent protoComponent;
 +
 
 +
  /* prepare and configure the resource finder */
 +
 
 +
  ResourceFinder rf;
 +
  rf.setVerbose(true);
 +
  rf.setDefaultConfigFile("protoComponent.ini");          // can be overridden by --from parameter
 +
  rf.setDefaultContext("protoComponent/configuration");  // can be overridden by --context parameter
 +
  rf.configure("DREAM_ROOT", argc, argv);                // environment variable with root of configuration path
 +
 
 +
  /* run the module: runModule() calls configure first and, if successful, it then runs */
 +
 
 +
  protoComponent.runModule(rf);
 +
 
 +
  return 0;
 
  }
 
  }

Revision as of 05:27, 4 November 2014

protoComponent.h

/** @file protoComponent.h  Interface file for the example DREAM component
 *
 * Version 1.0
 * 
 * 20/8/2014
 *
 *
 * \defgroup DREAM_protoComponent protoComponent
 * 
 * This application demonstates the use of the protoComponent module. 
 * This is a simple example to illustrate a component that is compliant with
 * mandatory DREAM software standards for
 * 
 * 1. File organization
 * 2. Internal source code documentation
 * 3. Component functionality
 * 
 * as well as recommended DREAM software standards for 
 * 
 * 4. Programming style
 * 5. Programming practice 
 * 
 * These standards are documented in Appendices A-E of Deliverable 3.2 
 * 
 * Overall, the standards address the 4 Cs of component-based software engineering:
 * 
 * - configuration
 * - coordination
 * - computation
 * - computation
 *
 * Functionally, the module 
 * - reads a colour image from an input port,
 * - reads a threshold value from an imput port,
 * - converts it to a binary image based on a supplied threshold,
 * - counts the number of foreground pixels and background pixels,
 * - writes the binary image to an output port,
 * - and writes the pixel statistics and the time to another output port.
 *
 * The purpose of these operations is simply to illustrate how input/ouput is performed.  
 * The image processing itself is trivial and of no importance.
 *
 * The module also reads a configuration file containing the intrinsic
 * parameters of the robot's two cameras as an example of more advanced parsing 
 * techniques.
 *
 * A complete tutorial on this example is available on the DREAM wiki 
 *
 * 
 * \section lib_sec Libraries
 *
 * YARP.
 *
 * \section parameters_sec Parameters
 * 
 * Command-line Parameters  
 * 
 * The following key-value pairs can be specified as command-line parameters 
 * by prefixing \c -- to the key e.g. \c --from file.ini. 
 * The value part can be changed to suit your needs; the default values are 
 * shown below. 
 *
 * - \c from \c protoComponent.ini \n 
 *   specifies the configuration file
 *
 * - \c context \c protoComponent/configuration \n
 *   specifies the sub-path from \c $DREAM_ROOT/protoComponent/configuration 
 *   to the configuration file
 *
 * - \c name \c protoComponent \n   
 *   specifies the name of the module (used to form the stem of module port names)  
 *
 *
 * Configuration File Parameters 
 *
 * The following key-value pairs can be specified as parameters in the configuration file 
 * (they can also be specified as command-line parameters if you so wish). 
 * The value part can be changed to suit your needs; the default values are shown below. 
 *   
 * - \c imageInputPort \c /image:i \n    
 *   specifies the image input port name (this string will be prefixed by \c /protoComponent 
 *   or whatever else is specifed by the name parameter
 *   
 * - \c thresholdInputPort \c /threshold:i \n    
 *   specifies the threshold input port name (this string will be prefixed by \c /protoComponent 
 *   or whatever else is specifed by the name parameter
 *
 * - \c imageOutputPort \c /image:o \n  
 *   specifies the image output port name (this string will be prefixed by \c /protoComponent 
 *   or whatever else is specifed by the name parameter
 * 
 * - \c statisticsOutputPort \c /statistics:o \n  
 *   specifies the statistics output port name (this string will be prefixed by \c /protoComponent 
 *   or whatever else is specifed by the name parameter
 *
 * - \c cameraConfig \c cameras.ini \n
 *   specifies the camera configuration file containing the intrinsic parameters of
 *   the left and right cameras
 *
 * - \c threshold \c 7 \n           
 *   specifies the threshold value
 *
 * 
 * \section portsa_sec Ports Accessed
 * 
 * - None
 *                      
 * \section portsc_sec Ports Created
 *
 *  Input ports
 *
 *  - \c /protoComponent \n
 *    This port is used to change the parameters of the module at run time or stop the module. \n
 *    The following commands are available
 * 
 *    \c help \n
 *    \c quit \n
 *    \c set \c thr \c <n>   ... set the threshold for binary segmentation of the input RGB image 
 *    (where \c <n> is an integer number)
 *
 *    Note that the name of this port mirrors whatever is provided by the \c --name parameter value
 *    The port is attached to the terminal so that you can type in commands and receive replies.
 *    The port can be used by other modules but also interactively by a user through the yarp rpc directive, viz.: \c yarp \c rpc \c /protoComponent
 *    This opens a connection from a terminal to the port and allows the user to then type in commands and receive replies.
 *       
 *  - \c /protoComponent/image:i \n
 *       
 *  - \c /protoComponent/threshold:i \n
 *
 * Output ports
 *
 *  - \c /protoComponent \n
 *    see above
 *
 *  - \c /protoComponent/image:o \n
 *
 *  - \c /protoComponent/statistics:o \n
 *
 * Port types 
 *
 * The functional specification only names the ports to be used to communicate with the module 
 * but doesn't say anything about the data transmitted on the ports. This is defined by the following code. 
 *
 * \c BufferedPort<ImageOf<PixelRgb> >   \c imageIn; \n 
 * \c BufferedPort<VectorOf<int> >       \c thresholdIn; //int threshold  \n  
 * \c BufferedPort<ImageOf<PixelRgb> >   \c imageOut; \n  
 * \c BufferedPort                       \c statisticsOut; \n      
 *
 * Thus, there are three types of port in use here, all buffered: 
 * 
 * - image, 
 * - vector of int (there will be just one element in the vector in this case), and 
 * - a bottle comprising alphanumerics messages.
 *
 *
 * \section in_files_sec Input Data Files
 *
 * None
 *
 * \section out_data_sec Output Data Files
 *
 * None
 *
 * \section conf_file_sec Configuration Files
 *
 * \c protoComponent.ini   
 * \c cameras.ini  
 *
 * \section example_sec Example Instantiation of the Module
 * 
 * protoComponent --name protoComponent --context components/protoComponent/config --from protoComponent.ini 
 *
 * \author 
 * 
 * <name of author>, <author institute>  
 * 
 * Copyright (C) 2014 DREAM Consortium
 * 
 */

/* 
 * Copyright (C) 2014 DREAM Consortium
 * FP7 Project 611391 co-funded by the European Commission
 *
 * Author:  David Vernon, University of Skövde 
 * Email:   david.vernon@his.se 
 * Website: www.dream20202.eu 
 *
 * This program comes with ABSOLUTELY NO WARRANTY 
 */
  
  
/* 
 * Audit Trail
 * -----------
 * 20/08/14  First version validated (David Vernon)
 * 06/10/14  Additional ports for threshold input and statistic output (David Vernon)
 *
 */ 
 
#include <iostream>
#include <string>

#include <yarp/sig/all.h>
#include <yarp/os/all.h>
#include <yarp/os/RFModule.h>
#include <yarp/os/Network.h>
#include <yarp/os/Thread.h>
 
using namespace std;
using namespace yarp::os; 
using namespace yarp::sig;
  
class ProtoComponentThread : public Thread {

private:

   /* class variables */

    bool               debug;
   int                x, y;
   PixelRgb           rgbPixel;
   ImageOf<PixelRgb> *image;
   int               *thresholdValue;   
   VectorOf<int>     *thresholdVector;
   int               numberOfForegroundPixels;

   /* thread parameters: they are pointers so that they refer to the original variables in protoComponent */

   BufferedPort<ImageOf<PixelRgb> > *imagePortIn;
   BufferedPort<VectorOf<int> >     *thresholdPortIn; 
   BufferedPort<ImageOf<PixelRgb> > *imagePortOut; 
   BufferedPort<Bottle>             *statisticsPortOut; 
  

  public:
 
    /* class methods */
 
    ProtoComponentThread(BufferedPort<ImageOf<PixelRgb> > *imageIn, 
                         BufferedPort<VectorOf<int> >     *thresholdIn, 
                         BufferedPort<ImageOf<PixelRgb> > *imageOut,
                         BufferedPort<Bottle>             *statisticsOut, 
                         int *threshold );
    bool threadInit();     
    void threadRelease();
    void run(); 
};


class ProtoComponent:public RFModule {

   /* module parameters */

   string moduleName;
   string imageInputPortName;
   string thresholdInputPortName;
   string imageOutputPortName;
   string statisticsOutputPortName;  
   string handlerPortName;
   string cameraConfigFilename;
   float  fxLeft,  fyLeft;          // focal length
   float  fxRight, fyRight;         // focal length
   float  cxLeft,  cyLeft;          // coordinates of the principal point
   float  cxRight, cyRight;         // coordinates of the principal point
   int    thresholdValue;

   /* class variables */

   BufferedPort<ImageOf<PixelRgb> > imageIn;       // example image input port
   BufferedPort<VectorOf<int> >     thresholdIn;   // example vector input port 
   BufferedPort<ImageOf<PixelRgb> > imageOut;      // example image output port
   BufferedPort<Bottle>             statisticsOut; // example bottle output port
   Port handlerPort;                               // a port to handle interactive messages (also uses bottles)

   /* pointer to a new thread to be created and started in configure() and stopped in close() */

   ProtoComponentThread *protoComponentThread;

public:
  
   bool configure(yarp::os::ResourceFinder &rf); // configure all the module parameters and return true if successful
   bool interruptModule();                       // interrupt, e.g., the ports 
   bool close();                                 // close and shut down the module
   bool respond(const Bottle& command, Bottle& reply);
   double getPeriod(); 
   bool updateModule();
}; 


protoComponentConfiguration.cpp

/* 
 * Copyright (C) 2014 DREAM Consortium
 * FP7 Project 611391 co-funded by the European Commission
 *
 * Author:  David Vernon, University of Skövde 
 * Email:   david.vernon@his.se 
 * Website: www.dream20202.eu  
 *
 * This program comes with ABSOLUTELY NO WARRANTY 
 */
  
 
/*
 * Audit Trail
 * -----------
 * 20/08/14  First version validated (David Vernon)
 * 06/10/14  Additional ports for threshold input and statistic output (David Vernon)
 *
 */ 

#include "protoComponent.h"


/* 
 * Configure method ... use it to do component coordination, 
 * i.e. to configure your component at runtime
 */

bool ProtoComponent::configure(yarp::os::ResourceFinder &rf)
{    
   /* Process all parameters from both command-line and .ini file */

   /* get the module name which will form the stem of all module port names */

   moduleName            = rf.check("name", 
                           Value("protoComponent"), 
                           "module name (string)").asString();

   /*
    * before continuing, set the module name before getting any other parameters, 
    * specifically the port names which are dependent on the module name
    */
  
   setName(moduleName.c_str());

   /* now, get the rest of the parameters */

   /* get the name of the input and output ports, automatically prefixing the module name by using getName() */

   imageInputPortName    =      "/";
   imageInputPortName   +=      getName(
                                rf.check("imageInputPort", 
                                Value("/image:i"),
                                "Input image port (string)").asString()
                                );
   
   thresholdInputPortName =     "/";
   thresholdInputPortName +=    getName(
                                rf.check("thresholdInputPort", 
                                Value("/threshold:i"),
                                "Threshold input port (string)").asString()
                                );

   imageOutputPortName   =      "/";
   imageOutputPortName  +=      getName(
                                rf.check("imageOutputPort", 
                                Value("/image:o"),
                                "Output image port (string)").asString()
                                );

   statisticsOutputPortName   = "/";
   statisticsOutputPortName  += getName(
                                rf.check("statisticsOutputPort", 
                                Value("/statistics:o"),
                                "Output image port (string)").asString()
                                );


   /* get the threshold value */

   thresholdValue        = rf.check("threshold",
                           Value(8),
                           "Key value (int)").asInt();

   
   /* 
    * get the cameraConfig file and read the required parameter values cx, cy 
    * in both the groups [CAMERA_CALIBRATION_LEFT] and [CAMERA_CALIBRATION_RIGHT]
    */

   cameraConfigFilename  = rf.check("cameraConfig", 
                           Value("cameras.ini"), 
                           "camera configuration filename (string)").asString();

   cameraConfigFilename = (rf.findFile(cameraConfigFilename.c_str())).c_str();

   Property cameraProperties;

   if (cameraProperties.fromConfigFile(cameraConfigFilename.c_str()) == false) {
      cout << "protoComponent: unable to read camera configuration file" << cameraConfigFilename << endl;
      return 0;
   }
   else {
      cxLeft  = (float) cameraProperties.findGroup("CAMERA_CALIBRATION_LEFT").check("cx", Value(160.0), "cx left").asDouble();
      cyLeft  = (float) cameraProperties.findGroup("CAMERA_CALIBRATION_LEFT").check("cy", Value(120.0), "cy left").asDouble();
      cxRight = (float) cameraProperties.findGroup("CAMERA_CALIBRATION_RIGHT").check("cx", Value(160.0), "cx right").asDouble();
      cyRight = (float) cameraProperties.findGroup("CAMERA_CALIBRATION_RIGHT").check("cy", Value(120.0), "cy right").asDouble();
   }


   /* do all initialization here */
     
   /* open ports  */ 
       
   if (!imageIn.open(imageInputPortName.c_str())) {
      cout << getName() << ": unable to open port " << imageInputPortName << endl;
      return false;  // unable to open; let RFModule know so that it won't run
   }

   if (!thresholdIn.open(thresholdInputPortName.c_str())) {
      cout << getName() << ": unable to open port " << thresholdInputPortName << endl;
      return false;  // unable to open; let RFModule know so that it won't run
   }


   if (!imageOut.open(imageOutputPortName.c_str())) {
      cout << getName() << ": unable to open port " << imageOutputPortName << endl;
      return false;  // unable to open; let RFModule know so that it won't run
   }

   if (!statisticsOut.open(statisticsOutputPortName.c_str())) {
      cout << getName() << ": unable to open port " << statisticsOutputPortName << endl;
      return false;  // unable to open; let RFModule know so that it won't run
   }


   /*
    * attach a port of the same name as the module (prefixed with a /) to the module
    * so that messages received from the port are redirected to the respond method
    */

   handlerPortName =  "/";
   handlerPortName += getName();         // use getName() rather than a literal 
 
   if (!handlerPort.open(handlerPortName.c_str())) {           
      cout << getName() << ": Unable to open port " << handlerPortName << endl;  
      return false;
   }

   attach(handlerPort);                  // attach to port
 
   /* create the thread and pass pointers to the module parameters */

   protoComponentThread = new ProtoComponentThread(&imageIn, &thresholdIn, &imageOut, &statisticsOut, &thresholdValue);

   /* now start the thread to do the work */

   protoComponentThread->start(); // this calls threadInit() and it if returns true, it then calls run()
 
   return true ;      // let the RFModule know everything went well
                      // so that it will then run the module
}


bool ProtoComponent::interruptModule()
{
   protoComponentThread->stop();

   imageIn.interrupt();
   thresholdIn.interrupt();
   imageOut.interrupt();
   handlerPort.interrupt();

   return true;
}


bool ProtoComponent::close()
{
   /* stop the thread */

   imageIn.close();
   thresholdIn.close();
   imageOut.close();
   handlerPort.close();

   return true;
} 


bool ProtoComponent::respond(const Bottle& command, Bottle& reply) 
{
  string helpMessage =  string(getName().c_str()) + 
                        " commands are: \n" +  
                        "help \n" + 
                        "quit \n" + 
                        "set thr <n> ... set the threshold \n" + 
                        "(where <n> is an integer number) \n";

  reply.clear(); 

  if (command.get(0).asString()=="quit") {
       reply.addString("quitting");
       return false;     
   }
   else if (command.get(0).asString()=="help") {
      cout << helpMessage;
	  reply.addString("command is: set thr <n>");
   }
   else if (command.get(0).asString()=="set") {
      if (command.get(1).asString()=="thr") {
         thresholdValue = command.get(2).asInt(); // set parameter value
         reply.addString("ok");
      }
   }
   return true;
}


/* Called periodically every getPeriod() seconds */

bool ProtoComponent::updateModule()
{
   return true;
}

double ProtoComponent::getPeriod()
{
   /* module periodicity (seconds), called implicitly by protoComponent */
    
   return 0.1;
}


protoComponentComputation.cpp

/* 
 * Copyright (C) 2014 DREAM Consortium
 * FP7 Project 611391 co-funded by the European Commission
 *
 * Author:  David Vernon, University of Skövde 
 * Email:   david.vernon@his.se 
 * Website: www.dream20202.eu 
 *
 * This program comes with ABSOLUTELY NO WARRANTY 
 */

 
/*
 * Audit Trail
 * -----------
 * 20/08/14  First version validated (David Vernon)
 * 06/10/14  Additional ports for threshold input and statistic output (David Vernon)
 *
 */ 
 

#include "protoComponent.h"

ProtoComponentThread::ProtoComponentThread(BufferedPort<ImageOf<PixelRgb> > *imageIn, 
                                           BufferedPort<VectorOf<int> >     *thresholdIn, 
                                           BufferedPort<ImageOf<PixelRgb> > *imageOut,
                                           BufferedPort<Bottle>             *statisticsOut, 
                                           int *threshold)
{
   imagePortIn       = imageIn;
   thresholdPortIn   = thresholdIn;
   imagePortOut      = imageOut; 
   statisticsPortOut = statisticsOut;
   thresholdValue    = threshold;
}

bool ProtoComponentThread::threadInit() 
{
   /* initialize variables and create data-structures if needed */

   debug = false;

   return true;
} 

void ProtoComponentThread::run(){

   /* 
    * do some work ....
    * for example, convert the input image to a binary image using the threshold provided 
    */ 
   
   unsigned char value;
   double start;
 
   start = yarp::os::Time::now(); // start time

   while (isStopping() != true) { // the thread continues to run until isStopping() returns true
  
      if (debug)
         cout << "protoComponentThread: threshold value is " << *thresholdValue << endl;
      
      /* read image ... block until image is received */

      do {
         image = imagePortIn->read(true);
      } while ((image == NULL) && (isStopping() != true));  // exit loop if shutting down;
      
      if (isStopping()) break; // abort this loop to avoid make sure we don't continue and possibly use NULL images 


      /* read threshold ... block if threshold is not received */
      /*
      do {
         thresholdVector = thresholdPortIn->read(false);
      } while ((thresholdVector == NULL) && (isStopping() != true));  // exit loop if shutting down;
      */
  
      /* read threshold ... do not block if threshold is not received */

      thresholdVector = thresholdPortIn->read(false);
    
      if (thresholdVector != NULL) {
            *thresholdValue = (int) (*thresholdVector)[0];
      }


      if (debug)
         cout << "protoComponentThread: threshold value is " << *thresholdValue << endl;
      

      /* write out the binary image */

      ImageOf<PixelRgb> &binary_image = imagePortOut->prepare();
      binary_image.resize(image->width(),image->height());

      numberOfForegroundPixels = 0;

      for (x=0; x<image->width(); x++) {
         for (y=0; y<image->height(); y++) {

             rgbPixel = image->safePixel(x,y);

             if (((rgbPixel.r + rgbPixel.g + rgbPixel.b)/3) > *thresholdValue) {
                value = (unsigned char) 255;
                numberOfForegroundPixels++;
             }
             else {
                value = (unsigned char) 0;
             }

             rgbPixel.r = value;
             rgbPixel.g = value;
             rgbPixel.b = value;

             binary_image(x,y) = rgbPixel;
          }
       }
       
       imagePortOut->write();

       /* write out the image statistics */

       Bottle &statisticsMessage = statisticsPortOut->prepare();

       statisticsMessage.clear();

       statisticsMessage.addInt((int)(yarp::os::Time::now()-start));
       statisticsMessage.addString("seconds elapsed");
       statisticsMessage.addString(" - foreground pixel count is");
       statisticsMessage.addInt(numberOfForegroundPixels);
       statisticsPortOut->write();
   }
}

void ProtoComponentThread::threadRelease() 
{
   /* for example, delete dynamically created data-structures */
}


protoComponentMain.cpp

/* 
 * Copyright (C) 2014 DREAM Consortium
 * FP7 Project 611391 co-funded by the European Commission
 *
 * Author:  <name of author>, <author institute> 
 * Email:   <preferred email address> 
 * Website: www.dream20202.eu 
 *
 * This program comes with ABSOLUTELY NO WARRANTY 
 */
  

/*
 * Audit Trail
 * -----------
 * 20/08/14  First version validated (David Vernon)
 */ 
 
#include "protoComponent.h" 
 
int main(int argc, char * argv[])
{
  /* initialize yarp network */ 
  
  Network yarp;
 
  /* create your module */
 
  ProtoComponent protoComponent; 
 
  /* prepare and configure the resource finder */
 
  ResourceFinder rf;
  rf.setVerbose(true);
  rf.setDefaultConfigFile("protoComponent.ini");          // can be overridden by --from parameter
  rf.setDefaultContext("protoComponent/configuration");   // can be overridden by --context parameter
  rf.configure("DREAM_ROOT", argc, argv);                 // environment variable with root of configuration path
  
  /* run the module: runModule() calls configure first and, if successful, it then runs */
 
  protoComponent.runModule(rf);
 
  return 0;
}