/*========================================================================= * * Copyright NumFOCUS * * 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 * * https://www.apache.org/licenses/LICENSE-2.0.txt * * 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 itkJensenHavrdaCharvatTsallisPointSetToPointSetMetricv4_h #define itkJensenHavrdaCharvatTsallisPointSetToPointSetMetricv4_h #include "itkPointSetToPointSetMetricv4.h" #include "itkManifoldParzenWindowsPointSetFunction.h" namespace itk { /** \class JensenHavrdaCharvatTsallisPointSetToPointSetMetricv4 * * \brief Implementation of the Jensen Havrda Charvat Tsallis Point Set metric. * * Given a specified transform and direction, this class calculates the * value and derivative between a "fixed" and "moving" point set pair using * the Havrda-Charvat-Tsallis entropy family, a generalization of the well-known * Shannon entropy, and the Jensen divergence. Another way to look at the * family of information-theoretic measures is that the points are used to * construct the corresponding probably density functions. * * In addition, we allow the user to invoke a manifold parzen windowing of the * data. Instead of an isotropic Gaussian being associated with each point, * we can actually calculate the covariance matrix for each point such that it * reflects the locate point set structure. * * To speed up the metric calculation, we use ITK's K-d tree to query the * metric value only for a given neighborhood. Considering that probably only * a small subset of points is needed to get a good approximation of the * metric value for a single point, this is probably warranted. So what we do * is transform each point (with the specified transform) and construct the * k-d tree from the transformed points. * * Contributed by Nicholas J. Tustison, James C. Gee in the Insight Journal * paper: https://www.insight-journal.org/browse/publication/317 * * \note The original work reported in Tustison et al. 2011 optionally employed * a regularization term to prevent the moving point set(s) from coalescing * to a single point location. However, within the registration framework, * this term is of limited utility as such regularization is dictated by the * transform and any explicit regularization terms. Also note that the * published work applies to multiple points sets each of which could * be considered "moving" but this is also not applicable for this particular * implementation. * * \par REFERENCE * * N.J. Tustison, S. P. Awate, G. Song, T. S. Cook, and J. C. Gee. * "Point set registration using Havrda-Charvat-Tsallis entropy measures" * IEEE Transactions on Medical Imaging, 30(2):451-60, 2011. * \ingroup ITKMetricsv4 */ template class ITK_TEMPLATE_EXPORT JensenHavrdaCharvatTsallisPointSetToPointSetMetricv4 : public PointSetToPointSetMetricv4 { public: ITK_DISALLOW_COPY_AND_MOVE(JensenHavrdaCharvatTsallisPointSetToPointSetMetricv4); /** Standard class type aliases. */ using Self = JensenHavrdaCharvatTsallisPointSetToPointSetMetricv4; using Superclass = PointSetToPointSetMetricv4; using Pointer = SmartPointer; using ConstPointer = SmartPointer; /** Method for creation through the object factory. */ itkSimpleNewMacro(Self); /** \see LightObject::GetNameOfClass() */ itkOverrideGetNameOfClassMacro(JensenHavrdaCharvatTsallisPointSetToPointSetMetricv4); using PointSetType = TPointSet; using PointsContainer = typename PointSetType::PointsContainer; using PointsContainerConstIterator = typename PointsContainer::ConstIterator; static constexpr unsigned int PointDimension = TPointSet::PointDimension; /** Types transferred from the base class */ using typename Superclass::MeasureType; using typename Superclass::DerivativeType; using typename Superclass::DerivativeValueType; using typename Superclass::LocalDerivativeType; using typename Superclass::PointType; using typename Superclass::PixelType; using typename Superclass::CoordRepType; using typename Superclass::PointIdentifier; using typename Superclass::NeighborsIdentifierType; using typename Superclass::NumberOfParametersType; using typename Superclass::JacobianType; using typename Superclass::FixedTransformJacobianType; using typename Superclass::MovingTransformJacobianType; using RealType = MeasureType; /** * Other typedefs */ using DensityFunctionType = ManifoldParzenWindowsPointSetFunction; using GaussianType = typename DensityFunctionType::GaussianType; using DensityFunctionPointer = typename DensityFunctionType::Pointer; /** Initialize the Metric by making sure that all the components are present and plugged together correctly. */ void Initialize() override; /** * Set the alpha parameter used to tune the point-set metric from * a maximum-likelihood measure (alpha = 1) to the more robust L2 * solution (alpha = 2). Typically, "robustness" is associated with * performance in the presence of uniform noise but in most applications * the noise will be highly correlated with the point sets, therefore * an alpha value close to 1, in general, provides better performance. * Only values between 1 and 2 are convex. */ itkSetClampMacro(Alpha, RealType, 1.0, 2.0); /** * Get the alpha parameter used to tune the point-set metric. */ itkGetConstMacro(Alpha, RealType); /** * Each point is associated with a Gaussian characterized by m_PointSetSigma * which provides a sense of scale for determining the similarity between two * point sets. Default = 1.0. */ itkSetMacro(PointSetSigma, RealType); /** Get the point set sigma function */ itkGetConstMacro(PointSetSigma, RealType); /** * Set the neighborhood size used to evaluate the measurement at each * point. Default = 50. */ itkSetMacro(EvaluationKNeighborhood, unsigned int); /** * Get the neighborhood size used to evaluate the measurement at each * point. Default = 50. */ itkGetConstMacro(EvaluationKNeighborhood, unsigned int); /** * Set whether or not anisotropic covariances are determined for each * Gaussian. Default = false. */ itkSetMacro(UseAnisotropicCovariances, bool); /** * Get whether or not anisotropic covariances are determined for each * Gaussian. Default = false. */ itkGetConstMacro(UseAnisotropicCovariances, bool); /** * Get/set whether or not anisotropic covariances are determined for each * Gaussian. Default = false. */ itkBooleanMacro(UseAnisotropicCovariances); /** * Set the size of the covariance neighborhood used to construct the * anisotropic covariances. Only relevant if m_UseAnisotropicCovariances = * true. Default = 5. */ itkSetMacro(CovarianceKNeighborhood, unsigned int); /** * Get the size of the covariance neighborhood used to construct the * anisotropic covariances. Only relevant if m_UseAnisotropicCovariances = * true. Default = 5. */ itkGetConstMacro(CovarianceKNeighborhood, unsigned int); /** * Set the size of the noise kernel used to construct each covariance image. * To avoid the case where the local point set structure would result in a * degenerate covariance matrix, a small amount of noise is added along the * diagonal represented by this variable. Only relevant if * m_UseAnisotropicCovariances = true. Default = 10.0. */ itkSetMacro(KernelSigma, RealType); /** Get the noise kernel sigma for the anisotropic covariances. */ itkGetConstMacro(KernelSigma, RealType); MeasureType GetLocalNeighborhoodValue(const PointType & point, const PixelType & pixel = 0) const override; /** Get the local measure and the derivative values. */ void GetLocalNeighborhoodValueAndDerivative(const PointType &, MeasureType &, LocalDerivativeType &, const PixelType & pixel = 0) const override; /** Clone method will clone the existing instance of this type, * including its internal member variables. */ typename LightObject::Pointer InternalClone() const override; protected: JensenHavrdaCharvatTsallisPointSetToPointSetMetricv4(); ~JensenHavrdaCharvatTsallisPointSetToPointSetMetricv4() override = default; void ComputeValueAndDerivative(const PointType & samplePoint, MeasureType & value, LocalDerivativeType & derivativeReturn, bool calcValue, bool calcDerivative) const; void PrintSelf(std::ostream & os, Indent indent) const override; bool RequiresFixedPointsLocator() const override { return false; } bool RequiresMovingPointsLocator() const override { return false; } private: DensityFunctionPointer m_MovingDensityFunction{}; bool m_UseAnisotropicCovariances{ false }; RealType m_PointSetSigma{}; RealType m_KernelSigma{}; unsigned int m_CovarianceKNeighborhood{}; unsigned int m_EvaluationKNeighborhood{}; RealType m_Alpha{}; /** Precomputed cached values */ mutable RealType m_TotalNumberOfPoints{}; mutable RealType m_Prefactor0{}; mutable RealType m_Prefactor1{}; }; } // end namespace itk #ifndef ITK_MANUAL_INSTANTIATION # include "itkJensenHavrdaCharvatTsallisPointSetToPointSetMetricv4.hxx" #endif #endif