otbDimensionalityReduction.cxx 21.9 KB
Newer Older
1
/*
2
 * Copyright (C) 2005-2022 Centre National d'Etudes Spatiales (CNES)
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 *
 * This file is part of Orfeo Toolbox
 *
 *     https://www.orfeo-toolbox.org/
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

#include "otbWrapperApplication.h"
#include "otbWrapperApplicationFactory.h"


#include "otbMaximumAutocorrelationFactorImageFilter.h"
#include "otbNAPCAImageFilter.h"
#include "otbLocalActivityVectorImageFilter.h"
#include "otbMaximumAutocorrelationFactorImageFilter.h"
#include "otbFastICAImageFilter.h"

#include "otbStreamingMinMaxVectorImageFilter.h"
#include "otbVectorRescaleIntensityImageFilter.h"

namespace otb
{
namespace Wrapper
{

39
class DimensionalityReduction : public Application
40
41
42
{
public:
  /** Standard class typedefs. */
43
44
45
  typedef DimensionalityReduction       Self;
  typedef Application                   Superclass;
  typedef itk::SmartPointer<Self>       Pointer;
46
47
  typedef itk::SmartPointer<const Self> ConstPointer;

48
  // Dimensionality reduction typedef
49
50
  typedef otb::MaximumAutocorrelationFactorImageFilter<FloatVectorImageType, FloatVectorImageType> MAFFilterType;

51
  typedef itk::ImageToImageFilter<FloatVectorImageType, FloatVectorImageType> DimensionalityReductionFilter;
52
53
54
55

  // Reduction dimensio filters
  typedef otb::PCAImageFilter<FloatVectorImageType, FloatVectorImageType, otb::Transform::FORWARD> PCAForwardFilterType;
  typedef otb::PCAImageFilter<FloatVectorImageType, FloatVectorImageType, otb::Transform::INVERSE> PCAInverseFilterType;
56
  // typedef otb::PCAImageFilter< FloatVectorImageType, FloatVectorImageType, otb::Transform::FORWARD >
57
58
59

  typedef otb::LocalActivityVectorImageFilter<FloatVectorImageType, FloatVectorImageType> NoiseFilterType;

60
61
  typedef otb::NAPCAImageFilter<FloatVectorImageType, FloatVectorImageType, NoiseFilterType, otb::Transform::FORWARD> NAPCAForwardFilterType;
  typedef otb::NAPCAImageFilter<FloatVectorImageType, FloatVectorImageType, NoiseFilterType, otb::Transform::INVERSE> NAPCAInverseFilterType;
62
63
64

  typedef otb::MaximumAutocorrelationFactorImageFilter<FloatVectorImageType, FloatVectorImageType> MAFForwardFilterType;

65
66
  typedef otb::FastICAImageFilter<FloatVectorImageType, FloatVectorImageType, otb::Transform::FORWARD> ICAForwardFilterType;
  typedef otb::FastICAImageFilter<FloatVectorImageType, FloatVectorImageType, otb::Transform::INVERSE> ICAInverseFilterType;
67

68
69
  typedef otb::StreamingStatisticsVectorImageFilter<FloatVectorImageType> StreamingStatisticsVectorImageFilterType;

70
  typedef StreamingStatisticsVectorImageFilterType::MatrixObjectType::ComponentType MatrixType;
71
72

  // output rescale
73
  typedef otb::StreamingMinMaxVectorImageFilter<FloatVectorImageType>  MinMaxFilterType;
74
75
76
  typedef otb::VectorRescaleIntensityImageFilter<FloatVectorImageType> RescaleImageFilterType;

  /** Standard macro */
77
  itkNewMacro(Self);
78

79
  itkTypeMacro(DimensionalityReduction, otb::Wrapper::Application);
80
81

private:
82
  void DoInit() override
