diff --git a/Modules/Numerics/PrincipalComponentsAnalysis/CMakeLists.txt b/Modules/Numerics/PrincipalComponentsAnalysis/CMakeLists.txt new file mode 100644 index 00000000000..c372726e883 --- /dev/null +++ b/Modules/Numerics/PrincipalComponentsAnalysis/CMakeLists.txt @@ -0,0 +1,3 @@ +project(PrincipalComponentsAnalysis) + +itk_module_impl() diff --git a/Modules/Numerics/PrincipalComponentsAnalysis/README.md b/Modules/Numerics/PrincipalComponentsAnalysis/README.md new file mode 100644 index 00000000000..bbca9ec7fb7 --- /dev/null +++ b/Modules/Numerics/PrincipalComponentsAnalysis/README.md @@ -0,0 +1,24 @@ +# PrincipalComponentsAnalysis + +In-tree ITK module providing a principal component analysis filter for +scalar, vector, and mesh-vertex data. The flagship class is +`itk::VectorFieldPCA`, which computes the principal components of an +ensemble of vector fields defined on a common mesh, useful for +shape-modeling and multivariate statistics workflows. + +## Origin + +Ingested from the standalone remote module +[**InsightSoftwareConsortium/ITKPrincipalComponentsAnalysis**](https://github.com/InsightSoftwareConsortium/ITKPrincipalComponentsAnalysis) +on 2026-05-08, following the v4 ingestion guidelines defined in +InsightSoftwareConsortium/ITK#6204. The upstream repository will be +archived read-only after this PR merges; it remains reachable at the +URL above for historical reference (notably the `doc/` and +`examples/` directories, which were intentionally left in the +upstream archive). + +## References + +- Bowers M., Younes L. *Principal Components Analysis of Scalar, + Vector, and Mesh Vertex Data.* The Insight Journal. August, 2013. + diff --git a/Modules/Numerics/PrincipalComponentsAnalysis/include/itkVectorFieldPCA.h b/Modules/Numerics/PrincipalComponentsAnalysis/include/itkVectorFieldPCA.h new file mode 100644 index 00000000000..744989cb08e --- /dev/null +++ b/Modules/Numerics/PrincipalComponentsAnalysis/include/itkVectorFieldPCA.h @@ -0,0 +1,245 @@ +/*========================================================================= + * + * 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 itkVectorFieldPCA_h +#define itkVectorFieldPCA_h + +#include "itkObject.h" +#include "itkPointSet.h" +#include "itkKernelFunctionBase.h" +#include "vnl/vnl_vector.h" +#include "vnl/vnl_matrix.h" + +namespace itk +{ + +/** \class VectorFieldPCA + * \brief Produce the principle components of a vector valued function. + * + * This calculator produces a set of basis functions composed of the + * principal components of a set of vector valued functions. + * + * Specify an itk::KernelFunction for Kernel PCA. The Kernel Function + * can take as input an optional point set. + * + * This class is templated over the types of the vector valued functions, + * the output point types, and optionally the point set type. + * + * \author Michael Bowers, Laurent Younes + * + * This code was contributed in the Insight Journal paper: + * + * "Principal Components Analysis of Scalar, Vector, and Mesh Vertex Data" + * https://www.insight-journal.org/browse/publication/878 + * + * \ingroup ITKStatistics + * \ingroup PrincipalComponentsAnalysis + */ + +template +class ITK_TEMPLATE_EXPORT GaussianDistanceKernel : public KernelFunctionBase +{ +public: + /** Standard class type alias. */ + using Self = GaussianDistanceKernel; + using Superclass = KernelFunctionBase; + using Pointer = SmartPointer; + using ConstPointer = SmartPointer; + + /** Run-time type information (and related methods). */ + itkTypeMacro(GaussianDistanceKernel, KernelFunction); + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** + * \brief Set and get the Kernel sigma. + */ + void + SetKernelSigma(double s) + { + m_KernelSigma = s; + m_OneOverMinusTwoSigmaSqr = -1.0 / (2.0 * s * s); + } + itkGetMacro(KernelSigma, double); + + /** + * \brief Evaluate the function. Input is the squared distance + */ + inline TRealValueType + Evaluate(const TRealValueType & u) const override + { + return (std::exp(u * m_OneOverMinusTwoSigmaSqr)); + } + +protected: + GaussianDistanceKernel() = default; + ~GaussianDistanceKernel() override = default; + void + PrintSelf(std::ostream & os, Indent indent) const override + { + Superclass::PrintSelf(os, indent); + } + +private: + double m_KernelSigma{ 1.0 }; + double m_OneOverMinusTwoSigmaSqr{ -0.5 }; +}; + +template , + class TPointSetType = + PointSet>> +class ITK_TEMPLATE_EXPORT VectorFieldPCA : public Object +{ +public: + ITK_DISALLOW_COPY_AND_MOVE(VectorFieldPCA); + + /** Standard class type alias. */ + using Self = VectorFieldPCA; + using Superclass = Object; + using Pointer = SmartPointer; + using ConstPointer = SmartPointer; + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** Run-time type information (and related methods). */ + itkTypeMacro(VectorFieldPCA, Object); + + /** Type definitions for the PointSet. */ + using InputPointSetType = TPointSetType; + + /** Definitions for points of the PointSet. */ + using InputPointType = typename InputPointSetType::PointType; + + /** Definitions for the PointsContainer. */ + using PointsContainer = typename InputPointSetType::PointsContainer; + using PointsContainerIterator = typename PointsContainer::Iterator; + + /** Pointer types for the PointSet. */ + using InputPointSetPointer = typename InputPointSetType::Pointer; + + /** Const Pointer type for the PointSet. */ + using InputPointSetConstPointer = typename InputPointSetType::ConstPointer; + + /** + * \brief Input PointSet dimension + */ + itkStaticConstMacro(InputMeshDimension, unsigned int, TPointSetType::PointDimension); + + /** type for the vector fields. */ + using VectorFieldType = vnl_matrix; + using VectorFieldSetType = VectorContainer; + + using VectorFieldSetTypePointer = typename VectorFieldSetType::Pointer; + using VectorFieldSetTypeConstPointer = typename VectorFieldSetType::ConstPointer; + + /** types for the output. */ + using MatrixType = vnl_matrix; + using VectorType = vnl_vector; + + using BasisSetType = VectorContainer; + using ResSetType = VectorContainer; + + using BasisSetTypePointer = typename BasisSetType::Pointer; + using KernelFunctionPointer = typename KernelFunctionType::Pointer; + + /** + * \brief Set and get the input point set. + */ + itkSetMacro(PointSet, InputPointSetPointer); + itkGetMacro(PointSet, InputPointSetPointer); + + /** + * \brief Set and get the vector fields for the analysis. + */ + itkSetMacro(VectorFieldSet, VectorFieldSetTypePointer); + itkGetMacro(VectorFieldSet, VectorFieldSetTypePointer); + + /** + * \brief Set and get the PCA count. + */ + itkSetMacro(ComponentCount, unsigned int); + itkGetMacro(ComponentCount, unsigned int); + + /** + * \brief Set pointer to the Kernel object. + */ + itkSetMacro(KernelFunction, KernelFunctionPointer); + + /** + * \brief Compute the PCA decomposition of the input point set. + If a Kernel and a Kernel Sigma are set , + the calculator will perform Kernel PCA. + */ + void + Compute(); + + /** + * \brief Return the results. + */ + itkGetConstReferenceMacro(AveVectorField, MatrixType); + itkGetConstReferenceMacro(PCAEigenValues, VectorType); + itkGetConstObjectMacro(BasisVectors, BasisSetType); + +protected: + VectorFieldPCA(); + ~VectorFieldPCA() override = default; + void + PrintSelf(std::ostream & os, Indent indent) const override; + + /** Kernel PCA. */ + void + KernelPCA(); + + /** Compute Momentum SCP. */ + void + ComputeMomentumSCP(); + +private: + VectorType m_PCAEigenValues; + + BasisSetTypePointer m_BasisVectors; + VectorFieldSetTypePointer m_VectorFieldSet; + InputPointSetPointer m_PointSet; + KernelFunctionPointer m_KernelFunction; + + // Problem dimensions + unsigned int m_ComponentCount{ 0 }; + unsigned int m_SetSize{ 0 }; + unsigned int m_VectorDimCount{ 0 }; + unsigned int m_PointDim{ 0 }; + + MatrixType m_V0; + MatrixType m_AveVectorField; + MatrixType m_K; + + bool m_PCACalculated{ false }; +}; + +} // end namespace itk + +#ifndef ITK_MANUAL_INSTANTIATION +# include "itkVectorFieldPCA.hxx" +#endif + +#endif diff --git a/Modules/Numerics/PrincipalComponentsAnalysis/include/itkVectorFieldPCA.hxx b/Modules/Numerics/PrincipalComponentsAnalysis/include/itkVectorFieldPCA.hxx new file mode 100644 index 00000000000..4d36b2f3064 --- /dev/null +++ b/Modules/Numerics/PrincipalComponentsAnalysis/include/itkVectorFieldPCA.hxx @@ -0,0 +1,332 @@ +/*========================================================================= + * + * 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 itkVectorFieldPCA_hxx +#define itkVectorFieldPCA_hxx + +#include "vnl/algo/vnl_symmetric_eigensystem.h" +#include "vnl/vnl_c_vector.h" +#include "itkMath.h" + +namespace itk +{ + +template +VectorFieldPCA::VectorFieldPCA() + : m_BasisVectors(BasisSetType::New()) + +{} + +template +void +VectorFieldPCA::Compute() +{ + // Check parameters + if (!m_VectorFieldSet || !m_VectorFieldSet->Size()) + { + itkExceptionMacro("Vector Field Set not specified."); + return; + } + + m_SetSize = m_VectorFieldSet->Size(); + if (m_ComponentCount <= 0 || m_ComponentCount > m_SetSize) + { + itkExceptionMacro("Component Count N must be 0 < N <= VectorFieldSetSize (" << m_VectorFieldSet->Size() << ")."); + return; + } + + // Get vector/point dim from the first member of the vector set + + VectorFieldType & firstField = m_VectorFieldSet->ElementAt(0); + m_VectorDimCount = firstField.rows(); + m_PointDim = firstField.cols(); + + // Check all vector dimensions in the set + for (unsigned int i = 1; i < m_VectorFieldSet->Size(); i++) + { + VectorFieldType & thisField = m_VectorFieldSet->ElementAt(i); + if (thisField.rows() != m_VectorDimCount || thisField.cols() != m_PointDim) + { + itkExceptionMacro("Vector " << i << " dimensions (" << thisField.rows() << "x" << thisField.cols() + << ") does not match other vector fields dimensions (" << m_VectorDimCount << "x" + << m_PointDim << ")."); + return; + } + } + + if (m_KernelFunction) + { + // will try Kernel PCA, so need a point set... + if (!m_PointSet) + { + itkExceptionMacro("KernelFunction is set but no PointSet is available."); + return; + } + + // PointSet only necessary for Kernel PCA, check that it matches. + if (m_PointSet->GetNumberOfPoints() != m_VectorDimCount) + { + itkExceptionMacro("Point Set count (" << m_PointSet->GetNumberOfPoints() + << ") does not match vector field count (" << m_VectorDimCount << ")."); + } + } + + this->ComputeMomentumSCP(); + this->KernelPCA(); + + // Save only the desired eigenvalues + m_PCAEigenValues = m_PCAEigenValues.extract(m_ComponentCount); + + // Save only the desired eigenvectors + m_V0 = m_V0.extract(m_V0.rows(), m_ComponentCount); + + m_BasisVectors->Reserve(m_ComponentCount); + for (unsigned int k = 0; k < m_ComponentCount; k++) + { + MatrixType basisVector(m_VectorDimCount, m_PointDim); + VectorFieldType accum(m_VectorDimCount, m_PointDim); + accum = 0.0; + basisVector = 0.0; + for (unsigned int j = 0; j < m_SetSize; j++) + { + vnl_c_vector::saxpy( + m_V0(j, k), (m_VectorFieldSet->ElementAt(j)).data_block(), accum.data_block(), accum.size()); + } + + for (unsigned int i = 0; i < accum.size(); ++i) + basisVector.begin()[i] = TPCType(accum.begin()[i]); + m_BasisVectors->SetElement(k, basisVector); + } + + m_PCAEigenValues /= m_SetSize; + m_PCAEigenValues = m_PCAEigenValues.apply(sqrt); + + m_PCACalculated = true; +} + +template +void +VectorFieldPCA::ComputeMomentumSCP() +{ + VectorFieldType accum; + accum.set_size(m_VectorDimCount, m_PointDim); + accum = 0.0; + + // Determine the average of the vector field over the set + for (unsigned k = 0; k < m_SetSize; k++) + { + accum += m_VectorFieldSet->ElementAt(k); + } + accum /= (double)m_SetSize; + + m_AveVectorField.set_size(m_VectorDimCount, m_PointDim); + + for (unsigned int i = 0; i < accum.size(); ++i) + m_AveVectorField.begin()[i] = TPCType(accum.begin()[i]); + + + MatrixType kernelM(m_VectorDimCount, m_VectorDimCount); + + // Check whether we're doing kernel PCA + if (!m_KernelFunction.IsNull()) + { + unsigned k1, l1; + k1 = 0; + for (PointsContainerIterator kIx = m_PointSet->GetPoints()->Begin(); kIx != m_PointSet->GetPoints()->End(); kIx++) + { + l1 = 0; + for (PointsContainerIterator lIx = m_PointSet->GetPoints()->Begin(); lIx != m_PointSet->GetPoints()->End(); lIx++) + { + kernelM(k1, l1) = m_KernelFunction->Evaluate((kIx.Value()).SquaredEuclideanDistanceTo(lIx.Value())); + kernelM(l1, k1) = kernelM(k1, l1); + l1++; + } + k1++; + } + } + + m_K.set_size(m_SetSize, m_SetSize); + MatrixType alphaK(m_VectorDimCount, m_PointDim); + MatrixType alphaL(m_VectorDimCount, m_PointDim); + MatrixType tmpA; + for (unsigned k = 0; k < m_SetSize; k++) + { + for (unsigned l = k; l < m_SetSize; l++) + { + for (unsigned int i = 0; i < alphaK.size(); ++i) + { + alphaK.begin()[i] = TPCType(m_VectorFieldSet->ElementAt(k).begin()[i]); + } + for (unsigned int i = 0; i < alphaL.size(); ++i) + { + alphaL.begin()[i] = TPCType(m_VectorFieldSet->ElementAt(l).begin()[i]); + } + + if (m_KernelFunction) + { + tmpA = kernelM * (alphaL - m_AveVectorField); + } + else + { + tmpA = alphaL - m_AveVectorField; + } + + MatrixType tmpB = alphaK - m_AveVectorField; + m_K(k, l) = vnl_c_vector::dot_product(tmpA.data_block(), tmpB.data_block(), tmpA.size()); + m_K(l, k) = m_K(k, l); + } + } +} + +template +void +VectorFieldPCA::KernelPCA() +{ + VectorType rowMeans(m_SetSize); + + for (unsigned int k = 0; k < m_SetSize; k++) + { + rowMeans(k) = m_K.get_row(k).mean(); + } + + TPCType meanOfMeans = rowMeans.mean(); + MatrixType K0(m_K - meanOfMeans); + for (unsigned int k = 0; k < m_SetSize; k++) + { + for (unsigned int l = 0; l < m_SetSize; l++) + { + K0(k, l) -= rowMeans(k) + rowMeans(l); + } + } + + vnl_symmetric_eigensystem eigs(K0); + + m_PCAEigenValues = eigs.D.diagonal(); + + // Eigenvalues come out in ascending order, reorder them + m_PCAEigenValues.flip(); + + // Reorder eigenvectors + m_V0 = eigs.V; + m_V0.fliplr(); + + const double eigenvalue_epsilon = 1.0e-10; + for (unsigned int k = 0; k < m_SetSize; k++) + { + m_V0.scale_column(k, 1.0 / std::sqrt(m_PCAEigenValues(k) + eigenvalue_epsilon)); + } +} + +template +void +VectorFieldPCA::PrintSelf(std::ostream & os, Indent indent) const +{ + Superclass::PrintSelf(os, indent); + + os << indent << "PCAEigenvalues: " << this->m_PCAEigenValues << std::endl; + + if (this->m_BasisVectors.IsNotNull()) + { + os << indent << "Basis Vector count: " << this->m_BasisVectors->Size() << std::endl; + if (this->m_BasisVectors->Size()) + { + MatrixType & thisBasis = this->m_BasisVectors->ElementAt(0); + os << indent << "Basis Vector dimensions: " << thisBasis.rows() << "x" << thisBasis.cols() << std::endl; + } + } + itkPrintSelfObjectMacro(BasisVectors); + + if (this->m_VectorFieldSet.IsNotNull()) + { + os << indent << "Vector Field Set count: " << this->m_VectorFieldSet->Size() << std::endl; + } + itkPrintSelfObjectMacro(VectorFieldSet); + + if (this->m_PointSet.IsNotNull()) + { + os << indent << "PointSet dimensions: " << m_PointSet->GetNumberOfPoints() << "x" + << this->m_PointSet->PointDimension << std::endl; + } + itkPrintSelfObjectMacro(PointSet); + + itkPrintSelfObjectMacro(KernelFunction); + + os << indent << "ComponentCount: " << this->m_ComponentCount << std::endl; + os << indent << "SetSize: " << this->m_SetSize << std::endl; + os << indent << "VectorDimCount: " << this->m_VectorDimCount << std::endl; + os << indent << "PointDim: " << this->m_PointDim << std::endl; + + os << indent << "V0 : " << this->m_V0 << std::endl; + os << indent << "AveVectorField: " << this->m_AveVectorField << std::endl; + os << indent << "K: " << this->m_K << std::endl; + + os << indent << "PCACalculated: " << this->m_PCACalculated << std::endl; +} +} // end namespace itk + +#endif diff --git a/Modules/Numerics/PrincipalComponentsAnalysis/itk-module.cmake b/Modules/Numerics/PrincipalComponentsAnalysis/itk-module.cmake new file mode 100644 index 00000000000..3d76265b276 --- /dev/null +++ b/Modules/Numerics/PrincipalComponentsAnalysis/itk-module.cmake @@ -0,0 +1,18 @@ +set( + DOCUMENTATION + "This module contains an implementation of the +principal component analysis for the ITK toolkit." +) + +itk_module( + PrincipalComponentsAnalysis + DEPENDS + ITKCommon + ITKMesh + ITKIOMesh + ITKIOImageBase + TEST_DEPENDS + ITKTestKernel + EXCLUDE_FROM_DEFAULT + DESCRIPTION "${DOCUMENTATION}" +) diff --git a/Modules/Numerics/PrincipalComponentsAnalysis/test/CMakeLists.txt b/Modules/Numerics/PrincipalComponentsAnalysis/test/CMakeLists.txt new file mode 100644 index 00000000000..9f691f972c4 --- /dev/null +++ b/Modules/Numerics/PrincipalComponentsAnalysis/test/CMakeLists.txt @@ -0,0 +1,54 @@ +itk_module_test() + +set(PCA PrincipalComponentsAnalysis) +set(${PCA}Tests itkVectorKernelPCATest.cxx) + +createtestdriver(${PCA} "${${PCA}-Test_LIBRARIES}" "${${PCA}Tests}") + +itk_add_test( + NAME itkVectorKernelPCATest + COMMAND + ${PCA}TestDriver + itkVectorKernelPCATest + DATA{Input/PCATestSurface.vtk} + DATA{Input/PCATestSurface_alpha0_01.vtk} + DATA{Input/PCATestSurface_alpha0_02.vtk} + DATA{Input/PCATestSurface_alpha0_03.vtk} + DATA{Input/PCATestSurface_alpha0_04.vtk} + DATA{Input/PCATestSurface_alpha0_05.vtk} + DATA{Input/PCATestSurface_alpha0_06.vtk} + DATA{Input/PCATestSurface_alpha0_07.vtk} + DATA{Input/PCATestSurface_alpha0_08.vtk} + DATA{Input/PCATestSurface_alpha0_09.vtk} + DATA{Input/PCATestSurface_alpha0_10.vtk} + DATA{Input/PCATestSurface_alpha0_11.vtk} + DATA{Input/PCATestSurface_alpha0_12.vtk} + DATA{Input/PCATestSurface_alpha0_13.vtk} + DATA{Input/PCATestSurface_alpha0_14.vtk} + DATA{Input/PCATestSurface_alpha0_15.vtk} + DATA{Input/PCATestSurface_alpha0_16.vtk} + DATA{Input/PCATestSurface_alpha0_17.vtk} + DATA{Input/PCATestSurface_alpha0_18.vtk} + DATA{Input/PCATestSurface_alpha0_19.vtk} + DATA{Input/PCATestSurface_alpha0_20.vtk} + DATA{Input/PCATestSurface_alpha0_21.vtk} + DATA{Input/PCATestSurface_alpha0_22.vtk} + DATA{Input/PCATestSurface_alpha0_23.vtk} + DATA{Input/PCATestSurface_alpha0_24.vtk} + DATA{Input/PCATestSurface_alpha0_25.vtk} + DATA{Input/PCATestSurface_alpha0_26.vtk} + DATA{Input/PCATestSurface_alpha0_27.vtk} + DATA{Input/PCATestSurface_alpha0_28.vtk} + DATA{Input/PCATestSurface_alpha0_29.vtk} + DATA{Input/PCATestSurface_alpha0_30.vtk} + DATA{Input/PCATestSurface_alpha0_31.vtk} + DATA{Input/PCATestSurface_alpha0_32.vtk} + DATA{Input/PCATestSurface_alpha0_33.vtk} + DATA{Input/PCATestSurface_alpha0_34.vtk} + DATA{Input/PCATestSurface_alpha0_35.vtk} + DATA{Input/PCATestSurface_alpha0_36.vtk} + DATA{Input/PCATestSurface_alpha0_37.vtk} + DATA{Input/PCATestSurface_alpha0_38.vtk} + DATA{Input/PCATestSurface_alpha0_39.vtk} + DATA{Input/PCATestSurface_alpha0_40.vtk} +) diff --git a/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface.vtk.cid b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface.vtk.cid new file mode 100644 index 00000000000..1add67feb28 --- /dev/null +++ b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface.vtk.cid @@ -0,0 +1 @@ +bafkreigbd7acneovictxmru3dswl3d4adf6yn4ebjzeoo7itmyivurt7ki diff --git a/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_01.vtk.cid b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_01.vtk.cid new file mode 100644 index 00000000000..804f52cbdca --- /dev/null +++ b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_01.vtk.cid @@ -0,0 +1 @@ +bafkreifcoh7xw7vto737pbvhxq2yxzdifoomtqlhd5bwe4yabuttldurzi diff --git a/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_02.vtk.cid b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_02.vtk.cid new file mode 100644 index 00000000000..6efc0056ded --- /dev/null +++ b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_02.vtk.cid @@ -0,0 +1 @@ +bafkreief5y3ievizak7qgtf6iaobfimv6fka5e2pdncy3qfv7rnnpidh64 diff --git a/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_03.vtk.cid b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_03.vtk.cid new file mode 100644 index 00000000000..a3b088ed3c1 --- /dev/null +++ b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_03.vtk.cid @@ -0,0 +1 @@ +bafkreihmxc72c2dx3ruavcaaiqwwv4mue67kceokqg3fcu3k74exsnoxma diff --git a/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_04.vtk.cid b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_04.vtk.cid new file mode 100644 index 00000000000..d23561f0a6b --- /dev/null +++ b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_04.vtk.cid @@ -0,0 +1 @@ +bafkreihmqlehsjjwkvid3r2cvvaabtr6lwicwyoyvhaadvjovshaxercdi diff --git a/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_05.vtk.cid b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_05.vtk.cid new file mode 100644 index 00000000000..69980dcd135 --- /dev/null +++ b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_05.vtk.cid @@ -0,0 +1 @@ +bafkreicoxwmt6dztdb5o6cvavdjli4q3ir464szqdddht56kfernedvobi diff --git a/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_06.vtk.cid b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_06.vtk.cid new file mode 100644 index 00000000000..c6144c6cf5c --- /dev/null +++ b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_06.vtk.cid @@ -0,0 +1 @@ +bafkreih5givsj7ikjkjevqym5bla3uc6zmlevegwwlm243ge6zi2uwctme diff --git a/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_07.vtk.cid b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_07.vtk.cid new file mode 100644 index 00000000000..ad244938ba5 --- /dev/null +++ b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_07.vtk.cid @@ -0,0 +1 @@ +bafkreiaghso7garm7zom2letqgjcljhxyqij26aoeviijdsucu7sirho7m diff --git a/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_08.vtk.cid b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_08.vtk.cid new file mode 100644 index 00000000000..bc1238493d2 --- /dev/null +++ b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_08.vtk.cid @@ -0,0 +1 @@ +bafkreiftluo5ts7ot6jezbqufe5hblxu5aex5bsvli4jxxafec2wchcpyy diff --git a/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_09.vtk.cid b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_09.vtk.cid new file mode 100644 index 00000000000..9620ab17f31 --- /dev/null +++ b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_09.vtk.cid @@ -0,0 +1 @@ +bafkreia3idvlzgoydmvjeu3q6p225btr7hkfuzecxyukg5nlhvlvnuzyzi diff --git a/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_10.vtk.cid b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_10.vtk.cid new file mode 100644 index 00000000000..49da6db2fc1 --- /dev/null +++ b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_10.vtk.cid @@ -0,0 +1 @@ +bafkreihfbaulqrmallerwrbycm7pt7v2wzvydhrpqgdh5zduqukmolcxla diff --git a/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_11.vtk.cid b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_11.vtk.cid new file mode 100644 index 00000000000..65989cc8bec --- /dev/null +++ b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_11.vtk.cid @@ -0,0 +1 @@ +bafkreiftrrhzc4po7rwul4azxetgcypuoh32hy6wcsgwngxroc7sfvw6kq diff --git a/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_12.vtk.cid b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_12.vtk.cid new file mode 100644 index 00000000000..46ab0d1edf1 --- /dev/null +++ b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_12.vtk.cid @@ -0,0 +1 @@ +bafkreigkyi2lc3vqmsd7iv7dk2ofjrpb3iwfrgyrgxajoacoclnub6p2nq diff --git a/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_13.vtk.cid b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_13.vtk.cid new file mode 100644 index 00000000000..e08cf539b93 --- /dev/null +++ b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_13.vtk.cid @@ -0,0 +1 @@ +bafkreihzrovm6twwavvv3jnyefmjaasvtg56vmzgwuy4uk7oae7pt6icpq diff --git a/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_14.vtk.cid b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_14.vtk.cid new file mode 100644 index 00000000000..815f9d5d35c --- /dev/null +++ b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_14.vtk.cid @@ -0,0 +1 @@ +bafkreigo7cfqcaokvwxffbq43dkkz2zfql5v2kxeqlpa7pzymoueduzkva diff --git a/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_15.vtk.cid b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_15.vtk.cid new file mode 100644 index 00000000000..afb9ac63309 --- /dev/null +++ b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_15.vtk.cid @@ -0,0 +1 @@ +bafkreib33ptbk2rre2zvf4cxf6uojrwdeyilesfhgwnslv35iuy7axtk6u diff --git a/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_16.vtk.cid b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_16.vtk.cid new file mode 100644 index 00000000000..30b43c9a6ed --- /dev/null +++ b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_16.vtk.cid @@ -0,0 +1 @@ +bafkreicakaxu4ugpsgjiqd6256tgo3tpqfw7qxibwc6teg2mjkgwgttubq diff --git a/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_17.vtk.cid b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_17.vtk.cid new file mode 100644 index 00000000000..f065d9a5770 --- /dev/null +++ b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_17.vtk.cid @@ -0,0 +1 @@ +bafkreifnpyijulntj4viwjdfjwgmnsvlhnibcoo3v6pfojpjckzpyopr3e diff --git a/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_18.vtk.cid b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_18.vtk.cid new file mode 100644 index 00000000000..b838014e030 --- /dev/null +++ b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_18.vtk.cid @@ -0,0 +1 @@ +bafkreiechpwk4rmjzvbt2t7k2zjhseje36iprorfbhhteejherdnx7a3a4 diff --git a/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_19.vtk.cid b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_19.vtk.cid new file mode 100644 index 00000000000..9818d225a50 --- /dev/null +++ b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_19.vtk.cid @@ -0,0 +1 @@ +bafkreibzjewk4dcsdcr2esg63rfq54yym666r6lliwo6dxncyy46y5p3ty diff --git a/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_20.vtk.cid b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_20.vtk.cid new file mode 100644 index 00000000000..85318884d4c --- /dev/null +++ b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_20.vtk.cid @@ -0,0 +1 @@ +bafkreig2enkxov3m4fpyxro7yfcytcxdrb57ton45zfmga7zkjszcf7aom diff --git a/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_21.vtk.cid b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_21.vtk.cid new file mode 100644 index 00000000000..36194919e1f --- /dev/null +++ b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_21.vtk.cid @@ -0,0 +1 @@ +bafkreiaojvyakbxkvgrf52zqfreffsnw3p7wwlgwbziussj5ghi6vh4zbm diff --git a/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_22.vtk.cid b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_22.vtk.cid new file mode 100644 index 00000000000..838f1366af1 --- /dev/null +++ b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_22.vtk.cid @@ -0,0 +1 @@ +bafkreieduudsx7kg3qugiy5mw5dujq4vvt3slweajtp4gsntdp5zddnmku diff --git a/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_23.vtk.cid b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_23.vtk.cid new file mode 100644 index 00000000000..1b532da6670 --- /dev/null +++ b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_23.vtk.cid @@ -0,0 +1 @@ +bafkreiexaokoaps44rvmvrhbpimnwh5nl3l6vtkfby52vq7jwbav6lhhoa diff --git a/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_24.vtk.cid b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_24.vtk.cid new file mode 100644 index 00000000000..b0d4ab63c2e --- /dev/null +++ b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_24.vtk.cid @@ -0,0 +1 @@ +bafkreiaojvtcz7edszllufts2hrotlfxs6m6y3mi4u3qunhscvt43y7hum diff --git a/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_25.vtk.cid b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_25.vtk.cid new file mode 100644 index 00000000000..5826f7d1651 --- /dev/null +++ b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_25.vtk.cid @@ -0,0 +1 @@ +bafkreigvg25ekb2mxzlu7ro3rhwwgpyoto57jy4ap4lzqdn5omaqxtsli4 diff --git a/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_26.vtk.cid b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_26.vtk.cid new file mode 100644 index 00000000000..662f3fd8062 --- /dev/null +++ b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_26.vtk.cid @@ -0,0 +1 @@ +bafkreibl2kma2urfnn6fvbs4glbsugdwzjo25bnov3nbzohfjbaa2krfxi diff --git a/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_27.vtk.cid b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_27.vtk.cid new file mode 100644 index 00000000000..6150dc71caf --- /dev/null +++ b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_27.vtk.cid @@ -0,0 +1 @@ +bafkreigxwwmowl7fgc52ea4s7zuodfuyhg34y63m2gqawg46zg7u5aa2s4 diff --git a/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_28.vtk.cid b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_28.vtk.cid new file mode 100644 index 00000000000..69909bebe71 --- /dev/null +++ b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_28.vtk.cid @@ -0,0 +1 @@ +bafkreiep2xvavh6k4nbxxcfio2zi62ucdskp4yra24jcrpaqxpve7jgq64 diff --git a/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_29.vtk.cid b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_29.vtk.cid new file mode 100644 index 00000000000..b37e07ab013 --- /dev/null +++ b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_29.vtk.cid @@ -0,0 +1 @@ +bafkreiabw6pqerteqnzibv5eqhnyhaybj5fs5nqxo2wtizpocsrudpquve diff --git a/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_30.vtk.cid b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_30.vtk.cid new file mode 100644 index 00000000000..ee7e78dc198 --- /dev/null +++ b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_30.vtk.cid @@ -0,0 +1 @@ +bafkreic7j5mkyx5yw2ehqkbnw22moov5wx4jt6rex5sub6m3istnt5iutm diff --git a/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_31.vtk.cid b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_31.vtk.cid new file mode 100644 index 00000000000..43bb7342508 --- /dev/null +++ b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_31.vtk.cid @@ -0,0 +1 @@ +bafkreihujqd7jhvqyc3ck3qa6fu2cze323scmwwroaudf7ubkve3nelz3e diff --git a/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_32.vtk.cid b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_32.vtk.cid new file mode 100644 index 00000000000..fc4ccac129a --- /dev/null +++ b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_32.vtk.cid @@ -0,0 +1 @@ +bafkreihufhgeshfggqduqeeaiqh3cmwqfm3yfyenjget5nxwdrfvjjyz6u diff --git a/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_33.vtk.cid b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_33.vtk.cid new file mode 100644 index 00000000000..c8d7835774f --- /dev/null +++ b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_33.vtk.cid @@ -0,0 +1 @@ +bafkreifjrlasosabu7gn4s6lmr5sfyvjwswq5fsrqlvul24bvuz4ul4x4y diff --git a/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_34.vtk.cid b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_34.vtk.cid new file mode 100644 index 00000000000..bb300b41ab7 --- /dev/null +++ b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_34.vtk.cid @@ -0,0 +1 @@ +bafkreia3tytko47jg7zjf3p3er74v6s2aiagxar7g4cgfmsxstejnz7fre diff --git a/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_35.vtk.cid b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_35.vtk.cid new file mode 100644 index 00000000000..a3eca2528ef --- /dev/null +++ b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_35.vtk.cid @@ -0,0 +1 @@ +bafkreie7kgcdnrjo2t5f6ist3yzfxv3n4d6dq2p7c2cad4npmfyspmgpsm diff --git a/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_36.vtk.cid b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_36.vtk.cid new file mode 100644 index 00000000000..3bde884310f --- /dev/null +++ b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_36.vtk.cid @@ -0,0 +1 @@ +bafkreihgxlnb24swo6rjhgz6aiuitpbnsdkiog7sd2e24jtyoq3633d27u diff --git a/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_37.vtk.cid b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_37.vtk.cid new file mode 100644 index 00000000000..028247727b7 --- /dev/null +++ b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_37.vtk.cid @@ -0,0 +1 @@ +bafkreifo6qjhthbdqasemq6d53aaefd64phyyjknzdooruji72ahpbrquy diff --git a/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_38.vtk.cid b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_38.vtk.cid new file mode 100644 index 00000000000..0624fc93514 --- /dev/null +++ b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_38.vtk.cid @@ -0,0 +1 @@ +bafkreid6glw7uwrdugnpaq77vkxvla4fyfunu42fbpa3zqujoa7lab5oom diff --git a/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_39.vtk.cid b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_39.vtk.cid new file mode 100644 index 00000000000..d2b90a54677 --- /dev/null +++ b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_39.vtk.cid @@ -0,0 +1 @@ +bafkreia7kmezz3fov4ycosvj57nxrhx7kn4sbwhmoqono5nc3sl4ubxfdy diff --git a/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_40.vtk.cid b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_40.vtk.cid new file mode 100644 index 00000000000..8075ef939ad --- /dev/null +++ b/Modules/Numerics/PrincipalComponentsAnalysis/test/Input/PCATestSurface_alpha0_40.vtk.cid @@ -0,0 +1 @@ +bafkreifyywfd4mddt5sbatvqsk7bn7d4gm2pij4b7ywdm3n623qczth3dy diff --git a/Modules/Numerics/PrincipalComponentsAnalysis/test/itkVectorKernelPCATest.cxx b/Modules/Numerics/PrincipalComponentsAnalysis/test/itkVectorKernelPCATest.cxx new file mode 100644 index 00000000000..b140df074e5 --- /dev/null +++ b/Modules/Numerics/PrincipalComponentsAnalysis/test/itkVectorKernelPCATest.cxx @@ -0,0 +1,258 @@ +/*========================================================================= + * + * 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. + * +=========================================================================*/ + +#include "itkMesh.h" +#include "itkMeshFileReader.h" +#include "itkVectorFieldPCA.h" +#include "itkTestingMacros.h" +#include "vnl/vnl_vector.h" + + +template +int +ParseVectorFields(std::vector vectorFieldFilenames, typename TVectorContainer::Pointer vectorFieldSet) +{ + int testStatus = EXIT_SUCCESS; + + using ReaderType = itk::MeshFileReader; + typename ReaderType::Pointer meshReader = ReaderType::New(); + + unsigned int fieldSetCount = vectorFieldFilenames.size(); + vectorFieldSet->Reserve(fieldSetCount); + + + typename TVectorContainer::Element vectorField; + + unsigned int vectorFieldDim = 0; + unsigned int vectorFieldCount = 0; + + unsigned int setIx = 0; + for (unsigned int i = 0; i < fieldSetCount; i++) + { + std::string vectorFieldName = vectorFieldFilenames[i]; + + meshReader->SetFileName(vectorFieldName); + + ITK_TRY_EXPECT_NO_EXCEPTION(meshReader->Update()); + + // Get the objects + typename TMesh::Pointer meshWithField = meshReader->GetOutput(); + + typename TMesh::PointDataContainerPointer pointData = meshWithField->GetPointData(); + if (setIx == 0) + { + vectorFieldCount = pointData->Size(); + if (vectorFieldCount) + { + TPixel oneDataSetVal = pointData->GetElement(0); + vectorFieldDim = oneDataSetVal.size(); + } + if (vectorFieldCount != meshWithField->GetNumberOfPoints()) + { + std::cerr << "Test failed!" << std::endl; + std::cerr << "Vector field count (" << vectorFieldCount << ") doesn't match mesh vertext count (" + << meshWithField->GetNumberOfPoints() << ")." << std::endl; + testStatus = EXIT_FAILURE; + } + vectorField.set_size(vectorFieldCount, vectorFieldDim); + } + else + { + if (vectorFieldDim != vectorField.cols() || vectorFieldCount != meshWithField->GetNumberOfPoints()) + { + std::cerr << "Test failed!" << std::endl; + std::cerr << "Unexpected dimensions in vector field file " << vectorFieldName << std::endl; + std::cerr << "Expected: " << vectorFieldCount << " x " << vectorFieldDim << ", but got " + << meshWithField->GetNumberOfPoints() << " x " << vectorField.cols() << std::endl; + testStatus = EXIT_FAILURE; + } + } + + for (unsigned int k = 0; k < pointData->Size(); k++) + { + TPixel oneDataSetVal = pointData->GetElement(k); + vectorField.set_row(k, oneDataSetVal); + } + + vectorFieldSet->SetElement(setIx++, vectorField); + } + + return testStatus; +} + + +int +itkVectorKernelPCATest(int argc, char * argv[]) +{ + if (argc < 6) + { + std::cerr << "Missing parameters." << std::endl; + std::cerr << "Usage: " << argv[0] << " ... " << std::endl; + std::cerr << "where N must be greater than 3" << std::endl; + return EXIT_FAILURE; + } + + + int testStatus = EXIT_SUCCESS; + + const unsigned int Dimension = 3; + + using PointDataType = double; + using PointDataVectorType = itk::Array; + using PixelType = PointDataVectorType; + using CoordRep = double; + + using PCAResultsType = double; + + // Declare the type of the input mesh + using MeshType = itk::Mesh; + + // Declare the type of the kernel function class + using KernelType = itk::GaussianDistanceKernel; + + // Declare the type of the PCA calculator + using PCACalculatorType = + itk::VectorFieldPCA; + + // Instantiate the reader + using ReaderType = itk::MeshFileReader; + ReaderType::Pointer meshReader = ReaderType::New(); + + meshReader->SetFileName(argv[1]); + + ITK_TRY_EXPECT_NO_EXCEPTION(meshReader->Update()); + + + // Get the input mesh + MeshType::Pointer mesh = meshReader->GetOutput(); + + + PCACalculatorType::Pointer pcaCalc = PCACalculatorType::New(); + + ITK_EXERCISE_BASIC_OBJECT_METHODS(pcaCalc, VectorFieldPCA, Object); + + // Test exception when trying to compute before setting much of anything + ITK_TRY_EXPECT_EXCEPTION(pcaCalc->Compute()); + + + // Set user variables + unsigned int pcaCount = 3; + pcaCalc->SetComponentCount(pcaCount); + + // Connect the input + pcaCalc->SetPointSet(mesh); + ITK_TEST_SET_GET_VALUE(mesh, pcaCalc->GetPointSet()); + + // Set vector fields + + PCACalculatorType::VectorFieldType vectorField; + + // Should know vector field dimensions now + unsigned int vectorFieldDim = 0; + + // how many vector field sets? + std::vector vectorFieldFilenames; + unsigned int firstVectorFieldIdx = 2; + unsigned int fieldSetCount = argc - firstVectorFieldIdx; + for (unsigned int i = firstVectorFieldIdx; i < firstVectorFieldIdx + fieldSetCount; i++) + { + vectorFieldFilenames.emplace_back(argv[i]); + } + + PCACalculatorType::VectorFieldSetTypePointer vectorFieldSet = PCACalculatorType::VectorFieldSetType::New(); + + testStatus = + ParseVectorFields(vectorFieldFilenames, vectorFieldSet); + + pcaCalc->SetVectorFieldSet(vectorFieldSet); + ITK_TEST_SET_GET_VALUE(vectorFieldSet, pcaCalc->GetVectorFieldSet()); + + // Execute the PCA calculator + ITK_TRY_EXPECT_NO_EXCEPTION(pcaCalc->Compute()); + + double kernelSigma = 6.25; + KernelType::Pointer distKernel = KernelType::New(); + distKernel->SetKernelSigma(kernelSigma); + pcaCalc->SetKernelFunction(distKernel); + + + // Get the output and perform basic checks + unsigned int computedNumberOfAverageVectorFieldCols = pcaCalc->GetAveVectorField().cols(); + + unsigned int computedNumberOfAverageVectorFieldRows = pcaCalc->GetAveVectorField().rows(); + + for (unsigned int j = 0; j < pcaCalc->GetComponentCount(); j++) + { + unsigned int expectedBasisVectorCols = pcaCalc->GetVectorFieldSet()->GetElement(j).cols(); + unsigned int computedBasisVectorCols = pcaCalc->GetBasisVectors()->GetElement(j).cols(); + if (computedBasisVectorCols != expectedBasisVectorCols) + { + std::cout << "Test failed!" << std::endl; + std::cout << "Error in GetBasisVectors() dimension check at index [" << j << "]" << std::endl; + std::cout << "Expected: " << expectedBasisVectorCols << " columns, but got: " << computedBasisVectorCols + << std::endl; + testStatus = EXIT_FAILURE; + } + + unsigned int expectedBasisVectorRows = pcaCalc->GetVectorFieldSet()->GetElement(j).rows(); + unsigned int computedBasisVectorRows = pcaCalc->GetBasisVectors()->GetElement(j).rows(); + if (computedBasisVectorRows != expectedBasisVectorRows) + { + std::cout << "Test failed!" << std::endl; + std::cout << "Error in GetBasisVectors() dimension check at index [" << j << "]" << std::endl; + std::cout << "Expected: " << expectedBasisVectorRows << " row, but got: " << computedBasisVectorRows << std::endl; + testStatus = EXIT_FAILURE; + } + + if (computedNumberOfAverageVectorFieldCols != expectedBasisVectorCols) + { + std::cout << "Test failed!" << std::endl; + std::cout << "Error in GetAveVectorField() dimension check at index [" << j << "]" << std::endl; + std::cout << "Expected: " << vectorFieldDim << " columns, but got: " << computedNumberOfAverageVectorFieldCols + << std::endl; + testStatus = EXIT_FAILURE; + } + + if (computedNumberOfAverageVectorFieldRows != expectedBasisVectorRows) + { + std::cout << "Test failed!" << std::endl; + std::cout << "Error in GetAveVectorField() dimension check at index [" << j << "]" << std::endl; + std::cout << "Expected: " << vectorFieldDim << " rows, but got: " << computedNumberOfAverageVectorFieldRows + << std::endl; + testStatus = EXIT_FAILURE; + } + } + + unsigned int computedNumberOfEigenValueVectors = pcaCalc->GetPCAEigenValues().size(); + if (computedNumberOfEigenValueVectors != pcaCount) + { + std::cout << "Test failed!" << std::endl; + std::cout << "Error in GetPCAEigenValues() dimension check." << std::endl; + std::cout << "Expected: " << pcaCount << ", but got: " << computedNumberOfEigenValueVectors << std::endl; + testStatus = EXIT_FAILURE; + } + + // Test exception when trying to compute with a requested input count greater + // than the number of vector field sets + pcaCalc->SetComponentCount(fieldSetCount + 1); + + ITK_TRY_EXPECT_EXCEPTION(pcaCalc->Compute()); + + std::cout << "Test finished." << std::endl; + return testStatus; +} diff --git a/Modules/Numerics/PrincipalComponentsAnalysis/wrapping/CMakeLists.txt b/Modules/Numerics/PrincipalComponentsAnalysis/wrapping/CMakeLists.txt new file mode 100644 index 00000000000..de38eb1e8bd --- /dev/null +++ b/Modules/Numerics/PrincipalComponentsAnalysis/wrapping/CMakeLists.txt @@ -0,0 +1,4 @@ +itk_wrap_module(PrincipalComponentsAnalysis) +set(WRAPPER_SUBMODULE_ORDER) +itk_auto_load_submodules() +itk_end_wrap_module() diff --git a/Modules/Numerics/PrincipalComponentsAnalysis/wrapping/itkGaussianDistanceKernel.wrap b/Modules/Numerics/PrincipalComponentsAnalysis/wrapping/itkGaussianDistanceKernel.wrap new file mode 100644 index 00000000000..3277fd74733 --- /dev/null +++ b/Modules/Numerics/PrincipalComponentsAnalysis/wrapping/itkGaussianDistanceKernel.wrap @@ -0,0 +1,7 @@ +set(WRAPPER_AUTO_INCLUDE_HEADERS OFF) +itk_wrap_include("itkVectorFieldPCA.h") +itk_wrap_class("itk::GaussianDistanceKernel" POINTER) +foreach(r ${WRAP_ITK_REAL}) + itk_wrap_template("${ITKM_${r}}" "${ITKT_${r}}") +endforeach() +itk_end_wrap_class() diff --git a/Modules/Remote/PrincipalComponentsAnalysis.remote.cmake b/Modules/Remote/PrincipalComponentsAnalysis.remote.cmake deleted file mode 100644 index 4c15f7e3d2c..00000000000 --- a/Modules/Remote/PrincipalComponentsAnalysis.remote.cmake +++ /dev/null @@ -1,56 +0,0 @@ -#-- # Grading Level Criteria Report -#-- EVALUATION DATE: 2020-03-01 -#-- EVALUATORS: [<>,<>] -#-- -#-- ## Compliance level 5 star (AKA ITK main modules, or remote modules that could become core modules) -#-- - [ ] Widespread community dependance -#-- - [ ] Above 90% code coverage -#-- - [ ] CI dashboards and testing monitored rigorously -#-- - [ ] Key API features are exposed in wrapping interface -#-- - [ ] All requirements of Levels 4,3,2,1 -#-- -#-- ## Compliance Level 4 star (Very high-quality code, perhaps small community dependance) -#-- - [ ] Meets all ITK code style standards -#-- - [ ] No external requirements beyond those needed by ITK proper -#-- - [ ] Builds and passes tests on all supported platforms within 1 month of each core tagged release -#-- - [ ] Windows Shared Library Build with Visual Studio -#-- - [ ] Mac with clang compiller -#-- - [ ] Linux with gcc compiler -#-- - [ ] Active developer community dedicated to maintaining code-base -#-- - [ ] 75% code coverage demonstrated for testing suite -#-- - [ ] Continuous integration testing performed -#-- - [ ] All requirements of Levels 3,2,1 -#-- -#-- ## Compliance Level 3 star (Quality beta code) -#-- - [ ] API | executable interface is considered mostly stable and feature complete -#-- - [ ] 10% C0-code coverage demonstrated for testing suite -#-- - [ ] Some tests exist and pass on at least some platform -#-- - [X] All requirements of Levels 2,1 -#-- -#-- ## Compliance Level 2 star (Alpha code feature API development or niche community/execution environment dependance ) -#-- - [X] Compiles for at least 1 niche set of execution envirionments, and perhaps others -#-- (may depend on specific external tools like a java environment, or specific external libraries to work ) -#-- - [X] All requirements of Levels 1 -#-- -#-- ## Compliance Level 1 star (Pre-alpha features under development and code of unknown quality) -#-- - [X] Code complies on at least 1 platform -#-- -#-- ## Compliance Level 0 star ( Code/Feature of known poor-quality or deprecated status ) -#-- - [ ] Code reviewed and explicitly identified as not recommended for use -#-- -#-- ### Please document here any justification for the criteria above -# Code style enforced by clang-format on 2020-02-19, and clang-tidy modernizations completed - -# Contact: Johan Andruejol -itk_fetch_module( - PrincipalComponentsAnalysis - "An ITK_-based implementation of principal components analysis. -A more detailed description can be found in the Insight Journal article: - Bowers M., Younes L. ''Principal Components Analysis of Scalar, Vector, and Mesh Vertex Data.'' - https://doi.org/10.54294/loekqj - August, 2013. -" - MODULE_COMPLIANCE_LEVEL 2 - GIT_REPOSITORY https://github.com/InsightSoftwareConsortium/ITKPrincipalComponentsAnalysis.git - GIT_TAG 88e3f65aabdc9cf2c11f03907975a4e605676504 - ) diff --git a/Utilities/Maintenance/RemoteModuleIngest/whitelists/PrincipalComponentsAnalysis.list b/Utilities/Maintenance/RemoteModuleIngest/whitelists/PrincipalComponentsAnalysis.list new file mode 100644 index 00000000000..1297ab5fe37 --- /dev/null +++ b/Utilities/Maintenance/RemoteModuleIngest/whitelists/PrincipalComponentsAnalysis.list @@ -0,0 +1,8 @@ +# PrincipalComponentsAnalysis — files that migrate into ITK at +# Modules/Numerics/PrincipalComponentsAnalysis/ +include +test +wrapping +CMakeLists.txt +itk-module.cmake +LICENSE diff --git a/pyproject.toml b/pyproject.toml index c73ae38c83d..00f4f39346e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -62,6 +62,7 @@ cmd = '''cmake \ -DModule_MeshNoise:BOOL=ON \ -DModule_MGHIO:BOOL=ON \ -DModule_PolarTransform:BOOL=ON \ + -DModule_PrincipalComponentsAnalysis:BOOL=ON \ -DModule_SplitComponents:BOOL=ON \ -DModule_IOMeshMZ3:BOOL=ON \ -DModule_IOFDF:BOOL=ON \