Skip to content

Large refactoring of radiometric indices

Julien Michel requested to merge 1870-refactor-indices-functor into develop

Summary

This merge request:

  • Adds a single base class for all radiometric indices
  • Add a functor to stack indices
  • Simplifies the radiometric indices application
  • Add unit tests for all indices and for new classes
  • Remove some useless indices (see below)

Closes #1870 (closed) Closes #1774 (closed)

Rationale

The radiometric indices design was full of boiler plate code and classes. This redesign aims at a shorter code with better performances.

Implementation Details

Classes and files

All radiometric indices now derive from the RadiometricIndice class. Required bands are specified when calling parent constructor:

  NDVI() : RadiometricIndice<TInput,TOutput>({CommonBandNames::RED, CommonBandNames::NIR}) {}

The RadiometricIndice class works with an enum class of bands, and offers an API to retrieve the band required by the indice, as well as set the band index for each band (this was covered by the RAndNIRIndexBase family of classes).

To avoid look-up of indices of band on the critical path, the RadiometricIndice class uses arrays. It offers services for subclasses to parse the input pixel (received as a VariableLengthVector) and retrieves the band values.

See for instance implementation of RVI operator:

  TOutput operator()(const itk::VariableLengthVector<TInput> & input) const override
  {
    auto red = this->Value(CommonBandNames::RED,input);
    auto nir = this->Value(CommonBandNames::NIR,input);

    if (std::abs(red)  < RadiometricIndice<TInput,TOutput>::Epsilon)
      {
      return static_cast<TOutput>(0.);
      }
    return (static_cast<TOutput>(nir / red));
  }
};

This makes the code a lot easier to read.

Moreover, in all radiometric indices, parameters have been made static constexpr, as they are not likely to be changed by anyone.

Another functor class StackIndicesFunctor has been added to stack several indices into an output VariableLengthVector. This functor is compatible with FunctorImageFilter.

Applications

The RadiometricIndices application has been revamped in depth.

The most important change is the use of the StackIndicesFunctor along with FunctorImageFilter to compute all indices at once (the previous code was using one filter per indice and then a concatenate filter). This will save a lot of time and memory.

Code has been greatly simplified (no need to typedef all indices, no more macros).

Moreover, it is now possible to retrieve the list of required bands from the selection of indices. This could be used to enhance user experience with this application.

I also added the ISU indice to the application, which was missing.

Tests

Unit tests for all indices have been added (no inputs, no outputs, checks in test code). Unit tests for new classes have been added (no inputs, no outputs, checks in test code). Some tests have been removed as they were duplicating checks of new tests.

Documentation

Doxygen documentation of new classes has been added.

Additional notes

  • I removed some indices that look useless to me:
    • TSARVI because it always returns 0
    • SRWI Because it is the only one that works with MODIS band, and its formula is a simple ratio
    • NDBI Because it is exactly the same as NDVI
    • NDPI Because it is completely equivalent to MNDWI
  • I did not refactor the Landsat TM indices, as @jinglada told me that this code should rather be removed
  • There are enhancement that can be made to the radiometric indices. They will be easier to achieve when this MR is merged.

Copyright

The copyright owner is CNES and has signed the ORFEO ToolBox Contributor License Agreement.


Check before merging:

  • All discussions are resolved
  • At least 2 👍 votes from core developers, no 👎 vote.
  • The feature branch is (reasonably) up-to-date with the base branch
  • Dashboard is green
  • Copyright owner has signed the ORFEO ToolBox Contributor License Agreement
Edited by Julien Michel

Merge request reports