83
  {
84
    SetName("DimensionalityReduction");
85
    SetDescription("Perform Dimension reduction of the input image.");
86
87
88
89
90
91
    SetDocLongDescription(
        "Performs dimensionality reduction on input image. PCA,NA-PCA,MAF,ICA methods are available. It is also possible to compute the inverse transform to "
        "reconstruct the image and to optionally export the transformation matrix to a text file.");
    SetDocLimitations(
        "This application does not provide the inverse transform and the transformation matrix export for the MAF. the background value option is not "
        "supported for MAF and ICA.");
92
93
    SetDocAuthors("OTB-Team");
    SetDocSeeAlso(
94
95
        "\"Kernel maximum autocorrelation factor and minimum noise fraction transformations,\" IEEE Transactions on Image Processing, vol. 20, no. 3, pp. "
        "612-624, (2011)");
96
97

    AddDocTag(Tags::Filter);
98
    AddDocTag(Tags::DimensionReduction);
99
100

    AddParameter(ParameterType_InputImage, "in", "Input Image");
101
    SetParameterDescription("in", "The input image to apply dimensionality reduction.");
102
103
    AddParameter(ParameterType_OutputImage, "out", "Output Image");
    SetParameterDescription("out", "output image. Components are ordered by decreasing eigenvalues.");
104
    MandatoryOff("out");
Cédric Traizet's avatar
Cédric Traizet committed
105

106
107
    AddParameter(ParameterType_Choice, "rescale", "Rescale Output");
    SetParameterDescription("rescale", "Enable rescaling of the reduced output image.");
108
109

    MandatoryOff("rescale");
Cédric Traizet's avatar
Cédric Traizet committed
110
111
    AddChoice("rescale.no", "No rescale");
    AddChoice("rescale.minmax", "rescale to min max value");
112

113
114
115
116
117
118
    AddParameter(ParameterType_Float, "rescale.minmax.outmin", "Output min value");
    AddParameter(ParameterType_Float, "rescale.minmax.outmax", "Output max value");
    SetDefaultParameterFloat("rescale.minmax.outmin", 0.0);
    SetParameterDescription("rescale.minmax.outmin", "Minimum value of the output image.");
    SetDefaultParameterFloat("rescale.minmax.outmax", 255.0);
    SetParameterDescription("rescale.minmax.outmax", "Maximum value of the output image.");
119
120
121
122
123
124
125
126
127
128

    AddParameter(ParameterType_OutputImage, "outinv", " Inverse Output Image");
    SetParameterDescription("outinv", "reconstruct output image.");
    MandatoryOff("outinv");

    AddParameter(ParameterType_Choice, "method", "Algorithm");
    SetParameterDescription("method", "Selection of the reduction dimension method.");

    AddChoice("method.pca", "PCA");
    SetParameterDescription("method.pca", "Principal Component Analysis.");
129
130
131
    AddParameter(ParameterType_OutputFilename, "method.pca.outeigenvalues", "Output file containing eigenvalues (txt format)");
    SetParameterDescription("method.pca.outeigenvalues", "Output file containing eigenvalues (txt format).");
    MandatoryOff("method.pca.outeigenvalues");
132
133
134
135
    AddParameter(ParameterType_Bool, "method.pca.whiten", "Perform pca whitening");
    SetParameterDescription("method.pca.whiten", "Perform whitening and ensure uncorrelated outputs with unit component wise variances");
    SetParameterInt("method.pca.whiten", 1);
    MandatoryOff("method.pca.whiten");
Cédric Traizet's avatar
Cédric Traizet committed
136

137
138
    AddChoice("method.napca", "NA-PCA");
    SetParameterDescription("method.napca", "Noise Adjusted Principal Component Analysis.");
Victor Poughon's avatar
Victor Poughon committed
139
    AddParameter(ParameterType_Int, "method.napca.radiusx", "Set the x radius of the sliding window");
140
141
    SetMinimumParameterIntValue("method.napca.radiusx", 1);
    SetDefaultParameterInt("method.napca.radiusx", 1);
Victor Poughon's avatar
Victor Poughon committed
142
    AddParameter(ParameterType_Int, "method.napca.radiusy", "Set the y radius of the sliding window");
143
144
145
146
147
    SetMinimumParameterIntValue("method.napca.radiusy", 1);
    SetDefaultParameterInt("method.napca.radiusy", 1);

    AddChoice("method.maf", "MAF");
    SetParameterDescription("method.maf", "Maximum Autocorrelation Factor.");
Cédric Traizet's avatar
Cédric Traizet committed
148

149
    AddChoice("method.ica", "ICA");
150
    SetParameterDescription("method.ica", "Independent Component Analysis using a stabilized fixed point FastICA algorithm.");
151
    AddParameter(ParameterType_Int, "method.ica.iter", "number of iterations");
152
153
154
155
156
157
158
159
160
161
    SetMinimumParameterIntValue("method.ica.iter", 1);
    SetDefaultParameterInt("method.ica.iter", 20);
    MandatoryOff("method.ica.iter");

    AddParameter(ParameterType_Float, "method.ica.mu", "Give the increment weight of W in [0, 1]");
    SetMinimumParameterFloatValue("method.ica.mu", 0.);
    SetMaximumParameterFloatValue("method.ica.mu", 1.);
    SetDefaultParameterFloat("method.ica.mu", 1.);
    MandatoryOff("method.ica.mu");

162
163
164
165
166
167
168
169
170
    AddParameter(ParameterType_Choice, "method.ica.g", "Nonlinearity");
    SetParameterDescription("method.ica.g", "Nonlinearity used in the FastICA algorithm");
    AddChoice("method.ica.g.tanh", "tanh");
    SetParameterDescription("method.ica.g.tanh", "g(x) = tanh(x)");
    AddChoice("method.ica.g.exp", "exp");
    SetParameterDescription("method.ica.g.exp", "g(x) = -exp(-x^2/2)");
    AddChoice("method.ica.g.u3", "u^3");
    SetParameterDescription("method.ica.g.u3", "g(x) = u^3(x)");

Victor Poughon's avatar
Victor Poughon committed
171
    AddParameter(ParameterType_Int, "nbcomp", "Number of Components");
Jonathan Guinet's avatar
Jonathan Guinet committed
172
    SetParameterDescription("nbcomp", "Number of relevant components kept. By default all components are kept.");
173
174
175
176
    SetDefaultParameterInt("nbcomp", 0);
    MandatoryOff("nbcomp");
    SetMinimumParameterIntValue("nbcomp", 0);

Cédric Traizet's avatar
Cédric Traizet committed
177
    AddParameter(ParameterType_Bool, "normalize", "Center and reduce data");
178
179
    SetParameterDescription(
        "normalize", "Center and reduce data before Dimensionality reduction (if this parameter is set to false, the data will be centered but not reduced.");
180

181
    AddParameter(ParameterType_OutputFilename, "outmatrix", "Transformation matrix output (text format)");
182
183
    SetParameterDescription("outmatrix", "Filename to store the transformation matrix (csv format)");
    MandatoryOff("outmatrix");
184
    DisableParameter("outmatrix");
185

186
    AddParameter(ParameterType_Float, "bv", "Background Value");
187
188
189
    SetParameterDescription("bv",
                            "Background value to ignore in computation of the transformation matrix. Note that all pixels will still be processed when "
                            "applying the transformation.");
190
191
    MandatoryOff("bv");

192
193
    AddRAMParameter();

194
195
    SetMultiWriting(true);

196
197
198
199
    // Doc example parameter settings
    SetDocExampleParameterValue("in", "cupriteSubHsi.tif");
    SetDocExampleParameterValue("out", "FilterOutput.tif");
    SetDocExampleParameterValue("method", "pca");
200

201
    SetOfficialDocLink();
202
203
  }

