MixtureModelLinearStrategy.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/MixtureModelLinearStrategy.cpp
22 
23  \brief Raster linear strategy for mixture model classification.
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 namespace
41 {
42  static te::rp::MixtureModelLinearStrategyFactory mixtureModelLinearStrategyFactoryInstance;
43 }
44 
46 {
47  reset();
48 }
49 
51 {
52 }
53 
55 {
56  reset();
57 
58  return *this;
59 }
60 
62 {
63 }
64 
66 {
68 }
69 
71 {
72  m_isInitialized = false;
73 }
74 
76 {
77 }
78 
79 bool te::rp::MixtureModelLinearStrategy::initialize(te::rp::StrategyParameters const* const strategyParams) throw(te::rp::Exception)
80 {
81  m_isInitialized = false;
82 
83  te::rp::MixtureModelLinearStrategy::Parameters const* paramsPtr = dynamic_cast<te::rp::MixtureModelLinearStrategy::Parameters const*>(strategyParams);
84 
85  if(!paramsPtr)
86  return false;
87 
88  m_parameters = *(paramsPtr);
89 
90  m_isInitialized = true;
91 
92  return true;
93 }
94 
95 bool te::rp::MixtureModelLinearStrategy::execute(const te::rst::Raster& inputRaster, const std::vector<unsigned int>& inputRasterBands,
96  const std::vector<std::string>& inputSensorBands, const std::map<std::string, std::vector<double> >& components,
97  std::vector<te::rst::Raster*>& outputRaster, const bool normalize, const bool enableProgressInterface) throw(te::rp::Exception)
98 {
99  TERP_TRUE_OR_RETURN_FALSE(m_isInitialized, "Instance not initialized")
100 
101  const unsigned int nComponents = (unsigned int)components.size();
102  const unsigned int nBands = (unsigned int)inputRasterBands.size();
103 
104  double dummy = outputRaster[0]->getBand(0)->getProperty()->m_noDataValue;
105 
106  std::vector<double> Qmax;
107  std::vector<double> Qmin;
108  for (unsigned i = 0; i < inputSensorBands.size(); i++)
109  {
110  Qmax.push_back(GetDigitalNumberBandMax(inputSensorBands[i]));
111  Qmin.push_back(GetDigitalNumberBandMin(inputSensorBands[i]));
112  }
113 
114  te::rst::Grid* tmpgrid = new te::rst::Grid(*inputRaster.getGrid());
115 
116  std::vector<te::rst::BandProperty*> tmpbandsProperties;
117  for (unsigned i = 0; i < outputRaster[0]->getNumberOfBands(); i++)
118  {
119  te::rst::BandProperty* bprop = new te::rst::BandProperty(*(outputRaster[0]->getBand(i)->getProperty()));
121  bprop->m_type = te::dt::DOUBLE_TYPE;
122  tmpbandsProperties.push_back(bprop);
123  }
124  std::unique_ptr<te::rst::Raster> tmpRaster (te::rst::RasterFactory::make("MEM", tmpgrid, tmpbandsProperties, std::map<std::string, std::string>()));
125 
126  // used to calculate minimum e maximum values of outputraster using statitical minmax algorithm
127  std::vector<double> tmp_min;
128  std::vector<double> tmp_max;
129  for (unsigned i = 0; i < tmpRaster->getNumberOfBands(); i++)
130  {
131  tmp_min.push_back(std::numeric_limits< double >::max());
132  tmp_max.push_back(-std::numeric_limits< double >::max());
133  if (normalize)
134  {
135  m_min.push_back(0);
136  m_max.push_back(255);
137  }
138  else
139  {
140  m_min.push_back(std::numeric_limits< double >::max());
141  m_max.push_back(-std::numeric_limits< double >::max());
142  }
143  m_minerror.push_back(std::numeric_limits< double >::max());
144  m_maxerror.push_back(-std::numeric_limits< double >::max());
145  }
146 
147  if (m_transfMatrix.size1() == 0)
148  generateTransformMatrix(inputRasterBands, inputSensorBands, components);
149  else
150  m_transposeA = boost::numeric::ublas::trans(m_transfMatrix);
151 
152  // calculate the product A' * A
153  boost::numeric::ublas::matrix<double> productAtA = boost::numeric::ublas::matrix<double>(m_transposeA.size1(), m_transfMatrix.size2());
154  productAtA = boost::numeric::ublas::prod(m_transposeA, m_transfMatrix);
155 
156  // calculate the inverse of A' * A
157  boost::numeric::ublas::matrix<double> invertAtA = boost::numeric::ublas::matrix<double>(productAtA.size1(), productAtA.size2());
158  te::common::GetInverseMatrix(productAtA, invertAtA);
159 
160  boost::numeric::ublas::matrix<double> matrixR = boost::numeric::ublas::matrix<double>(m_transfMatrix.size1(), 1);
161  boost::numeric::ublas::matrix<double> productAtR = boost::numeric::ublas::matrix<double>(m_transposeA.size1(), matrixR.size2());
162  boost::numeric::ublas::matrix<double> matrixX = boost::numeric::ublas::matrix<double>(invertAtA.size1(), productAtR.size2());
163  boost::numeric::ublas::matrix<double> productAX = boost::numeric::ublas::matrix<double>(m_transfMatrix.size1(), matrixX.size2());
164  boost::numeric::ublas::matrix<double> matrixE = boost::numeric::ublas::matrix<double>(matrixR.size1(), matrixR.size2());
165 
166  te::common::TaskProgress task(TE_TR("Linear Mixture Model"), te::common::TaskProgress::UNDEFINED, inputRaster.getNumberOfRows());
167  double value;
168 
169  for (unsigned r = 0; r < inputRaster.getNumberOfRows(); r++)
170  {
171  for (unsigned c = 0; c < inputRaster.getNumberOfColumns(); c++)
172  {
173 // read input values
174  for (unsigned b = 0; b < nBands; b++)
175  {
176  inputRaster.getValue(c, r, value, inputRasterBands[b]);
177  if (value == dummy)
178  matrixR(b, 0) = 0.;
179  else
180  matrixR(b, 0) = value / Qmax[b];
181  }
182  matrixR(nBands, 0) = 0.0;
183 // calculate the product A' * R
184  productAtR = boost::numeric::ublas::prod(m_transposeA, matrixR);
185 // compute matrix X
186  matrixX = boost::numeric::ublas::prod(invertAtA, productAtR);
187 // write output fractions
188  for (unsigned b = 0; b < nBands; b++)
189  {
190  value = matrixX(b + 1, 0);
191  tmpRaster->setValue(c, r, value, b);
192  if (value != dummy)
193  {
194  tmp_min[b] = value < tmp_min[b] ? value : tmp_min[b];
195  tmp_max[b] = value > tmp_max[b] ? value : tmp_max[b];
196  }
197  }
198 
199 // compute error matrix
200  if (outputRaster.size() > 1)
201  {
202  productAX = boost::numeric::ublas::prod(m_transfMatrix, matrixX);
203  matrixE = matrixR - productAX;
204 
205 // write output errors
206  for (unsigned b = 0, e = 0; b < nBands; b++, e++)
207  {
208  value = matrixE(e, 0);
209  outputRaster[1]->setValue(c, r, value, b);
210  m_minerror[b] = value < m_minerror[b] ? value : m_minerror[b];
211  m_maxerror[b] = value > m_maxerror[b] ? value : m_maxerror[b];
212  }
213  }
214  }
215  task.pulse();
216  }
217 
218  //Transform to output type
219  for (unsigned r = 0; r < tmpRaster->getNumberOfRows(); r++)
220  {
221  for (unsigned c = 0; c < tmpRaster->getNumberOfColumns(); c++)
222  {
223  for (unsigned b = 0; b < nComponents; b++)
224  {
225  tmpRaster->getValue(c, r, value, b);
226  if (value != dummy)
227  {
228  if (normalize) //to 8 bits
229  value = 255 * (value - tmp_min[b]) / (tmp_max[b] - tmp_min[b]);
230  else
231  value = (Qmax[b] - Qmin[b]) * (value - tmp_min[b]) / (tmp_max[b] - tmp_min[b]);
232  }
233  outputRaster[0]->setValue(c, r, value, b);
234  m_min[b] = value < m_min[b] ? value : m_min[b];
235  m_max[b] = value > m_max[b] ? value : m_max[b];
236  }
237  }
238  }
239 
240  return true;
241 }
242 
244  boost::numeric::ublas::matrix<double>& matrix) const
245 {
246  matrix = m_transfMatrix;
247  return true;
248 }
249 
250 
252  boost::numeric::ublas::matrix<double>& matrix) {
253  m_transfMatrix = matrix;
254  return true;
255 }
256 
257 bool te::rp::MixtureModelLinearStrategy::generateTransformMatrix(const std::vector<unsigned int>& inputRasterBands, const std::vector<std::string>& inputSensorBands,
258  const std::map<std::string, std::vector<double> >& components)
259 {
260  const unsigned int nComponents = (unsigned int)components.size();
261  const unsigned int nBands = (unsigned int)inputRasterBands.size();
262 
263  boost::numeric::ublas::matrix<double> transposeA = boost::numeric::ublas::matrix<double>(nComponents + 1, nBands + 1);
264  boost::numeric::ublas::matrix<double> matrixA(transposeA.size2(), transposeA.size1());
265 
266  // by definition, A * X = R, we have A, so that X = inv(A' * A) * A' * R
267  // A is the set of known reflectances for each component
268  // R is the reflectances of a specific pixel
269  // X is the proportion of each component
270 
271  std::vector<double> Qmax;
272  for (unsigned i = 0; i < inputSensorBands.size(); i++)
273  {
274  Qmax.push_back(GetDigitalNumberBandMax(inputSensorBands[i]));
275  }
276 
277  // retrieve the transposed A matrix, normalizing values using band/sensor info
278  unsigned row = 0;
279  for (unsigned j = 0; j < nBands; j++)
280  transposeA(row, j) = 1.0;
281  transposeA(row, nBands) = 0.0;
282 
283  std::map<std::string, std::vector<double> >::const_iterator it;
284  for (row = 1, it = components.begin(); it != components.end(); row++, it++)
285  {
286  for (unsigned j = 0; j < nBands; j++)
287  transposeA(row, j) = it->second[j] / Qmax[j];
288  transposeA(row, nBands) = 1.0;
289  }
290 
291  // calculate the matrixA from the transpose of A
292  matrixA = boost::numeric::ublas::trans(transposeA);
293  m_transfMatrix = matrixA;
294  m_transposeA = transposeA;
295 
296  return true;
297 }
298 
299 bool te::rp::MixtureModelLinearStrategy::getMinMax(std::vector<double>& min, std::vector<double>& max) const
300 {
301  min = m_min;
302  max = m_max;
303  return true;
304 }
305 
306 bool te::rp::MixtureModelLinearStrategy::getMinMaxError(std::vector<double>& min, std::vector<double>& max) const
307 {
308  min = m_minerror;
309  max = m_maxerror;
310  return true;
311 }
312 
313 
315  : te::rp::MixtureModelStrategyFactory("linear")
316 {
317 }
318 
320 {
321 }
322 
324 {
326 }
327 
328 
double GetDigitalNumberBandMax(std::string bandName)
Returns the maximum digital number of a given sensor/band.
Raster Mixture model strategy factory base class.
te::rp::MixtureModelStrategy * build()
Concrete factories (derived from this one) must implement this method in order to create objects...
Raster linear mixture model strategy factory.
bool generateTransformMatrix(const std::vector< unsigned int > &inputRasterBands, const std::vector< std::string > &inputSensorBands, const std::map< std::string, std::vector< double > > &components)
Generates the used transformation matrix (when applicable).
Index into a lookup table.
bool getMinMaxError(std::vector< double > &, std::vector< double > &) const
std::vector< double > m_maxerror
Maximum error value.
A raster band description.
Definition: BandProperty.h:61
Base exception class for plugin module.
This class can be used to inform the progress of a task.
Definition: TaskProgress.h:53
boost::numeric::ublas::matrix< double > m_transposeA
Transformation matrix;.
bool getTransformMatrix(boost::numeric::ublas::matrix< double > &matrix) const
Returns the used transformation matrix (when applicable).
int m_type
The data type of the elements in the band ( See te::dt namespace basic data types for reference )...
Definition: BandProperty.h:133
#define TE_TR(message)
It marks a string in order to get translated.
Definition: Translator.h:242
double GetDigitalNumberBandMin(std::string bandName)
Returns the minimum digital number of a given sensor/band.
#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:185
std::vector< double > m_minerror
Minimun error value.
boost::numeric::ublas::matrix< double > m_transfMatrix
int b
Definition: TsRtree.cpp:32
std::vector< double > m_min
Transpose of A (A is the set of known reflectances for each component);.
Raster mixture model strategy base class.
bool getMinMax(std::vector< double > &, std::vector< double > &) const
An abstract class for raster data strucutures.
URI C++ Library.
Definition: Attributes.h:37
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, std::vector< te::rst::Raster * > &outputRaster, const bool normalize, const bool enableProgressInterface)
Executes the segmentation strategy.
Raster strategy parameters base class.
Raster linear strategy for mixture model classification.
AbstractParameters * clone() const
Create a clone copy of this instance.
Abstract parameters base interface.
bool initialize(StrategyParameters const *const strategyParams)
Initialize the segmentation strategy.
MixtureModelLinearStrategy::Parameters m_parameters
Internal execution parameters.
static Raster * make()
It creates and returns an empty raster with default raster driver.
bool GetInverseMatrix(const boost::numeric::ublas::matrix< T > &inputMatrix, boost::numeric::ublas::matrix< T > &outputMatrix)
Matrix inversion.
Definition: MatrixUtils.h:143
void reset()
Clear all internal allocated resources and reset the parameters instance to its initial state...
Raster Processing functions.
std::vector< double > m_max
Maximum value.
A rectified grid is the spatial support for raster data.
Definition: raster/Grid.h:68
const Parameters & operator=(const Parameters &params)
ColorInterp m_colorInterp
The color interpretation.
Definition: BandProperty.h:140
bool m_isInitialized
True if this instance is initialized.
bool setTransformMatrix(boost::numeric::ublas::matrix< double > &matrix)
Sets the used transformation matrix.