Skip to content

protoComponent source code

Robert Homewood edited this page Dec 12, 2017 · 1 revision

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
  * 
  * <b>Command-line Parameters </b> 
  * 
  * 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)  
  *
  *
  * <b>Configuration File Parameters </b>
  *
  * 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
  *
  *  <b>Input ports</b>
  *
  *  - \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
  *
  * <b>Output ports</b>
  *
  *  - \c /protoComponent \n
  *    see above
  *
  *  - \c /protoComponent/image:o \n
  *
  *  - \c /protoComponent/statistics:o \n
  *
  * <b>Port types </b>
  *
  * 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; <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
  *
  * 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
  * 
  * <tt>protoComponent --name protoComponent --context components/protoComponent/config --from protoComponent.ini </tt>
  *
  * \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();
 }; 

Back to Software Development Guide

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;
 }

Back to Software Development Guide

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 */
 }

Back to Software Development Guide

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;
 }

Back to Software Development Guide


Clone this wiki locally