ClassifierISOSegStrategy.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/ClassifierISOSegStrategy.cpp
22 
23  \brief Raster ISOSeg strategy for segmentation-based classification.
24 */
25 
26 // TerraLib
27 #include "../common/MatrixUtils.h"
28 #include "../common/progress/TaskProgress.h"
29 #include "../geometry/Coord2D.h"
30 #include "../geometry/Envelope.h"
31 #include "../geometry/Point.h"
32 #include "../geometry/Polygon.h"
33 #include "../raster/Grid.h"
34 #include "../raster/PositionIterator.h"
35 #include "../raster/Utils.h"
36 #include "../raster/SynchronizedRaster.h"
37 #include "../memory/CachedRaster.h"
39 #include "Functions.h"
40 #include "Macros.h"
41 
42 // STL
43 #include <iostream>
44 #include <set>
45 #include <stdlib.h>
46 #include <thread>
47 
48 // Boost
49 #include <boost/numeric/ublas/io.hpp>
50 #include <boost/numeric/ublas/lu.hpp>
51 #include <boost/numeric/ublas/matrix.hpp>
52 #include <boost/ptr_container/ptr_vector.hpp>
53 
54 // STL
55 #include <cfloat>
56 
57 namespace
58 {
59  static te::rp::ClassifierISOSegStrategyFactory classifierISOSegStrategyFactoryInstance;
60 }
61 
62 const static double classifierISOSegStrategyChiTable[10][6] =
63 {
64 // 75.0% 90.0% 95.0% 99.0% 99.9% 100.%
65  { 1.32, 2.71, 3.84, 6.64, 10.83, std::numeric_limits<double>::max()},
66  { 2.77, 4.61, 5.99, 9.21, 13.82, std::numeric_limits<double>::max()},
67  { 4.11, 6.25, 7.82, 11.35, 16.27, std::numeric_limits<double>::max()},
68  { 5.39, 7.78, 9.49, 13.28, 18.47, std::numeric_limits<double>::max()},
69  { 6.63, 9.24, 11.07, 15.09, 20.52, std::numeric_limits<double>::max()},
70  { 7.84, 10.65, 12.59, 16.81, 22.46, std::numeric_limits<double>::max()},
71  { 9.04, 12.02, 14.07, 18.48, 24.32, std::numeric_limits<double>::max()},
72  {10.22, 13.36, 15.51, 20.09, 26.13, std::numeric_limits<double>::max()},
73  {11.39, 14.68, 16.92, 21.67, 27.88, std::numeric_limits<double>::max()},
74  {12.55, 15.99, 18.31, 23.21, 29.59, std::numeric_limits<double>::max()}
75 };
76 
77 // ---------------------------------------------------------------------------
78 
80 {
81  reset();
82 }
83 
85 
87 {
88  reset();
89 
92 
93  return *this;
94 }
95 
97 {
100 }
101 
103 {
105 }
106 
107 // ---------------------------------------------------------------------------
108 
110 {
111  reset();
112 }
113 
114 te::rp::ClassifierISOSegStrategy::Pattern::Pattern(int i, double a, std::vector<double> mv, boost::numeric::ublas::matrix<double> cm)
115  : m_id(i),
116  m_myCluster(this),
117  m_area(a),
118  m_meanVector(mv),
119  m_covarianceMatrix(cm)
120 {
121  m_covarianceInversion = boost::numeric::ublas::matrix<double>(m_covarianceMatrix.size1(), m_covarianceMatrix.size2());
122 
124  {
126  }
127 
129 }
130 
132 {
133  operator=( rhs );
134 }
135 
137 
139  Pattern const * const p ) const
140 {
141  assert(m_meanVector.size() == p->m_meanVector.size());
142 
143  unsigned int nBands = static_cast<unsigned int>(m_meanVector.size());
144 
145  boost::numeric::ublas::matrix<double> term1(1, nBands);
146  boost::numeric::ublas::matrix<double> term2(nBands, 1);
147 
148  for (unsigned int i = 0; i < nBands; i++)
149  {
150  term1(0, i) = m_meanVector[i] - p->m_meanVector[i];
151 
152  term2(i, 0) = term1(0, i);
153  }
154 
155  term1 = prod(term1, m_covarianceInversion);
156  term1 = prod(term1, term2);
157 
158  if (term1(0, 0) < 0)
159  return std::numeric_limits<double>::max();
160 
161  return term1(0, 0);
162 }
163 
165  Pattern const * const p) const
166 {
167  assert(m_meanVector.size() == p->m_meanVector.size());
168 
169  if( ( m_covarianceMatrixDet == 0 ) || ( p->m_covarianceMatrixDet == 0 ) )
170  {
171  return std::numeric_limits< double >::max();
172  }
173 
174  m_getBhattacharyyaDistance_nBands = static_cast<unsigned int>(m_meanVector.size());
175 
177  1 );
178 
181  {
185  }
186 
188  + p->m_covarianceMatrix ) / 2.0;
189 
192  {
193  return std::numeric_limits< double >::max();
194  }
195 
198  {
199  return std::numeric_limits< double >::max();
200  }
201 
203  boost::numeric::ublas::prod(
204  boost::numeric::ublas::trans( m_getBhattacharyyaDistance_meansDif )
205  ,
207  );
209  boost::numeric::ublas::prod(
211  ,
213  );
214 
217  /
218  8.0;
220  (
221  0.5
222  *
223  std::log(
225  /
226  (
228  )
229  )
230  );
231 
233 }
234 
236 {
237  assert(m_myCluster == nullptr);
238  assert(rhs.m_myCluster == nullptr);
239 
240  return m_id == rhs.m_id;
241 }
242 
244 {
245  m_id = rhs.m_id;
246  m_myCluster = rhs.m_myCluster;
247  m_area = rhs.m_area;
252 
253  return *this;
254 }
255 
257 {
258  return m_area < rhs.m_area;
259 }
260 
262 {
263  m_id = -1;
264  m_myCluster = this;
265  m_area = 0.0;
267  m_meanVector.clear();
268  m_covarianceMatrix.clear();
269  m_covarianceInversion.clear();
270 }
271 
272 // ---------------------------------------------------------------------------
273 
275 {
276  m_isInitialized = false;
277 }
278 
280 
281 bool te::rp::ClassifierISOSegStrategy::initialize(te::rp::ClassifierStrategyParameters const* const strategyParams) throw(te::rp::Exception)
282 {
283  m_isInitialized = false;
284 
285  te::rp::ClassifierISOSegStrategy::Parameters const* paramsPtr = dynamic_cast<te::rp::ClassifierISOSegStrategy::Parameters const*>(strategyParams);
286 
287  if(!paramsPtr)
288  return false;
289 
290  m_parameters = *(paramsPtr);
291 
295  "Invalid distance type" );
296 
297  TERP_INSTANCE_TRUE_OR_RETURN_FALSE(m_parameters.m_acceptanceThreshold > 0 && m_parameters.m_acceptanceThreshold <= 100, "Invalid acceptance threshold [0, 100].")
298 
299  m_isInitialized = true;
300 
301  return true;
302 }
303 
304 double te::rp::ClassifierISOSegStrategy::getThreshold(const double acceptanceThreshold, const unsigned nBands) const
305 {
306  if(acceptanceThreshold < 90.0)
307  return classifierISOSegStrategyChiTable[ std::min( nBands, 6u ) -1 ][0];
308  else if(acceptanceThreshold < 95.0)
309  return classifierISOSegStrategyChiTable[ std::min( nBands, 6u ) -1 ][1];
310  else if(acceptanceThreshold < 99.0)
311  return classifierISOSegStrategyChiTable[ std::min( nBands, 6u ) -1 ][2];
312  else if(acceptanceThreshold < 99.9)
313  return classifierISOSegStrategyChiTable[ std::min( nBands, 6u ) -1 ][3];
314  else if(acceptanceThreshold < 100.0)
315  return classifierISOSegStrategyChiTable[ std::min( nBands, 6u ) -1 ][4];
316  else
317  return classifierISOSegStrategyChiTable[ std::min( nBands, 6u ) -1 ][5];
318 }
319 
321 {
322  TERP_INSTANCE_TRUE_OR_RETURN_FALSE(m_isInitialized, "Instance not initialized")
323  TERP_INSTANCE_TRUE_OR_RETURN_FALSE(m_inputPolygonsPtr != nullptr, "ISOSeg algorithm needs polygons")
324  TERP_INSTANCE_TRUE_OR_RETURN_FALSE(m_inputPolygonsPtr->size() > 0, "ISOSeg algorithm needs polygons")
325 
326  // globals
327 
328  // raster cache
329 
330  te::rst::Raster const* inputRasterPtr = m_inputRasterPtr;
331  std::unique_ptr< te::mem::CachedRaster > cachedRasterPtr;
332 
334  {
335  cachedRasterPtr.reset( new te::mem::CachedRaster( *m_inputRasterPtr, 25, 0 ) );
336  inputRasterPtr = cachedRasterPtr.get();
337  }
338 
339  // pre-processing polygons
340 
341  std::vector<te::gm::Polygon*> const * inputPolygonsPtr = m_inputPolygonsPtr;
342  boost::ptr_vector< te::gm::Polygon > reprojectedPolsHandler;
343  std::vector< te::gm::Polygon* > reprojectedPolsNPtrs;
344 
345  if( inputRasterPtr->getSRID() != m_inputPolygonsPtr->operator[]( 0 )->getSRID() )
346  {
347  const std::size_t inputPolygonsPtrSize = m_inputPolygonsPtr->size();
348  const int rasterSRID = inputRasterPtr->getSRID();
349  std::unique_ptr< te::gm::Geometry > transformedGeomPtr;
350 
351  std::unique_ptr< te::common::TaskProgress > taskPtr;
353  {
354  taskPtr.reset( new te::common::TaskProgress(
355  TE_TR("ISOSeg algorithm - processing polygons"), te::common::TaskProgress::UNDEFINED,
356  static_cast<int>(inputPolygonsPtrSize)));
357  };
358 
359  for( std::size_t inputPolygonsPtrIdx = 0 ; inputPolygonsPtrIdx <
360  inputPolygonsPtrSize ; ++inputPolygonsPtrIdx )
361  {
362  transformedGeomPtr.reset( (te::gm::Geometry*)
363  m_inputPolygonsPtr->operator[]( inputPolygonsPtrIdx )->clone() );
364  transformedGeomPtr->transform( rasterSRID );
365  reprojectedPolsNPtrs.push_back( (te::gm::Polygon*)transformedGeomPtr.get() );
366  reprojectedPolsHandler.push_back( (te::gm::Polygon*)transformedGeomPtr.release() );
367 
369  {
370  taskPtr->pulse();
371  if( !taskPtr->isActive() ) return false;
372  }
373  }
374 
375  inputPolygonsPtr = &reprojectedPolsNPtrs;
376  }
377 
378  // fill regions, in the beginning, each region is a cluster
379 
380  std::multimap< double, Pattern > regions; //!< A descriptive set of regions (area, features).
381 
382  {
383  std::mutex globalMutex;
384  std::mutex condVarMutex;
385  std::condition_variable condVar;
386  te::rst::RasterSynchronizer inputRasterSync( *((te::rst::Raster*)inputRasterPtr),
388  std::size_t nextInputPolIdx2Process = 0;
389  unsigned int runningThreadsCounter = 0;
390  bool continueProcessingFlag = true;
391 
392  FillRegionsThreadEntryParams threadParams;
393  threadParams.m_globalMutexPtr = &globalMutex;
394  threadParams.m_condVarMutexPtr = &condVarMutex;
395  threadParams.m_condVarPtr = &condVar;
396  threadParams.m_inputRasterSyncPtr = &inputRasterSync;
397  threadParams.m_inputPolygonsPtr = inputPolygonsPtr;
399  threadParams.m_outputRegionsPtr = &regions;
400  threadParams.m_nextInputPolIdx2ProcessPtr = &nextInputPolIdx2Process;
401  threadParams.m_runningThreadsCounterPtr = &runningThreadsCounter;
402  threadParams.m_enableProgress = false;
403  threadParams.m_continueProcessingFlagPtr = &continueProcessingFlag;
404 
405  if( m_enableMultiThread )
406  {
407  // creating threads
408 
409  const unsigned int maxSegThreads = runningThreadsCounter =
411  const std::size_t inputPolygonsSize = inputPolygonsPtr->size();
412  std::vector< std::shared_ptr< std::thread > > threadsPtrs;
413  std::shared_ptr< std::thread > threadPtr;
414 
415  std::unique_ptr< te::common::TaskProgress > taskPtr;
417  {
418  taskPtr.reset( new te::common::TaskProgress(
419  TE_TR("ISOSeg algorithm - Extracting features"), te::common::TaskProgress::UNDEFINED,
420  (int)inputPolygonsSize) );
421  };
422 
423  threadParams.m_enableProgress = false;
424 
425  for( unsigned int threadIdx = 0 ; threadIdx < maxSegThreads ; ++threadIdx )
426  {
427  threadPtr.reset( new std::thread( fillRegionsThreadEntry, &threadParams ) );
428  threadsPtrs.push_back( threadPtr );
429  }
430 
431  // waiting all threads to finish
432 
433  while( true )
434  {
435  std::unique_lock<std::mutex> condVarLocker( condVarMutex );
436  condVar.wait_for( condVarLocker, std::chrono::seconds( 1 ) );
437  condVarLocker.unlock();
438 
439 // std::cout << std::endl << "Woke up" << std::endl;
440 
441  std::unique_lock<std::mutex> globalLocker( globalMutex );
442 
444  {
445  taskPtr->setCurrentStep( nextInputPolIdx2Process );
446  if( !taskPtr->isActive() )
447  {
448  continueProcessingFlag = false;
449  break;
450  }
451  }
452 
453  if( (!continueProcessingFlag) || ( runningThreadsCounter == 0 ) )
454  {
455  break;
456  }
457  }
458 
459  // joining all threads
460 
461  for( unsigned int threadIdx = 0 ; threadIdx < maxSegThreads ; ++threadIdx )
462  {
463  threadsPtrs[ threadIdx ]->join();
464  }
465  }
466  else
467  {
469  runningThreadsCounter = 1;
470  fillRegionsThreadEntry( &threadParams );
471  }
472  }
473 
474  // each region is a cluster at the beginning
475  // Zero determinant regions will be grouped inside the same cluster
476 
477  {
478  Pattern* firstZeroDeterminantClusterPtr = 0;
479  std::multimap< double, Pattern >::iterator regionsIt = regions.begin();
480  const std::multimap< double, Pattern >::iterator regionsItEnd = regions.end();
481  std::unique_ptr< te::common::TaskProgress > taskPtr;
483  {
484  taskPtr.reset( new te::common::TaskProgress(
485  TE_TR("ISOSeg algorithm - initializing clusters"), te::common::TaskProgress::UNDEFINED,
486  regions.size() ) );
487  };
488 
489  while( regionsIt != regionsItEnd )
490  {
491  if( regionsIt->second.m_covarianceMatrixDet == 0 )
492  {
493  if( firstZeroDeterminantClusterPtr )
494  {
495  regionsIt->second.m_myCluster = firstZeroDeterminantClusterPtr;
496  }
497  else
498  {
499  firstZeroDeterminantClusterPtr = &( regionsIt->second );
500  regionsIt->second.m_myCluster = &( regionsIt->second );
501  }
502  }
503  else
504  {
505 // printMatrix( regionsIt->second.m_covarianceMatrix );
506 // printMatrix( regionsIt->second.m_covarianceInversion );
507  regionsIt->second.m_myCluster = &( regionsIt->second );
508  }
509 
511  {
512  taskPtr->pulse();
513  if( ! taskPtr->isActive() ) return false;
514  }
515 
516  ++regionsIt;
517  }
518  }
519 
520  // merge similar clusters
521  // loops until all the regions are classified
522  // Initiating with the greater area region
523 
524  {
525  double distance = 0;
526  double distance2 = 0;
527  std::multimap<double, Pattern >::reverse_iterator regionsRIt1;
528  std::multimap<double, Pattern >::reverse_iterator regionsRIt2;
529  std::multimap<double, Pattern >::reverse_iterator regionsRIt3;
530  const std::multimap<double, Pattern >::reverse_iterator regionsItRBegin = regions.rbegin();
531  const std::multimap<double, Pattern >::reverse_iterator regionsItREnd = regions.rend();
532  bool stable = false;
533  int oldid = 0;
534  std::set<std::pair<unsigned int, unsigned int> > compared;
535 
536  std::unique_ptr< te::common::TaskProgress > taskPtr;
538  {
539  taskPtr.reset( new te::common::TaskProgress(
540  TE_TR("ISOSeg algorithm - detecting clusters") ) );
541  };
542 
543  double maxDistance = getThreshold(m_parameters.m_acceptanceThreshold, static_cast<unsigned int>(m_inputRasterBands.size()));
544 
545  while (!stable)
546  {
547  stable = true;
548 
549  compared.clear();
550 
551  // analyze all regions
552 
553  for (regionsRIt1 = regionsItRBegin; regionsRIt1 != regionsItREnd; ++regionsRIt1)
554  {
555  // compare all clusters to detect if they are still similar
556 
557  for (regionsRIt2 = regionsRIt1; regionsRIt2 != regionsItREnd; ++regionsRIt2)
558  {
559  if (regionsRIt1->second.m_myCluster != regionsRIt2->second.m_myCluster)
560  {
561  if (compared.find(std::pair<unsigned int, unsigned int>(
562  regionsRIt1->second.m_myCluster->m_id,
563  regionsRIt2->second.m_myCluster->m_id)) == compared.end())
564  {
565  compared.insert(std::pair<unsigned int, unsigned int>(
566  regionsRIt1->second.m_myCluster->m_id,
567  regionsRIt2->second.m_myCluster->m_id));
568  compared.insert(std::pair<unsigned int, unsigned int>(
569  regionsRIt2->second.m_myCluster->m_id,
570  regionsRIt1->second.m_myCluster->m_id));
571 
572  // use the smallest distance between region1 <-> cluster2, and region2 <-> cluster1
573 
574  switch( m_parameters.m_distanceType )
575  {
577  distance = regionsRIt1->second.m_myCluster->getMahalanobisDistance(
578  regionsRIt2->second.m_myCluster );
579  distance2 = regionsRIt2->second.m_myCluster->getMahalanobisDistance(
580  regionsRIt1->second.m_myCluster );
581  distance = (distance2 < distance? distance2: distance);
582  break;
584  distance = regionsRIt1->second.m_myCluster->getBhattacharyyaDistance(
585  regionsRIt2->second.m_myCluster );
586  break;
587  default :
588  TERP_LOG_AND_THROW( "Invalid distance" );
589  }
590 
591  if (distance <= maxDistance)
592  {
593  // two clusters are similar and must be merged
594  stable = false;
595 
596  oldid = regionsRIt2->second.m_myCluster->m_id;
597 
598  for (regionsRIt3 = regionsRIt2; regionsRIt3 != regionsItREnd; ++regionsRIt3)
599  {
600  // find all clusters with riti class and merge with rit cluster
601  if (regionsRIt3->second.m_myCluster->m_id == oldid)
602  {
603  regionsRIt3->second.m_myCluster = regionsRIt1->second.m_myCluster;
604  }
605  }
606  }
607  }
608  }
609  }
610  }
611 
613  {
614  taskPtr->pulse();
615  if( ! taskPtr->isActive() ) return false;
616  }
617  }
618  }
619 
620  // remap cluster values to 1 -> N
621 
622  unsigned int maxColorMapOutValue = 0;
623  std::map< int, unsigned int > clusterId2OutputValueMap;
624 
625  {
626  std::multimap<double, Pattern >::iterator regionsIt;
627  const std::multimap<double, Pattern >::iterator regionsItEnd = regions.end();
628  unsigned int outputValue = 1;
629 
630  for (regionsIt = regions.begin(); regionsIt != regionsItEnd; ++regionsIt)
631  {
632  if( clusterId2OutputValueMap.find( regionsIt->second.m_myCluster->m_id ) ==
633  clusterId2OutputValueMap.end() )
634  {
635  clusterId2OutputValueMap[ regionsIt->second.m_myCluster->m_id ] = outputValue;
636  ++outputValue;
637  }
638  }
639 
640  maxColorMapOutValue = outputValue - 1;
641  }
642 
643  // Creating the output raster
644 
645  {
646  std::vector< int > dt;
647  dt.push_back( te::dt::UINT32_TYPE );
648 
649  std::vector< double > noDataValues;
650  noDataValues.push_back( (double)( maxColorMapOutValue + 2 ) );
651 
653  "Output raster creation error" );
654 
656  "Output raster palette creation error" );
657 
658  // no-data fill
659 
660  const double outNoDataValue = m_outputRasterPtr->getBand( 0 )->getProperty()->m_noDataValue;
661  const unsigned int nCols = m_outputRasterPtr->getNumberOfColumns();
662  const unsigned int nRows = m_outputRasterPtr->getNumberOfRows();
663  unsigned int col = 0;
664  te::rst::Band& outBand = *m_outputRasterPtr->getBand( 0 );
665 
666  for( unsigned int row = 0 ; row < nRows ; ++row )
667  {
668  for( col = 0 ; col < nCols ; ++col )
669  {
670  outBand.setValue( col, row, outNoDataValue );
671  }
672  }
673  }
674 
675  // classify output image
676 
677  {
678  const std::multimap<double, Pattern >::iterator regionsItEnd = regions.end();
679  double outputValue = 0;
680 
681  std::unique_ptr< te::common::TaskProgress > taskPtr;
683  {
684  taskPtr.reset( new te::common::TaskProgress(
685  TE_TR("ISOSeg algorithm - classifying image"), te::common::TaskProgress::UNDEFINED,
686  static_cast<int>(regions.size())));
687  };
688 
689  for (std::multimap<double, Pattern >::iterator regionsIt = regions.begin();
690  regionsIt != regionsItEnd; ++regionsIt)
691  {
692  te::gm::Polygon* polygon = inputPolygonsPtr->operator[]( regionsIt->second.m_id );
693  outputValue = clusterId2OutputValueMap[regionsIt->second.m_myCluster->m_id ];
694 
695  // iterate over polygon to classify output image
697  (te::rst::Raster*)inputRasterPtr, polygon);
699  (te::rst::Raster*)inputRasterPtr, polygon);
700 
701  while (it != itend)
702  {
703  m_outputRasterPtr->setValue(it.getColumn(), it.getRow(), outputValue, 0);
704 
705  ++it;
706  }
707 
709  {
710  taskPtr->pulse();
711  if( ! taskPtr->isActive() ) return false;
712  }
713  }
714  }
715 
716  return true;
717 }
718 
720 {
721  std::unique_lock<std::mutex> locker( *paramsPtr->m_globalMutexPtr );
722 
723  const std::size_t inputPolygonsSize = paramsPtr->m_inputPolygonsPtr->size();
724  const std::vector< unsigned int > inputRasterBands = *paramsPtr->m_inputRasterBandsPtr;
725 
726  locker.unlock();
727 
728  const std::size_t inputRasterBandsSize = inputRasterBands.size();
729  const te::rst::SynchronizedRaster inputRaster( *(paramsPtr->m_inputRasterSyncPtr), 25 );
730  std::size_t inputRasterBandsIdx1 = 0;
731  std::size_t inputRasterBandsIdx2 = 0;
732  std::size_t currentPolIdx = 0;
733  te::gm::Polygon* currentPolPtr = nullptr;
734  unsigned int validPixelsCount = 0;
735  std::vector< double > pixelValues( inputRasterBandsSize );
736  bool isValidPixel = false;
737  double covariance = 0;
738  double pixelValue1 = 0;
739  double pixelValue2 = 0;
740 
741  std::pair<double, Pattern> auxPair;
742  auxPair.second.m_id = -1;
743  auxPair.second.m_myCluster = 0;
744  auxPair.second.m_area = 0;
745  auxPair.second.m_covarianceMatrixDet = 0;
746  auxPair.second.m_meanVector.resize( inputRasterBandsSize );
747  auxPair.second.m_covarianceMatrix.resize( inputRasterBandsSize, inputRasterBandsSize );
748  auxPair.second.m_covarianceInversion.resize( inputRasterBandsSize, inputRasterBandsSize );
749 
750  std::vector< double > bandsNoDataValues( inputRasterBandsSize );
751  for( inputRasterBandsIdx1 = 0 ; inputRasterBandsIdx1 <
752  inputRasterBandsSize ; ++inputRasterBandsIdx1 )
753  {
754  bandsNoDataValues[ inputRasterBandsIdx1 ] =
755  inputRaster.getBand( inputRasterBands[ inputRasterBandsIdx1 ] )->getProperty()->m_noDataValue;
756  }
757 
758  std::unique_ptr< te::common::TaskProgress > taskPtr;
759  if( paramsPtr->m_enableProgress )
760  {
761  taskPtr.reset( new te::common::TaskProgress(
762  TE_TR("ISOSeg algorithm - Extracting features"), te::common::TaskProgress::UNDEFINED,
763  (int)inputPolygonsSize) );
764  };
765 
766  while( true )
767  {
768  locker.lock();
769 
770  if( ! paramsPtr->m_continueProcessingFlagPtr )
771  {
772  --( *( paramsPtr->m_runningThreadsCounterPtr ) );
773  return;
774  }
775 
776  currentPolIdx = (*paramsPtr->m_nextInputPolIdx2ProcessPtr);
777 
778  if( currentPolIdx >= inputPolygonsSize )
779  {
780  --( *( paramsPtr->m_runningThreadsCounterPtr ) );
781  return;
782  }
783 
784  ++( *paramsPtr->m_nextInputPolIdx2ProcessPtr );
785 
786  currentPolPtr = paramsPtr->m_inputPolygonsPtr->operator[]( currentPolIdx );
787 
788  locker.unlock();
789 
790  // Is this a valid polygon ?
791 
793  &inputRaster, currentPolPtr );
795  &inputRaster, currentPolPtr );
796 
797  if ( polIt != polItEnd )
798  {
799  auxPair.second.m_id = currentPolIdx;
800 
801  // means calcule
802 
803  for( inputRasterBandsIdx1 = 0 ; inputRasterBandsIdx1 <
804  inputRasterBandsSize ; ++inputRasterBandsIdx1 )
805  {
806  auxPair.second.m_meanVector[ inputRasterBandsIdx1 ] = 0.0;
807  }
808 
809  validPixelsCount = 0;
810 
811  while ( polIt != polItEnd )
812  {
813  isValidPixel = true;
814 
815  for( inputRasterBandsIdx1 = 0 ; inputRasterBandsIdx1 <
816  inputRasterBandsSize ; ++inputRasterBandsIdx1 )
817  {
818  inputRaster.getValue( polIt.getColumn(), polIt.getRow(),
819  pixelValues[ inputRasterBandsIdx1 ], inputRasterBands[
820  inputRasterBandsIdx1 ] );
821 
822  if(
823  ( inputRasterBandsIdx1 == 0 )
824  &&
825  ( pixelValues[ 0 ] == bandsNoDataValues[ 0 ] )
826  )
827  {
828  isValidPixel = false;
829  break;
830  }
831  }
832 
833  if( isValidPixel )
834  {
835  for( inputRasterBandsIdx1 = 0 ; inputRasterBandsIdx1 <
836  inputRasterBandsSize ; ++inputRasterBandsIdx1 )
837  {
838  auxPair.second.m_meanVector[ inputRasterBandsIdx1 ] +=
839  pixelValues[ inputRasterBandsIdx1 ];
840  }
841 
842  ++validPixelsCount;
843  }
844 
845  ++polIt;
846  }
847 
848  if( validPixelsCount )
849  {
850  for( inputRasterBandsIdx1 = 0 ; inputRasterBandsIdx1 <
851  inputRasterBandsSize ; ++inputRasterBandsIdx1 )
852  {
853  auxPair.second.m_meanVector[ inputRasterBandsIdx1 ] /= (double)validPixelsCount;
854  }
855  }
856 
857  // Region real area
858 
859  auxPair.first = (double)validPixelsCount;
860  auxPair.second.m_area = auxPair.first;
861 
862  // covariance matrix
863 
864  if( validPixelsCount > 2 )
865  {
866  for( inputRasterBandsIdx1 = 0 ; inputRasterBandsIdx1 <
867  inputRasterBandsSize ; ++inputRasterBandsIdx1 )
868  {
869  for( inputRasterBandsIdx2 = 0 ; inputRasterBandsIdx2 <
870  inputRasterBandsSize ; ++inputRasterBandsIdx2 )
871  {
872  if( inputRasterBandsIdx1 <= inputRasterBandsIdx2 )
873  {
875  &inputRaster, currentPolPtr );
876  covariance = 0;
877 
878  while ( polIt != polItEnd )
879  {
880  inputRaster.getValue( polIt.getColumn(), polIt.getRow(),
881  pixelValue1, inputRasterBands[ inputRasterBandsIdx1 ] );
882  inputRaster.getValue( polIt.getColumn(), polIt.getRow(),
883  pixelValue2, inputRasterBands[ inputRasterBandsIdx2 ] );
884 
885  if(
886  ( pixelValue1 != bandsNoDataValues[ inputRasterBandsIdx1 ] )
887  )
888  {
889  covariance +=
890  (
891  (
892  pixelValue1
893  -
894  auxPair.second.m_meanVector[ inputRasterBandsIdx1 ]
895  )
896  *
897  (
898  pixelValue2
899  -
900  auxPair.second.m_meanVector[ inputRasterBandsIdx2 ]
901  )
902  );
903  }
904 
905  ++polIt;
906  }
907 
908  covariance /= (double)( validPixelsCount - 1 );
909 
910  auxPair.second.m_covarianceMatrix( inputRasterBandsIdx1, inputRasterBandsIdx2 ) = covariance;
911  auxPair.second.m_covarianceMatrix( inputRasterBandsIdx2, inputRasterBandsIdx1 ) = covariance;
912  }
913  }
914  }
915 
916 // printMatrix( auxPair.second.m_covarianceMatrix );
917 
918  // inverse covariance matrix
919 
920  if( te::common::GetDeterminant( auxPair.second.m_covarianceMatrix, auxPair.second.m_covarianceMatrixDet ) )
921  {
922  if( ! te::common::GetInverseMatrix(auxPair.second.m_covarianceMatrix, auxPair.second.m_covarianceInversion) )
923  {
924  auxPair.second.m_covarianceMatrixDet = 0;
925  }
926  }
927  else
928  {
929  auxPair.second.m_covarianceMatrixDet = 0;
930  }
931 
932 // printMatrix( auxPair.second.m_covarianceInversion );
933  }
934  else
935  {
936  auxPair.second.m_covarianceMatrixDet = 0;
937  }
938 
939  locker.lock();
940  paramsPtr->m_outputRegionsPtr->insert( auxPair );
941  locker.unlock();
942  }
943 
944  if( paramsPtr->m_enableProgress )
945  {
946  taskPtr->setCurrentStep( currentPolIdx );
947 
948  if( !taskPtr->isActive() )
949  {
950  locker.lock();
951  (*paramsPtr->m_continueProcessingFlagPtr) = false;
952  --( *( paramsPtr->m_runningThreadsCounterPtr ) );
953  return;
954  }
955  }
956  }
957 
958  locker.lock();
959  --( *( paramsPtr->m_runningThreadsCounterPtr ) );
960 }
961 
962 void te::rp::ClassifierISOSegStrategy::printMatrix(const boost::numeric::ublas::matrix<double>& matrix)
963 {
964  unsigned int size1 = matrix.size1();
965  unsigned int size2 = matrix.size2();
966 
967  std::cout << std::endl << "size1=" << size1;
968  std::cout << std::endl << "size2=" << size2;
969 
970  for (unsigned int i = 0; i < size1; ++ i)
971  {
972  std::cout << std::endl << "|";
973 
974  for (unsigned int j = 0; j < size2; ++ j)
975  {
976  std::cout << " " << matrix (i, j);
977  }
978 
979  std::cout << " |";
980  }
981 
982  std::cout << std::endl;
983 }
984 
985 // ---------------------------------------------------------------------------
986 
988  : te::rp::ClassifierStrategyFactory("isoseg")
989 {
990 }
991 
993  default;
994 
996 {
998 }
Raster ISOSeg Classifier strategy factory.
An adapter class to allow concurrent access to raster data by multiple threads.
double getMahalanobisDistance(Pattern const *const p) const
Returns the Mahalanobis distance between two patterns.
AbstractParameters * clone() const
Create a clone copy of this instance.
bool m_enableRasterCache
Enable or disable the use a raster data cache.
Base exception class for plugin module.
boost::numeric::ublas::matrix< double > m_getBhattacharyyaDistance_distanceTerm1
bool createOutputRaster(const std::vector< int > &bandsDataTypes, const std::vector< double > &noDataValues)
Create the output raster using the EXPANSIBLE driver.
double getBhattacharyyaDistance(Pattern const *const p) const
Returns the Bhattacharyya distance between two patterns.
This class implements the strategy to iterate with spatial restriction, the iteration occurs inside a...
boost::numeric::ublas::matrix< double > m_covarianceInversion
The inversion of covariance matrix between bands.
std::size_t * m_nextInputPolIdx2ProcessPtr
Pointer to variable pointing the next polygon index to process.
This class can be used to inform the progress of a task.
Definition: TaskProgress.h:53
std::mutex * m_condVarMutexPtr
Pointer to the condition variable mutex.
boost::numeric::ublas::matrix< double > m_getBhattacharyyaDistance_meansDif
unsigned int getRow() const
Returns the current row in iterator.
An access synchronizer to be used in SynchronizedRaster raster instances.
boost::numeric::ublas::matrix< double > m_getBhattacharyyaDistance_covsMege
double m_noDataValue
Value to indicate elements where there is no data, default is std::numeric_limits<double>::max().
Definition: BandProperty.h:136
#define TE_TR(message)
It marks a string in order to get translated.
Definition: Translator.h:242
bool m_isInitialized
True if this instance is initialized.
boost::numeric::ublas::matrix< double > m_getBhattacharyyaDistance_covsMegeInv
The parameters passed to the fill regions thread entry.
bool execute()
Executes the classification strategy.
bool m_enableProgress
Pointer to variable pointing the variable to enable or disable the thread internal progress interface...
std::vector< unsigned int > const * m_inputRasterBandsPtr
Pointer to the input raster bands do be processed.
const te::rst::Band * getBand(std::size_t i) const
Returns the raster i-th band.
std::vector< unsigned int > m_inputRasterBands
Input raster bands.
static const double classifierISOSegStrategyChiTable[10][6]
te::rst::RasterSynchronizer * m_inputRasterSyncPtr
Pointer to the input raster sync.
static void printMatrix(const boost::numeric::ublas::matrix< double > &matrix)
Print a matrix to std::out.
Raster classifier strategy factory base class.
ISOSeg strategy for OBIA classification. The algorithm orders regions by area (larger first)...
const Parameters & operator=(const Parameters &params)
unsigned int unsigned int nCols
TECOMMONEXPORT unsigned int GetPhysProcNumber()
Returns the number of physical processors.
bool GetDeterminant(const boost::numeric::ublas::matrix< T > &inputMatrix, double &determinant)
Get the Matrix determinant value.
Definition: MatrixUtils.h:57
static PolygonIterator end(const te::rst::Raster *r, const te::gm::Polygon *p)
Returns an iterator referring to after the end of the iterator.
An abstract class for raster data strucutures.
#define TERP_LOG_AND_THROW(message)
Logs a error message and throws.
Definition: Macros.h:139
BandProperty * getProperty()
Returns the band property.
URI C++ Library.
Definition: Attributes.h:37
static te::dt::TimeDuration dt(20, 30, 50, 11)
bool m_enableMultiThread
Enable or disable the use multipe threads.
bool operator==(const Pattern &rhs) const
Return true if two clusters are equal.
A RAM cache adaptor to an external existent raster that must always be avaliable. ...
Definition: CachedRaster.h:52
double getThreshold(const double acceptanceThreshold, const unsigned nBands) const
te::gm::Polygon * p
A raster band description.
Geometry is the root class of the geometries hierarchy, it follows OGC and ISO standards.
std::condition_variable * m_condVarPtr
Pointer to the condition variable.
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.
static PolygonIterator begin(const te::rst::Raster *r, const te::gm::Polygon *p, const IterationType iterationType)
Returns an iterator referring to the first value of the band.
virtual void setValue(unsigned int c, unsigned int r, const double value)=0
Sets the cell attribute value.
std::unique_ptr< te::rst::Raster > m_outputRasterPtr
A pointer to the output raster.
int m_id
The id of the region of the pattern.
te::rp::ClassifierStrategy * build()
Concrete factories (derived from this one) must implement this method in order to create objects...
Abstract parameters base interface.
Polygon is a subclass of CurvePolygon whose rings are defined by linear rings.
Definition: Polygon.h:50
bool m_progressInterfaceEnabled
Progress interface status.
Describes a region or a cluster (group of regions with similar properties) to be used by ISOSeg metho...
bool * m_continueProcessingFlagPtr
Pointer to variable pointing the variable to allow the process to continue.
te::rst::Raster const * m_inputRasterPtr
A pointer to the input raster.
unsigned int * m_runningThreadsCounterPtr
Pointer to variable pointing the current number of running threads.
Raster classifier strategy base class.
std::multimap< double, Pattern > * m_outputRegionsPtr
Pointer to the output regions container.
bool initialize(ClassifierStrategyParameters const *const strategyParams)
Initialize the classification strategy.
bool GetInverseMatrix(const boost::numeric::ublas::matrix< T > &inputMatrix, boost::numeric::ublas::matrix< T > &outputMatrix)
Matrix inversion.
Definition: MatrixUtils.h:143
ClassifierISOSegStrategy::Parameters m_parameters
Internal execution parameters.
double m_area
The area of all regions inside a pattern.
std::vector< double > m_meanVector
The vector of mean values, 1 value per band;.
Raster Processing functions.
double m_acceptanceThreshold
The acceptance threshold (the closer to 100%, few clusters are created).
ISOSeg strategy for segmentation-based classification.
unsigned int getColumn() const
Returns the current column in iterator.
Pattern * m_myCluster
The associated cluster of this pattern (optional).
std::vector< te::gm::Polygon * > const * m_inputPolygonsPtr
Input polygons.
#define TERP_INSTANCE_TRUE_OR_RETURN_FALSE(value, message)
Checks if value is true. For false values a warning message will be logged, the current instance erro...
Definition: Macros.h:200
bool setOutputRasterPalette(const unsigned int size)
Create and set the output raster palette folowing the current internal settings.
unsigned int col
static void fillRegionsThreadEntry(FillRegionsThreadEntryParams *paramsPtr)
Fill regions thread entry.
double m_covarianceMatrixDet
The covariance matrix determinant.
void reset()
Clear all internal allocated resources and reset the parameters instance to its initial state...
boost::numeric::ublas::matrix< double > m_covarianceMatrix
The covariance matrix between bands.