204
  void DoUpdateParameters() override
205
  {
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
    if (HasValue("in"))
    {
      FloatVectorImageType::Pointer inImage = this->GetParameterImage("in");
      inImage->UpdateOutputInformation();

      // Update the values of the channels to be selected
      unsigned int nbComponents = inImage->GetNumberOfComponentsPerPixel();
      unsigned int nbComp       = static_cast<unsigned int>(GetParameterInt("nbcomp"));
      if (nbComp > nbComponents)
      {
        SetParameterInt("nbcomp", nbComponents);
        otbAppLogINFO(<< "number of selected components can't exceed image dimension : " << nbComponents);
      }
    }
    if (GetParameterInt("method") == 2) // maf
    {
      if (this->GetParameterString("outinv").size() != 0)
      {
        otbAppLogWARNING(<< "This application only provides the forward transform for the MAF method.");
        this->SetParameterString("outinv", "");
      }
      this->DisableParameter("outinv");

      if (this->GetParameterString("outmatrix").size() != 0)
      {
        otbAppLogWARNING(<< "No transformation matrix available for MAF method.");
        this->SetParameterString("outmatrix", "");
      }
      this->DisableParameter("outmatrix");

      FloatVectorImageType::Pointer inImage = this->GetParameterImage("in");
      inImage->UpdateOutputInformation();

      // Update the values of the channels to be selected
      unsigned int nbComponents = inImage->GetNumberOfComponentsPerPixel();
      unsigned int nbComp       = static_cast<unsigned int>(GetParameterInt("nbcomp"));
      if ((nbComp != 0) && (nbComp != nbComponents))
      {
        SetParameterInt("nbcomp", nbComponents);
        otbAppLogINFO(<< "all components are kept when using MAF filter method.");
      }
    }
248
249
  }

