PCAFusion.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/PCAFusion.cpp
22  \brief Creation of skeleton imagems.
23 */
24 
25 #include "PCAFusion.h"
26 #include "Macros.h"
27 #include "Functions.h"
28 
29 #include "../raster/BandProperty.h"
30 #include "../raster/RasterFactory.h"
31 #include "../raster/Band.h"
32 #include "../raster/Grid.h"
33 #include "../geometry/Envelope.h"
34 #include "../common/progress/TaskProgress.h"
35 #include "../memory/ExpansibleRaster.h"
36 
37 #include <cmath>
38 #include <limits>
39 
40 namespace te
41 {
42  namespace rp
43  {
44 
46  {
47  reset();
48  }
49 
51  {
52  reset();
53  operator=( other );
54  }
55 
57  {
58  reset();
59  }
60 
62  {
63  m_lowResRasterPtr = nullptr;
64  m_lowResRasterBands.clear();
65  m_highResRasterPtr = nullptr;
67  m_enableProgress = false;
70  }
71 
73  const PCAFusion::InputParameters& params )
74  {
75  reset();
76 
84 
85  return *this;
86  }
87 
89  {
90  return new InputParameters( *this );
91  }
92 
94  {
95  reset();
96  }
97 
99  {
100  reset();
101  operator=( other );
102  }
103 
105  {
106  reset();
107  }
108 
110  {
111  m_rType.clear();
112  m_rInfo.clear();
113  m_outputRasterPtr.reset();
114  }
115 
117  const PCAFusion::OutputParameters& params )
118  {
119  reset();
120 
121  m_rType = params.m_rType;
122  m_rInfo = params.m_rInfo;
123 
124  return *this;
125  }
126 
128  {
129  return new OutputParameters( *this );
130  }
131 
133  {
134  reset();
135  }
136 
137  PCAFusion::~PCAFusion() = default;
138 
140  throw( te::rp::Exception )
141  {
142  if( ! m_isInitialized ) return false;
143 
144  PCAFusion::OutputParameters* outParamsPtr = dynamic_cast<
145  PCAFusion::OutputParameters* >( &outputParams );
146  TERP_TRUE_OR_THROW( outParamsPtr, "Invalid paramters" );
147 
148  // progress
149 
150  std::unique_ptr< te::common::TaskProgress > progressPtr;
152  {
153  progressPtr.reset( new te::common::TaskProgress );
154 
155  progressPtr->setTotalSteps( 4 );
156 
157  progressPtr->setMessage( "Fusing images" );
158  }
159 
160  // Loading ressampled data
161 
162  std::unique_ptr< te::rst::Raster > ressampledRasterPtr;
163 
165  "Ressampled raster data loading error" );
166 
167 // te::rp::Copy2DiskRaster( *ressampledRasterPtr, "ressampledRaster.tif" );
168 
170  {
171  progressPtr->pulse();
172  if( ! progressPtr->isActive() ) return false;
173  }
174 
175  // Compute PCA space raster
176 
177  std::unique_ptr< te::rst::Raster > pcaRasterPtr;
178  boost::numeric::ublas::matrix< double > pcaMatrix;
179 
180  {
181  te::rst::Grid* gridPtr = new te::rst::Grid( *ressampledRasterPtr->getGrid() );
182  std::vector< te::rst::BandProperty * > bandProperties;
183  std::vector< unsigned int > ressampledRasterBands;
184 
185  for( unsigned int bandIdx = 0 ; bandIdx <
186  ressampledRasterPtr->getNumberOfBands() ; ++bandIdx )
187  {
188  bandProperties.push_back( new te::rst::BandProperty(
189  *ressampledRasterPtr->getBand( bandIdx )->getProperty() ) );
190  bandProperties[ bandIdx ]->m_type = te::dt::DOUBLE_TYPE;
191  bandProperties[ bandIdx ]->m_noDataValue = std::numeric_limits< double >::max();
192 
193  ressampledRasterBands.push_back( bandIdx );
194  }
195 
196  try
197  {
198  pcaRasterPtr.reset( new te::mem::ExpansibleRaster( 20, gridPtr,
199  bandProperties ) );
200  }
201  catch( te::common::Exception& e )
202  {
204  }
205 
207  ressampledRasterBands, pcaMatrix, *pcaRasterPtr, ressampledRasterBands,
209  "Principal components generation error" );
210 
211 // te::rp::Copy2DiskRaster( *pcaRasterPtr, "pcaRaster.tif" );
212  }
213 
215  {
216  progressPtr->pulse();
217  if( ! progressPtr->isActive() ) return false;
218  }
219 
220  // Swapping the first PCA band by the high resolution raster
221 
223  "Band swap error" );
224 
225 // te::rp::Copy2DiskRaster( *pcaRasterPtr, "swappedpcaRaster.tif" );
226 
228  {
229  progressPtr->pulse();
230  if( ! progressPtr->isActive() ) return false;
231  }
232 
233  // Generating the output fused raster
234 
235  {
237 
238  std::vector< te::rst::BandProperty * > bandProperties;
239  std::vector< unsigned int > outputRasterBands;
240 
241  for( unsigned int bandIdx = 0 ; bandIdx <
242  pcaRasterPtr->getNumberOfBands() ; ++bandIdx )
243  {
244  bandProperties.push_back( new te::rst::BandProperty(
245  *pcaRasterPtr->getBand( bandIdx )->getProperty() ) );
246  bandProperties[ bandIdx ]->m_type =
247  ressampledRasterPtr->getBand( bandIdx )->getProperty()->m_type;
248  bandProperties[ bandIdx ]->m_noDataValue =
249  ressampledRasterPtr->getBand( bandIdx )->getProperty()->m_noDataValue;
250 
251  outputRasterBands.push_back( bandIdx );
252  }
253 
254  outParamsPtr->m_outputRasterPtr.reset(
256  outParamsPtr->m_rType,
257  gridPtr,
258  bandProperties,
259  outParamsPtr->m_rInfo,
260  nullptr,
261  nullptr ) );
263  "Output raster creation error" );
264 
266  pcaMatrix, *outParamsPtr->m_outputRasterPtr, outputRasterBands,
268  "Inverse PCA error" );
269  }
270 
272  {
273  progressPtr->pulse();
274  if( ! progressPtr->isActive() ) return false;
275  }
276 
277  return true;
278  }
279 
280  void PCAFusion::reset() throw( te::rp::Exception )
281  {
283 
285  m_isInitialized = false;
286  }
287 
289  throw( te::rp::Exception )
290  {
291  reset();
292 
293  PCAFusion::InputParameters const* inputParamsPtr = dynamic_cast<
294  PCAFusion::InputParameters const* >( &inputParams );
295  TERP_TRUE_OR_THROW( inputParamsPtr, "Invalid paramters pointer" );
296 
297  m_inputParameters = *inputParamsPtr;
298 
299  // Checking the m_lowResRasterPtr and m_lowResRasterBands
300 
302  "Invalid low Resolution Raster Pointer" )
303 
306  "Invalid raster" );
307 
308  for( unsigned int lowResRasterBandsIdx = 0 ; lowResRasterBandsIdx <
309  inputParamsPtr->m_lowResRasterBands.size() ; ++lowResRasterBandsIdx )
310  {
312  inputParamsPtr->m_lowResRasterBands[ lowResRasterBandsIdx ] <
314  "Invalid raster band" );
315  }
316 
317  // Checking the m_highResRasterPtr and m_highResRasterBand
318 
320  "Invalid high resolution Raster Pointer" )
321 
324  "Invalid raster" );
325 
329  "Invalid raster band" );
330 
331  m_isInitialized = true;
332 
333  return true;
334  }
335 
337  {
338  return m_isInitialized;
339  }
340 
341  bool PCAFusion::loadRessampledRaster( std::unique_ptr< te::rst::Raster >& ressampledRasterPtr ) const
342  {
343  // Creating the ressampled raster
344 
345  const unsigned int outNCols = m_inputParameters.m_highResRasterPtr->getNumberOfColumns();
346  const unsigned int outNRows = m_inputParameters.m_highResRasterPtr->getNumberOfRows();
347  unsigned int lowResRasterBandsIdx = 0;
348  unsigned int lowResRasterBandIdx = 0;
349 
350  te::rst::Grid* ressampledGrid = new te::rst::Grid( outNCols, outNRows,
353 
354  std::vector< te::rst::BandProperty * > ressampledBandProperties;
355 
356  for( lowResRasterBandsIdx = 0 ; lowResRasterBandsIdx <
357  m_inputParameters.m_lowResRasterBands.size() ; ++lowResRasterBandsIdx )
358  {
359  lowResRasterBandIdx = m_inputParameters.m_lowResRasterBands[ lowResRasterBandsIdx ];
360 
361  ressampledBandProperties.push_back( new te::rst::BandProperty(
362  *m_inputParameters.m_lowResRasterPtr->getBand( lowResRasterBandIdx )->getProperty() ) );
363  ressampledBandProperties[ lowResRasterBandsIdx ]->m_blkw = outNCols;
364  ressampledBandProperties[ lowResRasterBandsIdx ]->m_blkh = 1;
365  ressampledBandProperties[ lowResRasterBandsIdx ]->m_nblocksx = 1;
366  ressampledBandProperties[ lowResRasterBandsIdx ]->m_nblocksy = outNRows;
367  }
368 
369  try
370  {
371  ressampledRasterPtr.reset( new te::mem::ExpansibleRaster( 20, ressampledGrid,
372  ressampledBandProperties ) );
373  }
374  catch( te::common::Exception& e )
375  {
377  }
378 
379  const double colsRescaleFactor =
381  ((double)outNCols);
382  const double rowsRescaleFactor =
384  ((double)outNRows);
385  unsigned int outRow = 0;
386  unsigned int outCol = 0;
387  double inRow = 0;
388  double inCol = 0;
391  std::complex< double > value = 0;
392  te::rst::Raster& ressampledRaster = *ressampledRasterPtr;
393  double inNoDataValue = 0;
394  double outNoDataValue = 0;
395 
396  for( lowResRasterBandsIdx = 0 ; lowResRasterBandsIdx <
397  m_inputParameters.m_lowResRasterBands.size() ; ++lowResRasterBandsIdx )
398  {
399  lowResRasterBandIdx = m_inputParameters.m_lowResRasterBands[ lowResRasterBandsIdx ];
400  inNoDataValue = m_inputParameters.m_lowResRasterPtr->getBand( lowResRasterBandIdx )->getProperty()->m_noDataValue;
401  outNoDataValue = ressampledRaster.getBand( lowResRasterBandsIdx )->getProperty()->m_noDataValue;
402 
403  for( outRow = 0 ; outRow < outNRows ; ++outRow )
404  {
405  inRow = ((double)outRow) * rowsRescaleFactor;
406 
407  for( outCol = 0 ; outCol < outNCols ; ++outCol )
408  {
409  inCol = ((double)outCol) * colsRescaleFactor;
410 
411  interpol.getValue( inCol, inRow, value, lowResRasterBandIdx );
412 
413  if( value.real() == inNoDataValue )
414  {
415  ressampledRaster.setValue( outCol, outRow, outNoDataValue, lowResRasterBandsIdx );
416  }
417  else
418  {
419  ressampledRaster.setValue( outCol, outRow, value.real(), lowResRasterBandsIdx );
420  }
421  }
422  }
423  }
424 
425  return true;
426  }
427 
428  bool PCAFusion::swapBandByHighResRaster( te::rst::Raster& pcaRaster, const unsigned int pcaRasterBandIdx )
429  {
432 
433  assert( pcaRasterBandIdx < pcaRaster.getNumberOfBands() );
434  te::rst::Band& pcaBand = (*pcaRaster.getBand( pcaRasterBandIdx ));
436 
437  double pcaZeroMean = 0.0;
439  0 : 1, pcaZeroMean ) )
440  {
441  return false;
442  }
443 
444  double pcaZeroStdDev = 0.0;
446  0 : 1, &pcaZeroMean, pcaZeroStdDev ) )
447  {
448  return false;
449  }
450 
451  double hrMean = 0.0;
452  if( ! te::rp::GetMeanValue( hrBand, m_inputParameters.m_enableThreadedProcessing ? 0 : 1, hrMean ) )
453  {
454  return false;
455  }
456 
457  double hrStdDev = 0.0;
458  if( ! te::rp::GetStdDevValue( hrBand, m_inputParameters.m_enableThreadedProcessing ? 0 : 1, &hrMean, hrStdDev ) )
459  {
460  return false;
461  }
462 
463  const double gain = ( ( hrStdDev == 0.0 ) ? 0.0 : ( pcaZeroStdDev / hrStdDev ) );
464  const double& pcaNoDataValue = pcaBand.getProperty()->m_noDataValue;
465  const double& hrNoDataValue = hrBand.getProperty()->m_noDataValue;
466  const unsigned int nRows = pcaRaster.getNumberOfRows();
467  const unsigned int nCols = pcaRaster.getNumberOfColumns();
468  unsigned int col = 0;
469  unsigned int row = 0;
470  double value = 0;
471  double pcaAllowedMin = 0;
472  double pcaAllowedMax = 0;
473  te::rp::GetDataTypeRange( pcaBand.getProperty()->getType(), pcaAllowedMin,
474  pcaAllowedMax );
475 
476  for( row = 0 ; row < nRows ; ++row )
477  {
478  for( col = 0 ; col < nCols ; ++col )
479  {
480  hrBand.getValue( col, row, value );
481  if( value == hrNoDataValue )
482  {
483  pcaBand.setValue( col, row, pcaNoDataValue );
484  }
485  else
486  {
487  value = ( ( value - hrMean ) * gain ) + pcaZeroMean;
488  value = std::max( pcaAllowedMin, value );
489  value = std::min( pcaAllowedMax, value );
490 
491  pcaBand.setValue( col, row, value );
492  }
493  }
494  }
495 
496  return true;
497  }
498 
499  }
500 } // end namespace te
501 
bool GetMeanValue(const te::rst::Band &band, const unsigned int maxThreads, double &meanValue)
Get the mean of band pixel values.
bool m_enableProgress
Enable/Disable the progress interface (default:false).
Definition: PCAFusion.h:70
bool m_enableThreadedProcessing
If true, threaded processing will be performed (best with multi-core or multi-processor systems (defa...
Definition: PCAFusion.h:72
bool execute(AlgorithmOutputParameters &outputParams)
Executes the algorithm using the supplied parameters.
Definition: PCAFusion.cpp:139
virtual void setValue(unsigned int c, unsigned int r, const double value, std::size_t b=0)
Sets the attribute value in a band of a cell.
te::rst::Raster const * m_highResRasterPtr
Input high-resolution raster.
Definition: PCAFusion.h:66
Near neighborhood interpolation method.
AbstractParameters * clone() const
Create a clone copy of this instance.
Definition: PCAFusion.cpp:88
bool isInitialized() const
Returns true if the algorithm instance is initialized and ready for execution.
Definition: PCAFusion.cpp:336
bool swapBandByHighResRaster(te::rst::Raster &pcaRaster, const unsigned int pcaRasterBandIdx)
Swap the band values by the normalized high resolution raster data.
Definition: PCAFusion.cpp:428
A raster band description.
Definition: BandProperty.h:61
AbstractParameters * clone() const
Create a clone copy of this instance.
Definition: PCAFusion.cpp:127
void reset()
Clear all internal allocated resources and reset the parameters instance to its initial state...
Definition: PCAFusion.cpp:109
Base exception class for plugin module.
unsigned int getNumberOfColumns() const
Returns the raster number of columns.
virtual const char * what() const
It outputs the exception message.
bool m_isInitialized
Tells if this instance is initialized.
Definition: PCAFusion.h:142
It interpolates one pixel based on a selected algorithm. Methods currently available are Nearest Neig...
Definition: Interpolator.h:55
std::string m_rType
Output raster data source type (as described in te::raster::RasterFactory ).
Definition: PCAFusion.h:100
void TERPEXPORT GetDataTypeRange(const int dataType, double &min, double &max)
Returns the real data type range (all values that can be represented by the given data type)...
This class can be used to inform the progress of a task.
Definition: TaskProgress.h:53
Raster Processing algorithm output parameters base interface.
std::unique_ptr< te::rst::Raster > m_outputRasterPtr
The generated output fused raster.
Definition: PCAFusion.h:104
PCAFusion output parameters.
Definition: PCAFusion.h:96
void getValue(const double &c, const double &r, std::complex< double > &v, const std::size_t &b)
Get the interpolated value at specific band.
Definition: Interpolator.h:93
double m_noDataValue
Value to indicate elements where there is no data, default is std::numeric_limits<double>::max().
Definition: BandProperty.h:136
bool DirectPrincipalComponents(const te::rst::Raster &inputRaster, const std::vector< unsigned int > &inputRasterBands, boost::numeric::ublas::matrix< double > &pcaMatrix, te::rst::Raster &pcaRaster, const std::vector< unsigned int > &pcaRasterBands, const unsigned int maxThreads)
Generate all principal components from the given input raster.
te::rst::Raster const * m_lowResRasterPtr
Input low-resolution multi-band raster.
Definition: PCAFusion.h:62
const InputParameters & operator=(const InputParameters &params)
Definition: PCAFusion.cpp:72
te::rst::Interpolator::Method m_interpMethod
The raster interpolator method (default:NearestNeighbor).
Definition: PCAFusion.h:74
te::common::AccessPolicy getAccessPolicy() const
Returns the raster access policy.
bool loadRessampledRaster(std::unique_ptr< te::rst::Raster > &ressampledRasterPtr) const
Load resampled data from the input image.
Definition: PCAFusion.cpp:341
unsigned int unsigned int nCols
An Envelope defines a 2D rectangular region.
An abstract class for raster data strucutures.
unsigned int getNumberOfRows() const
Returns the raster number of rows.
virtual std::size_t getNumberOfBands() const =0
Returns the number of bands (dimension of cells attribute values) in the raster.
void reset()
Clear all internal allocated objects and reset the algorithm to its initial state.
Definition: PCAFusion.cpp:280
BandProperty * getProperty()
Returns the band property.
URI C++ Library.
Definition: Attributes.h:37
bool initialize(const AlgorithmInputParameters &inputParams)
Initialize the algorithm instance making it ready for execution.
Definition: PCAFusion.cpp:288
void reset()
Clear all internal allocated resources and reset the parameters instance to its initial state...
Definition: PCAFusion.cpp:61
A raster band description.
virtual const Band * getBand(std::size_t i) const =0
Returns the raster i-th band.
Grid * getGrid()
It returns the raster grid.
This class is designed to declare objects to be thrown as exceptions by TerraLib. ...
Abstract parameters base interface.
std::vector< unsigned int > m_lowResRasterBands
The low-resolution raster band indexes.
Definition: PCAFusion.h:64
int getSRID() const
Returns the raster spatial reference system identifier.
#define TERP_LOG_AND_RETURN_FALSE(message)
Logs a warning message will and return false.
Definition: Macros.h:269
std::map< std::string, std::string > m_rInfo
The necessary information to create the output rasters (as described in te::raster::RasterFactory).
Definition: PCAFusion.h:102
InputParameters m_inputParameters
Input execution parameters.
Definition: PCAFusion.h:140
A raster (stored in memory and eventually swapped to disk) where it is possible to dynamically add li...
PCAFusion input parameters.
Definition: PCAFusion.h:58
static Raster * make()
It creates and returns an empty raster with default raster driver.
te::gm::Envelope * getExtent()
Returns the geographic extension of the grid.
bool InversePrincipalComponents(const te::rst::Raster &pcaRaster, const boost::numeric::ublas::matrix< double > &pcaMatrix, te::rst::Raster &outputRaster, const std::vector< unsigned int > &outputRasterBands, const unsigned int maxThreads)
Regenerate the original raster from its principal components.
Raster Processing algorithm input parameters base interface.
Raster Processing functions.
virtual void reset() _NOEXCEPT_OP(false)
Clear all internal allocated objects and reset the algorithm to its initial state.
A rectified grid is the spatial support for raster data.
Definition: raster/Grid.h:68
Creation of skeleton imagems.
#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
unsigned int col
bool GetStdDevValue(const te::rst::Band &band, const unsigned int maxThreads, double const *const meanValuePtr, double &stdDevValue)
Get the standard deviation of band pixel values.
#define TERP_TRUE_OR_THROW(value, message)
Checks if value is true and throws an exception if not.
Definition: Macros.h:150
unsigned int m_highResRasterBand
Band to process from the high-resolution raster.
Definition: PCAFusion.h:68
virtual void getValue(unsigned int c, unsigned int r, double &value) const =0
Returns the cell attribute value.
const OutputParameters & operator=(const OutputParameters &params)
Definition: PCAFusion.cpp:116
#define TERP_INSTANCE_LOG_AND_RETURN_FALSE(message)
Logs a warning message, update the current instance error messsage and return false.
Definition: Macros.h:279