-
Victor Poughon authored761510cb
/*
* Copyright (C) 2005-2019 Centre National d'Etudes Spatiales (CNES)
*
* 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.
*/
#ifndef otbRadiometricIndex_h
#define otbRadiometricIndex_h
#include "itkVariableLengthVector.h"
#include "otbBandName.h"
#include <array>
#include <set>
#include <string>
#include <map>
#include <stdexcept>
using namespace otb::BandName;
namespace otb
{
namespace Functor
{
/**
* \class RadiometricIndex
* \brief Base class for all radiometric indices
*
* This class is the base class for all radiometric indices.
*
* It offers services to:
* - Indicate which band are required among CommonBandNames enum
* - Set indices of each required band
* - Compute the indice response to a pixel by subclassing the pure
* virtual operator()
*
* This class is designed for performance on the critical path. For
* best performances use the Value() method when implementing
* operator() to avoid branches.
*
* \ingroup OTBIndices
*/
template <typename TInput, typename TOutput>
class RadiometricIndex
{
public:
/// Types for input/output
using InputType = TInput;
using PixelType = itk::VariableLengthVector<InputType>;
using OutputType = TOutput;
/// Enum Among which bands are used
using BandNameType = CommonBandNames;
/// The number of bands, derived from the Enum MAX value
static constexpr size_t NumberOfBands = static_cast<size_t>(BandNameType::MAX);
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
static constexpr double Epsilon = 0.0000001;
/**
* \param requiredBands the set<CommonBandNames> of required bands
* \throw runtime_error if requiredBands contains CommonBandNames::MAX
*/
RadiometricIndex(const std::set<BandNameType>& requiredBands) : m_RequiredBands(), m_BandIndices()
{
if (requiredBands.find(BandNameType::MAX) != requiredBands.end())
{
throw std::runtime_error("TBandNameEnum::MAX can not be used as a required band");
}
// Fill the required bands array
m_RequiredBands.fill(false);
m_BandIndices.fill(0);
for (auto b : requiredBands)
{
m_RequiredBands[static_cast<size_t>(b)] = true;
}
}
/**
* \return a set<CommandBandName> containing the required bands for
* this indice.
*/
std::set<BandNameType> GetRequiredBands() const
{
std::set<BandNameType> resp;
for (size_t i = 0; i < NumberOfBands; ++i)
{
if (m_RequiredBands[i])
{
resp.insert(static_cast<BandNameType>(i));
}
}
return resp;
}
/**
* \param band The band to set (value in CommandBandName)
* \param index The index of the band to set (starts at 1 for first band)
* \throw runtime_error if band is CommandBandName::MAX
*/
void SetBandIndex(BandNameType band, size_t index)
{
if (band == BandNameType::MAX)
{
throw std::runtime_error("Can not set index for CommandBandName::MAX");
}
m_BandIndices[static_cast<size_t>(band)] = index;
}
/**
* \param indicesMap a std::map<CommandBandName,size_t> containing all
* bands indices to set (starts at 1 for first band)
* \throw runtime_error if indicesMap contains CommandBandName::MAX
*/
void SetBandsIndices(const std::map<BandNameType, size_t>& indicesMap)
{
for (auto it : indicesMap)
{
SetBandIndex(it.first, it.second);
}
}
/**
* \param band The band for which to retrieve indice
141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
* \return The indices of the band
* \throw runtime_error if band is CommandBandName::MAX
*/
size_t GetBandIndex(BandNameType band) const
{
if (band == BandNameType::MAX)
{
throw std::runtime_error("Can not get index for CommandBandName::MAX");
}
return m_BandIndices[static_cast<size_t>(band)];
}
/**
* Astract method which will compute the radiometric indice
* \param input A itk::VariableLengthVector<TInput> holding the
* pixel values for each band
* \return The indice value as TOutput (starts at 1 for first band)
*/
virtual TOutput operator()(const itk::VariableLengthVector<TInput>& input) const = 0;
protected:
/**
* Helper method to retrieve index for band name. With respect to
* the public method, this method will not throw an exception if
* CommandBandName::MAX is used as a parameter. Since it is meant for
* internal use in the critical path and not for client code, it
* will only assert that band is not CommandBandName::MAX in debug
* mode.
*
* \param band The band for which to retrieve indice
* \return The indices of the band
*/
size_t UncheckedBandIndex(BandNameType band) const
{
assert(band != BandNameType::MAX && "Can not retrieve index for band CommandBandName::MAX");
return m_BandIndices[static_cast<size_t>(band)];
}
/**
* Helper method to parse input itk::VariableLengthVector<TInput>
* and get the corresponding band value.
* For instance:
* \snippet auto red = this->Value(CommonBandNamess::RED,input);
*
* As this function is on the critical performance path, no checks
* are made to see wether this band is really required for this
* indice. However an assertion will be raised in debug mode.
*
* \param band The band for which to retrieve the value
* \param input A itk::VariableLengthVector<TInput> holding the
* pixel values for each band
* \return The value of the band as double
*
*/
double Value(BandNameType band, const itk::VariableLengthVector<TInput>& input) const
{
assert(m_RequiredBands[static_cast<size_t>(band)] && "Retrieving value for a band that is not in the required bands list");
return static_cast<double>(input[UncheckedBandIndex(band) - 1]);
}
private:
// Explicitely disable default constructor
RadiometricIndex() = delete;
/// An array storing the required status for each band
using RequiredBandsContainer = std::array<bool, NumberOfBands>;
RequiredBandsContainer m_RequiredBands;
/// An array storing the indice for each band
using BandIndicesContainer = std::array<size_t, NumberOfBands>;
211212213214215216217218
BandIndicesContainer m_BandIndices;
};
} // namespace Functor
} // End namespace otb
#endif