diff --git a/Modules/Filtering/HigherOrderAccurateGradient/CMakeLists.txt b/Modules/Filtering/HigherOrderAccurateGradient/CMakeLists.txt new file mode 100644 index 00000000000..e56131d5a48 --- /dev/null +++ b/Modules/Filtering/HigherOrderAccurateGradient/CMakeLists.txt @@ -0,0 +1,3 @@ +project(HigherOrderAccurateGradient) + +itk_module_impl() diff --git a/Modules/Filtering/HigherOrderAccurateGradient/README.md b/Modules/Filtering/HigherOrderAccurateGradient/README.md new file mode 100644 index 00000000000..98adbf9706b --- /dev/null +++ b/Modules/Filtering/HigherOrderAccurateGradient/README.md @@ -0,0 +1,25 @@ +# HigherOrderAccurateGradient + +In-tree ITK module providing higher-order accurate numerical +derivative and gradient image filters. The flagship classes +`itk::HigherOrderAccurateDerivativeImageFilter`, +`itk::HigherOrderAccurateDerivativeOperator`, and +`itk::HigherOrderAccurateGradientImageFilter` compute centered finite +differences of arbitrary even order on N-dimensional scalar images. + +## Origin + +Ingested from the standalone remote module +[**InsightSoftwareConsortium/ITKHigherOrderAccurateGradient**](https://github.com/InsightSoftwareConsortium/ITKHigherOrderAccurateGradient) +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/` directory, +which was intentionally left in the upstream archive). + +## References + +- McCormick M.M., Liu X., Jomier J., Marion C., Ibanez L. + *Higher Order Accurate Derivative and Gradient Calculation in ITK.* + The Insight Journal. January-December. 2014. + diff --git a/Modules/Filtering/HigherOrderAccurateGradient/include/itkHigherOrderAccurateDerivativeImageFilter.h b/Modules/Filtering/HigherOrderAccurateGradient/include/itkHigherOrderAccurateDerivativeImageFilter.h new file mode 100644 index 00000000000..065bce56efa --- /dev/null +++ b/Modules/Filtering/HigherOrderAccurateGradient/include/itkHigherOrderAccurateDerivativeImageFilter.h @@ -0,0 +1,161 @@ +/*========================================================================= + * + * 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 itkHigherOrderAccurateDerivativeImageFilter_h +#define itkHigherOrderAccurateDerivativeImageFilter_h + +#include "itkImageToImageFilter.h" + +namespace itk +{ + +/** \class HigherOrderAccurateDerivativeImageFilter + * \brief Computes the higher order accurate directional derivative of an image. + * The directional derivative at each pixel location is computed by convolution + * with a higher order accurate derivative operator of user-specified order. + * + * SetOrder() specifies the order of the derivative. + * + * SetDirection() specifies the direction of the derivative with respect to the + * coordinate axes of the image. + * + * To specify the order of accuracy, use SetOrderOfAccuracy(). The + * approximation will be accurate to two times the OrderOfAccuracy in terms of + * Taylor series terms. + * + * \sa Image + * \sa Neighborhood + * \sa NeighborhoodOperator + * \sa NeighborhoodIterator + * + * \ingroup ImageFeatureExtraction + * \ingroup HigherOrderAccurateGradient + */ +template +class HigherOrderAccurateDerivativeImageFilter : public ImageToImageFilter +{ +public: + ITK_DISALLOW_COPY_AND_MOVE(HigherOrderAccurateDerivativeImageFilter); + + /** Standard class type alias. */ + using Self = HigherOrderAccurateDerivativeImageFilter; + using Superclass = ImageToImageFilter; + using Pointer = SmartPointer; + using ConstPointer = SmartPointer; + + /** Extract some information from the image types. Dimensionality + * of the two images is assumed to be the same. */ + using OutputPixelType = typename TOutputImage::PixelType; + using OutputInternalPixelType = typename TOutputImage::InternalPixelType; + using InputPixelType = typename TInputImage::PixelType; + using InputInternalPixelType = typename TInputImage::InternalPixelType; + + /** Extract some information from the image types. Dimensionality + * of the two images is assumed to be the same. */ + static constexpr unsigned int ImageDimension = TOutputImage::ImageDimension; + + /** Image type alias support. */ + using InputImageType = TInputImage; + using OutputImageType = TOutputImage; + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** Run-time type information (and related methods). */ + itkTypeMacro(HigherOrderAccurateDerivativeImageFilter, ImageToImageFilter); + + /** The output pixel type must be signed. */ +#ifdef ITK_USE_CONCEPT_CHECKING + /** Begin concept checking */ + itkConceptMacro(SignedOutputPixelType, (Concept::Signed)); + /** End concept checking */ +#endif + + /** Standard get/set macros for filter parameters. */ + itkSetMacro(Order, unsigned int); + itkGetConstMacro(Order, unsigned int); + itkSetMacro(OrderOfAccuracy, unsigned int); + itkGetConstMacro(OrderOfAccuracy, unsigned int); + itkSetMacro(Direction, unsigned int); + itkGetConstMacro(Direction, unsigned int); + + /** Use the image spacing information in calculations. Use this option if you + * want derivatives in physical space. Default is UseImageSpacingOn. */ + void + SetUseImageSpacingOn() + { + this->SetUseImageSpacing(true); + } + + /** Ignore the image spacing. Use this option if you want derivatives in + isotropic pixel space. Default is UseImageSpacingOn. */ + void + SetUseImageSpacingOff() + { + this->SetUseImageSpacing(false); + } + + /** Set/Get whether or not the filter will use the spacing of the input + image in its calculations */ + itkSetMacro(UseImageSpacing, bool); + itkGetConstMacro(UseImageSpacing, bool); + +protected: + HigherOrderAccurateDerivativeImageFilter() = default; + + ~HigherOrderAccurateDerivativeImageFilter() override = default; + void + PrintSelf(std::ostream & os, Indent indent) const override; + + /** HigherOrderAccurateDerivativeImageFilter needs a larger input requested region than + * the output requested region (larger in the direction of the + * derivative). As such, HigherOrderAccurateDerivativeImageFilter needs to provide an + * implementation for GenerateInputRequestedRegion() in order to + * inform the pipeline execution model. + * + * \sa ImageToImageFilter::GenerateInputRequestedRegion() */ + void + GenerateInputRequestedRegion() override; + + /** Standard pipeline method. While this class does not implement a + * ThreadedGenerateData(), its GenerateData() delegates all + * calculations to an NeighborhoodOperatorImageFilter. Since the + * NeighborhoodOperatorImageFilter is multithreaded, this filter is + * multithreaded by default. */ + void + GenerateData() override; + +private: + /** The order of the derivative. */ + unsigned int m_Order{ 1 }; + + /** Order of accuracy. */ + unsigned int m_OrderOfAccuracy{ 2 }; + + /** The direction of the derivative. */ + unsigned int m_Direction{ 0 }; + + bool m_UseImageSpacing{ true }; +}; + +} // end namespace itk + +#ifndef ITK_MANUAL_INSTANTIATION +# include "itkHigherOrderAccurateDerivativeImageFilter.hxx" +#endif + +#endif diff --git a/Modules/Filtering/HigherOrderAccurateGradient/include/itkHigherOrderAccurateDerivativeImageFilter.hxx b/Modules/Filtering/HigherOrderAccurateGradient/include/itkHigherOrderAccurateDerivativeImageFilter.hxx new file mode 100644 index 00000000000..a42b947a86e --- /dev/null +++ b/Modules/Filtering/HigherOrderAccurateGradient/include/itkHigherOrderAccurateDerivativeImageFilter.hxx @@ -0,0 +1,161 @@ +/*========================================================================= + * + * 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 itkHigherOrderAccurateDerivativeImageFilter_hxx +#define itkHigherOrderAccurateDerivativeImageFilter_hxx + +#include "itkNumericTraits.h" +#include "itkNeighborhoodOperatorImageFilter.h" +#include "itkHigherOrderAccurateDerivativeOperator.h" +#include "itkProgressAccumulator.h" + +namespace itk +{ + +template +void +HigherOrderAccurateDerivativeImageFilter::GenerateInputRequestedRegion() +{ + // call the superclass' implementation of this method. this should + // copy the output requested region to the input requested region + Superclass::GenerateInputRequestedRegion(); + + // get pointers to the input and output + typename Superclass::InputImagePointer inputPtr = const_cast(this->GetInput()); + + if (!inputPtr) + { + return; + } + + // Build an operator so that we can determine the kernel size + HigherOrderAccurateDerivativeOperator oper; + oper.SetDirection(m_Direction); + oper.SetOrder(m_Order); + oper.SetOrderOfAccuracy(m_OrderOfAccuracy); + oper.CreateDirectional(); + + // get a copy of the input requested region (should equal the output + // requested region) + typename TInputImage::RegionType inputRequestedRegion; + inputRequestedRegion = inputPtr->GetRequestedRegion(); + + // pad the input requested region by the operator radius + inputRequestedRegion.PadByRadius(oper.GetRadius()); + + // crop the input requested region at the input's largest possible region + if (inputRequestedRegion.Crop(inputPtr->GetLargestPossibleRegion())) + { + inputPtr->SetRequestedRegion(inputRequestedRegion); + return; + } + else + { + // Couldn't crop the region (requested region is outside the largest + // possible region). Throw an exception. + + // store what we tried to request (prior to trying to crop) + inputPtr->SetRequestedRegion(inputRequestedRegion); + + // build an exception + InvalidRequestedRegionError e(__FILE__, __LINE__); + e.SetLocation(ITK_LOCATION); + e.SetDescription("Requested region is (at least partially) outside the largest possible region."); + e.SetDataObject(inputPtr); + throw e; + } +} + + +template +void +HigherOrderAccurateDerivativeImageFilter::GenerateData() +{ + ZeroFluxNeumannBoundaryCondition nbc; + + // Define the operator value type so that we can filter integral + // images and have the proper operator defined. + using OperatorValueType = typename NumericTraits::RealType; + + // Filter + HigherOrderAccurateDerivativeOperator oper; + oper.SetDirection(m_Direction); + oper.SetOrder(m_Order); + oper.SetOrderOfAccuracy(m_OrderOfAccuracy); + oper.CreateDirectional(); + oper.FlipAxes(); + + if (m_UseImageSpacing) + { + if (this->GetInput()->GetSpacing()[m_Direction] == 0.0) + { + itkExceptionMacro(<< "Image spacing cannot be zero."); + } + else + { + oper.ScaleCoefficients(1.0 / this->GetInput()->GetSpacing()[m_Direction]); + } + } + + typename NeighborhoodOperatorImageFilter::Pointer filter = + NeighborhoodOperatorImageFilter::New(); + + // Create a process accumulator for tracking the progress of this minipipeline + ProgressAccumulator::Pointer progress = ProgressAccumulator::New(); + progress->SetMiniPipelineFilter(this); + + // Register the filter with the with progress accumulator using + // equal weight proportion + progress->RegisterInternalFilter(filter, 1.0f); + + filter->OverrideBoundaryCondition(&nbc); + + // + // Set up the mini-pipline + // + filter->SetOperator(oper); + filter->SetInput(this->GetInput()); + + // Graft this filter's output to the mini-pipeline. this sets up + // the mini-pipeline to write to this filter's output and copies + // region ivars and meta-data + filter->GraftOutput(this->GetOutput()); + + // Execute the mini-pipeline. + filter->Update(); + + // Graft the output of the mini-pipeline back onto the filter's output, + // this copies back the region ivars and meta-data. + this->GraftOutput(filter->GetOutput()); +} + + +template +void +HigherOrderAccurateDerivativeImageFilter::PrintSelf(std::ostream & os, Indent indent) const +{ + Superclass::PrintSelf(os, indent); + + os << indent << "Order: " << m_Order << std::endl; + os << indent << "OrderOfAccuracy: " << m_OrderOfAccuracy << std::endl; + os << indent << "Direction: " << m_Direction << std::endl; + os << indent << "UseImageSpacing: " << m_UseImageSpacing << std::endl; +} + +} // end namespace itk + +#endif diff --git a/Modules/Filtering/HigherOrderAccurateGradient/include/itkHigherOrderAccurateDerivativeOperator.h b/Modules/Filtering/HigherOrderAccurateGradient/include/itkHigherOrderAccurateDerivativeOperator.h new file mode 100644 index 00000000000..5a426f5798b --- /dev/null +++ b/Modules/Filtering/HigherOrderAccurateGradient/include/itkHigherOrderAccurateDerivativeOperator.h @@ -0,0 +1,166 @@ +/*========================================================================= + * + * 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 itkHigherOrderAccurateDerivativeOperator_h +#define itkHigherOrderAccurateDerivativeOperator_h + +#include "itkNeighborhoodOperator.h" + +namespace itk +{ + +/** + * \class HigherOrderAccurateDerivativeOperator + * \brief A NeighborhoodOperator for calculating an n-th order accurate derivative + * at a pixel. + * + * \brief Calculate the image derivative from a higher order accurate + * central-difference derivative kernel. + * + * Based on the work here: + * + * Khan, IR and Ohba, Ryoji. "Closed-form expressions for the finite difference + * approximations of first and higher derivatives based on Taylor series." + * Journal of Computational and Applied Mathematics. vol 107. p. 179-193. + * 1999. + * + * Khan, IR and Ohba, Ryoji. "Taylor series based finite difference + * approximations of higher-degree derivatives." Journal of Computational and + * Applied Mathematics. vol 154. p. 115-124. 2003. + * + * To specify the order of accuracy, use SetOrderOfAccuracy(). The + * approximation will be accurate to two times the OrderOfAccuracy in terms of + * Taylor series terms. + * + * @todo: implement support for higher order derivatives. + * + * \sa DerivativeOperator + * \sa NeighborhoodOperator + * \sa Neighborhood + * \sa ForwardDifferenceOperator + * \sa BackwardDifferenceOperator + * + * \ingroup Operators + * \ingroup HigherOrderAccurateGradient + */ +template > +class HigherOrderAccurateDerivativeOperator : public NeighborhoodOperator +{ +public: + /** Standard class type alias. */ + using Self = HigherOrderAccurateDerivativeOperator; + using Superclass = NeighborhoodOperator; + + using PixelType = typename Superclass::PixelType; + using PixelRealType = typename Superclass::PixelRealType; + + /** Run-time type information (and related methods). */ + itkTypeMacro(HigherOrderAccurateDerivativeOperator, NeighborhoodOperator); + + /** Constructor. */ + HigherOrderAccurateDerivativeOperator() = default; + + /** Copy constructor. */ + HigherOrderAccurateDerivativeOperator(const Self & other) + : NeighborhoodOperator(other) + { + m_Order = other.m_Order; + } + + /** Assignment operator */ + Self & + operator=(const Self & other) + { + Superclass::operator=(other); + m_Order = other.m_Order; + return *this; + } + + /** Sets the order of the derivative. Only `order == 1` is currently + * implemented; any other value triggers a runtime exception in + * GenerateCoefficients(). */ + void + SetOrder(const unsigned int & order) + { + this->m_Order = order; + } + + /** Returns the order of the derivative. */ + unsigned int + GetOrder() const + { + return m_Order; + } + + /** Sets the order of accuracy of the derivative. The derivative estimate will + * be accurate out to two times the given order in terms of Taylor Series terms. The + * radius of the neighborhood operator is also equal to the given order. */ + void + SetOrderOfAccuracy(const unsigned int & order) + { + this->m_OrderOfAccuracy = order; + } + + unsigned int + GetOrderOfAccuracy() const + { + return m_OrderOfAccuracy; + } + + /** Prints some debugging information */ + void + PrintSelf(std::ostream & os, Indent i) const override + { + os << i << "HigherOrderAccurateDerivativeOperator { this=" << this << ", m_Order = " << m_Order + << ", m_OrderOfAccuracy = " << m_OrderOfAccuracy << "}" << std::endl; + Superclass::PrintSelf(os, i.GetNextIndent()); + } + +protected: + /** Typedef support for coefficient vector type. Necessary to + * work around compiler bug on VC++. */ + using CoefficientVector = typename Superclass::CoefficientVector; + + /** Calculates operator coefficients. */ + CoefficientVector + GenerateCoefficients() override; + + /** Arranges coefficients spatially in the memory buffer. */ + void + Fill(const CoefficientVector & coeff) override + { + Superclass::FillCenteredDirectional(coeff); + } + +private: + CoefficientVector + GenerateFirstOrderCoefficients(); + + /** Order of the derivative. */ + unsigned int m_Order{ 1 }; + + /** Order of accuracy. */ + unsigned int m_OrderOfAccuracy{ 2 }; +}; + +} // namespace itk + +#ifndef ITK_MANUAL_INSTANTIATION +# include "itkHigherOrderAccurateDerivativeOperator.hxx" +#endif + +#endif diff --git a/Modules/Filtering/HigherOrderAccurateGradient/include/itkHigherOrderAccurateDerivativeOperator.hxx b/Modules/Filtering/HigherOrderAccurateGradient/include/itkHigherOrderAccurateDerivativeOperator.hxx new file mode 100644 index 00000000000..73ed9621e68 --- /dev/null +++ b/Modules/Filtering/HigherOrderAccurateGradient/include/itkHigherOrderAccurateDerivativeOperator.hxx @@ -0,0 +1,79 @@ +/*========================================================================= + * + * 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 itkHigherOrderAccurateDerivativeOperator_hxx +#define itkHigherOrderAccurateDerivativeOperator_hxx + +#include "itkNumericTraits.h" + +namespace itk +{ + +template +typename HigherOrderAccurateDerivativeOperator::CoefficientVector +HigherOrderAccurateDerivativeOperator::GenerateCoefficients() +{ + switch (m_Order) + { + case 1: + return this->GenerateFirstOrderCoefficients(); + default: + itkExceptionMacro(<< "The specified derivative order/degree is not yet supported."); + } +} + + +template +typename HigherOrderAccurateDerivativeOperator::CoefficientVector +HigherOrderAccurateDerivativeOperator::GenerateFirstOrderCoefficients() +{ + unsigned int order = this->m_OrderOfAccuracy; + if (order == 0) + { + itkExceptionMacro(<< "OrderOfAccuracy must be >= 1."); + } + unsigned int length = 2 * order + 1; + CoefficientVector coeff(length); + + coeff[order + 1] = static_cast(order) / (order + 1); + coeff[order - 1] = -1 * coeff[order + 1]; + + unsigned int i; + // TODO Try to refactor this loop to pull out common multiplications + for (i = 1; i < order; ++i) + { + coeff[order + 1 + i] = + -1 * (i * static_cast(order - i)) / (static_cast(order + i + 1) * (i + 1)) * coeff[order + i]; + coeff[order - 1 - i] = -1 * coeff[order + 1 + i]; + } + + // We perform a flip of axes here to keep in line with + // itk::DerivativeOperator. The DerivativeImageFilter then calls FlipAxes(), + // so I am not sure why they put it in reverse order in the first place. Note + // that a flip in this case is the same as flipping the sign. + for (i = 0; i < length; ++i) + coeff[i] *= -1; + + // Center point. + coeff[order] = 0.0; + + return coeff; +} + +} // namespace itk + +#endif diff --git a/Modules/Filtering/HigherOrderAccurateGradient/include/itkHigherOrderAccurateGradientImageFilter.h b/Modules/Filtering/HigherOrderAccurateGradient/include/itkHigherOrderAccurateGradientImageFilter.h new file mode 100644 index 00000000000..efc205851fd --- /dev/null +++ b/Modules/Filtering/HigherOrderAccurateGradient/include/itkHigherOrderAccurateGradientImageFilter.h @@ -0,0 +1,169 @@ +/*========================================================================= + * + * 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 itkHigherOrderAccurateGradientImageFilter_h +#define itkHigherOrderAccurateGradientImageFilter_h + +#include "itkImageToImageFilter.h" +#include "itkCovariantVector.h" + +namespace itk +{ + +/** \class HigherOrderAccurateGradientImageFilter + * + * \brief Calculate the image gradient from a higher order accurate + * central-difference derivative kernel. + * + * Based on the work here: + * + * Khan, IR and Ohba, Ryoji. "Closed-form expressions for the finite difference + * approximations of first and higher derivatives based on Taylor series." + * Journal of Computational and Applied Mathematics. vol 107. p. 179-193. + * 1999. + * + * Khan, IR and Ohba, Ryoji. "Taylor series based finite difference + * approximations of higher-degree derivatives." Journal of Computational and + * Applied Mathematics. vol 154. p. 115-124. 2003. + * + * To specify the order of accuracy, use SetOrderOfAccuracy(). The + * approximation will be accurate to two times the OrderOfAccuracy in terms of + * Taylor series terms. + * + * \sa HigherOrderAccurateDerivativeOperator + * \sa HigherOrderAccurateDerivativeImageFilter + * + * \ingroup GradientFilters + * \ingroup HigherOrderAccurateGradient + */ +template +class HigherOrderAccurateGradientImageFilter + : public ImageToImageFilter< + TInputImage, + Image, TInputImage::ImageDimension>> +{ +public: + ITK_DISALLOW_COPY_AND_MOVE(HigherOrderAccurateGradientImageFilter); + + /** Extract dimension from input image. */ + static constexpr unsigned int ImageDimension = TInputImage::ImageDimension; + + /** Standard class type alias. */ + using Self = HigherOrderAccurateGradientImageFilter; + + /** Convenient type alias for simplifying declarations. */ + using InputImageType = TInputImage; + using InputImagePointer = typename InputImageType::Pointer; + using OutputImageType = Image, + itkGetStaticConstMacro(OutputImageDimension)>; + using OutputImagePointer = typename OutputImageType::Pointer; + + /** Standard class type alias. */ + using Superclass = ImageToImageFilter; + using Pointer = SmartPointer; + using ConstPointer = SmartPointer; + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** Run-time type information (and related methods). */ + itkTypeMacro(HigherOrderAccurateGradientImageFilter, ImageToImageFilter); + + /** Image type alias support. */ + using InputPixelType = typename InputImageType::PixelType; + using OperatorValueType = TOperatorValueType; + using OutputValueType = TOutputValueType; + using OutputPixelType = CovariantVector; + using OutputImageRegionType = typename OutputImageType::RegionType; + + /** Set/Get whether or not the filter will use the spacing of the input + image in its calculations */ + itkSetMacro(UseImageSpacing, bool); + itkGetConstMacro(UseImageSpacing, bool); + itkBooleanMacro(UseImageSpacing); + +#ifdef ITK_USE_CONCEPT_CHECKING + /** Begin concept checking */ + itkConceptMacro(InputConvertibleToOutputCheck, (Concept::Convertible)); + itkConceptMacro(OutputHasNumericTraitsCheck, (Concept::HasNumericTraits)); + /** End concept checking */ +#endif + + /** The UseImageDirection flag determines whether image derivatives are + * computed with respect to the image grid or with respect to the physical + * space. When this flag is ON the derivatives are computed with respect to + * the coodinate system of physical space. The difference is whether we take + * into account the image Direction or not. The flag ON will take into + * account the image direction and will result in an extra matrix + * multiplication compared to the amount of computation performed when the + * flag is OFF. + * The default value of this flag is On. + */ + itkSetMacro(UseImageDirection, bool); + itkGetConstMacro(UseImageDirection, bool); + itkBooleanMacro(UseImageDirection); + + /** Set/Get the order of accuracy of the derivative operator. For more + * information, see HigherOrderAccurateDerivativeOperator. */ + itkSetMacro(OrderOfAccuracy, unsigned int); + itkGetConstMacro(OrderOfAccuracy, unsigned int); + +protected: + HigherOrderAccurateGradientImageFilter(); + ~HigherOrderAccurateGradientImageFilter() override = default; + void + PrintSelf(std::ostream & os, Indent indent) const override; + + /** GradientImageFilter needs a larger input requested region than + * the output requested region. As such, GradientImageFilter needs + * to provide an implementation for GenerateInputRequestedRegion() + * in order to inform the pipeline execution model. + * + * \sa ImageToImageFilter::GenerateInputRequestedRegion() */ + void + GenerateInputRequestedRegion() override; + + /** GradientImageFilter can be implemented as a multithreaded filter. + * Therefore, this implementation provides a ThreadedGenerateData() + * routine which is called for each processing thread. The output + * image data is allocated automatically by the superclass prior to + * calling ThreadedGenerateData(). ThreadedGenerateData can only + * write to the portion of the output image specified by the + * parameter "outputRegionForThread" + * + * \sa ImageToImageFilter::ThreadedGenerateData(), + * ImageToImageFilter::GenerateData() */ + void + DynamicThreadedGenerateData(const OutputImageRegionType & outputRegionForThread) override; + +private: + bool m_UseImageSpacing{ true }; + + // flag to take or not the image direction into account + // when computing the derivatives. + bool m_UseImageDirection{ true }; + + unsigned int m_OrderOfAccuracy{ 2 }; +}; + +} // end namespace itk + +#ifndef ITK_MANUAL_INSTANTIATION +# include "itkHigherOrderAccurateGradientImageFilter.hxx" +#endif + +#endif diff --git a/Modules/Filtering/HigherOrderAccurateGradient/include/itkHigherOrderAccurateGradientImageFilter.hxx b/Modules/Filtering/HigherOrderAccurateGradient/include/itkHigherOrderAccurateGradientImageFilter.hxx new file mode 100644 index 00000000000..f355e60da98 --- /dev/null +++ b/Modules/Filtering/HigherOrderAccurateGradient/include/itkHigherOrderAccurateGradientImageFilter.hxx @@ -0,0 +1,211 @@ +/*========================================================================= + * + * 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 itkHigherOrderAccurateGradientImageFilter_hxx +#define itkHigherOrderAccurateGradientImageFilter_hxx + +#include "itkConstNeighborhoodIterator.h" +#include "itkNeighborhoodInnerProduct.h" +#include "itkImageRegionIterator.h" +#include "itkHigherOrderAccurateDerivativeOperator.h" +#include "itkNeighborhoodAlgorithm.h" +#include "itkOffset.h" + +namespace itk +{ + +template +HigherOrderAccurateGradientImageFilter:: + HigherOrderAccurateGradientImageFilter() = default; + + +template +void +HigherOrderAccurateGradientImageFilter:: + GenerateInputRequestedRegion() +{ + // call the superclass' implementation of this method + Superclass::GenerateInputRequestedRegion(); + + // get pointers to the input and output + InputImagePointer inputPtr = const_cast(this->GetInput()); + OutputImagePointer outputPtr = this->GetOutput(); + + if (!inputPtr || !outputPtr) + { + return; + } + + // Build an operator so that we can determine the kernel size + HigherOrderAccurateDerivativeOperator oper; + oper.SetDirection(0); + oper.SetOrder(1); + oper.SetOrderOfAccuracy(this->m_OrderOfAccuracy); + oper.CreateDirectional(); + unsigned long radius = oper.GetRadius()[0]; + + // get a copy of the input requested region (should equal the output + // requested region) + typename TInputImage::RegionType inputRequestedRegion; + inputRequestedRegion = inputPtr->GetRequestedRegion(); + + // pad the input requested region by the operator radius + inputRequestedRegion.PadByRadius(radius); + + // crop the input requested region at the input's largest possible region + if (inputRequestedRegion.Crop(inputPtr->GetLargestPossibleRegion())) + { + inputPtr->SetRequestedRegion(inputRequestedRegion); + return; + } + else + { + // Couldn't crop the region (requested region is outside the largest + // possible region). Throw an exception. + + // store what we tried to request (prior to trying to crop) + inputPtr->SetRequestedRegion(inputRequestedRegion); + + // build an exception + InvalidRequestedRegionError e(__FILE__, __LINE__); + e.SetLocation(ITK_LOCATION); + e.SetDescription("Requested region is (at least partially) outside the largest possible region."); + e.SetDataObject(inputPtr); + throw e; + } +} + + +template +void +HigherOrderAccurateGradientImageFilter::DynamicThreadedGenerateData( + const OutputImageRegionType & outputRegionForThread) +{ + unsigned int i; + OutputPixelType gradient; + + ZeroFluxNeumannBoundaryCondition nbc; + + ConstNeighborhoodIterator nit; + ImageRegionIterator it; + + NeighborhoodInnerProduct SIP; + + // Get the input and output + OutputImageType * outputImage = this->GetOutput(); + const InputImageType * inputImage = this->GetInput(); + + // Set up operators + HigherOrderAccurateDerivativeOperator op[ImageDimension]; + + for (i = 0; i < ImageDimension; i++) + { + op[i].SetDirection(0); + op[i].SetOrder(1); + op[i].SetOrderOfAccuracy(this->m_OrderOfAccuracy); + op[i].CreateDirectional(); + + // Reverse order of coefficients for the convolution with the image to + // follow. + op[i].FlipAxes(); + + // Take into account the pixel spacing if necessary + if (m_UseImageSpacing) + { + if (this->GetInput()->GetSpacing()[i] == 0.0) + { + itkExceptionMacro(<< "Image spacing cannot be zero."); + } + else + { + op[i].ScaleCoefficients(1.0 / this->GetInput()->GetSpacing()[i]); + } + } + } + + // Calculate iterator radius + Size radius; + for (i = 0; i < ImageDimension; ++i) + { + radius[i] = op[0].GetRadius()[0]; + } + + // Find the data-set boundary "faces" + typename NeighborhoodAlgorithm::ImageBoundaryFacesCalculator::FaceListType faceList; + NeighborhoodAlgorithm::ImageBoundaryFacesCalculator bC; + faceList = bC(inputImage, outputRegionForThread, radius); + + typename NeighborhoodAlgorithm::ImageBoundaryFacesCalculator::FaceListType::iterator fit; + fit = faceList.begin(); + + // Initialize the x_slice array + nit = ConstNeighborhoodIterator(radius, inputImage, *fit); + + std::slice x_slice[ImageDimension]; + const unsigned long center = nit.Size() / 2; + for (i = 0; i < ImageDimension; ++i) + { + x_slice[i] = std::slice(center - nit.GetStride(i) * radius[i], op[i].GetSize()[0], nit.GetStride(i)); + } + + // Process non-boundary face and then each of the boundary faces. + // These are N-d regions which border the edge of the buffer. + for (fit = faceList.begin(); fit != faceList.end(); ++fit) + { + nit = ConstNeighborhoodIterator(radius, inputImage, *fit); + it = ImageRegionIterator(outputImage, *fit); + nit.OverrideBoundaryCondition(&nbc); + nit.GoToBegin(); + + while (!nit.IsAtEnd()) + { + for (i = 0; i < ImageDimension; ++i) + { + gradient[i] = SIP(x_slice[i], nit, op[i]); + } + + if (this->m_UseImageDirection) + { + inputImage->TransformLocalVectorToPhysicalVector(gradient, it.Value()); + } + else + { + it.Value() = gradient; + } + ++nit; + ++it; + } + } +} + + +template +void +HigherOrderAccurateGradientImageFilter::PrintSelf( + std::ostream & os, + Indent indent) const +{ + Superclass::PrintSelf(os, indent); + + os << indent << "UseImageSpacing: " << (this->m_UseImageSpacing ? "On" : "Off") << std::endl; + os << indent << "UseImageDirection = " << (this->m_UseImageDirection ? "On" : "Off") << std::endl; + os << indent << "OrderOfAccuracy: " << this->m_OrderOfAccuracy << std::endl; +} + +} // end namespace itk + +#endif diff --git a/Modules/Filtering/HigherOrderAccurateGradient/itk-module.cmake b/Modules/Filtering/HigherOrderAccurateGradient/itk-module.cmake new file mode 100644 index 00000000000..e048c143122 --- /dev/null +++ b/Modules/Filtering/HigherOrderAccurateGradient/itk-module.cmake @@ -0,0 +1,14 @@ +# Maintainer: Matt McCormick +itk_module( + HigherOrderAccurateGradient + DEPENDS + ITKCommon + ITKImageGradient + ITKImageIntensity + ITKImageFeature + TEST_DEPENDS + ITKTestKernel + EXCLUDE_FROM_DEFAULT + DESCRIPTION + "Filters that compute higher-order accurate numerical derivatives and gradients from a scalar image (Insight Journal: https://www.insight-journal.org/browse/publication/775, https://hdl.handle.net/10380/3231)." +) diff --git a/Modules/Filtering/HigherOrderAccurateGradient/test/CMakeLists.txt b/Modules/Filtering/HigherOrderAccurateGradient/test/CMakeLists.txt new file mode 100644 index 00000000000..0619328aa3c --- /dev/null +++ b/Modules/Filtering/HigherOrderAccurateGradient/test/CMakeLists.txt @@ -0,0 +1,36 @@ +itk_module_test() + +set( + HigherOrderAccurateGradientTests + itkHigherOrderAccurateGradientImageFilterTest.cxx + itkHigherOrderAccurateDerivativeImageFilterTest.cxx +) + +createtestdriver(HigherOrderAccurateGradient "${HigherOrderAccurateGradient-Test_LIBRARIES}" "${HigherOrderAccurateGradientTests}") + +itk_add_test( + NAME itkHigherOrderAccurateGradientImageFilterTest + COMMAND + HigherOrderAccurateGradientTestDriver + --compare + ${ITK_TEST_OUTPUT_DIR}/itkHigherOrderAccurateGradientImageFilterTest_Accuracy1_Magnitude.mha + ${ITK_TEST_OUTPUT_DIR}/itkHigherOrderAccurateGradientImageFilterTest_GradientImageFilter_Magnitude.mha + itkHigherOrderAccurateGradientImageFilterTest + DATA{Input/foot.mha} + ${ITK_TEST_OUTPUT_DIR}/itkHigherOrderAccurateGradientImageFilterTest +) + +itk_add_test( + NAME itkHigherOrderAccurateDerivativeImageFilterTest + COMMAND + HigherOrderAccurateGradientTestDriver + --compare + ${ITK_TEST_OUTPUT_DIR}/itkHigherOrderAccurateDerivativeImageFilterTest_Accuracy1_Direction0.mha + ${ITK_TEST_OUTPUT_DIR}/itkHigherOrderAccurateDerivativeImageFilterTest_DerivativeImageFilter_Direction0.mha + --compare + ${ITK_TEST_OUTPUT_DIR}/itkHigherOrderAccurateDerivativeImageFilterTest_Accuracy1_Direction1.mha + ${ITK_TEST_OUTPUT_DIR}/itkHigherOrderAccurateDerivativeImageFilterTest_DerivativeImageFilter_Direction1.mha + itkHigherOrderAccurateDerivativeImageFilterTest + DATA{Input/foot.mha} + ${ITK_TEST_OUTPUT_DIR}/itkHigherOrderAccurateDerivativeImageFilterTest +) diff --git a/Modules/Filtering/HigherOrderAccurateGradient/test/Input/foot.mha.cid b/Modules/Filtering/HigherOrderAccurateGradient/test/Input/foot.mha.cid new file mode 100644 index 00000000000..cb03d7b09a1 --- /dev/null +++ b/Modules/Filtering/HigherOrderAccurateGradient/test/Input/foot.mha.cid @@ -0,0 +1 @@ +bafkreicsnenkzoqwpvk5qscxqdmavlmfjmb3totuplgy6btdkiauwj5gma diff --git a/Modules/Filtering/HigherOrderAccurateGradient/test/itkHigherOrderAccurateDerivativeImageFilterTest.cxx b/Modules/Filtering/HigherOrderAccurateGradient/test/itkHigherOrderAccurateDerivativeImageFilterTest.cxx new file mode 100644 index 00000000000..9fb7d05c61d --- /dev/null +++ b/Modules/Filtering/HigherOrderAccurateGradient/test/itkHigherOrderAccurateDerivativeImageFilterTest.cxx @@ -0,0 +1,94 @@ +/*========================================================================= + * + * 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 "itkDerivativeImageFilter.h" +#include "itkImageFileReader.h" +#include "itkImageFileWriter.h" + +#include "itkHigherOrderAccurateDerivativeImageFilter.h" + +int +itkHigherOrderAccurateDerivativeImageFilterTest(int argc, char * argv[]) +{ + if (argc < 3) + { + std::cerr << "Usage: " << argv[0]; + std::cerr << " inputImage outputPrefix "; + std::cerr << std::endl; + return EXIT_FAILURE; + } + + constexpr unsigned int Dimension = 2; + using PixelType = float; + using ImageType = itk::Image; + + std::string outputPrefix = argv[2]; + + using ReaderType = itk::ImageFileReader; + ReaderType::Pointer reader = ReaderType::New(); + reader->SetFileName(argv[1]); + + using HigherFilterType = itk::HigherOrderAccurateDerivativeImageFilter; + HigherFilterType::Pointer nthFilter = HigherFilterType::New(); + nthFilter->SetInput(reader->GetOutput()); + nthFilter->SetOrder(1); + + using WriterType = itk::ImageFileWriter; + WriterType::Pointer nthWriter = WriterType::New(); + nthWriter->SetInput(nthFilter->GetOutput()); + + // First order accurate. + using FirstFilterType = itk::DerivativeImageFilter; + FirstFilterType::Pointer firstFilter = FirstFilterType::New(); + firstFilter->SetInput(reader->GetOutput()); + firstFilter->SetOrder(1); + + using WriterType = itk::ImageFileWriter; + WriterType::Pointer firstWriter = WriterType::New(); + firstWriter->SetInput(firstFilter->GetOutput()); + + std::ostringstream ostrm; + try + { + for (unsigned int direction = 0; direction < 2; ++direction) + { + firstFilter->SetDirection(direction); + ostrm.str(""); + ostrm << outputPrefix << "_DerivativeImageFilter_Direction" << direction << ".mha"; + firstWriter->SetFileName(ostrm.str()); + firstWriter->Update(); + + for (unsigned int accuracy = 1; accuracy < 6; ++accuracy) + { + nthFilter->SetDirection(direction); + nthFilter->SetOrderOfAccuracy(accuracy); + ostrm.str(""); + ostrm << outputPrefix << "_Accuracy" << accuracy << "_Direction" << direction << ".mha"; + nthWriter->SetFileName(ostrm.str()); + nthWriter->Update(); + } + } + } + catch (itk::ExceptionObject & ex) + { + std::cerr << "Exception caught!" << std::endl; + std::cerr << ex << std::endl; + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/Modules/Filtering/HigherOrderAccurateGradient/test/itkHigherOrderAccurateGradientImageFilterTest.cxx b/Modules/Filtering/HigherOrderAccurateGradient/test/itkHigherOrderAccurateGradientImageFilterTest.cxx new file mode 100644 index 00000000000..d23e0d00d26 --- /dev/null +++ b/Modules/Filtering/HigherOrderAccurateGradient/test/itkHigherOrderAccurateGradientImageFilterTest.cxx @@ -0,0 +1,89 @@ +/*========================================================================= + * + * 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 "itkGradientImageFilter.h" +#include "itkVectorMagnitudeImageFilter.h" +#include "itkImageFileReader.h" +#include "itkImageFileWriter.h" + +#include "itkHigherOrderAccurateGradientImageFilter.h" + +int +itkHigherOrderAccurateGradientImageFilterTest(int argc, char * argv[]) +{ + if (argc < 3) + { + std::cerr << "Usage: " << argv[0]; + std::cerr << " inputImage outputPrefix "; + std::cerr << std::endl; + return EXIT_FAILURE; + } + + constexpr unsigned int Dimension = 2; + using PixelType = float; + using ImageType = itk::Image; + + using ReaderType = itk::ImageFileReader; + ReaderType::Pointer reader = ReaderType::New(); + reader->SetFileName(argv[1]); + + // First order accurate. + using FirstFilterType = itk::GradientImageFilter; + FirstFilterType::Pointer firstFilter = FirstFilterType::New(); + firstFilter->SetInput(reader->GetOutput()); + + using FilterType = itk::HigherOrderAccurateGradientImageFilter; + using GradientImageType = FilterType::OutputImageType; + FilterType::Pointer filter = FilterType::New(); + filter->SetInput(reader->GetOutput()); + + std::string outputPrefix = argv[2]; + + using GradientMagnitudeFilterType = itk::VectorMagnitudeImageFilter; + GradientMagnitudeFilterType::Pointer gradientMagnitude = GradientMagnitudeFilterType::New(); + + using GradientMagnitudeWriterType = itk::ImageFileWriter; + GradientMagnitudeWriterType::Pointer gradientMagnitudeWriter = GradientMagnitudeWriterType::New(); + gradientMagnitudeWriter->SetInput(gradientMagnitude->GetOutput()); + + std::ostringstream ostrm; + try + { + gradientMagnitude->SetInput(firstFilter->GetOutput()); + ostrm.str(""); + ostrm << outputPrefix + "_GradientImageFilter_Magnitude.mha"; + gradientMagnitudeWriter->SetFileName(ostrm.str()); + gradientMagnitudeWriter->Update(); + gradientMagnitude->SetInput(filter->GetOutput()); + for (unsigned int accuracy = 1; accuracy < 6; ++accuracy) + { + filter->SetOrderOfAccuracy(accuracy); + ostrm.str(""); + ostrm << outputPrefix << "_Accuracy" << accuracy << "_Magnitude.mha"; + gradientMagnitudeWriter->SetFileName(ostrm.str()); + gradientMagnitudeWriter->Update(); + } + } + catch (itk::ExceptionObject & ex) + { + std::cerr << "Exception caught!" << std::endl; + std::cerr << ex << std::endl; + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/Modules/Filtering/HigherOrderAccurateGradient/wrapping/CMakeLists.txt b/Modules/Filtering/HigherOrderAccurateGradient/wrapping/CMakeLists.txt new file mode 100644 index 00000000000..838523995e4 --- /dev/null +++ b/Modules/Filtering/HigherOrderAccurateGradient/wrapping/CMakeLists.txt @@ -0,0 +1,3 @@ +itk_wrap_module(HigherOrderAccurateGradient) +itk_auto_load_submodules() +itk_end_wrap_module() diff --git a/Modules/Filtering/HigherOrderAccurateGradient/wrapping/itkHigherOrderAccurateDerivativeImageFilter.wrap b/Modules/Filtering/HigherOrderAccurateGradient/wrapping/itkHigherOrderAccurateDerivativeImageFilter.wrap new file mode 100644 index 00000000000..dcc2e92f4e0 --- /dev/null +++ b/Modules/Filtering/HigherOrderAccurateGradient/wrapping/itkHigherOrderAccurateDerivativeImageFilter.wrap @@ -0,0 +1,10 @@ +itk_wrap_class("itk::HigherOrderAccurateDerivativeImageFilter" POINTER) +foreach(d ${ITK_WRAP_IMAGE_DIMS}) + foreach(t ${WRAP_ITK_REAL}) + itk_wrap_template( + "${ITKM_I${t}${d}}${ITKM_I${t}${d}}" + "${ITKT_I${t}${d}}, ${ITKT_I${t}${d}}" + ) + endforeach() +endforeach() +itk_end_wrap_class() diff --git a/Modules/Filtering/HigherOrderAccurateGradient/wrapping/itkHigherOrderAccurateGradientImageFilter.wrap b/Modules/Filtering/HigherOrderAccurateGradient/wrapping/itkHigherOrderAccurateGradientImageFilter.wrap new file mode 100644 index 00000000000..09f2d124255 --- /dev/null +++ b/Modules/Filtering/HigherOrderAccurateGradient/wrapping/itkHigherOrderAccurateGradientImageFilter.wrap @@ -0,0 +1,10 @@ +itk_wrap_class("itk::HigherOrderAccurateGradientImageFilter" POINTER) +foreach(d ${ITK_WRAP_IMAGE_DIMS}) + foreach(t ${WRAP_ITK_REAL}) + itk_wrap_template( + "${ITKM_I${t}${d}}${ITKM_${t}}${ITKM_${t}}" + "${ITKT_I${t}${d}}, ${ITKT_${t}}, ${ITKT_${t}}" + ) + endforeach() +endforeach() +itk_end_wrap_class() diff --git a/Modules/Remote/HigherOrderAccurateGradient.remote.cmake b/Modules/Remote/HigherOrderAccurateGradient.remote.cmake deleted file mode 100644 index 9b101929e7a..00000000000 --- a/Modules/Remote/HigherOrderAccurateGradient.remote.cmake +++ /dev/null @@ -1,54 +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: Matt McCormick -itk_fetch_module( - HigherOrderAccurateGradient - "This module contains a filter to compute higher order - accurate numerical derivatives and gradients from an input scalar image. - Higher Order Accurate Derivative and Gradient Calculation in ITK - https://doi.org/10.54294/zv7979" - MODULE_COMPLIANCE_LEVEL 2 - GIT_REPOSITORY https://github.com/InsightSoftwareConsortium/ITKHigherOrderAccurateGradient.git - GIT_TAG 7c074d12718a7de9e7219b2ce27415a590411e72 - ) diff --git a/pyproject.toml b/pyproject.toml index 3f7fc02a387..4766f57dcf3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -58,6 +58,7 @@ cmd = '''cmake \ -DModule_Montage:BOOL=ON \ -DModule_FastBilateral:BOOL=ON \ -DModule_GenericLabelInterpolator:BOOL=ON \ + -DModule_HigherOrderAccurateGradient:BOOL=ON \ -DModule_IOMeshSTL:BOOL=ON \ -DModule_LabelErodeDilate:BOOL=ON \ -DModule_MeshNoise:BOOL=ON \