All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
MixtureModelPCAStrategy.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2001-2009 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/MixtureModelPCAStrategy.cpp
22 
23  \brief PCA (Principal Component Analysis) strategy for mixture model.
24 */
25 
26 // TerraLib
27 #include "../common/MatrixUtils.h"
28 #include "../common/progress/TaskProgress.h"
29 #include "../raster/Grid.h"
30 #include "../raster/Utils.h"
31 #include "Functions.h"
32 #include "Macros.h"
34 #include "Functions.h"
35 
36 // Boost
37 #include <boost/numeric/ublas/io.hpp>
38 #include <boost/numeric/ublas/matrix.hpp>
39 
40 bool gaussElimination(boost::numeric::ublas::matrix<double>& Z, std::vector<int>& row, unsigned int nComponents);
41 bool fowardBackSubstitution(boost::numeric::ublas::matrix<double>& Z, std::vector<double>& y, unsigned int ys, std::vector<int>& row, unsigned int rows, std::vector<double>& x, unsigned int xs);
42 
43 namespace
44 {
45  static te::rp::MixtureModelPCAStrategyFactory mixtureModelPCAStrategyFactoryInstance;
46 }
47 
49 {
50  reset();
51 }
52 
54 {
55 }
56 
58 {
59  reset();
60 
61  return *this;
62 }
63 
65 {
66 }
67 
69 {
71 }
72 
74 {
75  m_isInitialized = false;
76 }
77 
79 {
80 }
81 
82 bool te::rp::MixtureModelPCAStrategy::initialize(te::rp::StrategyParameters const* const strategyParams) throw(te::rp::Exception)
83 {
84  m_isInitialized = false;
85 
86  te::rp::MixtureModelPCAStrategy::Parameters const* paramsPtr = dynamic_cast<te::rp::MixtureModelPCAStrategy::Parameters const*>(strategyParams);
87 
88  if(!paramsPtr)
89  return false;
90 
91  m_parameters = *(paramsPtr);
92 
93  // TERP_TRUE_OR_RETURN_FALSE(m_parameters.m_acceptanceThreshold > 0 && m_parameters.m_acceptanceThreshold <= 100, "Invalid acceptance threshold [0, 100].")
94 
95  m_isInitialized = true;
96 
97  return true;
98 }
99 
100 bool te::rp::MixtureModelPCAStrategy::execute(const te::rst::Raster& inputRaster, const std::vector<unsigned int>& inputRasterBands,
101  const std::vector<std::string>& inputSensorBands, const std::map<std::string, std::vector<double> >& components,
102  te::rst::Raster& outputRaster, const bool enableProgressInterface) throw(te::rp::Exception)
103 {
104 // this source code is based on TerraLib 4
105  TERP_TRUE_OR_RETURN_FALSE(m_isInitialized, "Instance not initialized")
106 
107  const unsigned int nComponents = components.size();
108  const unsigned int nBands = inputSensorBands.size();
109 
110  bool computeErrorRasters = false;
111  if (nComponents < outputRaster.getNumberOfBands())
112  computeErrorRasters = true;
113 
114 // indexes variables
115  unsigned int i, j, k, m;
116 
117  std::vector<double> Qmax;
118  for (i = 0; i < inputSensorBands.size(); i++)
119  Qmax.push_back(GetDigitalNumberBandMax(inputSensorBands[i]));
120 
121 // buildind the SpectralBandsComponents Matrix
122  boost::numeric::ublas::matrix<double> SpectralBandsComponents(nBands, nComponents);
123  std::map<std::string, std::vector<double> >::const_iterator it;
124  for(i = 0; i < nBands; i++)
125  for (j = 0, it = components.begin(); it != components.end(); j++, it++)
126  SpectralBandsComponents(i, j) = it->second[i] / Qmax[i];
127 
128 // Part I : mathematical processing independend on image data
129 
130 // SpectralBandsComponentsTransposed stores SpectralBandsComponents and other things after
131  boost::numeric::ublas::matrix<double> SpectralBandsComponentsTransposed(nComponents, nBands);
132 
133 // Initializing SpectralBandsComponentsTransposed Matrix = Transpose of SpectralBandsComponents
134  SpectralBandsComponentsTransposed = boost::numeric::ublas::trans(SpectralBandsComponents);
135 
136 // compute componentsMean vector as the mean coefficient value per band and subtract the componentsMeanAfter from the coefficients matrix
137 // creating two double vectors to store de means of the spectralBands of each component
138  std::vector<double> componentsMean(nBands, 0.0);
139  std::vector<double> componentsMeanAfter(nBands, 0.0);
140 
141  for (j = 0; j < nBands; j++)
142  {
143 // compute original mean (componentsMean)
144  componentsMean[j] = 0;
145  for(i = 0; i < nComponents; i++)
146  componentsMean[j] = componentsMean[j] + SpectralBandsComponentsTransposed(i, j);
147  componentsMean[j] = componentsMean[j] / (double) nComponents;
148 
149 // subtract mean from SpectralBandsComponents and compute new matrix mean (componentsMeanAfter)
150  componentsMeanAfter[j] = 0;
151  for(i = 0; i < nComponents; i++)
152  {
153  SpectralBandsComponentsTransposed(i, j) = SpectralBandsComponentsTransposed(i, j) - componentsMean[j];
154  componentsMeanAfter[j] = componentsMeanAfter[j] + SpectralBandsComponentsTransposed(i, j);
155  }
156  componentsMeanAfter[j] = componentsMeanAfter[j] / (double) nComponents;
157  }
158 
159 // compute covarianceVector vector
160  std::vector<double> covarianceVector(nBands * nBands, 0.0);
161  for(k = 0; k < nBands * nBands; k++)
162  covarianceVector[k] = 0;
163 
164  k = 0 ;
165  for(j = 0; j < nBands; j++)
166  for(m = 0; m < j + 1; m++)
167  {
168  for(i = 0; i < nComponents; i++)
169  covarianceVector[k] = covarianceVector[k] + (SpectralBandsComponentsTransposed(i, j) - componentsMeanAfter[j]) *
170  (SpectralBandsComponentsTransposed(i, m) - componentsMeanAfter[m]);
171  covarianceVector[k] = covarianceVector[k] / (double) nComponents;
172 
173  k++;
174  }
175 
176  k = 0;
177  boost::numeric::ublas::matrix<double> covarianceMatrix(nBands, nBands);
178  for (i = 0; i < nBands; i++)
179  for (j = 0; j <= i; j++)
180  covarianceMatrix(i, j) = covarianceVector[k++];
181 
182 // compute eigenvectors -> auxMatrix and eigenvalues -> tmpMatrix
183  boost::numeric::ublas::matrix<double> auxMatrix(covarianceMatrix);
184  boost::numeric::ublas::matrix<double> tmpMatrix;
185 
186  if(!te::common::EigenVectors(covarianceMatrix, auxMatrix, tmpMatrix))
187  return false; // print error in eigenvectors
188 
189 // keep only significant eigenvectors (nComponents - 1): results eigenReduced
190  boost::numeric::ublas::matrix<double> eigenReduced(nBands, nComponents - 1);
191  for (j = 0; j < nBands; j++)
192  for (i = 0; i < nComponents - 1; i++)
193  eigenReduced(j, i) = auxMatrix(j, i);
194 
195 // rotate SpectralBandsComponentsTransposed to PCA space; result SpectralBandsComponentsPCA
196  boost::numeric::ublas::matrix<double> SpectralBandsComponentsPCA(SpectralBandsComponentsTransposed.size1(), eigenReduced.size2()); // (nrow x ncol)???
197  SpectralBandsComponentsPCA = boost::numeric::ublas::prod(SpectralBandsComponentsTransposed, eigenReduced);
198 
199 // Initialize one more column to SpectralBandsComponentsPCA to incorporate sum restriction to equations; results auxMatrix
200  auxMatrix.resize(SpectralBandsComponentsPCA.size1(), SpectralBandsComponentsPCA.size2() + 1); // nrow, ncol + 1 ???
201  auxMatrix.clear();
202 
203  for (j = 0; j < SpectralBandsComponentsPCA.size1(); j++) // nrow
204  {
205  for (i = 0; i < SpectralBandsComponentsPCA.size2(); i++) // ncol
206  auxMatrix(j, i) = SpectralBandsComponentsPCA(j, i);
207 
208  auxMatrix(j, SpectralBandsComponentsPCA.size2()) = 1.0;
209  }
210 
211 // Transpose auxMatrix; results SpectralBandsComponentsPCA
212  SpectralBandsComponentsPCA.clear();
213  SpectralBandsComponentsPCA = boost::numeric::ublas::trans(auxMatrix);
214 
215 // invert matrix SpectralBandsComponentsPCA; results SpectralBandsComponentsPCA
216  std::vector<int> rows(nComponents, 0);
217 
218  if (!gaussElimination(SpectralBandsComponentsPCA, rows, nComponents))
219  return false; // print "Error in gauss elimination");
220 
221 // Part II : mathematical processing dependend on image data
222 
223 // Initialize matrices that will help to prepare vector Y
224  auxMatrix.resize(1, nBands);
225  auxMatrix.clear();
226  boost::numeric::ublas::matrix<double> ymat(nComponents - 1, nComponents - 1);
227 
228 // initialize proportion vector X and image dependent values for the linear equations Y
229  std::vector<double> x(nComponents, 0.0);
230  std::vector<double> y(nComponents, 0.0);
231 
232  unsigned int prop;
233  std::vector<unsigned int> rowsIn(nBands, 0);
234  std::vector<unsigned int> columnIn(nBands, 0);
235  std::vector<unsigned int> columnsIn(nBands, 0);
236  std::vector<double> spectralBandsError(nBands, 0.0);
237 
238  boost::numeric::ublas::matrix<double> rasterRowsIn(nBands, inputRaster.getNumberOfColumns());
239  boost::numeric::ublas::matrix<double> rasterRowsOut(nComponents, inputRaster.getNumberOfColumns());
240 
241  te::common::TaskProgress task(TR_RP("PCA Mixture Model"), te::common::TaskProgress::UNDEFINED, inputRaster.getNumberOfRows());
242  double value;
243  for (unsigned int rowout = 0; rowout < inputRaster.getNumberOfRows(); rowout++)
244  {
245 // read input row for each band
246  for (i = 0; i < nBands; i++)
247  {
248  for (j = 0; j < inputRaster.getNumberOfColumns(); j++)
249  {
250  inputRaster.getValue(j, rowsIn[i], value, inputRasterBands[i]);
251  rasterRowsIn(i, j) = value;
252  }
253 
254 // update next row to be read for band i
255  rowsIn[i]++;
256 
257 // reinitialize first column for band i
258  columnIn[i] = columnsIn[i];
259  }
260 
261 // compute proportions for each column
262  for (unsigned int colout = 0; colout < inputRaster.getNumberOfColumns(); colout++)
263  {
264 // prepare y
265  for (i = 0; i < nBands; i++)
266  auxMatrix(0, i) = (double) (rasterRowsIn(i, columnIn[i])) / 255.0 - componentsMean[i];
267 
268  ymat = boost::numeric::ublas::prod(auxMatrix, eigenReduced);
269 
270  for (i = 0; i < nComponents - 1; i++)
271  y[i] = ymat(0, i);
272 
273 // compute proportions
274  if (!fowardBackSubstitution(SpectralBandsComponentsPCA, y, nComponents, rows, nComponents, x, nComponents))
275  return false; // print "error in function fowardBackSubstitution"
276 
277 // store proportion in buffers
278  for (i = 0; i < nComponents; i++)
279  {
280  prop = (short) (x[i] * 100 + 100);
281  rasterRowsOut(i, colout) = (unsigned char) prop;
282  }
283 
284  double aux;
285  double error;
286 
287 // verify if it is necessary to compute the error
288  if (computeErrorRasters)
289  {
290  for (i = 0; i < nBands; i++)
291  {
292 // compute digital value from the proportions
293  aux = 0.0;
294  for (j = 0; j < nComponents; j++)
295  aux += x[j] * SpectralBandsComponents(i, j);
296 
297 // compute error as module of the difference between the original value and aux
298  error = (long) (rasterRowsIn(i, columnIn[i])) / 255.0 - aux;
299  if (error < 0)
300  error *= -1;
301 
302  if (computeErrorRasters)
303  rasterRowsIn(i, colout) = error * 255.0;
304  }
305  }
306 
307 // update current column number
308  for (i = 0; i < nBands; i++)
309  columnIn[i]++;
310 
311  }
312 
313 // write processed row to disk
314  for (i = 0; i < nComponents; i++)
315  for (j = 0; j < inputRaster.getNumberOfColumns(); j++)
316  outputRaster.setValue(j, rowout, rasterRowsOut(i, j), i);
317 
318 // store output error rasters
319  if (computeErrorRasters)
320  {
321  for (i = 0; i < nComponents; i++)
322  for (j = 0; j < inputRaster.getNumberOfColumns(); j++)
323  outputRaster.setValue(j, rowout, rasterRowsIn(i, j), i + nComponents); // ???
324  }
325  task.pulse();
326  }
327 
328  return true;
329 }
330 
332  : te::rp::MixtureModelStrategyFactory("pca")
333 {
334 }
335 
337 {
338 }
339 
341 {
342  return new te::rp::MixtureModelPCAStrategy();
343 }
344 
345 bool gaussElimination(boost::numeric::ublas::matrix<double>& Z, std::vector<int>& row, unsigned int nComponents)
346 {
347 // verify matrix and vector sizes
348  assert(Z.size1() >= Z.size2());
349  unsigned int nrows = Z.size1(); // rows = size2?
350  assert(nComponents >= nrows);
351 
352  unsigned int i;
353  unsigned int j;
354  unsigned int k;
355  unsigned int aux;
356  double auxd;
357  double m;
358 
359 // initialize changed rows indicator
360  for (i = 0; i < nrows; i++)
361  row[i] = i;
362 
363 // diagonalization
364  for (k = 0; k < nrows; k++)
365  {
366  i = k;
367  while (Z(i, k) == 0.0)
368  {
369  if (i == nrows - 1)
370  return false; // print "Singular matrix"
371 
372  i++;
373  }
374 
375  if (k != i)
376  {
377 // update changed rows indicator
378  aux = row[i];
379  row[i] = row[k];
380  row[k] = aux;
381 
382 // change rows
383  for (j=0; j < nrows; j ++)
384  {
385  auxd = Z(k, j);
386  Z(k, j) = Z (i, j);
387  Z (i, j) = auxd;
388  }
389  }
390 
391 // recompute rows i = k + 1,..., nComponents - 1
392  for (i = k + 1; i < nrows; i++)
393  {
394  m = Z(i, k)/Z(k, k);
395  Z(i, k) = m;
396  for (j = k + 1; j < nrows; j++)
397  Z (i, j) = Z (i, j) - m * Z(k, j);
398  }
399 
400  }
401 
402  if (Z(nrows - 1, nrows - 1) == 0.0)
403  return false; // print "Singular Matrix"
404 
405  return true;
406 }
407 
408 bool fowardBackSubstitution(boost::numeric::ublas::matrix<double>& Z, std::vector<double>& y, unsigned int ys, std::vector<int>& row, unsigned int rows, std::vector<double>& x, unsigned int xs)
409 {
410 // verify matrix size
411  assert(Z.size1() >= Z.size2());
412  unsigned int nrows = Z.size1(); // rows = size2?
413 
414  if (((rows < nrows) || (ys < nrows) || (xs < nrows)))
415  return false; // print "Vector Size"
416 
417  int j, k;
418  double aux;
419  std::vector<double> F(nrows, 0.0);
420 
421 // foward substuitution
422  for (k = 0; k < (int) nrows; k++)
423  {
424  aux = 0.0;
425  for (j = 0; j <= k - 1; j++)
426  aux = aux + Z(k, j) * F[j];
427 
428  F[k] = y[row[k]] - aux;
429  }
430 
431 // backward substitution
432  for (k = ((int) nrows) - 1; k >= 0; k--)
433  {
434  aux = 0.0;
435  for (j = k + 1; j < (int) nrows; j++)
436  aux = aux + Z(k, j) * x[j];
437 
438  x[k] = (F[k] - aux) / Z(k, k);
439  }
440 
441  return true;
442 }
bool execute(const te::rst::Raster &inputRaster, const std::vector< unsigned int > &inputRasterBands, const std::vector< std::string > &inputSensorBands, const std::map< std::string, std::vector< double > > &components, te::rst::Raster &outputRaster, const bool enableProgressInterface)
Executes the segmentation strategy.
Raster strategy parameters base class.
Raster Processing functions.
void reset()
Clear all internal allocated resources and reset the parameters instance to its initial state...
Raster mixture model strategy base class.
bool m_isInitialized
True if this instance is initialized.
double GetDigitalNumberBandMax(std::string bandName)
Returns the maximum digital number of a given sensor/band.
Definition: Functions.cpp:651
bool gaussElimination(boost::numeric::ublas::matrix< double > &Z, std::vector< int > &row, unsigned int nComponents)
#define TR_RP(message)
It marks a string in order to get translated. This is a special mark used in the Raster Processing mo...
Definition: Config.h:58
MixtureModelPCAStrategy::Parameters m_parameters
Internal execution parameters.
#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
Abstract parameters base interface.
Raster PCA mixture model strategy factory.
te::rp::MixtureModelStrategy * build()
Concrete factories (derived from this one) must implement this method in order to create objects...
const Parameters & operator=(const Parameters &params)
AbstractParameters * clone() const
Create a clone copy of this instance.
An abstract class for raster data strucutures.
Definition: Raster.h:70
This class can be used to inform the progress of a task.
Definition: TaskProgress.h:53
bool initialize(StrategyParameters const *const strategyParams)
Initialize the segmentation strategy.
bool fowardBackSubstitution(boost::numeric::ublas::matrix< double > &Z, std::vector< double > &y, unsigned int ys, std::vector< int > &row, unsigned int rows, std::vector< double > &x, unsigned int xs)
Raster Mixture model strategy factory base class.
PCA (Principal Component Analysis) strategy for mixture model.
bool EigenVectors(const boost::numeric::ublas::matrix< T > &inputMatrix, boost::numeric::ublas::matrix< T > &eigenVectorsMatrix, boost::numeric::ublas::matrix< T > &eigenValuesMatrix)
Computes the eigenvectors of a given matrix.
Definition: MatrixUtils.h:211