/* * 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 #include #include #include #include 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 class RadiometricIndex { public: /// Types for input/output using InputType = TInput; using PixelType = itk::VariableLengthVector; 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(BandNameType::MAX); static constexpr double Epsilon = 0.0000001; // Necessary to be used as an abstract base class virtual ~RadiometricIndex() = default; /** * \param requiredBands the set of required bands * \throw runtime_error if requiredBands contains CommonBandNames::MAX */ RadiometricIndex(const std::set& 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(b)] = true; } } /** * \return a set containing the required bands for * this indice. */ std::set GetRequiredBands() const { std::set resp; for (size_t i = 0; i < NumberOfBands; ++i) { if (m_RequiredBands[i]) { resp.insert(static_cast(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(band)] = index; } /** * \param indicesMap a std::map 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& indicesMap) { for (auto it : indicesMap) { SetBandIndex(it.first, it.second); } } /** * \param band The band for which to retrieve indice * \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(band)]; } /** * Astract method which will compute the radiometric indice * \param input A itk::VariableLengthVector 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& 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(band)]; } /** * Helper method to parse input itk::VariableLengthVector * 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 holding the * pixel values for each band * \return The value of the band as double * */ double Value(BandNameType band, const itk::VariableLengthVector& input) const { assert(m_RequiredBands[static_cast(band)] && "Retrieving value for a band that is not in the required bands list"); return static_cast(input[UncheckedBandIndex(band) - 1]); } private: // Explicitely disable default constructor RadiometricIndex() = delete; /// An array storing the required status for each band using RequiredBandsContainer = std::array; RequiredBandsContainer m_RequiredBands; /// An array storing the indice for each band using BandIndicesContainer = std::array; BandIndicesContainer m_BandIndices; }; } // namespace Functor } // End namespace otb #endif