250
  void DoExecute() override
251
252
253
  {

    // Get Parameters
254
255
    int  nbComp       = GetParameterInt("nbcomp");
    bool normalize    = GetParameterInt("normalize");
256
    bool invTransform = HasValue("outinv") && IsParameterEnabled("outinv");
257
    switch (GetParameterInt("method"))
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
    {
    // PCA Algorithm
    case 0:
    {
      otbAppLogINFO("Using the PCA Algorithm ");
      PCAForwardFilterType::Pointer filter    = PCAForwardFilterType::New();
      m_ForwardFilter                         = filter;
      PCAInverseFilterType::Pointer invFilter = PCAInverseFilterType::New();
      m_InverseFilter                         = invFilter;

      filter->SetInput(GetParameterFloatVectorImage("in"));
      filter->SetNumberOfPrincipalComponentsRequired(nbComp);
      filter->SetWhitening(GetParameterInt("method.pca.whiten"));

      // Center AND reduce the input data.
      if (normalize)
274
      {
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
        filter->SetUseNormalization(true);
        filter->SetUseVarianceForNormalization(true);
      }
      // Only center the input data.
      else
      {
        filter->SetUseNormalization(true);
        filter->SetUseVarianceForNormalization(false);
      }

      if (HasValue("bv"))
      {
        filter->SetStatisticsUserIgnoredValue(GetParameterFloat("bv"));
      }

      m_ForwardFilter->GetOutput()->UpdateOutputInformation();

      // Write eigenvalues
      std::ofstream outFile;
      outFile.open(this->GetParameterString("method.pca.outeigenvalues"));
      if (outFile.is_open())
      {
        outFile << std::fixed;
        outFile.precision(10);

        outFile << filter->GetEigenValues() << std::endl;
        ;
        outFile.close();
      }

      if (invTransform)
      {
        invFilter->SetInput(m_ForwardFilter->GetOutput());
        // Data has been centered and reduced by the forward filter
        if (normalize)
310
        {
311
312
313
          otbAppLogINFO(<< "Normalization MeanValue:" << filter->GetMeanValues());
          invFilter->SetMeanValues(filter->GetMeanValues());
          invFilter->SetStdDevValues(filter->GetStdDevValues());
314
        }
315
316
        // Data has been centered by the forward filter
        else
317
        {
318
319
          invFilter->SetMeanValues(filter->GetMeanValues());
        }
320

321
322
323
        invFilter->SetTransformationMatrix(filter->GetTransformationMatrix());
        m_TransformationMatrix = invFilter->GetTransformationMatrix();
      }
324

325
      m_TransformationMatrix = filter->GetTransformationMatrix();
326

327
328
329
330
331
332
      otbAppLogINFO("PCA transform has been computed.");
      break;
    }
    case 1:
    {
      otbAppLogINFO("Using the NA-PCA Algorithm ");
333

334
      // NA-PCA
335

336
337
      unsigned int radiusX = static_cast<unsigned int>(GetParameterInt("method.napca.radiusx"));
      unsigned int radiusY = static_cast<unsigned int>(GetParameterInt("method.napca.radiusy"));
338

339
340
      // Noise filtering
      NoiseFilterType::RadiusType radius = {{radiusX, radiusY}};
341

342
343
344
345
      NAPCAForwardFilterType::Pointer filter    = NAPCAForwardFilterType::New();
      m_ForwardFilter                           = filter;
      NAPCAInverseFilterType::Pointer invFilter = NAPCAInverseFilterType::New();
      m_InverseFilter                           = invFilter;
Cédric Traizet's avatar
Cédric Traizet committed
346

347

348
349
350
351
352
353
354
355
356
      filter->SetInput(GetParameterFloatVectorImage("in"));
      filter->SetNumberOfPrincipalComponentsRequired(nbComp);
      filter->SetUseNormalization(normalize);
      filter->GetNoiseImageFilter()->SetRadius(radius);

      if (HasValue("bv"))
      {
        filter->SetStatisticsUserIgnoredValue(GetParameterFloat("bv"));
      }
357

358
      m_ForwardFilter->GetOutput()->UpdateOutputInformation();
359

360
361
362
363
364
365
366
367
368
369
      if (invTransform)
      {
        otbAppLogDEBUG(<< "Compute Inverse Transform");
        invFilter->SetInput(m_ForwardFilter->GetOutput());
        otbAppLogINFO(<< "Normalization MeanValue:" << filter->GetMeanValues());
        invFilter->SetMeanValues(filter->GetMeanValues());
        if (normalize)
        {
          otbAppLogINFO(<< "Normalization StdDevValue:" << filter->GetStdDevValues());
          invFilter->SetStdDevValues(filter->GetStdDevValues());
370
        }
371
372
373
374
        invFilter->SetUseNormalization(normalize);
        invFilter->SetTransformationMatrix(filter->GetTransformationMatrix());
        m_TransformationMatrix = invFilter->GetTransformationMatrix();
      }
375

376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
      m_TransformationMatrix = filter->GetTransformationMatrix();
      otbAppLogINFO("NA-PCA transform has been computed.");
      break;
    }
    case 2:
    {
      otbAppLogINFO("Using the MAF Algorithm ");
      MAFForwardFilterType::Pointer filter = MAFForwardFilterType::New();
      m_ForwardFilter                      = filter;
      filter->SetInput(GetParameterFloatVectorImage("in"));
      otbAppLogINFO(<< "V :" << std::endl << filter->GetV() << "Auto-Correlation :" << std::endl << filter->GetAutoCorrelation());

      break;
    }
    case 3:
    {
      otbAppLogINFO("Using the fast ICA Algorithm ");

      unsigned int nbIterations = static_cast<unsigned int>(GetParameterInt("method.ica.iter"));
      double       mu           = static_cast<double>(GetParameterFloat("method.ica.mu"));

      ICAForwardFilterType::Pointer filter    = ICAForwardFilterType::New();
      m_ForwardFilter                         = filter;
      ICAInverseFilterType::Pointer invFilter = ICAInverseFilterType::New();
      m_InverseFilter                         = invFilter;

      filter->SetInput(GetParameterFloatVectorImage("in"));
      filter->SetNumberOfPrincipalComponentsRequired(nbComp);
      filter->SetNumberOfIterations(nbIterations);
      filter->SetMu(mu);

      switch (GetParameterInt("method.ica.g"))
      {
      // tanh
      case 0:
      {
        otbAppLogDEBUG(<< "Using tanh nonlinearity");
        auto nonLinearity           = [](double x) { return std::tanh(x); };
        auto nonLinearityDerivative = [](double x) { return 1 - std::pow(std::tanh(x), 2.); };
        filter->SetNonLinearity(nonLinearity, nonLinearityDerivative);
        break;
      }
      // exp
      case 1:
      {
        otbAppLogDEBUG(<< "Using u*exp(-u^2/2) nonlinearity");
        auto nonLinearity           = [](double x) { return x * std::exp(-0.5 * std::pow(x, 2)); };
        auto nonLinearityDerivative = [](double x) { return (1 - std::pow(x, 2)) * std::exp(-0.5 * std::pow(x, 2)); };
        filter->SetNonLinearity(nonLinearity, nonLinearityDerivative);
        break;
      }
      // u^3
      case 2:
      {
        otbAppLogDEBUG(<< "Using u^3 nonlinearity");
        auto nonLinearity           = [](double x) { return std::pow(x, 3); };
        auto nonLinearityDerivative = [](double x) { return 3 * std::pow(x, 2); };
        filter->SetNonLinearity(nonLinearity, nonLinearityDerivative);
        break;
      }
436
      default:
437
438
      {
        otbAppLogFATAL(<< "non defined nonlinearity " << GetParameterString("method.ica.g") << std::endl);
439
        break;
440
441
      }
      }
442

443
444
445
446
447
448
449
450
451
452
453
454
455
      m_ForwardFilter->GetOutput()->UpdateOutputInformation();

      if (invTransform)
      {
        otbAppLogDEBUG(<< "Compute Inverse Transform");
        invFilter->SetInput(m_ForwardFilter->GetOutput());
        otbAppLogINFO(<< "Normalization MeanValue:" << filter->GetMeanValues());
        invFilter->SetMeanValues(filter->GetMeanValues());
        otbAppLogINFO(<< "Normalization StdDevValue:" << filter->GetStdDevValues());
        invFilter->SetStdDevValues(filter->GetStdDevValues());

        invFilter->SetPCATransformationMatrix(filter->GetPCATransformationMatrix());
        invFilter->SetTransformationMatrix(filter->GetTransformationMatrix());
456
      }
457
458
459
460
461
462
463
464
465
466
467
468
469
      otbAppLogINFO("ICA transform has been computed.");
      m_TransformationMatrix = filter->GetTransformationMatrix();

      break;
    }

    default:
    {
      otbAppLogFATAL(<< "non defined method " << GetParameterInt("method") << std::endl);
      break;
    }
      return;
    }
470
471

    if (invTransform)
472
473
    {
      if (GetParameterInt("method") == 2) // MAF
474
      {
475
        this->DisableParameter("outinv");
476
        otbAppLogWARNING(<< "This application only provides the forward transform for the MAF method.");
477
      }
478
479
480
      else
        SetParameterOutputImage("outinv", m_InverseFilter->GetOutput());
    }
481

482
    // Write transformation matrix
483
    if (this->GetParameterString("outmatrix").size() != 0)
484
485
    {
      if (GetParameterInt("method") == 2) // MAF
486
      {
487
488
        otbAppLogWARNING(<< "No transformation matrix available for MAF.");
      }
489
      else
490
491
      {
        // Write transformation matrix
492
        std::ofstream outFile;
493
        outFile.open(this->GetParameterString("outmatrix"));
494
        if (outFile.is_open())
Cédric Traizet's avatar
Cédric Traizet committed
495
        {
496
497
          outFile << std::fixed;
          outFile.precision(10);
498

499
500
          outFile << m_TransformationMatrix;
          outFile.close();
Cédric Traizet's avatar
Cédric Traizet committed
501
        }
502
      }
503
    }
504

505
506
    if (GetParameterString("rescale") == "no")
    {
507
      SetParameterOutputImage("out", m_ForwardFilter->GetOutput());
508
    }
509
    else
510
511
    {
      otbAppLogINFO("Starting Min/Max computation for rescaling");
512

513
514
515
      m_MinMaxFilter = MinMaxFilterType::New();
      m_MinMaxFilter->SetInput(m_ForwardFilter->GetOutput());
      m_MinMaxFilter->GetStreamer()->SetAutomaticAdaptativeStreaming(GetParameterInt("ram"));
516

517
518
      AddProcess(m_MinMaxFilter->GetStreamer(), "Min/Max computing");
      m_MinMaxFilter->Update();
519

520
      otbAppLogINFO(<< "Min/Max computation done : min=" << m_MinMaxFilter->GetMinimum() << " max=" << m_MinMaxFilter->GetMaximum())
521

522
523
          FloatVectorImageType::PixelType inMin,
          inMax;
524

525
526
527
528
529
      m_RescaleFilter = RescaleImageFilterType::New();
      m_RescaleFilter->SetInput(m_ForwardFilter->GetOutput());
      m_RescaleFilter->SetAutomaticInputMinMaxComputation(false);
      m_RescaleFilter->SetInputMinimum(m_MinMaxFilter->GetMinimum());
      m_RescaleFilter->SetInputMaximum(m_MinMaxFilter->GetMaximum());
530

531
532
533
534
535
      FloatVectorImageType::PixelType outMin, outMax;
      outMin.SetSize(m_ForwardFilter->GetOutput()->GetNumberOfComponentsPerPixel());
      outMax.SetSize(m_ForwardFilter->GetOutput()->GetNumberOfComponentsPerPixel());
      outMin.Fill(GetParameterFloat("rescale.minmax.outmin"));
      outMax.Fill(GetParameterFloat("rescale.minmax.outmax"));
536

537
538
539
      m_RescaleFilter->SetOutputMinimum(outMin);
      m_RescaleFilter->SetOutputMaximum(outMax);
      m_RescaleFilter->UpdateOutputInformation();
540

541
542
      SetParameterOutputImage("out", m_RescaleFilter->GetOutput());
    }
543
544
  }

545
546
547
548
549
  MinMaxFilterType::Pointer              m_MinMaxFilter;
  RescaleImageFilterType::Pointer        m_RescaleFilter;
  DimensionalityReductionFilter::Pointer m_ForwardFilter;
  DimensionalityReductionFilter::Pointer m_InverseFilter;
  MatrixType                             m_TransformationMatrix;
550
551
552
553
};
}
}

554
OTB_APPLICATION_EXPORT(otb::Wrapper::DimensionalityReduction)