All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
ClassifierMAPStrategy.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2008 National Institute For Space Research (INPE) - Brazil.
2 
3  This file is part of the TerraLib - a Framework for building GIS enabled applications.
4 
5  TerraLib is free software: you can redistribute it and/or modify
6  it under the terms of the GNU Lesser General Public License as published by
7  the Free Software Foundation, either version 3 of the License,
8  or (at your option) any later version.
9 
10  TerraLib is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU Lesser General Public License for more details.
14 
15  You should have received a copy of the GNU Lesser General Public License
16  along with TerraLib. See COPYING. If not, write to
17  TerraLib Team at <terralib-team@terralib.org>.
18  */
19 
20 /*!
21  \file terralib/rp/ClassifierMAPStrategy.cpp
22 
23  \brief Maximum a posteriori probability strategy.
24 */
25 
26 // TerraLib
27 
28 #include "ClassifierMAPStrategy.h"
29 #include "Macros.h"
30 #include "../raster/Band.h"
31 #include "../common/MatrixUtils.h"
32 
33 #include <cfloat>
34 
35 namespace
36 {
37  static te::rp::ClassifierMAPStrategyFactory classifierMAPStrategyFactoryInstance;
38 }
39 
40 //-----------------------------------------------------------------------------
41 
43 {
44  reset();
45 }
46 
48 {
49 }
50 
52 {
53  reset();
54 
55  m_trainSamplesPtr = rhs.m_trainSamplesPtr;
56  m_prioriProbs = rhs.m_prioriProbs;
57  m_prioriCalcSampleStep = rhs.m_prioriCalcSampleStep;
58 
59  return *this;
60 }
61 
62 void te::rp::ClassifierMAPStrategy::Parameters::reset() throw(te::rp::Exception)
63 {
64  m_trainSamplesPtr.reset();
65  m_prioriProbs.clear();
66  m_prioriCalcSampleStep = 2;
67 }
68 
70 {
72 }
73 
74 //-----------------------------------------------------------------------------
75 
77 {
78  m_isInitialized = false;
79 }
80 
82 {
83 }
84 
86  te::rp::StrategyParameters const* const strategyParams) throw(te::rp::Exception)
87 {
88  m_isInitialized = false;
90  m_classesIndex2ID.clear();
91  m_classesMeans.clear();
95 
96  ClassifierMAPStrategy::Parameters const * const castParamsPtr =
97  dynamic_cast< ClassifierMAPStrategy::Parameters const * >( strategyParams );
98  TERP_TRUE_OR_RETURN_FALSE( castParamsPtr, "Invalid parameters" );
99 
100  // Checking the input parameters
101 
103  "Invalid classes samples pointer" )
104  TERP_TRUE_OR_RETURN_FALSE( castParamsPtr->m_trainSamplesPtr->size() > 0,
105  "Invalid classes samples number" )
106  TERP_TRUE_OR_RETURN_FALSE( castParamsPtr->m_trainSamplesPtr->begin()->second.size() > 0,
107  "Invalid classes samples number" )
108 
109  if( ! castParamsPtr->m_prioriProbs.empty() )
110  {
111  TERP_TRUE_OR_RETURN_FALSE( castParamsPtr->m_prioriProbs.size() ==
112  castParamsPtr->m_trainSamplesPtr->size(), "Invalid classes priory probabilities" );
113  for( std::vector< double >::size_type pIdx = 0 ; pIdx <
114  castParamsPtr->m_prioriProbs.size() ; ++pIdx )
115  {
117  ( castParamsPtr->m_prioriProbs[ pIdx ] >= 0.0 ) &&
118  ( castParamsPtr->m_prioriProbs[ pIdx ] <= 1.0 ),
119  "Invalid classes priory probabilities" );
120  }
121  }
122 
124  "Invalid sample step" );
125 
126  m_initParams = (*castParamsPtr);
127 
128  // Calculating m_classesMeans and m_classesIndex2ID
129 
130  const unsigned int dimsNumber = (unsigned int)
131  castParamsPtr->m_trainSamplesPtr->begin()->second.operator[]( 0 ).size();
132 
133  {
134  Parameters::MClassesSamplesCT::const_iterator classesIt =
136  const Parameters::MClassesSamplesCT::const_iterator classesItE =
138 
139  while( classesIt != classesItE )
140  {
141  const Parameters::ClassIDT& classID = classesIt->first;
142 
143  const Parameters::ClassSamplesContainerT& classSamples = classesIt->second;
144  TERP_TRUE_OR_RETURN_FALSE( classSamples.size() > 0,
145  "Invalid class samples number" );
146 
147  Parameters::ClassSampleT classMeans( dimsNumber, 0.0 );
148 
149  unsigned int dimIdx = 0;
150 
151  for( dimIdx = 0 ; dimIdx < dimsNumber ; ++dimIdx )
152  {
153  double& dimMean = classMeans[ dimIdx ];
154  dimMean = 0.0;
155 
156  Parameters::ClassSamplesContainerT::const_iterator samplesIt =
157  classSamples.begin();
158  const Parameters::ClassSamplesContainerT::const_iterator samplesItE =
159  classSamples.end();
160 
161  while( samplesIt != samplesItE )
162  {
163  TERP_TRUE_OR_RETURN_FALSE( samplesIt->size() == dimsNumber,
164  "Sample size mismatch" )
165  dimMean += samplesIt->operator[]( dimIdx );
166 
167  ++samplesIt;
168  }
169 
170  dimMean /= (double)( classSamples.size() );
171  }
172 
173  m_classesMeans.push_back( classMeans );
174  m_classesIndex2ID.push_back( classID );
175 
176  ++classesIt;
177  }
178 
179  }
180 
181  // Calculating m_classesCovarianceMatrixes, m_classesCovarianceInvMatrixes
182  // and m_classesCovarianceMatrixesHalfDetLog
183 
184  {
185  Parameters::MClassesSamplesCT::const_iterator classesIt =
187  const Parameters::MClassesSamplesCT::const_iterator classesItE =
189  unsigned int classIdx = 0;
190 
191  while( classesIt != classesItE )
192  {
193  const Parameters::ClassSamplesContainerT& classSamples = classesIt->second;
194  TERP_TRUE_OR_RETURN_FALSE( classSamples.size() > 0,
195  "Invalid class samples number" );
196 
197  const std::vector< double >& classMeans = m_classesMeans[ classIdx ];
198 
199  boost::numeric::ublas::matrix< double > classCovarianceMatrix( dimsNumber, dimsNumber );
200 
201  unsigned int dimIdx1 = 0;
202  unsigned int dimIdx2 = 0;
203 
204  for( dimIdx1 = 0 ; dimIdx1 < dimsNumber ; ++dimIdx1 )
205  {
206  const double& dimMean1 = classMeans[ dimIdx1 ];
207 
208  for( dimIdx2 = 0 ; dimIdx2 < dimsNumber ; ++dimIdx2 )
209  {
210  const double& dimMean2 = classMeans[ dimIdx2 ];
211 
212  double& covariance = classCovarianceMatrix( dimIdx1, dimIdx2 );
213  covariance = 0.0;
214 
215  Parameters::ClassSamplesContainerT::const_iterator samplesIt =
216  classSamples.begin();
217  const Parameters::ClassSamplesContainerT::const_iterator samplesItE =
218  classSamples.end();
219 
220  while( samplesIt != samplesItE )
221  {
222  covariance +=
223  (
224  ( samplesIt->operator[]( dimIdx1 ) - dimMean1 )
225  *
226  ( samplesIt->operator[]( dimIdx2 ) - dimMean2 )
227  );
228 
229  ++samplesIt;
230  }
231 
232  covariance /= (double)( classSamples.size() );
233  }
234  }
235 
236  m_classesCovarianceMatrixes.push_back( classCovarianceMatrix );
237 
238  double classCovarianceMatrixDet = 0;
240  classCovarianceMatrixDet ), "Determinant matrix error" );
241  if( classCovarianceMatrixDet > 0.0 )
242  {
243  m_classesOptizedMAPDiscriminantTerm.push_back( -0.5 * std::log(
244  classCovarianceMatrixDet ) );
245  }
246  else
247  {
248  m_classesOptizedMAPDiscriminantTerm.push_back( 0.0 );
249  }
250 
251  boost::numeric::ublas::matrix< double > classCovarianceInvMatrix;
253  classCovarianceInvMatrix ), "Inverse matrix calcule error" );
254  m_classesCovarianceInvMatrixes.push_back( classCovarianceInvMatrix );
255 
256  ++classIdx;
257  ++classesIt;
258  }
259 
260  }
261 
262  // Finalizing
263 
264  m_isInitialized = true;
265 
266  return true;
267 }
268 
270  const std::vector<unsigned int>& inputRasterBands,
271  const std::vector<te::gm::Polygon*>&, te::rst::Raster& outputRaster,
272  const unsigned int outputRasterBand,
273  const bool enableProgressInterface) throw(te::rp::Exception)
274 {
276  "Classification strategy not initialized" );
277  TERP_TRUE_OR_RETURN_FALSE( inputRasterBands.size() > 0, "Invalid input bands" );
278  TERP_TRUE_OR_RETURN_FALSE( inputRasterBands.size() == m_classesMeans[ 0 ].size(),
279  "Invalid input bands" );
280  TERP_DEBUG_TRUE_OR_THROW( outputRasterBand < outputRaster.getNumberOfBands(),
281  "Invalid output band" );
282  TERP_DEBUG_TRUE_OR_THROW( inputRaster.getNumberOfColumns() ==
283  outputRaster.getNumberOfColumns(), "Rasters dims mismatch" );
284  TERP_DEBUG_TRUE_OR_THROW( inputRaster.getNumberOfRows() ==
285  outputRaster.getNumberOfRows(), "Rasters dims mismatch" );
286 
287  // progress
288 
289  std::auto_ptr< te::common::TaskProgress > progressPtr;
290  if( enableProgressInterface )
291  {
292  progressPtr.reset( new te::common::TaskProgress );
293 
294  if( m_initParams.m_prioriProbs.empty() )
295  progressPtr->setTotalSteps( inputRaster.getNumberOfRows() +
296  ( inputRaster.getNumberOfRows() / m_initParams.m_prioriCalcSampleStep ) );
297  else
298  progressPtr->setTotalSteps( inputRaster.getNumberOfRows() );
299 
300  progressPtr->setMessage( "Classifying" );
301  }
302 
303  // Dealing with the logarithm of priori probabilities
304 
305  std::vector< double > logPrioriProbs;
306 
307  if( m_initParams.m_prioriProbs.empty() )
308  {
310  inputRasterBands, progressPtr.get(), logPrioriProbs ), "Priori probabilities calcule error" );
311 
312  for( unsigned int pIdx = 0 ; pIdx < logPrioriProbs.size() ; ++pIdx )
313  logPrioriProbs[ pIdx ] = ( logPrioriProbs[ pIdx ] > 0.0 ) ?
314  std::log( logPrioriProbs[ pIdx ] ) : 0.0;
315  }
316  else
317  {
318  for( unsigned int pIdx = 0 ; pIdx < m_initParams.m_prioriProbs.size() ;
319  ++pIdx )
320  logPrioriProbs.push_back( std::log( m_initParams.m_prioriProbs[ pIdx ] ) );
321  }
322 
323  // Classifying
324 
325  const unsigned int classesNumber = (unsigned int)m_classesMeans.size();
326  const unsigned int nRows = (unsigned int)inputRaster.getNumberOfRows();
327  const unsigned int nCols = (unsigned int)inputRaster.getNumberOfColumns();
328  const unsigned int nDims = (unsigned int)inputRasterBands.size();
329  unsigned int col = 0;
330  unsigned int dim = 0;
331  boost::numeric::ublas::matrix< double > sample( nDims, 1 );
332  boost::numeric::ublas::matrix< double > sampleMinusMean( nDims, 1 );
333  boost::numeric::ublas::matrix< double > sampleMinusMeanT( 1, nDims );
334  boost::numeric::ublas::matrix< double > auxMatrix;
335  boost::numeric::ublas::matrix< double > mahalanobisDistanceMatrix;
336  unsigned int bandIdx = 0;
337  unsigned int classIdx = 0;
338  double discriminantFunctionValue = 0;
339  double closestClassdiscriminantFunctionValue = 0;
340  unsigned int closestClassIdx = 0;
341 
342  for( unsigned int row = 0 ; row < nRows ; ++row )
343  {
344  for( col = 0 ; col < nCols ; ++col )
345  {
346  // Creating the sample
347 
348  for( dim = 0 ; dim < nDims ; ++dim )
349  {
350  bandIdx = inputRasterBands[ dim ];
351  TERP_DEBUG_TRUE_OR_THROW( bandIdx < inputRaster.getNumberOfBands(),
352  "Invalid band index" );
353 
354  inputRaster.getValue( col, row, sample( dim, 0 ), bandIdx );
355  }
356 
357  // Looking the the closest class
358 
359  closestClassdiscriminantFunctionValue = -1.0 * DBL_MAX;
360 
361  for( classIdx = 0 ; classIdx < classesNumber ; ++classIdx )
362  {
363  const Parameters::ClassSampleT& classMeans = m_classesMeans[ classIdx ];
364 
365  for( dim = 0 ; dim < nDims ; ++dim )
366  {
367  sampleMinusMean( dim, 0 ) = sampleMinusMeanT( 0, dim ) =
368  ( sample( dim, 0 ) - classMeans[ dim ] );
369  }
370 
371  //calculate the mahalanobis distance: (x-mean)T * CovMatrizInvert * (x-mean)
372  auxMatrix = boost::numeric::ublas::prod( sampleMinusMeanT,
373  m_classesCovarianceInvMatrixes[ classIdx ] );
374  mahalanobisDistanceMatrix = boost::numeric::ublas::prod( auxMatrix, sampleMinusMean );
375  TERP_DEBUG_TRUE_OR_THROW( mahalanobisDistanceMatrix.size1() == 1, "Internal error" );
376  TERP_DEBUG_TRUE_OR_THROW( mahalanobisDistanceMatrix.size2() == 1, "Internal error" );
377 
378  discriminantFunctionValue = logPrioriProbs[ classIdx ]
380  - ( 0.5 * mahalanobisDistanceMatrix( 0, 0 ) );
381 
382  if( discriminantFunctionValue > closestClassdiscriminantFunctionValue )
383  {
384  closestClassdiscriminantFunctionValue = discriminantFunctionValue;
385  closestClassIdx = classIdx;
386  }
387  }
388 
389  outputRaster.setValue( col, row, m_classesIndex2ID[ closestClassIdx ] );
390  }
391 
392  if( enableProgressInterface )
393  {
394  progressPtr->pulse();
395  if( ! progressPtr->isActive() ) return false;
396  }
397  }
398 
399  return true;
400 }
401 
403  const te::rst::Raster& inputRaster,
404  const std::vector<unsigned int>& inputRasterBands,
405  te::common::TaskProgress * const progressPtr,
406  std::vector< double >& prioriProbabilities ) const
407 {
409  "Classification strategy not initialized" );
410  TERP_DEBUG_TRUE_OR_THROW( inputRasterBands.size() > 0, "Invalid input bands" );
411  TERP_DEBUG_TRUE_OR_THROW( inputRasterBands.size() == m_classesMeans[ 0 ].size(),
412  "Invalid input bands" );
413 
414  prioriProbabilities.clear();
415 
416  // Classifying
417 
418  const unsigned int classesNumber = (unsigned int)m_classesMeans.size();
419  const unsigned int nRows = (unsigned int)inputRaster.getNumberOfRows();
420  const unsigned int nCols = (unsigned int)inputRaster.getNumberOfColumns();
421  const unsigned int nDims = (unsigned int)inputRasterBands.size();
422  const double initialPrioriProbLog = std::log( 1.0 / ( (double)classesNumber ) );
423  unsigned int col = 0;
424  unsigned int dim = 0;
425  boost::numeric::ublas::matrix< double > sample( nDims, 1 );
426  boost::numeric::ublas::matrix< double > sampleMinusMean( nDims, 1 );
427  boost::numeric::ublas::matrix< double > sampleMinusMeanT( 1, nDims );
428  boost::numeric::ublas::matrix< double > auxMatrix;
429  boost::numeric::ublas::matrix< double > mahalanobisDistanceMatrix;
430  unsigned int bandIdx = 0;
431  unsigned int classIdx = 0;
432  double discriminantFunctionValue = 0;
433  double closestClassdiscriminantFunctionValue = 0;
434  unsigned int closestClassIdx = 0;
435  std::vector< unsigned long int > elementsNumberByClass( classesNumber, 0 );
436  unsigned int totalSamplesNumber = 0;
437 
438  for( unsigned int row = 0 ; row < nRows ; row += m_initParams.m_prioriCalcSampleStep )
439  {
440  for( col = 0 ; col < nCols ; col += m_initParams.m_prioriCalcSampleStep )
441  {
442  // Creating the sample
443 
444  for( dim = 0 ; dim < nDims ; ++dim )
445  {
446  bandIdx = inputRasterBands[ dim ];
447  TERP_DEBUG_TRUE_OR_THROW( bandIdx < inputRaster.getNumberOfBands(),
448  "Invalid band index" );
449 
450  inputRaster.getValue( col, row, sample( dim, 0 ), bandIdx );
451  }
452 
453  // Looking the the closest class
454 
455  closestClassdiscriminantFunctionValue = -1.0 * DBL_MAX;
456 
457  for( classIdx = 0 ; classIdx < classesNumber ; ++classIdx )
458  {
459  const Parameters::ClassSampleT& classMeans = m_classesMeans[ classIdx ];
460 
461  for( dim = 0 ; dim < nDims ; ++dim )
462  {
463  sampleMinusMean( dim, 0 ) = sampleMinusMeanT( 0, dim ) =
464  ( sample( dim, 0 ) - classMeans[ dim ] );
465  }
466 
467  //calculate the mahalanobis distance: (x-mean)T * CovMatrizInvert * (x-mean)
468  auxMatrix = boost::numeric::ublas::prod( sampleMinusMeanT,
469  m_classesCovarianceInvMatrixes[ classIdx ] );
470  mahalanobisDistanceMatrix = boost::numeric::ublas::prod( auxMatrix, sampleMinusMean );
471  TERP_DEBUG_TRUE_OR_THROW( mahalanobisDistanceMatrix.size1() == 1, "Internal error" );
472  TERP_DEBUG_TRUE_OR_THROW( mahalanobisDistanceMatrix.size2() == 1, "Internal error" );
473 
474  discriminantFunctionValue = initialPrioriProbLog
476  - ( 0.5 * mahalanobisDistanceMatrix( 0, 0 ) );
477 
478  if( discriminantFunctionValue > closestClassdiscriminantFunctionValue )
479  {
480  closestClassdiscriminantFunctionValue = discriminantFunctionValue;
481  closestClassIdx = classIdx;
482  }
483  }
484 
485  ++( elementsNumberByClass[ closestClassIdx ] );
486  ++totalSamplesNumber;
487  }
488 
489  if( progressPtr )
490  {
491  progressPtr->pulse();
492  if( ! progressPtr->isActive() ) return false;
493  }
494  }
495 
496  if( totalSamplesNumber )
497  {
498  for( classIdx = 0 ; classIdx < classesNumber ; ++classIdx )
499  {
500  prioriProbabilities.push_back( ( (double)elementsNumberByClass[ classIdx ] ) /
501  ( (double)( totalSamplesNumber ) ) );
502  }
503 
504  return true;
505  }
506  else
507  {
508  return false;
509  }
510 }
511 
512 //-----------------------------------------------------------------------------
513 
515  : te::rp::ClassifierStrategyFactory("map")
516 {
517 }
518 
520 {
521 }
522 
524 {
525  return new te::rp::ClassifierMAPStrategy();
526 }
ClassifierMAPStrategy::Parameters m_initParams
Initialization parameters.
std::vector< Parameters::ClassIDT > m_classesIndex2ID
An class index ordered vector of classes IDs;.
MClassesSamplesCTPtr m_trainSamplesPtr
A shared pointer to a always-valid structure where trainning samples are stored.
Maximum a posteriori probability strategy factory.
bool execute(const te::rst::Raster &inputRaster, const std::vector< unsigned int > &inputRasterBands, const std::vector< te::gm::Polygon * > &inputPolygons, te::rst::Raster &outputRaster, const unsigned int outputRasterBand, const bool enableProgressInterface)
Executes the classification strategy.
unsigned int m_prioriCalcSampleStep
A positive non-zero sample step used when calculating piori probabilities (default:2 - half of sample...
Maximum a posteriori probability strategy.
std::vector< std::vector< double > > m_classesMeans
Classes means;.
unsigned int getNumberOfColumns() const
Returns the raster number of columns.
Definition: Raster.cpp:213
std::vector< double > m_classesOptizedMAPDiscriminantTerm
An optimized portion of the MAP discriminant function.
const Parameters & operator=(const Parameters &params)
This class can be used to inform the progress of a task.
Definition: TaskProgress.h:53
unsigned int ClassIDT
Class ID type definition (zero means invalid ID).
bool isActive() const
Verify if the task is active.
std::vector< double > m_prioriProbs
Priori probabilities, one for each class. Values from 0 to 1 (use an empty vector to allow internal c...
#define TERP_TRUE_OR_RETURN_FALSE(value, message)
Checks if value is true. For false values a warning message will be logged and a return of context wi...
Definition: Macros.h:183
Raster classifier strategy factory base class.
std::vector< boost::numeric::ublas::matrix< double > > m_classesCovarianceInvMatrixes
Classes covariance inverse matrixes.
bool GetDeterminant(const boost::numeric::ublas::matrix< T > &inputMatrix, double &determinant)
Get the Matrix determinant value.
Definition: MatrixUtils.h:57
std::vector< double > ClassSampleT
Class sample type definition.
An abstract class for raster data strucutures.
Definition: Raster.h:71
unsigned int getNumberOfRows() const
Returns the raster number of rows.
Definition: Raster.cpp:208
virtual std::size_t getNumberOfBands() const =0
Returns the number of bands (dimension of cells attribute values) in the raster.
Raster strategy parameters base class.
bool m_isInitialized
Is this instance initialized?
void pulse()
Calls setCurrentStep() function using getCurrentStep() + 1.
virtual void getValue(unsigned int c, unsigned int r, double &value, std::size_t b=0) const
Returns the attribute value of a band of a cell.
Definition: Raster.cpp:228
Maximum a posteriori probability strategy.
Abstract parameters base interface.
te::rp::ClassifierStrategy * build()
Concrete factories (derived from this one) must implement this method in order to create objects...
AbstractParameters * clone() const
Create a clone copy of this instance.
bool initialize(StrategyParameters const *const strategyParams)
Initialize the classification strategy.
Raster classifier strategy base class.
bool GetInverseMatrix(const boost::numeric::ublas::matrix< T > &inputMatrix, boost::numeric::ublas::matrix< T > &outputMatrix)
Matrix inversion.
Definition: MatrixUtils.h:104
bool getPrioriProbabilities(const te::rst::Raster &inputRaster, const std::vector< unsigned int > &inputRasterBands, te::common::TaskProgress *const progressPtr, std::vector< double > &prioriProbabilities) const
Calcule of priori probabilities following the current internal state.
#define TERP_DEBUG_TRUE_OR_THROW(value, message)
Checks if value is true and throws an exception if not.
Definition: Macros.h:356
void reset()
Clear all internal allocated resources and reset the parameters instance to its initial state...
std::vector< ClassSampleT > ClassSamplesContainerT
Class samples container type definition.
std::vector< boost::numeric::ublas::matrix< double > > m_classesCovarianceMatrixes
Classes covariance matrixes.