InterIMAGE wiki

InterIMAGE: Creating an operator

TerraAIDA project aims to build InterIMAGE operators using the TerraLib library following the GNU LGLP license model. More information at http://www.dpi.inpe.br/terraaida/.

This page will present an example of how to create your own InterIMAGE operator, using TerraLib.

After created, your operator must have two files, to be inserted into InterIMAGE:

  • The binary, which will perform the implemented operation,
  • The .op file descriptor, describing the parameters, understandable by InterIMAGE GUI.

In this page we describe how to create the source-code of the operator. For information about how to define your .op file descriptor, read the Section “3.1. Operator Description File”, in the System Overview Operation Guide.

The structure of files should follow this example in order to run properly.

The operator main file will call the operator function, which checks the parameters and produces the output. The operator function header can also communicate with InterIMAGE GUI in order to be called directly. Here we create a simple operator, which gets an image by input, and outputs the regions according a certain threshold defined by the user.

Download source-code here.

Operator .op file

The following code represents the .op file to be loaded into InterIMAGE GUI.

<operator type=topdown class=gis name=TerraAIDA_Threshold
  cmd="ta_threshold \"@geoWest@\" \"@geoNorth@\" \"@geoEast@\" \"@geoSouth@\" \"@output@\" \"@class@\" \"@tmpdir@\" \"@mask_file@\" \"@image_name@\" \"@image_channel@\" \"@threshold_min@\" \"@threshold_max@\" \"@reliability@\" "
  runglobal=false tip="Threshold one image by min and max values" >
  <attribute name=image_name type=file ext="tif;jpg" label="Input Image">
  <attribute name=image_channel label="Image channel/band" type=int value=0>
  <attribute name=threshold_min label="Threshold Min" type=double value=0 >
  <attribute name=threshold_max label="Threshold Max" type=double value=255 >
  <attribute name=reliability label="Reliability" type=double value=1.0>
</operator>

The resultant set of parameters will appear in InterIMAGE like the next figure.

Operator Main File

#include <execTAThreshold.hpp>
#include <OpSupportFunctions.hpp>
 
#include <iostream>
 
int main( int argc, char ** argv )
{
  // if executed with no parameters
  if( argc == 1 )
  {
    std::cout << std::endl << "TerraAIDA threshold operator - Version " + 
      OpSupportFunctions::getTAVersion() << std::endl;
    return EXIT_SUCCESS;
  }
 
  // if executed with parameters
  return TerraAIDA::execTAThreshold( argc, argv );
}

Operator Function Header

#ifndef TAEXECTHRESHOLD_HPP
  #define TAEXECTHRESHOLD_HPP
 
  namespace TerraAIDA
  {
    /**
     * @brief TerraAIDA threshold operator function.
     * @param argc Arguments count.
     * @param argv Arguments strings.
     * @return EXIT_FAILURE or EXIT_SUCCESS
     */  
    int execTAThreshold( int argc, char ** argv );
  }
 
#endif  

Operator Function Implementation

#include "execTAThreshold.hpp"
#include "OpSupportFunctions.hpp"
 
#include <TePDIUtils.hpp>
#include <TePDIRaster2Vector.hpp>
 
namespace TerraAIDA
{
  int execTAThreshold( int argc, char ** argv )
  {
    try 
    {
      // read input
      // process input
      // generate output
    }
    catch( const TeException& e ) {
      TEAGN_LOGERR( e.message() )
      return EXIT_FAILURE;
    }    
    catch( ... ) {
      TEAGN_LOGERR( "Unhandled exception" )
      return EXIT_FAILURE;
    }  
 
    TEAGN_LOGMSG( "Thresholding finished" )
    return EXIT_SUCCESS;
  }
 
}

Reading Input

      /* Extracting system default parameters */
 
      int param_index = 1;
 
      const double geoWest = atof( argv[ param_index ] );
      ++param_index;
 
      const double geoNorth = atof( argv[ param_index ] );
      ++param_index;
 
      const double geoEast = atof( argv[ param_index ] );
      ++param_index;
 
      const double geoSouth = atof( argv[ param_index ] );
      ++param_index;
 
      const std::string output = argv[ param_index ];
      ++param_index;
 
      const std::string class_str = argv[ param_index ];
      ++param_index;
 
      const std::string tmpdir = argv[ param_index ];
      ++param_index;
 
      bool use_mask = true;
      const std::string mask_file = argv[ param_index ];
      if( mask_file.empty() ) use_mask = false;
      ++param_index;
 
      /* Extracting user parameters */
 
      const std::string image_name = argv[ param_index ];
      ++param_index;
      TEAGN_TRUE_OR_THROW( image_name.find( ";" ) ==
        image_name.npos, "Only one input image file must be used" )    
 
      const int image_channel = atoi( argv[ param_index ] );    
      ++param_index;
 
      const double treshold_min = atof( argv[ param_index ] );
      ++param_index;
 
      const double treshold_max = atof( argv[ param_index ] );
      ++param_index;
 
      const double node_weight = atof( argv[ param_index ] );
      ++param_index;       
 

