xai-corner

SourceForge.net Logo

Documentation

  1. Starting new block
  2. Implementing the block
  3. Internal parameters
  4. IO Types
  5. Available macros and methods

Starting new block

  1. The blocks are written in C++ and compiled and linked into a shared, dynamically linked library.
  2. The best way to start, is to use a perl script, available in ##blocks/util/XaiBlock2HTML## directory - ##create_block.pl##
  3. The script requires two things: a block specification file and a template directory. The latter can be found in ##blocks/util/BlockTemplate##. Just copy the template directory to a place where You want to work on Your block.
  4. The block specification file is a little more cumbersome. Here is an example specification (covering all possible options):
    block IPLSmooth {
       path = "/OpenCV";
         
       description = <<"MAINDESC"
       The function cvSmooth smooths image using one of several methods 
       MAINDESC
       
         inputs = [
          {
             name = ipl_image;
             description = "";
             type = IOOpenCVIPL 
           }
         ];
       
         outputs = [
           {
             name = ipl_image;
             description = "";
             type = IOOpenCVIPL
           } 
         ];
       
         parameters = [ 
         { 
           name = smoothtype; 
           description = "Type of the smoothing";
           type = EnumParameter; 
           values = { 
             CV_BLUR_NO_SCALE = CV_BLUR_NO_SCALE;
             CV_BLUR  = CV_BLUR;
             CV_GAUSSIAN = CV_GAUSSIAN;
             CV_MEDIAN = CV_MEDIAN;
             CV_BILATERAL = CV_BILATERAL;
           }; 
           default = CV_BLUR_NO_SCALE
         },
         {
           name = param1;
           description = "The first parameter of smoothing operation";
           type = IntegerParameter;
           default = 3;
         },
         {
           name = param2;
           description = "The second parameter of smoothing operation";
           type = IntegerParameter;
           default = 0;   
         } 
         ];
       
       }
       

Implementing the block

