/* * 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 otbHuMomentsImageFunction_hxx #define otbHuMomentsImageFunction_hxx #include "otbHuMomentsImageFunction.h" #include "itkConstNeighborhoodIterator.h" #include "itkNumericTraits.h" #include namespace otb { /** * Constructor */ template HuMomentsImageFunction::HuMomentsImageFunction() { m_NeighborhoodRadius = 1; } template void HuMomentsImageFunction::PrintSelf(std::ostream& os, itk::Indent indent) const { this->Superclass::PrintSelf(os, indent); os << indent << " Neighborhood radius value : " << m_NeighborhoodRadius << std::endl; } template typename HuMomentsImageFunction::OutputType HuMomentsImageFunction::EvaluateAtIndex(const IndexType& index) const { // Build moments vector OutputType moments; // Initialize moments moments.Fill(itk::NumericTraits::Zero); // Check for input image if (!this->GetInputImage()) { return moments; } // Check for out of buffer if (!this->IsInsideBuffer(index)) { return moments; } // Define complex type typedef std::complex ComplexType; // Define and initialize cumulants for complex moments ComplexType c11, c20, c02, c30, c03, c21, c12; c11 = itk::NumericTraits::Zero; c20 = itk::NumericTraits::Zero; c02 = itk::NumericTraits::Zero; c30 = itk::NumericTraits::Zero; c03 = itk::NumericTraits::Zero; c21 = itk::NumericTraits::Zero; c12 = itk::NumericTraits::Zero; ScalarRealType c00 = itk::NumericTraits::Zero; // Create an N-d neighborhood kernel, using a zeroflux boundary condition typename InputImageType::SizeType kernelSize; kernelSize.Fill(m_NeighborhoodRadius); itk::ConstNeighborhoodIterator it(kernelSize, this->GetInputImage(), this->GetInputImage()->GetBufferedRegion()); // Set the iterator at the desired location it.SetLocation(index); // Walk the neighborhood const unsigned int size = it.Size(); for (unsigned int i = 0; i < size; ++i) { // Retrieve value, and centered-reduced position ScalarRealType value = static_cast(it.GetPixel(i)); ScalarRealType x = static_cast(it.GetOffset(i)[0]) / (2 * m_NeighborhoodRadius + 1); ScalarRealType y = static_cast(it.GetOffset(i)[1]) / (2 * m_NeighborhoodRadius + 1); // Build complex value ComplexType xpy(x, y), xqy(x, -y); // Update cumulants c00 += value; c11 += xpy * xqy * value; c20 += xpy * xpy * value; c02 += xqy * xqy * value; c30 += xpy * xpy * xpy * value; c03 += xqy * xqy * xqy * value; c21 += xpy * xpy * xqy * value; c12 += xpy * xqy * xqy * value; } // Nomalisation c11 /= c00; c20 /= c00; c02 /= c00; c30 /= c00; c03 /= c00; c21 /= c00; c12 /= c00; // Compute moments combinations moments[0] = static_cast(c11.real()); moments[1] = static_cast((c20 * c02).real()); moments[2] = static_cast((c30 * c03).real()); moments[3] = static_cast((c21 * c12).real()); moments[4] = static_cast((c30 * c12 * c12 * c12).real()); moments[5] = static_cast((c20 * c12 * c12).real()); moments[6] = static_cast((c30 * c12 * c12 * c12).imag()); // Return result return moments; } } // namespace otb #endif