[[interimage:|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 [[http://www.dpi.inpe.br/terraaida/documentos/referencias/GeoAIDA_Overview.doc|System Overview Operation Guide]]. The structure of files should follow this example in order to run properly. {{interimage:operators_400.png|}} 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 {{interimage:ta_threshold.zip|here}}. ===== Operator .op file ===== The following code represents the .op file to be loaded into InterIMAGE GUI. The resultant set of parameters will appear in InterIMAGE like the next figure. {{interimage:op_parameters.png|}} ===== Operator Main File ===== #include #include #include 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 #include 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" );