The output from the example specification above is presented below. In order to get a functioning block, You have to implement at least the run() and reset() methods. The first one takes the inputs and/or the parameters and updates the outputs of the block, if any. Let's go through the resulting parts of the block one by one:
  1. The constructor

    This constructor was automatically generated simply from the above specification.

      IPLSmooth::IPLSmooth() {
       
           name = "IPLSmooth";
           path = "/OpenCV/Image_Processing_and_Analysis/";
           description = "The function cvSmooth smooths image using ...";   
           
           inputs.clear();
           outputs.clear();
       
           // Inputs
           addInput(Input("ipl_image", "", new IOType<IplImage>()));
       
       
           // Outputs
           addOutput(Output("ipl_image", "", new IOType<IplImage>()));
       
           // Parameters
           EnumParameter* par0 = new EnumParameter("smoothtype");
           par0->setValue("CV_BLUR_NO_SCALE");
           par0->addValueForKey("CV_BLUR", CV_BLUR);
           par0->addValueForKey("CV_BLUR_NO_SCALE", CV_BLUR_NO_SCALE);
           par0->addValueForKey("CV_GAUSSIAN", CV_GAUSSIAN);
           par0->addValueForKey("CV_MEDIAN", CV_MEDIAN);
           par0->addValueForKey("CV_BILATERAL", CV_BILATERAL);
           addParameter(par0);
       
           IntParameter* par1 = new IntParameter("param1", 3);
           addParameter(par1);
       
           IntParameter* par2 = new IntParameter("param2", 0);
           addParameter(par2);
       
           output_image = NULL;
       
         }
       
  2. The run() method

    This method is more tricky, since it contains the logic of the block. If the method needs to maintain state between the calls (iterations of algorithm) the variables representing the state must be declared as private fields of the class in the blocks header file. It is best to keep the code of this method as optimal as possible. Especially such things as memory allocation or initialization should be done only when necassary (preferably once). For instance the first block of this method, allocates a new IplImage structure. Note, that it cannot be done before the actual execution of the algorithm, since otherwise we wouldn't know some of the parameters of the actual input data, such as size or depth. If the block that provides this input is for instance a AVI file reader, this block will adapt to its resolution and depth. Next step is the extraction of input data from the inputs. This will be more detailed in the section on the type system of Xai, for now, we can see that we have to take the input we want using simple index (inputs is a std::vector object). The input has a pointer to the output that is connected to this input and from this output we can extract the interesting information. After we have input data, we can extract current values of internal parameters of the block. There exists only a limited amount of parameter types, so some convienience macros are defined to help with there extraction. When we have the inputs and parameters we can now perform the actual operation of the block, here it is simply the cvSmooth() method from OpenCV library. Finally, we assign the obtained result to the proper outputs of the block. When the method is finished, the blocks that wait on this output will be able to use it.

      void IPLSmooth::run(void) {
           //
           // Get the input image
           //
           IplImage* input_image = GET_INPUT_DATA(IplImage, 0);
       
           //
           // Create new image with proper parameters depending on input image
           //
           if(!output_image_created) {
             CvSize input_img_size;
             input_img_size.width = input_image->width;
             input_img_size.height = input_image->height;      
             int depth = input_image->depth;      
             int nchannel = input_image->nChannels;      
       
             output_image = cvCreateImage(input_img_size, depth, nchannel);
       
             XAILOGCPP(XAIINFO, getName()<<": Creating output image ");
       
             output_image_created = true;    
       
           }
       
           //
           // Get internal parameter values
           //    
           int smoothtype = GET_ENUM_PARAM_VALUE("smoothtype");
           int param1 = GET_INT_PARAM_VALUE("param1");
           int param2 = GET_INT_PARAM_VALUE("param2");
       
           //
           // Perform the operation
           //    
           cvSmooth(input_image, output_image, smoothtype, param1, param2);
       
           //
           // Assign the output data
           //
           SET_OUTPUT_DATA(IplImage, 0, output_image);
         }
       
  3. The reset() method

    The reset() method is called when the algorithm is stopped. So in order to avoid memory leaks in the blocks, each block should release all memory that he allocated in method run().

      void IPLSmooth::reset() {
           output_image_created = false;
       
           if(output_image != NULL) {
             cvReleaseImage(&output_image);
             output_image = NULL;
           }
         }
       

Internal parameters

The internal parameters of the blocks can be of the following types:
Parameter type Description
integer implemented by class xai::IntParameter
float implemented by class xai::FloatParameter
double implemented by class xai::DoubleParameter
string implemented by class xai::StringParameter, wraps standard std::string class
enum implemented by class xai::EnumParameter, contains a std::map with (name, value) mappings.

Input and Output types

See API docs here

Available macros and methods

Accessing inputs and outputs:
Macro name Description
GET_INPUT_DATA(type, io_number) Returns the pointer to data from input 'io_number' casted to type.
SET_OUTPUT_DATA(type, io_number, data) Sets the 'io_number's output data to 'data' casted to type.
Accessing block params:
Macro name Description
GET_INT_PARAM_VALUE() Returns the int value for given name of the parameter (e.g. GET_INT_PARAM_VALUE("threshold")
GET_STRING_PARAM_VALUE() Returns std::string value for given name
GET_DOUBLE_PARAM_VALUE() Returns double value for param name
GET_FLOAT_PARAM_VALUE() Returns float value for param name
GET_ENUM_PARAM_VALUE() Returns current selected value of enumeration for given name
Error handling methods:
Macro name Description
XAI_REPORT_INFO() Reports to subscribers (e.g. the GUI) some information of low priority - XAI_REPORT_INFO("Calculated first frame")
XAI_REPORT_WARNING() Reports to subscribers (e.g. the GUI) some information of higher priority - XAI_REPORT_WARNING("Processing empty image")
XAI_REPORT_ERROR() Reports to subscribers (e.g. the GUI) some information of highest priority, this call stops the algorithm - XAI_REPOTR_WARNING("Cannot open input file")
STOP_ALGORITHM() This macro can be called from any point in the run() method. It immediately stops the algorithm execution. Preferably You should use XAI_REPORT_ERROR() since it also allows You to forward some meaningful message to the user.