Processing Input

      /* output image file names */
 
      const std::string output_image_file_name = output +
        ".plm";    
 
      /* Initiating image_name image  */
 
      TePDITypes::TePDIRasterPtrType image_ptr;
      TePDITypes::TePDIRasterPtrType image_clip_ptr;
      {
        image_ptr.reset(
          new TeRaster( image_name, 'r' ) ) ;
        TEAGN_TRUE_OR_THROW( image_ptr->init(), 
          "Unable to get " + image_name ); 
 
        TEAGN_TRUE_OR_THROW( 
          ( image_channel < image_ptr->params().nBands() ),
          "Invalid image channel" )        
 
        std::vector< unsigned int > image_channels_vec;
        image_channels_vec.push_back( image_channel );
 
        TEAGN_TRUE_OR_THROW( OpSupportFunctions::createRasterClip( 
          image_ptr, image_channels_vec,
          geoWest, geoNorth, geoEast, geoSouth, image_clip_ptr ),
          "Error clipping raster" )
      }
 
      /* Initiating mask image */
 
      TePDITypes::TePDIRasterPtrType mask_raster_ptr;
      if( use_mask ) {
        TEAGN_TRUE_OR_THROW( OpSupportFunctions::getMaskRaster( 
          mask_file, geoWest, geoNorth, geoEast, geoSouth,
          mask_raster_ptr ), "Unable to get mask image" );
      }
 
      /* Bring all rasters to match dimentions */
 
      {
        TePDITypes::TePDIRasterVectorType input_rasters_vec;
        input_rasters_vec.push_back( image_clip_ptr );
        TePDITypes::TePDIRasterVectorType output_rasters_vec;
 
        if( use_mask )
        {
          TEAGN_TRUE_OR_THROW( OpSupportFunctions::resampleRasters(
            mask_raster_ptr->params().nlines_,
            mask_raster_ptr->params().ncols_,
            input_rasters_vec, output_rasters_vec ),
            "Error resampling rasters" );
        }
        else
        {
          TEAGN_TRUE_OR_THROW( OpSupportFunctions::resampleRasters(
            input_rasters_vec, output_rasters_vec ),
            "Error resampling rasters" );
        }
 
        image_clip_ptr = output_rasters_vec[ 0 ];
      }
 
      /* allocating threshold raster */
 
      TePDITypes::TePDIRasterPtrType thres_raster_ptr;
      {
        TeRasterParams thres_raster_params = 
          image_clip_ptr->params();
        thres_raster_params.nBands( 1 );
        thres_raster_params.setDataType( TeUNSIGNEDCHAR, -1 );
 
        TEAGN_TRUE_OR_THROW( OpSupportFunctions::createMemRaster( 
          thres_raster_params, thres_raster_ptr ),
          "Error creating threshold ram raster" )    
      }
 
      /* limiarizing  
         value 0 - no-data
         value 1 - data
      */
 
      {
        const unsigned int lines = (unsigned int)image_clip_ptr->params().nlines_;
        const unsigned int cols = (unsigned int)image_clip_ptr->params().ncols_;
        unsigned int line = 0;
        unsigned int col = 0;
        double mask_value = 1.0;
        double thr_value = 0;
        double arith_value = 0;
 
        for( ; line < lines ; ++line ) {
          for( col = 0 ; col < cols ; ++col ) {
            if( use_mask ) {
              mask_raster_ptr->getElement( col, line, mask_value, 0 );
 
              if( mask_value != 0 ) 
              {
                thr_value = 0;
              }
              else
              {
                if( image_clip_ptr->getElement( col, line, 
                  arith_value, 0 ) ) 
                { 
                  if( ( arith_value > treshold_min ) &&
                    ( arith_value < treshold_max ) ) 
                  {
                    thr_value = 1;
                  } else {
                    thr_value = 0;
                  }
                }
                else
                {
                  thr_value = 0;
                }  
              }
            } 
            else // there is no mask  
            {
              if( image_clip_ptr->getElement( col, line, arith_value, 
                0 ) ) 
              { 
                if( ( arith_value > treshold_min ) &&
                  ( arith_value < treshold_max ) )
                {
                  thr_value = 1;
                } else {
                  thr_value = 0;
                }
              }
              else
              {
                thr_value = 0;
              }          
            }
 
            thres_raster_ptr->setElement( col, line, thr_value, 0 );
          }
        }
      }  
 
      /* Free unused resources */
 
      mask_raster_ptr.reset();
 
      /* Vectorizing the thres_raster_ptr */
 
      OpSupportFunctions::ClassesDataVectorT regions_data_vector;
      {
        // Preparing vector
 
        const std::string nClassStr = "n-" + class_str;
 
        regions_data_vector.push_back( OpSupportFunctions::ClassesDataNode() );
        regions_data_vector.push_back( OpSupportFunctions::ClassesDataNode() );
 
        OpSupportFunctions::ClassesDataNode& classNode = regions_data_vector[ 0 ];
        classNode.class_id_ = class_str;
        classNode.class_value_ = 1;
 
        OpSupportFunctions::ClassesDataNode& nClassNode = regions_data_vector[ 1 ];
        nClassNode.class_id_ = nClassStr;
        nClassNode.class_value_ = 2;
 
        // Vectorizing
 
        TePDITypes::TePDIPolSetMapPtrType aux_output_polsets( 
          new TePDITypes::TePDIPolSetMapType );
 
        TePDIParameters algo_params;
 
        algo_params.SetParameter( "rotulated_image", 
          thres_raster_ptr );
 
        algo_params.SetParameter( "output_polsets", aux_output_polsets );
        algo_params.SetParameter( "channel", (unsigned int)0 );
 
        TePDIRaster2Vector vectorizer_instance;
 
        TEAGN_TRUE_OR_THROW( vectorizer_instance.Reset( algo_params ), 
          "Algorithm Reset error" ); 
 
        TEAGN_TRUE_OR_THROW( vectorizer_instance.Apply(), 
          "Algorithm Apply error" );
 
        /* re-ordering polygons and filtering out polygons with area smaller 
           than area_min */
 
        unsigned int curr_pol_nmb = 1;
 
        TePDITypes::TePDIPolSetMapType::iterator map_it = 
          aux_output_polsets->begin();
        TePDITypes::TePDIPolSetMapType::iterator map_it_end = 
          aux_output_polsets->end();
        TePolygonSet::iterator ps_it;
        TePolygonSet::iterator ps_it_end;
 
        while( map_it != map_it_end ) {
          if( map_it->first == 1 ) {
            ps_it = map_it->second.begin();
            ps_it_end = map_it->second.end();
 
            while( ps_it != ps_it_end ) {
              TePolygon& curr_pol = *ps_it;
              classNode.pols_.add( curr_pol );
              ++curr_pol_nmb;
              ++ps_it;
            }       
          } else if( map_it->first == 0 ) {
            ps_it = map_it->second.begin();
            ps_it_end = map_it->second.end();
 
            while( ps_it != ps_it_end ) {
              TePolygon& curr_pol = *ps_it;
              nClassNode.pols_.add( curr_pol );
              ++curr_pol_nmb;
              ++ps_it;
            } 
          }
 
          ++map_it;
        }
 
         /* Updating the polygons indexed boxes */
 
         TEAGN_TRUE_OR_THROW( OpSupportFunctions::updatePolsIndexedBoxes(
           thres_raster_ptr, regions_data_vector ),
           "Error updating polygons indexed boxes" );
 
      }

Generating the Output

      /* Generating the output labeled image */
      TEAGN_TRUE_OR_THROW( OpSupportFunctions::saveLabeledImageFile(
        output_image_file_name, thres_raster_filtered_ptr, 0 ),
        "Error saving label image" )
 
      /* Generating output polygons file */
      TEAGN_TRUE_OR_THROW( OpSupportFunctions::createRegionsDescFile( 
        output, regions_data_vector, thres_raster_filtered_ptr->params(), 
        node_weight,
        geoWest, geoNorth, geoEast, geoSouth ), 
        "Unable to export polygons file" );

Navigation