From 3caa7e64c49d3334199c48e2c1133c3b81152097 Mon Sep 17 00:00:00 2001 From: Nick Tustison Date: Sat, 26 Sep 2020 10:31:08 -0700 Subject: [PATCH 01/31] ENH: Initial commit. --- .../AdaptiveDenoising/CMakeLists.txt | 12 + Modules/Filtering/AdaptiveDenoising/LICENSE | 202 +++++++ ...daptiveNonLocalMeansDenoisingImageFilter.h | 86 +++ ...ptiveNonLocalMeansDenoisingImageFilter.hxx | 63 +++ ...itkMinimalStandardRandomVariateGenerator.h | 96 ++++ .../AdaptiveDenoising/itk-module.cmake | 24 + .../AdaptiveDenoising/src/CMakeLists.txt | 5 + ...daptiveNonLocalMeansDenoisingImageFilter.h | 223 ++++++++ ...ptiveNonLocalMeansDenoisingImageFilter.hxx | 525 ++++++++++++++++++ ...kMinimalStandardRandomVariateGenerator.cxx | 52 ++ .../src/itkNonLocalPatchBasedImageFilter.h | 196 +++++++ .../src/itkNonLocalPatchBasedImageFilter.hxx | 255 +++++++++ .../src/itkVarianceImageFilter.h | 115 ++++ .../src/itkVarianceImageFilter.hxx | 102 ++++ ...sDenoisingImageFilterTestOutput.mha.sha512 | 1 + .../AdaptiveDenoising/test/CMakeLists.txt | 27 + ...eNonLocalMeansDenoisingImageFilterTest.cxx | 100 ++++ ...imalStandardRandomVariateGeneratorTest.cxx | 37 ++ .../AdaptiveDenoising/wrapping/CMakeLists.txt | 3 + ...tiveNonLocalMeansDenoisingImageFilter.wrap | 3 + ...MinimalStandardRandomVariateGenerator.wrap | 1 + 21 files changed, 2128 insertions(+) create mode 100644 Modules/Filtering/AdaptiveDenoising/CMakeLists.txt create mode 100644 Modules/Filtering/AdaptiveDenoising/LICENSE create mode 100644 Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.h create mode 100644 Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.hxx create mode 100644 Modules/Filtering/AdaptiveDenoising/include/itkMinimalStandardRandomVariateGenerator.h create mode 100644 Modules/Filtering/AdaptiveDenoising/itk-module.cmake create mode 100644 Modules/Filtering/AdaptiveDenoising/src/CMakeLists.txt create mode 100644 Modules/Filtering/AdaptiveDenoising/src/itkAdaptiveNonLocalMeansDenoisingImageFilter.h create mode 100644 Modules/Filtering/AdaptiveDenoising/src/itkAdaptiveNonLocalMeansDenoisingImageFilter.hxx create mode 100644 Modules/Filtering/AdaptiveDenoising/src/itkMinimalStandardRandomVariateGenerator.cxx create mode 100644 Modules/Filtering/AdaptiveDenoising/src/itkNonLocalPatchBasedImageFilter.h create mode 100644 Modules/Filtering/AdaptiveDenoising/src/itkNonLocalPatchBasedImageFilter.hxx create mode 100644 Modules/Filtering/AdaptiveDenoising/src/itkVarianceImageFilter.h create mode 100644 Modules/Filtering/AdaptiveDenoising/src/itkVarianceImageFilter.hxx create mode 100644 Modules/Filtering/AdaptiveDenoising/test/Baseline/itkAdaptiveNonLocalMeansDenoisingImageFilterTestOutput.mha.sha512 create mode 100644 Modules/Filtering/AdaptiveDenoising/test/CMakeLists.txt create mode 100644 Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx create mode 100644 Modules/Filtering/AdaptiveDenoising/test/itkMinimalStandardRandomVariateGeneratorTest.cxx create mode 100644 Modules/Filtering/AdaptiveDenoising/wrapping/CMakeLists.txt create mode 100644 Modules/Filtering/AdaptiveDenoising/wrapping/itkAdaptiveNonLocalMeansDenoisingImageFilter.wrap create mode 100644 Modules/Filtering/AdaptiveDenoising/wrapping/itkMinimalStandardRandomVariateGenerator.wrap diff --git a/Modules/Filtering/AdaptiveDenoising/CMakeLists.txt b/Modules/Filtering/AdaptiveDenoising/CMakeLists.txt new file mode 100644 index 000000000000..e683ff492f87 --- /dev/null +++ b/Modules/Filtering/AdaptiveDenoising/CMakeLists.txt @@ -0,0 +1,12 @@ +project(AdaptiveDenoising) + +set(AdaptiveDenoising_LIBRARIES AdaptiveDenoising) + +if(NOT ITK_SOURCE_DIR) + find_package(ITK REQUIRED) + list(APPEND CMAKE_MODULE_PATH ${ITK_CMAKE_DIR}) + include(ITKModuleExternal) +else() + set(ITK_DIR ${CMAKE_BINARY_DIR}) + itk_module_impl() +endif() diff --git a/Modules/Filtering/AdaptiveDenoising/LICENSE b/Modules/Filtering/AdaptiveDenoising/LICENSE new file mode 100644 index 000000000000..d64569567334 --- /dev/null +++ b/Modules/Filtering/AdaptiveDenoising/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.h b/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.h new file mode 100644 index 000000000000..64c75b351050 --- /dev/null +++ b/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.h @@ -0,0 +1,86 @@ +/*========================================================================= + * + * 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 + * + * http://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 itkAdaptiveNonLocalMeansDenoisingImageFilter_h +#define itkAdaptiveNonLocalMeansDenoisingImageFilter_h + +#include "itkImageToImageFilter.h" + +namespace itk +{ + +/** \class AdaptiveNonLocalMeansDenoisingImageFilter + * + * \brief Filters a image by iterating over its pixels. + * + * Filters a image by iterating over its pixels in a multi-threaded way + * and {to be completed by the developer}. + * + * \ingroup AdaptiveDenoising + * + */ +template +class AdaptiveNonLocalMeansDenoisingImageFilter : public ImageToImageFilter +{ +public: + ITK_DISALLOW_COPY_AND_ASSIGN(AdaptiveNonLocalMeansDenoisingImageFilter); + + static constexpr unsigned int InputImageDimension = TInputImage::ImageDimension; + static constexpr unsigned int OutputImageDimension = TOutputImage::ImageDimension; + + using InputImageType = TInputImage; + using OutputImageType = TOutputImage; + using InputPixelType = typename InputImageType::PixelType; + using OutputPixelType = typename OutputImageType::PixelType; + + /** Standard class typedefs. */ + using Self = AdaptiveNonLocalMeansDenoisingImageFilter; + using Superclass = ImageToImageFilter; + using Pointer = SmartPointer; + using ConstPointer = SmartPointer; + + /** Run-time type information. */ + itkTypeMacro(AdaptiveNonLocalMeansDenoisingImageFilter, ImageToImageFilter); + + /** Standard New macro. */ + itkNewMacro(Self); + +protected: + AdaptiveNonLocalMeansDenoisingImageFilter(); + ~AdaptiveNonLocalMeansDenoisingImageFilter() override = default; + + void + PrintSelf(std::ostream & os, Indent indent) const override; + + using OutputRegionType = typename OutputImageType::RegionType; + + void + DynamicThreadedGenerateData(const OutputRegionType & outputRegion) override; + +private: +#ifdef ITK_USE_CONCEPT_CHECKING + // Add concept checking such as + // itkConceptMacro( FloatingPointPixel, ( itk::Concept::IsFloatingPoint< typename InputImageType::PixelType > ) ); +#endif +}; +} // namespace itk + +#ifndef ITK_MANUAL_INSTANTIATION +# include "itkAdaptiveNonLocalMeansDenoisingImageFilter.hxx" +#endif + +#endif // itkAdaptiveNonLocalMeansDenoisingImageFilter diff --git a/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.hxx b/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.hxx new file mode 100644 index 000000000000..d407607e35a6 --- /dev/null +++ b/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.hxx @@ -0,0 +1,63 @@ +/*========================================================================= + * + * 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 + * + * http://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 itkAdaptiveNonLocalMeansDenoisingImageFilter_hxx +#define itkAdaptiveNonLocalMeansDenoisingImageFilter_hxx + +#include "itkAdaptiveNonLocalMeansDenoisingImageFilter.h" + +#include "itkImageRegionIterator.h" +#include "itkImageRegionConstIterator.h" + +namespace itk +{ + +template +AdaptiveNonLocalMeansDenoisingImageFilter::AdaptiveNonLocalMeansDenoisingImageFilter() +{} + + +template +void +AdaptiveNonLocalMeansDenoisingImageFilter::PrintSelf(std::ostream & os, Indent indent) const +{ + Superclass::PrintSelf(os, indent); +} + + +template +void +AdaptiveNonLocalMeansDenoisingImageFilter::DynamicThreadedGenerateData( + const OutputRegionType & outputRegion) +{ + OutputImageType * output = this->GetOutput(); + const InputImageType * input = this->GetInput(); + using InputRegionType = typename InputImageType::RegionType; + InputRegionType inputRegion = InputRegionType(outputRegion.GetSize()); + + itk::ImageRegionConstIterator in(input, inputRegion); + itk::ImageRegionIterator out(output, outputRegion); + + for (in.GoToBegin(), out.GoToBegin(); !in.IsAtEnd() && !out.IsAtEnd(); ++in, ++out) + { + out.Set(in.Get()); + } +} + +} // end namespace itk + +#endif // itkAdaptiveNonLocalMeansDenoisingImageFilter_hxx diff --git a/Modules/Filtering/AdaptiveDenoising/include/itkMinimalStandardRandomVariateGenerator.h b/Modules/Filtering/AdaptiveDenoising/include/itkMinimalStandardRandomVariateGenerator.h new file mode 100644 index 000000000000..3a6be913d94a --- /dev/null +++ b/Modules/Filtering/AdaptiveDenoising/include/itkMinimalStandardRandomVariateGenerator.h @@ -0,0 +1,96 @@ +/*========================================================================= + * + * 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 + * + * http://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 itkMinimalStandardRandomVariateGenerator_h +#define itkMinimalStandardRandomVariateGenerator_h + +#include "itkIntTypes.h" +#include "itkObjectFactory.h" +#include "itkRandomVariateGeneratorBase.h" +#include "AdaptiveDenoisingExport.h" +#include "itkNormalVariateGenerator.h" + +namespace itk +{ +namespace Statistics +{ +/** \class MinimalStandardRandomVariateGenerator + * \brief Linear congruential random random variate generator. + * + * This is a pseudo-random number generator for unsigned integers following + * + * \f[ + * X_{n+1} = (a X_n + c) \mod m + * \f] + * + * where \f$a\f$ is the Multiplier \f$c\f$ is the Increment and \f$m\f$ is + * the Modulus. + * + * http://en.wikipedia.com/wiki/Linear_congruential_generator + * + * The random numbers generated have a period \f$m\f$. + * + * This class uses \f$a = 48271\f$, \f$c = 0\f$, \f$m = 2^31 -1 = + * 2147483647\f$, the Minimial Standard configuration recommended by Park, + * Miller and Stockmeyer in 1993. + * + * \ingroup AdaptiveDenoising + */ +class AdaptiveDenoising_EXPORT MinimalStandardRandomVariateGenerator : public RandomVariateGeneratorBase +{ +public: + ITK_DISALLOW_COPY_AND_ASSIGN(MinimalStandardRandomVariateGenerator); + + /** Standard class typedefs. */ + using Self = MinimalStandardRandomVariateGenerator; + using Superclass = RandomVariateGeneratorBase; + using Pointer = SmartPointer; + using ConstPointer = SmartPointer; + + using IntegerType = uint32_t; + + using NormalGeneratorType = itk::Statistics::NormalVariateGenerator; + + /** Run-time type information (and related methods). */ + itkTypeMacro(MinimalStandardRandomVariateGenerator, RandomVariateGeneratorBase); + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** initialize with a simple IntegerType */ + void + Initialize(int randomSeed); + + /** Get a variate in the range [0, 1] */ + double + GetVariate() override; + +protected: + MinimalStandardRandomVariateGenerator(); + ~MinimalStandardRandomVariateGenerator() override = default; + + void + PrintSelf(std::ostream & os, Indent indent) const override; + +private: + NormalGeneratorType::Pointer m_NormalGenerator; +}; + +} // end of namespace Statistics +} // end of namespace itk + +#endif // itkMinimalStandardRandomVariateGenerator_h diff --git a/Modules/Filtering/AdaptiveDenoising/itk-module.cmake b/Modules/Filtering/AdaptiveDenoising/itk-module.cmake new file mode 100644 index 000000000000..de3b940c428a --- /dev/null +++ b/Modules/Filtering/AdaptiveDenoising/itk-module.cmake @@ -0,0 +1,24 @@ +# the top-level README is used for describing this module, just +# re-used it for documentation here +# itk_module() defines the module dependencies in AdaptiveDenoising +# AdaptiveDenoising depends on ITKCommon +# The testing module in AdaptiveDenoising depends on ITKTestKernel +# and ITKMetaIO(besides AdaptiveDenoising and ITKCore) +# By convention those modules outside of ITK are not prefixed with +# ITK. + +# define the dependencies of the include module and the tests +itk_module( + AdaptiveDenoising + DEPENDS + ITKCommon + ITKStatistics + COMPILE_DEPENDS + ITKImageSources + TEST_DEPENDS + ITKTestKernel + ITKMetaIO + DESCRIPTION "Module ingested from upstream." + EXCLUDE_FROM_DEFAULT + ENABLE_SHARED +) diff --git a/Modules/Filtering/AdaptiveDenoising/src/CMakeLists.txt b/Modules/Filtering/AdaptiveDenoising/src/CMakeLists.txt new file mode 100644 index 000000000000..77d4bd24ee3e --- /dev/null +++ b/Modules/Filtering/AdaptiveDenoising/src/CMakeLists.txt @@ -0,0 +1,5 @@ +set(AdaptiveDenoising_SRCS + itkMinimalStandardRandomVariateGenerator.cxx + ) + +itk_module_add_library(AdaptiveDenoising ${AdaptiveDenoising_SRCS}) diff --git a/Modules/Filtering/AdaptiveDenoising/src/itkAdaptiveNonLocalMeansDenoisingImageFilter.h b/Modules/Filtering/AdaptiveDenoising/src/itkAdaptiveNonLocalMeansDenoisingImageFilter.h new file mode 100644 index 000000000000..463e11004489 --- /dev/null +++ b/Modules/Filtering/AdaptiveDenoising/src/itkAdaptiveNonLocalMeansDenoisingImageFilter.h @@ -0,0 +1,223 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.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 itkAdaptiveNonLocalMeansDenoisingImageFilter_h +#define itkAdaptiveNonLocalMeansDenoisingImageFilter_h + +#include "itkNonLocalPatchBasedImageFilter.h" + +#include "itkConstNeighborhoodIterator.h" +#include "itkGaussianOperator.h" + +namespace itk +{ + +/** + * \class AdaptiveNonLocalMeansDenoisingImageFilter + * \brief Implementation of a denoising image filter. + * + * \author Jose V. Manjon with ITK porting by Nick Tustison + * + * Contributed by + * + * \par REFERENCE + * + * J. V. Manjon, P. Coupe, Luis Marti-Bonmati, D. L. Collins, + * and M. Robles. "Adaptive Non-Local Means Denoising of MR Images With + * Spatially Varying Noise Levels, Journal of Magnetic Resonance Imaging, + * 31:192-203, June 2010. + * + * \ingroup ITKNoiseFiltering + */ + +template > +class AdaptiveNonLocalMeansDenoisingImageFilter final : public NonLocalPatchBasedImageFilter +{ +public: + /** Standard class typedefs. */ + typedef AdaptiveNonLocalMeansDenoisingImageFilter Self; + typedef NonLocalPatchBasedImageFilter Superclass; + typedef SmartPointer Pointer; + typedef SmartPointer ConstPointer; + + /** Runtime information support. */ + itkTypeMacro(AdaptiveNonLocalMeansDenoisingImageFilter, NonLocalPatchBasedImageFilter); + + /** Standard New method. */ + itkNewMacro(Self); + + /** ImageDimension constants */ + itkStaticConstMacro(ImageDimension, unsigned int, TInputImage::ImageDimension); + + /** Some convenient typedefs. */ + typedef TInputImage InputImageType; + typedef typename InputImageType::PixelType InputPixelType; + typedef TOutputImage OutputImageType; + typedef typename Superclass::RegionType RegionType; + + typedef TMaskImage MaskImageType; + typedef typename MaskImageType::PixelType MaskPixelType; + typedef typename MaskImageType::PixelType LabelType; + + typedef typename Superclass::RealType RealType; + typedef typename Superclass::RealImageType RealImageType; + typedef typename Superclass::RealImagePointer RealImagePointer; + typedef typename Superclass::IndexType IndexType; + + typedef typename Superclass::ConstNeighborhoodIteratorType ConstNeighborhoodIteratorType; + typedef typename Superclass::NeighborhoodRadiusType NeighborhoodRadiusType; + typedef typename Superclass::NeighborhoodOffsetType NeighborhoodOffsetType; + typedef typename Superclass::NeighborhoodOffsetListType NeighborhoodOffsetListType; + + typedef GaussianOperator ModifiedBesselCalculatorType; + + /** + * The image expected for input for noise correction. + */ + void + SetInput1(const InputImageType * image) + { + this->SetInput(image); + } + + /** + * Set mask image function. If a binary mask image is specified, only + * those input image voxels corresponding with the mask image. + */ + void + SetMaskImage(const MaskImageType * mask) + { + this->SetNthInput(1, const_cast(mask)); + } + void + SetInput2(const MaskImageType * mask) + { + this->SetMaskImage(mask); + } + + /** + * Get mask image function. If a binary mask image is specified, only + * those input image voxels corresponding with the mask image. + */ + const MaskImageType * + GetMaskImage() const + { + return static_cast(this->ProcessObject::GetInput(1)); + } + + /** + * Employ Rician noise model. Otherwise use a Gaussian noise model. + * Default = true. + */ + itkSetMacro(UseRicianNoiseModel, bool); + itkGetConstMacro(UseRicianNoiseModel, bool); + itkBooleanMacro(UseRicianNoiseModel); + + /** + * Smoothing factor for noise. Default = 1.0. + */ + itkSetMacro(SmoothingFactor, RealType); + itkGetConstMacro(SmoothingFactor, RealType); + + /** + * Smoothing variance for Rician noise. Default = 2.0. + */ + itkSetMacro(SmoothingVariance, RealType); + itkGetConstMacro(SmoothingVariance, RealType); + + /** + * Epsilon for minimum value of mean and variance at a pixel. + * Default = 0.00001. + */ + itkSetMacro(Epsilon, RealType); + itkGetConstMacro(Epsilon, RealType); + + /** + * Mean threshold. + * Default = 0.95. + */ + itkSetMacro(MeanThreshold, RealType); + itkGetConstMacro(MeanThreshold, RealType); + + /** + * Variance threshold. + * Default = 0.5. + */ + itkSetMacro(VarianceThreshold, RealType); + itkGetConstMacro(VarianceThreshold, RealType); + + /** + * Neighborhood for computing local mean and variance images. + * Default = 1x1x... + */ + itkSetMacro(NeighborhoodRadiusForLocalMeanAndVariance, NeighborhoodRadiusType); + itkGetConstMacro(NeighborhoodRadiusForLocalMeanAndVariance, NeighborhoodRadiusType); + +protected: + AdaptiveNonLocalMeansDenoisingImageFilter(); + ~AdaptiveNonLocalMeansDenoisingImageFilter() override = default; + + void + PrintSelf(std::ostream & os, Indent indent) const override; + + void + ThreadedGenerateData(const RegionType &, ThreadIdType) override; + + void + BeforeThreadedGenerateData() override; + + void + AfterThreadedGenerateData() override; + +private: + AdaptiveNonLocalMeansDenoisingImageFilter(const Self &) = delete; + void + operator=(const Self &) = delete; + + RealType CalculateCorrectionFactor(RealType); + + bool m_UseRicianNoiseModel; + + ModifiedBesselCalculatorType m_ModifiedBesselCalculator; + + RealType m_Epsilon; + RealType m_MeanThreshold; + RealType m_VarianceThreshold; + RealType m_SmoothingFactor; + RealType m_SmoothingVariance; + + RealType m_MaximumInputPixelIntensity; + RealType m_MinimumInputPixelIntensity; + + RealImagePointer m_MeanImage; + RealImagePointer m_RicianBiasImage; + RealImagePointer m_VarianceImage; + RealImagePointer m_ThreadContributionCountImage; + RealImagePointer m_IntensitySquaredDistanceImage; + + NeighborhoodRadiusType m_NeighborhoodRadiusForLocalMeanAndVariance; +}; + +} // end namespace itk + +#ifndef ITK_MANUAL_INSTANTIATION +# include "itkAdaptiveNonLocalMeansDenoisingImageFilter.hxx" +#endif + +#endif diff --git a/Modules/Filtering/AdaptiveDenoising/src/itkAdaptiveNonLocalMeansDenoisingImageFilter.hxx b/Modules/Filtering/AdaptiveDenoising/src/itkAdaptiveNonLocalMeansDenoisingImageFilter.hxx new file mode 100644 index 000000000000..84c578924d5b --- /dev/null +++ b/Modules/Filtering/AdaptiveDenoising/src/itkAdaptiveNonLocalMeansDenoisingImageFilter.hxx @@ -0,0 +1,525 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.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 itkAdaptiveNonLocalMeansDenoisingImageFilter_hxx +#define itkAdaptiveNonLocalMeansDenoisingImageFilter_hxx + +#include "itkAdaptiveNonLocalMeansDenoisingImageFilter.h" + +#include "itkArray.h" +#include "itkDiscreteGaussianImageFilter.h" +#include "itkImageRegionConstIterator.h" +#include "itkImageRegionIterator.h" +#include "itkImageRegionIteratorWithIndex.h" +#include "itkMath.h" +#include "itkMeanImageFilter.h" +#include "itkNeighborhoodIterator.h" +#include "itkProgressReporter.h" +#include "itkStatisticsImageFilter.h" +#include "itkVarianceImageFilter.h" + +#include + +namespace itk +{ + +template +AdaptiveNonLocalMeansDenoisingImageFilter:: + AdaptiveNonLocalMeansDenoisingImageFilter() + : m_UseRicianNoiseModel(true) + , m_Epsilon(0.00001) + , m_MeanThreshold(0.95) + , m_VarianceThreshold(0.5) + , m_SmoothingFactor(1.0) + , m_SmoothingVariance(2.0) + , m_MaximumInputPixelIntensity(NumericTraits::NonpositiveMin()) + , m_MinimumInputPixelIntensity(NumericTraits::max()) +{ + this->SetNumberOfRequiredInputs(1); + + this->m_MeanImage = nullptr; + this->m_VarianceImage = nullptr; + this->m_IntensitySquaredDistanceImage = nullptr; + this->m_ThreadContributionCountImage = nullptr; + + this->m_RicianBiasImage = nullptr; + + this->m_NeighborhoodRadiusForLocalMeanAndVariance.Fill(1); + this->DynamicMultiThreadingOff(); +} + +template +void +AdaptiveNonLocalMeansDenoisingImageFilter::BeforeThreadedGenerateData() +{ + Superclass::BeforeThreadedGenerateData(); + + const InputImageType * inputImage = this->GetInput(); + + typedef MeanImageFilter MeanImageFilterType; + typename MeanImageFilterType::Pointer meanImageFilter = MeanImageFilterType::New(); + meanImageFilter->SetInput(inputImage); + meanImageFilter->SetRadius(this->GetNeighborhoodRadiusForLocalMeanAndVariance()); + + this->m_MeanImage = meanImageFilter->GetOutput(); + this->m_MeanImage->Update(); + this->m_MeanImage->DisconnectPipeline(); + + typedef VarianceImageFilter VarianceImageFilterType; + typename VarianceImageFilterType::Pointer varianceImageFilter = VarianceImageFilterType::New(); + varianceImageFilter->SetInput(inputImage); + varianceImageFilter->SetRadius(this->GetNeighborhoodRadiusForLocalMeanAndVariance()); + + this->m_VarianceImage = varianceImageFilter->GetOutput(); + this->m_VarianceImage->Update(); + this->m_VarianceImage->DisconnectPipeline(); + + typedef StatisticsImageFilter StatsFilterType; + typename StatsFilterType::Pointer statsFilter = StatsFilterType::New(); + statsFilter->SetInput(inputImage); + statsFilter->Update(); + + this->m_MaximumInputPixelIntensity = static_cast(statsFilter->GetMaximum()); + this->m_MinimumInputPixelIntensity = static_cast(statsFilter->GetMinimum()); + + this->m_ThreadContributionCountImage = RealImageType::New(); + this->m_ThreadContributionCountImage->CopyInformation(inputImage); + this->m_ThreadContributionCountImage->SetRegions(inputImage->GetRequestedRegion()); + this->m_ThreadContributionCountImage->Allocate(true); + + if (this->m_UseRicianNoiseModel) + { + this->m_RicianBiasImage = RealImageType::New(); + this->m_RicianBiasImage->CopyInformation(inputImage); + this->m_RicianBiasImage->SetRegions(inputImage->GetRequestedRegion()); + this->m_RicianBiasImage->Allocate(true); + } + + this->AllocateOutputs(); + // Output buffer needs to be zero initialized + this->GetOutput()->FillBuffer(0.0); +} + +template +void +AdaptiveNonLocalMeansDenoisingImageFilter::ThreadedGenerateData( + const RegionType & region, + ThreadIdType threadId) +{ + ProgressReporter progress(this, threadId, region.GetNumberOfPixels(), 100); + + const InputImageType * inputImage = this->GetInput(); + const MaskImageType * maskImage = this->GetMaskImage(); + + OutputImageType * outputImage = this->GetOutput(); + RegionType targetImageRegion = this->GetTargetImageRegion(); + + NeighborhoodOffsetListType neighborhoodPatchOffsetList = this->GetNeighborhoodPatchOffsetList(); + + NeighborhoodRadiusType neighborhoodSearchRadius = this->GetNeighborhoodSearchRadius(); + + ConstNeighborhoodIterator ItV(neighborhoodSearchRadius, this->m_VarianceImage, region); + ConstNeighborhoodIterator ItM(neighborhoodSearchRadius, this->m_MeanImage, region); + + const unsigned int neighborhoodSearchSize = this->GetNeighborhoodSearchSize(); + const unsigned int neighborhoodPatchSize = this->GetNeighborhoodPatchSize(); + + Array weightedAverageIntensities(neighborhoodPatchSize); + + ItM.GoToBegin(); + ItV.GoToBegin(); + + while (!ItM.IsAtEnd()) + { + typename InputImageType::IndexType centerIndex = ItM.GetIndex(); + + InputPixelType inputCenterPixel = inputImage->GetPixel(centerIndex); + RealType meanCenterPixel = this->m_MeanImage->GetPixel(centerIndex); + RealType varianceCenterPixel = this->m_VarianceImage->GetPixel(centerIndex); + + RealType maxWeight = NumericTraits::ZeroValue(); + RealType sumOfWeights = NumericTraits::ZeroValue(); + + weightedAverageIntensities.Fill(NumericTraits::ZeroValue()); + + RealType meanNeighborhoodPixel = NumericTraits::ZeroValue(); + RealType varianceNeighborhoodPixel = NumericTraits::ZeroValue(); + + if (inputCenterPixel > 0 && meanCenterPixel > this->m_Epsilon && varianceCenterPixel > this->m_Epsilon && + (!maskImage || maskImage->GetPixel(centerIndex) != NumericTraits::ZeroValue())) + { + // Calculate the minimum distance + + RealType minimumDistance = NumericTraits::max(); + for (unsigned int m = 0; m < neighborhoodSearchSize; m++) + { + if (!ItM.IndexInBounds(m) || m == static_cast(0.5 * neighborhoodSearchSize)) + { + continue; + } + + IndexType neighborhoodIndex = ItM.GetIndex(m); + + if (inputImage->GetPixel(neighborhoodIndex) <= 0) + { + continue; + } + + meanNeighborhoodPixel = this->m_MeanImage->GetPixel(neighborhoodIndex); + varianceNeighborhoodPixel = this->m_VarianceImage->GetPixel(neighborhoodIndex); + + if (meanNeighborhoodPixel <= this->m_Epsilon || varianceNeighborhoodPixel <= this->m_Epsilon) + { + continue; + } + + const RealType meanRatio = meanCenterPixel / meanNeighborhoodPixel; + const RealType meanRatioInverse = (this->m_MaximumInputPixelIntensity - meanCenterPixel) / + (this->m_MaximumInputPixelIntensity - meanNeighborhoodPixel); + + const RealType varianceRatio = varianceCenterPixel / varianceNeighborhoodPixel; + + if (((meanRatio > this->m_MeanThreshold && + meanRatio < itk::NumericTraits::OneValue() / this->m_MeanThreshold) || + (meanRatioInverse > this->m_MeanThreshold && + meanRatioInverse < itk::NumericTraits::OneValue() / this->m_MeanThreshold)) && + varianceRatio > this->m_VarianceThreshold && + varianceRatio < itk::NumericTraits::OneValue() / this->m_VarianceThreshold) + { + + RealType averageDistance = itk::NumericTraits::ZeroValue(); + RealType count = itk::NumericTraits::ZeroValue(); + + for (unsigned int n = 0; n < neighborhoodPatchSize; n++) + { + IndexType neighborhoodPatchIndex = neighborhoodIndex + neighborhoodPatchOffsetList[n]; + + if (!targetImageRegion.IsInside(neighborhoodPatchIndex)) + { + continue; + } + RealType neighborhoodInputImagePixel = static_cast(inputImage->GetPixel(neighborhoodPatchIndex)); + RealType neighborhoodMeanImagePixel = this->m_MeanImage->GetPixel(neighborhoodPatchIndex); + averageDistance += itk::Math::sqr(neighborhoodInputImagePixel - neighborhoodMeanImagePixel); + + count += itk::NumericTraits::OneValue(); + } + averageDistance /= count; + minimumDistance = std::min(averageDistance, minimumDistance); + } + } + + if (itk::Math::AlmostEquals(minimumDistance, NumericTraits::ZeroValue())) + { + minimumDistance = NumericTraits::OneValue(); + } + + // Rician correction + + if (this->m_UseRicianNoiseModel) + { + for (unsigned int n = 0; n < neighborhoodPatchSize; n++) + { + IndexType neighborhoodPatchIndex = centerIndex + neighborhoodPatchOffsetList[n]; + if (!targetImageRegion.IsInside(neighborhoodPatchIndex)) + { + continue; + } + + if (itk::Math::AlmostEquals(minimumDistance, NumericTraits::max())) + { + this->m_RicianBiasImage->SetPixel(neighborhoodPatchIndex, 0.0); + } + else + { + this->m_RicianBiasImage->SetPixel(neighborhoodPatchIndex, minimumDistance); + } + } + } + + // Patch filtering + + for (unsigned int m = 0; m < neighborhoodSearchSize; m++) + { + if (!ItM.IndexInBounds(m) || m == static_cast(0.5 * neighborhoodSearchSize)) + { + continue; + } + + IndexType neighborhoodIndex = ItM.GetIndex(m); + + if (inputImage->GetPixel(neighborhoodIndex) <= 0) + { + continue; + } + + meanNeighborhoodPixel = this->m_MeanImage->GetPixel(neighborhoodIndex); + varianceNeighborhoodPixel = this->m_VarianceImage->GetPixel(neighborhoodIndex); + + if (meanNeighborhoodPixel <= this->m_Epsilon || varianceNeighborhoodPixel <= this->m_Epsilon) + { + continue; + } + + const RealType meanRatio = meanCenterPixel / meanNeighborhoodPixel; + const RealType meanRatioInverse = (this->m_MaximumInputPixelIntensity - meanCenterPixel) / + (this->m_MaximumInputPixelIntensity - meanNeighborhoodPixel); + + const RealType varianceRatio = varianceCenterPixel / varianceNeighborhoodPixel; + + if (((meanRatio > this->m_MeanThreshold && + meanRatio < itk::NumericTraits::OneValue() / this->m_MeanThreshold) || + (meanRatioInverse > this->m_MeanThreshold && + meanRatioInverse < itk::NumericTraits::OneValue() / this->m_MeanThreshold)) && + varianceRatio > this->m_VarianceThreshold && + varianceRatio < itk::NumericTraits::OneValue() / this->m_VarianceThreshold) + { + + RealType averageDistance = 0.0; + RealType count = 0.0; + for (unsigned int n = 0; n < neighborhoodPatchSize; n++) + { + IndexType searchNeighborhoodPatchIndex = neighborhoodIndex + neighborhoodPatchOffsetList[n]; + IndexType centerNeighborhoodPatchIndex = centerIndex + neighborhoodPatchOffsetList[n]; + if (!targetImageRegion.IsInside(searchNeighborhoodPatchIndex) || + !targetImageRegion.IsInside(centerNeighborhoodPatchIndex)) + { + continue; + } + RealType distance1 = inputImage->GetPixel(searchNeighborhoodPatchIndex) - + this->m_MeanImage->GetPixel(searchNeighborhoodPatchIndex); + RealType distance2 = inputImage->GetPixel(centerNeighborhoodPatchIndex) - + this->m_MeanImage->GetPixel(centerNeighborhoodPatchIndex); + averageDistance += itk::Math::sqr(distance1 - distance2); + count += itk::NumericTraits::OneValue(); + } + averageDistance /= count; + + RealType weight = itk::NumericTraits::ZeroValue(); + if (averageDistance <= static_cast(3.0) * minimumDistance) + { + weight = std::exp(-averageDistance / minimumDistance); + } + if (weight > maxWeight) + { + maxWeight = weight; + } + + if (weight > itk::NumericTraits::ZeroValue()) + { + for (unsigned int n = 0; n < neighborhoodPatchSize; n++) + { + IndexType neighborhoodPatchIndex = neighborhoodIndex + neighborhoodPatchOffsetList[n]; + if (!targetImageRegion.IsInside(neighborhoodPatchIndex)) + { + continue; + } + if (this->m_UseRicianNoiseModel) + { + weightedAverageIntensities[n] += weight * itk::Math::sqr(inputImage->GetPixel(neighborhoodPatchIndex)); + } + else + { + weightedAverageIntensities[n] += weight * inputImage->GetPixel(neighborhoodPatchIndex); + } + } + sumOfWeights += weight; + } + } + } + + if (itk::Math::AlmostEquals(maxWeight, NumericTraits::ZeroValue())) + { + maxWeight = NumericTraits::OneValue(); + } + } + else + { + maxWeight = NumericTraits::OneValue(); + } + + for (unsigned int n = 0; n < neighborhoodPatchSize; n++) + { + IndexType neighborhoodPatchIndex = centerIndex + neighborhoodPatchOffsetList[n]; + if (!targetImageRegion.IsInside(neighborhoodPatchIndex)) + { + continue; + } + if (this->m_UseRicianNoiseModel) + { + weightedAverageIntensities[n] += maxWeight * itk::Math::sqr(inputImage->GetPixel(neighborhoodPatchIndex)); + } + else + { + weightedAverageIntensities[n] += maxWeight * inputImage->GetPixel(neighborhoodPatchIndex); + } + } + sumOfWeights += maxWeight; + + if (sumOfWeights > itk::NumericTraits::ZeroValue()) + { + for (unsigned int n = 0; n < neighborhoodPatchSize; n++) + { + IndexType neighborhoodPatchIndex = centerIndex + neighborhoodPatchOffsetList[n]; + if (!targetImageRegion.IsInside(neighborhoodPatchIndex)) + { + continue; + } + typename OutputImageType::PixelType estimate = outputImage->GetPixel(neighborhoodPatchIndex); + estimate += (weightedAverageIntensities[n] / sumOfWeights); + + outputImage->SetPixel(neighborhoodPatchIndex, estimate); + this->m_ThreadContributionCountImage->SetPixel( + neighborhoodPatchIndex, this->m_ThreadContributionCountImage->GetPixel(neighborhoodPatchIndex) + 1); + } + } + + ++ItM; + ++ItV; + + progress.CompletedPixel(); + } +} + +template +void +AdaptiveNonLocalMeansDenoisingImageFilter::AfterThreadedGenerateData() +{ + const MaskImageType * maskImage = this->GetMaskImage(); + + if (this->m_UseRicianNoiseModel) + { + typedef DiscreteGaussianImageFilter SmootherType; + typename SmootherType::Pointer smoother = SmootherType::New(); + smoother->SetInput(this->m_RicianBiasImage); + smoother->SetVariance(this->m_SmoothingVariance); + smoother->SetUseImageSpacingOn(); + smoother->Update(); + + ImageRegionConstIterator ItS(smoother->GetOutput(), smoother->GetOutput()->GetRequestedRegion()); + ImageRegionConstIteratorWithIndex ItM(this->m_MeanImage, this->m_MeanImage->GetRequestedRegion()); + ImageRegionIterator ItB(this->m_RicianBiasImage, this->m_RicianBiasImage->GetRequestedRegion()); + ItS.GoToBegin(); + ItM.GoToBegin(); + ItB.GoToBegin(); + + while (!ItS.IsAtEnd()) + { + if (ItS.Get() > itk::NumericTraits::ZeroValue() && + (!maskImage || maskImage->GetPixel(ItM.GetIndex()) != NumericTraits::ZeroValue())) + { + const RealType snr = ItM.Get() / std::sqrt(ItS.Get()); + + RealType bias = static_cast(2.0) * ItS.Get() / this->CalculateCorrectionFactor(snr); + + if (std::isnan(bias) || std::isinf(bias)) + { + bias = itk::NumericTraits::ZeroValue(); + } + ItB.Set(bias); + } + + ++ItS; + ++ItM; + ++ItB; + } + } + + ImageRegionIteratorWithIndex ItO(this->GetOutput(), this->GetOutput()->GetRequestedRegion()); + ImageRegionConstIterator ItL(this->m_ThreadContributionCountImage, + this->m_ThreadContributionCountImage->GetRequestedRegion()); + + for (ItO.GoToBegin(), ItL.GoToBegin(); !ItO.IsAtEnd(); ++ItO, ++ItL) + { + RealType estimate = ItO.Get(); + + if (itk::Math::FloatAlmostEqual(ItL.Get(), itk::NumericTraits::ZeroValue())) + { + continue; + } + + estimate /= ItL.Get(); + + if (this->m_UseRicianNoiseModel) + { + RealType bias = this->m_RicianBiasImage->GetPixel(ItO.GetIndex()); + + estimate -= bias; + if (estimate < itk::NumericTraits::ZeroValue()) + { + estimate = itk::NumericTraits::ZeroValue(); + } + estimate = std::sqrt(estimate); + } + + ItO.Set(estimate); + } +} + +template +typename AdaptiveNonLocalMeansDenoisingImageFilter::RealType +AdaptiveNonLocalMeansDenoisingImageFilter::CalculateCorrectionFactor( + RealType snr) +{ + const RealType snrSquared = itk::Math::sqr(snr); + + RealType value = + static_cast(2.0) + snrSquared - + static_cast(0.125) * static_cast(Math::pi) * + static_cast(std::exp(static_cast(-0.5) * snrSquared)) * + itk::Math::sqr((static_cast(2.0) + snrSquared) * + static_cast( + this->m_ModifiedBesselCalculator.ModifiedBesselI0(static_cast(0.25) * snrSquared)) + + snrSquared * static_cast(this->m_ModifiedBesselCalculator.ModifiedBesselI1( + static_cast(0.25) * snrSquared))); + + if (value < static_cast(0.001) || value > static_cast(10.0)) + { + value = itk::NumericTraits::OneValue(); + } + return value; +} + +template +void +AdaptiveNonLocalMeansDenoisingImageFilter::PrintSelf(std::ostream & os, + Indent indent) const +{ + Superclass::PrintSelf(os, indent); + + if (this->m_UseRicianNoiseModel) + { + os << indent << "Using Rician noise model." << std::endl; + } + else + { + os << indent << "Using Gaussian noise model." << std::endl; + } + + os << indent << "Epsilon = " << this->m_Epsilon << std::endl; + os << indent << "Mean threshold = " << this->m_MeanThreshold << std::endl; + os << indent << "Variance threshold = " << this->m_VarianceThreshold << std::endl; + os << indent << "Smoothing variance = " << this->m_SmoothingVariance << std::endl; + + os << indent + << "Neighborhood radius for local mean and variance = " << this->m_NeighborhoodRadiusForLocalMeanAndVariance + << std::endl; +} + +} // end namespace itk + +#endif diff --git a/Modules/Filtering/AdaptiveDenoising/src/itkMinimalStandardRandomVariateGenerator.cxx b/Modules/Filtering/AdaptiveDenoising/src/itkMinimalStandardRandomVariateGenerator.cxx new file mode 100644 index 000000000000..6c5cc9d7006c --- /dev/null +++ b/Modules/Filtering/AdaptiveDenoising/src/itkMinimalStandardRandomVariateGenerator.cxx @@ -0,0 +1,52 @@ +/*========================================================================= + * + * 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 + * + * http://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 "itkMinimalStandardRandomVariateGenerator.h" + +namespace itk +{ +namespace Statistics +{ + +MinimalStandardRandomVariateGenerator ::MinimalStandardRandomVariateGenerator() +{ + this->m_NormalGenerator = NormalGeneratorType::New(); + this->Initialize(1); +} + +void +MinimalStandardRandomVariateGenerator ::Initialize(int randomSeed) +{ + this->m_NormalGenerator->Initialize(randomSeed); +} + + +double +MinimalStandardRandomVariateGenerator ::GetVariate() +{ + return this->m_NormalGenerator->GetVariate(); +} + + +void +MinimalStandardRandomVariateGenerator ::PrintSelf(std::ostream & os, Indent indent) const +{ + Superclass::PrintSelf(os, indent); +} + +} // end namespace Statistics +} // end namespace itk diff --git a/Modules/Filtering/AdaptiveDenoising/src/itkNonLocalPatchBasedImageFilter.h b/Modules/Filtering/AdaptiveDenoising/src/itkNonLocalPatchBasedImageFilter.h new file mode 100644 index 000000000000..527b0361e877 --- /dev/null +++ b/Modules/Filtering/AdaptiveDenoising/src/itkNonLocalPatchBasedImageFilter.h @@ -0,0 +1,196 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.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 itkNonLocalPatchBasedImageFilter_h +#define itkNonLocalPatchBasedImageFilter_h + +#include "itkImageToImageFilter.h" + +#include "itkConstNeighborhoodIterator.h" + +namespace itk +{ + +/** + * \class NonLocalPatchBasedImageFilter + * \brief Implementation of a non-local upsampling (i.e., superresolution) image filter. + * + * \ingroup ITKFiltering + */ + +template +class NonLocalPatchBasedImageFilter : public ImageToImageFilter +{ +public: + /** Standard class typedefs. */ + using Self = NonLocalPatchBasedImageFilter; + using Superclass = ImageToImageFilter; + using Pointer = SmartPointer; + using ConstPointer = SmartPointer; + + /** Runtime information support. */ + itkTypeMacro(NonLocalPatchBasedImageFilter, ImageToImageFilter); + + /** Standard New method. */ + itkNewMacro(Self); + + /** ImageDimension constants */ + itkStaticConstMacro(ImageDimension, unsigned int, TInputImage::ImageDimension); + + /** Some convenient typedefs. */ + using InputImageType = TInputImage; + using InputPixelType = typename InputImageType::PixelType; + using InputImagePointer = typename InputImageType::Pointer; + using InputImageList = std::vector; + using InputImageSetList = std::vector; + using RegionType = typename InputImageType::RegionType; + + using OutputImageType = TOutputImage; + using OutputPixelType = typename OutputImageType::PixelType; + + using InputImagePixelVectorType = std::vector; + + using RealType = float; + using RealImageType = Image; + using RealImagePointer = typename RealImageType::Pointer; + using IndexType = typename RealImageType::IndexType; + + using NeighborhoodType = Neighborhood; + using NeighborhoodSizeType = SizeValueType; + + using ConstNeighborhoodIteratorType = ConstNeighborhoodIterator; + using NeighborhoodRadiusType = typename ConstNeighborhoodIteratorType::RadiusType; + using NeighborhoodOffsetType = typename ConstNeighborhoodIteratorType::OffsetType; + + using NeighborhoodOffsetListType = std::vector; + /** + * Neighborhood patch similarity metric enumerated type + */ + enum SimilarityMetricType + { + PEARSON_CORRELATION, + MEAN_SQUARES + }; + + /** + * Get/set neighborhood search radius. + * Default = 3x3x... + */ + itkSetMacro(NeighborhoodSearchRadius, NeighborhoodRadiusType); + itkGetConstMacro(NeighborhoodSearchRadius, NeighborhoodRadiusType); + + /** + * Get/set neighborhood search size. + */ + itkSetMacro(NeighborhoodSearchSize, NeighborhoodSizeType); + itkGetConstMacro(NeighborhoodSearchSize, NeighborhoodSizeType); + + /** + * Get/set neighborhood search offset list. + */ + virtual void + SetNeighborhoodSearchOffsetList(const NeighborhoodOffsetListType list) + { + this->m_NeighborhoodSearchOffsetList = list; + this->Modified(); + } + itkGetConstMacro(NeighborhoodSearchOffsetList, NeighborhoodOffsetListType); + + /** + * Get/set neighborhood patch radius. + * Default = 1x1x... + */ + itkSetMacro(NeighborhoodPatchRadius, NeighborhoodRadiusType); + itkGetConstMacro(NeighborhoodPatchRadius, NeighborhoodRadiusType); + + /** + * Get/set neighborhood patch size. + */ + itkSetMacro(NeighborhoodPatchSize, NeighborhoodSizeType); + itkGetConstMacro(NeighborhoodPatchSize, NeighborhoodSizeType); + + /** + * Get/set neighborhood patch offset list. + */ + virtual void + SetNeighborhoodPatchOffsetList(const NeighborhoodOffsetListType list) + { + this->m_NeighborhoodPatchOffsetList = list; + this->Modified(); + } + itkGetConstMacro(NeighborhoodPatchOffsetList, NeighborhoodOffsetListType); + + /** + * Enumerated type for neighborhood similarity. Default = MEAN_SQUARES + */ + itkSetMacro(SimilarityMetric, SimilarityMetricType); + itkGetConstMacro(SimilarityMetric, SimilarityMetricType); + +protected: + NonLocalPatchBasedImageFilter(); + ~NonLocalPatchBasedImageFilter() override = default; + + void + BeforeThreadedGenerateData() override; + + void + PrintSelf(std::ostream & os, Indent indent) const override; + + RealType + ComputeNeighborhoodPatchSimilarity(const InputImageList &, + const IndexType, + const InputImagePixelVectorType &, + const bool); + + InputImagePixelVectorType + VectorizeImageListPatch(const InputImageList &, const IndexType, const bool); + + InputImagePixelVectorType + VectorizeImagePatch(const InputImagePointer, const IndexType, const bool); + + void + GetMeanAndStandardDeviationOfVectorizedImagePatch(const InputImagePixelVectorType &, RealType &, RealType &); + + itkSetMacro(TargetImageRegion, RegionType); + itkGetConstMacro(TargetImageRegion, RegionType); + + SimilarityMetricType m_SimilarityMetric; + + SizeValueType m_NeighborhoodSearchSize; + NeighborhoodRadiusType m_NeighborhoodSearchRadius; + NeighborhoodOffsetListType m_NeighborhoodSearchOffsetList; + + SizeValueType m_NeighborhoodPatchSize; + NeighborhoodRadiusType m_NeighborhoodPatchRadius; + NeighborhoodOffsetListType m_NeighborhoodPatchOffsetList; + + RegionType m_TargetImageRegion; + + +private: + NonLocalPatchBasedImageFilter(const Self &) = delete; + void + operator=(const Self &) = delete; +}; + +} // end namespace itk + +#ifndef ITK_MANUAL_INSTANTIATION +# include "itkNonLocalPatchBasedImageFilter.hxx" +#endif + +#endif diff --git a/Modules/Filtering/AdaptiveDenoising/src/itkNonLocalPatchBasedImageFilter.hxx b/Modules/Filtering/AdaptiveDenoising/src/itkNonLocalPatchBasedImageFilter.hxx new file mode 100644 index 000000000000..24df7705ac13 --- /dev/null +++ b/Modules/Filtering/AdaptiveDenoising/src/itkNonLocalPatchBasedImageFilter.hxx @@ -0,0 +1,255 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.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 itkNonLocalPatchBasedImageFilter_hxx +#define itkNonLocalPatchBasedImageFilter_hxx + +#include "itkNonLocalPatchBasedImageFilter.h" + +#include "itkNeighborhood.h" + +namespace itk +{ + +template +NonLocalPatchBasedImageFilter::NonLocalPatchBasedImageFilter() +{ + this->m_SimilarityMetric = MEAN_SQUARES; + + this->m_NeighborhoodPatchRadius.Fill(1); + this->m_NeighborhoodPatchOffsetList.clear(); + + this->m_NeighborhoodSearchRadius.Fill(3); + this->m_NeighborhoodSearchOffsetList.clear(); +} + +template +void +NonLocalPatchBasedImageFilter::BeforeThreadedGenerateData() +{ + // Set up the search neighborhood parameters + + this->m_NeighborhoodSearchOffsetList.clear(); + + NeighborhoodType searchNeighborhood; + searchNeighborhood.SetRadius(this->m_NeighborhoodSearchRadius); + + this->m_NeighborhoodSearchSize = searchNeighborhood.Size(); + for (unsigned int n = 0; n < this->m_NeighborhoodSearchSize; n++) + { + this->m_NeighborhoodSearchOffsetList.push_back(searchNeighborhood.GetOffset(n)); + } + + // Set up the patch neighborhood parameters + + this->m_NeighborhoodPatchOffsetList.clear(); + + NeighborhoodType patchNeighborhood; + patchNeighborhood.SetRadius(this->m_NeighborhoodPatchRadius); + + this->m_NeighborhoodPatchSize = patchNeighborhood.Size(); + for (unsigned int n = 0; n < this->m_NeighborhoodPatchSize; n++) + { + this->m_NeighborhoodPatchOffsetList.push_back(patchNeighborhood.GetOffset(n)); + } + + this->m_TargetImageRegion = this->GetInput()->GetRequestedRegion(); +} + +template +typename NonLocalPatchBasedImageFilter::InputImagePixelVectorType +NonLocalPatchBasedImageFilter::VectorizeImageListPatch(const InputImageList & imageList, + const IndexType index, + const bool normalize) +{ + InputImagePixelVectorType patchVector(this->m_NeighborhoodPatchSize * imageList.size()); + for (unsigned int i = 0; i < imageList.size(); i++) + { + InputImagePixelVectorType patchVectorPerModality = this->VectorizeImagePatch(imageList[i], index, normalize); + for (unsigned int j = 0; j < this->m_NeighborhoodPatchSize; j++) + { + patchVector[i * this->m_NeighborhoodPatchSize + j] = patchVectorPerModality[j]; + } + } + return patchVector; +} + +template +typename NonLocalPatchBasedImageFilter::InputImagePixelVectorType +NonLocalPatchBasedImageFilter::VectorizeImagePatch(const InputImagePointer image, + const IndexType index, + const bool normalize) +{ + InputImagePixelVectorType patchVector(this->m_NeighborhoodPatchSize); + for (SizeValueType i = 0; i < this->m_NeighborhoodPatchSize; i++) + { + IndexType neighborhoodIndex = index + this->m_NeighborhoodPatchOffsetList[i]; + + bool isInBounds = this->m_TargetImageRegion.IsInside(neighborhoodIndex); + if (isInBounds) + { + InputPixelType pixel = image->GetPixel(neighborhoodIndex); + patchVector[i] = pixel; + } + else + { + patchVector[i] = std::numeric_limits::quiet_NaN(); + } + } + + if (normalize) + { + RealType mean = 0.0; + RealType standardDeviation = 0.0; + this->GetMeanAndStandardDeviationOfVectorizedImagePatch(patchVector, mean, standardDeviation); + + standardDeviation = std::max(standardDeviation, NumericTraits::OneValue()); + + typename InputImagePixelVectorType::iterator it; + for (it = patchVector.begin(); it != patchVector.end(); ++it) + { + *it = (*it - mean) / standardDeviation; + } + } + return patchVector; +} + +template +void +NonLocalPatchBasedImageFilter::GetMeanAndStandardDeviationOfVectorizedImagePatch( + const InputImagePixelVectorType & patchVector, + RealType & mean, + RealType & standardDeviation) +{ + RealType sum = 0.0; + RealType sumOfSquares = 0.0; + RealType count = 0.0; + + typename InputImagePixelVectorType::const_iterator it; + for (it = patchVector.begin(); it != patchVector.end(); ++it) + { + if (std::isfinite(*it)) + { + sum += *it; + sumOfSquares += itk::Math::sqr(*it); + count += itk::NumericTraits::OneValue(); + } + } + mean = sum / count; + standardDeviation = + std::sqrt((sumOfSquares - count * itk::Math::sqr(mean)) / (count - itk::NumericTraits::OneValue())); +} + +template +typename NonLocalPatchBasedImageFilter::RealType +NonLocalPatchBasedImageFilter::ComputeNeighborhoodPatchSimilarity( + const InputImageList & imageList, + const IndexType index, + const InputImagePixelVectorType & patchVectorY, + const bool useOnlyFirstImage) +{ + unsigned int numberOfImagesToUse = imageList.size(); + if (useOnlyFirstImage) + { + numberOfImagesToUse = 1; + } + + RealType sumX = 0.0; + RealType sumOfSquaresX = 0.0; + RealType sumOfSquaredDifferencesXY = 0.0; + RealType sumXY = 0.0; + RealType N = 0.0; + + SizeValueType count = 0; + for (SizeValueType i = 0; i < numberOfImagesToUse; i++) + { + for (SizeValueType j = 0; j < this->m_NeighborhoodPatchSize; j++) + { + IndexType neighborhoodIndex = index + this->m_NeighborhoodPatchOffsetList[j]; + + bool isInBounds = this->m_TargetImageRegion.IsInside(neighborhoodIndex); + if (isInBounds && std::isfinite(patchVectorY[count])) + { + auto x = static_cast(imageList[i]->GetPixel(neighborhoodIndex)); + auto y = static_cast(patchVectorY[count]); + + sumX += x; + sumOfSquaresX += itk::Math::sqr(x); + sumXY += (x * y); + + sumOfSquaredDifferencesXY += itk::Math::sqr(y - x); + N += itk::NumericTraits::OneValue(); + } + ++count; + } + } + + // If we are on the boundary, a neighborhood patch might not overlap + // with the image. If we have 2 voxels or less for a neighborhood patch + // we don't consider it to be a suitable match. + if (N < static_cast(3.0)) + { + return NumericTraits::max(); + } + + if (this->m_SimilarityMetric == PEARSON_CORRELATION) + { + RealType varianceX = sumOfSquaresX - itk::Math::sqr(sumX) / N; + varianceX = std::max(varianceX, static_cast(1.0e-6)); + + RealType measure = itk::Math::sqr(sumXY) / varianceX; + if (sumXY > 0) + { + return -measure; + } + else + { + return measure; + } + } + else if (this->m_SimilarityMetric == MEAN_SQUARES) + { + return (sumOfSquaredDifferencesXY / N); + } + else + { + itkExceptionMacro("Unrecognized similarity metric."); + } +} + +template +void +NonLocalPatchBasedImageFilter::PrintSelf(std::ostream & os, Indent indent) const +{ + Superclass::PrintSelf(os, indent); + + if (this->m_SimilarityMetric == PEARSON_CORRELATION) + { + os << "Using Pearson correlation to measure the patch similarity." << std::endl; + } + else if (this->m_SimilarityMetric == MEAN_SQUARES) + { + os << "Using mean squares to measure the patch similarity." << std::endl; + } + + os << indent << "Neighborhood search radius = " << this->m_NeighborhoodSearchRadius << std::endl; + os << indent << "Neighborhood patch radius = " << this->m_NeighborhoodPatchRadius << std::endl; +} + +} // end namespace itk + +#endif diff --git a/Modules/Filtering/AdaptiveDenoising/src/itkVarianceImageFilter.h b/Modules/Filtering/AdaptiveDenoising/src/itkVarianceImageFilter.h new file mode 100644 index 000000000000..620a31fce5b8 --- /dev/null +++ b/Modules/Filtering/AdaptiveDenoising/src/itkVarianceImageFilter.h @@ -0,0 +1,115 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.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 itkVarianceImageFilter_h +#define itkVarianceImageFilter_h + +#include "itkBoxImageFilter.h" +#include "itkImage.h" +#include "itkNumericTraits.h" + +namespace itk +{ +/** \class VarianceImageFilter + * \brief Applies an averaging filter to an image + * + * Computes an image where a given pixel is the variance value of the + * the pixels in a neighborhood about the corresponding input pixel. + * + * A variacne filter is one of the family of linear filters. + * + * \sa Image + * \sa Neighborhood + * \sa NeighborhoodOperator + * \sa NeighborhoodIterator + * + * \ingroup IntensityImageFilters + * \ingroup ITKSmoothing + * + * \wiki + * \wikiexample{Smoothing/VarianceImageFilter,Variance filter an image} + * \endwiki + */ +template +class VarianceImageFilter final : public BoxImageFilter +{ +public: + /** Extract dimension from input and output image. */ + itkStaticConstMacro(InputImageDimension, unsigned int, TInputImage::ImageDimension); + itkStaticConstMacro(OutputImageDimension, unsigned int, TOutputImage::ImageDimension); + + /** Convenient typedefs for simplifying declarations. */ + typedef TInputImage InputImageType; + typedef TOutputImage OutputImageType; + + /** Standard class typedefs. */ + typedef VarianceImageFilter Self; + typedef BoxImageFilter Superclass; + typedef SmartPointer Pointer; + typedef SmartPointer ConstPointer; + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** Run-time type information (and related methods). */ + itkTypeMacro(VarianceImageFilter, BoxImageFilter); + + /** Image typedef support. */ + typedef typename InputImageType::PixelType InputPixelType; + typedef typename OutputImageType::PixelType OutputPixelType; + typedef typename NumericTraits::RealType InputRealType; + + typedef typename InputImageType::RegionType InputImageRegionType; + typedef typename OutputImageType::RegionType OutputImageRegionType; + + typedef typename InputImageType::SizeType InputSizeType; + +#ifdef ITK_USE_CONCEPT_CHECKING + // Begin concept checking + itkConceptMacro(InputHasNumericTraitsCheck, (Concept::HasNumericTraits)); + // End concept checking +#endif + +protected: + VarianceImageFilter(); + ~VarianceImageFilter() override = default; + + /** VarianceImageFilter 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 BoxImageFilter::ThreadedGenerateData(), + * BoxImageFilter::GenerateData() */ + void + ThreadedGenerateData(const OutputImageRegionType & outputRegionForThread, ThreadIdType threadId) override; + +private: + VarianceImageFilter(const Self &) = delete; + void + operator=(const Self &) = delete; +}; +} // end namespace itk + +#ifndef ITK_MANUAL_INSTANTIATION +# include "itkVarianceImageFilter.hxx" +#endif + +#endif diff --git a/Modules/Filtering/AdaptiveDenoising/src/itkVarianceImageFilter.hxx b/Modules/Filtering/AdaptiveDenoising/src/itkVarianceImageFilter.hxx new file mode 100644 index 000000000000..cacc5e3cad2b --- /dev/null +++ b/Modules/Filtering/AdaptiveDenoising/src/itkVarianceImageFilter.hxx @@ -0,0 +1,102 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.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 itkVarianceImageFilter_hxx +#define itkVarianceImageFilter_hxx +#include "itkVarianceImageFilter.h" + +#include "itkConstNeighborhoodIterator.h" +#include "itkNeighborhoodInnerProduct.h" +#include "itkImageRegionIterator.h" +#include "itkNeighborhoodAlgorithm.h" +#include "itkOffset.h" +#include "itkProgressReporter.h" + +namespace itk +{ +template +VarianceImageFilter::VarianceImageFilter() +{ + this->DynamicMultiThreadingOff(); +} + +template +void +VarianceImageFilter::ThreadedGenerateData( + const OutputImageRegionType & outputRegionForThread, + ThreadIdType threadId) +{ + unsigned int i; + + ZeroFluxNeumannBoundaryCondition nbc; + + ConstNeighborhoodIterator bit; + ImageRegionIterator it; + + // Allocate output + typename OutputImageType::Pointer output = this->GetOutput(); + typename InputImageType::ConstPointer input = this->GetInput(); + + // Find the data-set boundary "faces" + typename NeighborhoodAlgorithm::ImageBoundaryFacesCalculator::FaceListType faceList; + NeighborhoodAlgorithm::ImageBoundaryFacesCalculator bC; + faceList = bC(input, outputRegionForThread, this->GetRadius()); + + typename NeighborhoodAlgorithm::ImageBoundaryFacesCalculator::FaceListType::iterator fit; + + // support progress methods/callbacks + ProgressReporter progress(this, threadId, outputRegionForThread.GetNumberOfPixels()); + + InputRealType sum; + InputRealType sumOfSquares; + + // Process 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) + { + bit = ConstNeighborhoodIterator(this->GetRadius(), input, *fit); + unsigned int neighborhoodSize = bit.Size(); + it = ImageRegionIterator(output, *fit); + bit.OverrideBoundaryCondition(&nbc); + bit.GoToBegin(); + + while (!bit.IsAtEnd()) + { + sum = NumericTraits::ZeroValue(); + sumOfSquares = NumericTraits::ZeroValue(); + + for (i = 0; i < neighborhoodSize; ++i) + { + sum += static_cast(bit.GetPixel(i)); + sumOfSquares += itk::Math::sqr(static_cast(bit.GetPixel(i))); + } + + // get the variance value + const double num = static_cast(neighborhoodSize); + OutputPixelType var = (sumOfSquares - (itk::Math::sqr(sum) / num)) / (num - 1.0); + + it.Set(var); + + ++bit; + ++it; + progress.CompletedPixel(); + } + } +} +} // end namespace itk + +#endif diff --git a/Modules/Filtering/AdaptiveDenoising/test/Baseline/itkAdaptiveNonLocalMeansDenoisingImageFilterTestOutput.mha.sha512 b/Modules/Filtering/AdaptiveDenoising/test/Baseline/itkAdaptiveNonLocalMeansDenoisingImageFilterTestOutput.mha.sha512 new file mode 100644 index 000000000000..c811785f3e70 --- /dev/null +++ b/Modules/Filtering/AdaptiveDenoising/test/Baseline/itkAdaptiveNonLocalMeansDenoisingImageFilterTestOutput.mha.sha512 @@ -0,0 +1 @@ +34cdd2aafce413dcf7efc692a707d53b7b57ebb006d0fbc20ecb42343f8a078b2252eff2137b17d3ab583d133f780438e247241ebf213c3289bd9ba1525081b7 diff --git a/Modules/Filtering/AdaptiveDenoising/test/CMakeLists.txt b/Modules/Filtering/AdaptiveDenoising/test/CMakeLists.txt new file mode 100644 index 000000000000..753b6c440b34 --- /dev/null +++ b/Modules/Filtering/AdaptiveDenoising/test/CMakeLists.txt @@ -0,0 +1,27 @@ +itk_module_test() + +set( + AdaptiveDenoisingTests + itkMinimalStandardRandomVariateGeneratorTest.cxx + itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx +) + +createtestdriver(AdaptiveDenoising "${AdaptiveDenoising-Test_LIBRARIES}" "${AdaptiveDenoisingTests}") + +itk_add_test( + NAME itkMinimalStandardRandomVariateGeneratorTest + COMMAND + AdaptiveDenoisingTestDriver + itkMinimalStandardRandomVariateGeneratorTest +) + +itk_add_test( + NAME itkAdaptiveNonLocalMeansDenoisingImageFilterTest + COMMAND + AdaptiveDenoisingTestDriver + --compare + DATA{Baseline/itkAdaptiveNonLocalMeansDenoisingImageFilterTestOutput.mha} + ${ITK_TEST_OUTPUT_DIR}/itkAdaptiveNonLocalMeansDenoisingImageFilterTestOutput.mha + itkAdaptiveNonLocalMeansDenoisingImageFilterTest + ${ITK_TEST_OUTPUT_DIR}/itkAdaptiveNonLocalMeansDenoisingImageFilterTestOutput.mha +) diff --git a/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx b/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx new file mode 100644 index 000000000000..9d40c4ac97dc --- /dev/null +++ b/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx @@ -0,0 +1,100 @@ +/*========================================================================= + * + * 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 + * + * http://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 "itkAdaptiveNonLocalMeansDenoisingImageFilter.h" + +#include "itkCommand.h" +#include "itkImageFileWriter.h" +#include "itkTestingMacros.h" + +namespace +{ +class ShowProgress : public itk::Command +{ +public: + itkNewMacro(ShowProgress); + + void + Execute(itk::Object * caller, const itk::EventObject & event) override + { + Execute((const itk::Object *)caller, event); + } + + void + Execute(const itk::Object * caller, const itk::EventObject & event) override + { + if (!itk::ProgressEvent().CheckEvent(&event)) + { + return; + } + const auto * processObject = dynamic_cast(caller); + if (!processObject) + { + return; + } + std::cout << " " << processObject->GetProgress(); + } +}; +} // namespace + +int +itkAdaptiveNonLocalMeansDenoisingImageFilterTest(int argc, char * argv[]) +{ + if (argc < 2) + { + std::cerr << "Missing parameters." << std::endl; + std::cerr << "Usage: " << itkNameOfTestExecutableMacro(argv); + std::cerr << " outputImage"; + std::cerr << std::endl; + return EXIT_FAILURE; + } + const char * outputImageFileName = argv[1]; + + constexpr unsigned int Dimension = 2; + using PixelType = float; + using ImageType = itk::Image; + + using FilterType = itk::AdaptiveNonLocalMeansDenoisingImageFilter; + FilterType::Pointer filter = FilterType::New(); + + ITK_EXERCISE_BASIC_OBJECT_METHODS(filter, AdaptiveNonLocalMeansDenoisingImageFilter, ImageToImageFilter); + + // Create input image to avoid test dependencies. + ImageType::SizeType size; + size.Fill(128); + ImageType::Pointer image = ImageType::New(); + image->SetRegions(size); + image->Allocate(); + image->FillBuffer(1.1f); + + ShowProgress::Pointer showProgress = ShowProgress::New(); + filter->AddObserver(itk::ProgressEvent(), showProgress); + filter->SetInput(image); + + using WriterType = itk::ImageFileWriter; + WriterType::Pointer writer = WriterType::New(); + writer->SetFileName(outputImageFileName); + writer->SetInput(filter->GetOutput()); + writer->SetUseCompression(true); + + ITK_TRY_EXPECT_NO_EXCEPTION(writer->Update()); + + + std::cout << "Test finished." << std::endl; + return EXIT_SUCCESS; +} diff --git a/Modules/Filtering/AdaptiveDenoising/test/itkMinimalStandardRandomVariateGeneratorTest.cxx b/Modules/Filtering/AdaptiveDenoising/test/itkMinimalStandardRandomVariateGeneratorTest.cxx new file mode 100644 index 000000000000..3bb91a1d3f16 --- /dev/null +++ b/Modules/Filtering/AdaptiveDenoising/test/itkMinimalStandardRandomVariateGeneratorTest.cxx @@ -0,0 +1,37 @@ +/*========================================================================= + * + * 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 + * + * http://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 "itkMinimalStandardRandomVariateGenerator.h" + +#include "itkTestingMacros.h" +#include "itkMath.h" + +int +itkMinimalStandardRandomVariateGeneratorTest(int, char *[]) +{ + typedef itk::Statistics::MinimalStandardRandomVariateGenerator GeneratorType; + GeneratorType::Pointer generator = GeneratorType::New(); + + ITK_EXERCISE_BASIC_OBJECT_METHODS(generator, MinimalStandardRandomVariateGenerator, RandomVariateGeneratorBase); + + generator->Initialize(324); + + ITK_TEST_EXPECT_TRUE(itk::Math::FloatAlmostEqual(generator->GetVariate(), 1.35581, 4, 0.0001)); + + return EXIT_SUCCESS; +} diff --git a/Modules/Filtering/AdaptiveDenoising/wrapping/CMakeLists.txt b/Modules/Filtering/AdaptiveDenoising/wrapping/CMakeLists.txt new file mode 100644 index 000000000000..4b5b7b9b2aad --- /dev/null +++ b/Modules/Filtering/AdaptiveDenoising/wrapping/CMakeLists.txt @@ -0,0 +1,3 @@ +itk_wrap_module(AdaptiveDenoising) +itk_auto_load_submodules() +itk_end_wrap_module() diff --git a/Modules/Filtering/AdaptiveDenoising/wrapping/itkAdaptiveNonLocalMeansDenoisingImageFilter.wrap b/Modules/Filtering/AdaptiveDenoising/wrapping/itkAdaptiveNonLocalMeansDenoisingImageFilter.wrap new file mode 100644 index 000000000000..4ecd0e25c81f --- /dev/null +++ b/Modules/Filtering/AdaptiveDenoising/wrapping/itkAdaptiveNonLocalMeansDenoisingImageFilter.wrap @@ -0,0 +1,3 @@ +itk_wrap_class("itk::AdaptiveNonLocalMeansDenoisingImageFilter" POINTER) +itk_wrap_image_filter("${WRAP_ITK_SCALAR}" 2) +itk_end_wrap_class() diff --git a/Modules/Filtering/AdaptiveDenoising/wrapping/itkMinimalStandardRandomVariateGenerator.wrap b/Modules/Filtering/AdaptiveDenoising/wrapping/itkMinimalStandardRandomVariateGenerator.wrap new file mode 100644 index 000000000000..e13dd73db38f --- /dev/null +++ b/Modules/Filtering/AdaptiveDenoising/wrapping/itkMinimalStandardRandomVariateGenerator.wrap @@ -0,0 +1 @@ +itk_wrap_simple_class("itk::Statistics::MinimalStandardRandomVariateGenerator" POINTER) From b5db1ce386dd249fd122c9430de0645d478a2962 Mon Sep 17 00:00:00 2001 From: Nick Tustison Date: Sat, 26 Sep 2020 13:18:15 -0700 Subject: [PATCH 02/31] ENH: Further organization. --- ...daptiveNonLocalMeansDenoisingImageFilter.h | 203 +++++-- ...ptiveNonLocalMeansDenoisingImageFilter.hxx | 502 ++++++++++++++++- ...itkMinimalStandardRandomVariateGenerator.h | 96 ---- .../itkNonLocalPatchBasedImageFilter.h | 0 .../itkNonLocalPatchBasedImageFilter.hxx | 0 .../{src => include}/itkVarianceImageFilter.h | 0 .../itkVarianceImageFilter.hxx | 0 .../AdaptiveDenoising/itk-module.cmake | 2 + .../AdaptiveDenoising/src/CMakeLists.txt | 5 - ...daptiveNonLocalMeansDenoisingImageFilter.h | 223 -------- ...ptiveNonLocalMeansDenoisingImageFilter.hxx | 525 ------------------ ...kMinimalStandardRandomVariateGenerator.cxx | 52 -- ...sDenoisingImageFilterTestOutput.mha.sha512 | 1 - .../AdaptiveDenoising/test/CMakeLists.txt | 28 +- ...eNonLocalMeansDenoisingImageFilterTest.cxx | 179 +++--- ...imalStandardRandomVariateGeneratorTest.cxx | 37 -- .../AdaptiveDenoising/wrapping/CMakeLists.txt | 3 + 17 files changed, 779 insertions(+), 1077 deletions(-) delete mode 100644 Modules/Filtering/AdaptiveDenoising/include/itkMinimalStandardRandomVariateGenerator.h rename Modules/Filtering/AdaptiveDenoising/{src => include}/itkNonLocalPatchBasedImageFilter.h (100%) rename Modules/Filtering/AdaptiveDenoising/{src => include}/itkNonLocalPatchBasedImageFilter.hxx (100%) rename Modules/Filtering/AdaptiveDenoising/{src => include}/itkVarianceImageFilter.h (100%) rename Modules/Filtering/AdaptiveDenoising/{src => include}/itkVarianceImageFilter.hxx (100%) delete mode 100644 Modules/Filtering/AdaptiveDenoising/src/CMakeLists.txt delete mode 100644 Modules/Filtering/AdaptiveDenoising/src/itkAdaptiveNonLocalMeansDenoisingImageFilter.h delete mode 100644 Modules/Filtering/AdaptiveDenoising/src/itkAdaptiveNonLocalMeansDenoisingImageFilter.hxx delete mode 100644 Modules/Filtering/AdaptiveDenoising/src/itkMinimalStandardRandomVariateGenerator.cxx delete mode 100644 Modules/Filtering/AdaptiveDenoising/test/Baseline/itkAdaptiveNonLocalMeansDenoisingImageFilterTestOutput.mha.sha512 delete mode 100644 Modules/Filtering/AdaptiveDenoising/test/itkMinimalStandardRandomVariateGeneratorTest.cxx diff --git a/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.h b/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.h index 64c75b351050..463e11004489 100644 --- a/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.h +++ b/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.h @@ -1,6 +1,6 @@ /*========================================================================= * - * Copyright NumFOCUS + * Copyright Insight Software Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,46 +18,156 @@ #ifndef itkAdaptiveNonLocalMeansDenoisingImageFilter_h #define itkAdaptiveNonLocalMeansDenoisingImageFilter_h -#include "itkImageToImageFilter.h" +#include "itkNonLocalPatchBasedImageFilter.h" + +#include "itkConstNeighborhoodIterator.h" +#include "itkGaussianOperator.h" namespace itk { -/** \class AdaptiveNonLocalMeansDenoisingImageFilter +/** + * \class AdaptiveNonLocalMeansDenoisingImageFilter + * \brief Implementation of a denoising image filter. + * + * \author Jose V. Manjon with ITK porting by Nick Tustison * - * \brief Filters a image by iterating over its pixels. + * Contributed by * - * Filters a image by iterating over its pixels in a multi-threaded way - * and {to be completed by the developer}. + * \par REFERENCE * - * \ingroup AdaptiveDenoising + * J. V. Manjon, P. Coupe, Luis Marti-Bonmati, D. L. Collins, + * and M. Robles. "Adaptive Non-Local Means Denoising of MR Images With + * Spatially Varying Noise Levels, Journal of Magnetic Resonance Imaging, + * 31:192-203, June 2010. * + * \ingroup ITKNoiseFiltering */ -template -class AdaptiveNonLocalMeansDenoisingImageFilter : public ImageToImageFilter + +template > +class AdaptiveNonLocalMeansDenoisingImageFilter final : public NonLocalPatchBasedImageFilter { public: - ITK_DISALLOW_COPY_AND_ASSIGN(AdaptiveNonLocalMeansDenoisingImageFilter); + /** Standard class typedefs. */ + typedef AdaptiveNonLocalMeansDenoisingImageFilter Self; + typedef NonLocalPatchBasedImageFilter Superclass; + typedef SmartPointer Pointer; + typedef SmartPointer ConstPointer; + + /** Runtime information support. */ + itkTypeMacro(AdaptiveNonLocalMeansDenoisingImageFilter, NonLocalPatchBasedImageFilter); - static constexpr unsigned int InputImageDimension = TInputImage::ImageDimension; - static constexpr unsigned int OutputImageDimension = TOutputImage::ImageDimension; + /** Standard New method. */ + itkNewMacro(Self); - using InputImageType = TInputImage; - using OutputImageType = TOutputImage; - using InputPixelType = typename InputImageType::PixelType; - using OutputPixelType = typename OutputImageType::PixelType; + /** ImageDimension constants */ + itkStaticConstMacro(ImageDimension, unsigned int, TInputImage::ImageDimension); - /** Standard class typedefs. */ - using Self = AdaptiveNonLocalMeansDenoisingImageFilter; - using Superclass = ImageToImageFilter; - using Pointer = SmartPointer; - using ConstPointer = SmartPointer; + /** Some convenient typedefs. */ + typedef TInputImage InputImageType; + typedef typename InputImageType::PixelType InputPixelType; + typedef TOutputImage OutputImageType; + typedef typename Superclass::RegionType RegionType; - /** Run-time type information. */ - itkTypeMacro(AdaptiveNonLocalMeansDenoisingImageFilter, ImageToImageFilter); + typedef TMaskImage MaskImageType; + typedef typename MaskImageType::PixelType MaskPixelType; + typedef typename MaskImageType::PixelType LabelType; - /** Standard New macro. */ - itkNewMacro(Self); + typedef typename Superclass::RealType RealType; + typedef typename Superclass::RealImageType RealImageType; + typedef typename Superclass::RealImagePointer RealImagePointer; + typedef typename Superclass::IndexType IndexType; + + typedef typename Superclass::ConstNeighborhoodIteratorType ConstNeighborhoodIteratorType; + typedef typename Superclass::NeighborhoodRadiusType NeighborhoodRadiusType; + typedef typename Superclass::NeighborhoodOffsetType NeighborhoodOffsetType; + typedef typename Superclass::NeighborhoodOffsetListType NeighborhoodOffsetListType; + + typedef GaussianOperator ModifiedBesselCalculatorType; + + /** + * The image expected for input for noise correction. + */ + void + SetInput1(const InputImageType * image) + { + this->SetInput(image); + } + + /** + * Set mask image function. If a binary mask image is specified, only + * those input image voxels corresponding with the mask image. + */ + void + SetMaskImage(const MaskImageType * mask) + { + this->SetNthInput(1, const_cast(mask)); + } + void + SetInput2(const MaskImageType * mask) + { + this->SetMaskImage(mask); + } + + /** + * Get mask image function. If a binary mask image is specified, only + * those input image voxels corresponding with the mask image. + */ + const MaskImageType * + GetMaskImage() const + { + return static_cast(this->ProcessObject::GetInput(1)); + } + + /** + * Employ Rician noise model. Otherwise use a Gaussian noise model. + * Default = true. + */ + itkSetMacro(UseRicianNoiseModel, bool); + itkGetConstMacro(UseRicianNoiseModel, bool); + itkBooleanMacro(UseRicianNoiseModel); + + /** + * Smoothing factor for noise. Default = 1.0. + */ + itkSetMacro(SmoothingFactor, RealType); + itkGetConstMacro(SmoothingFactor, RealType); + + /** + * Smoothing variance for Rician noise. Default = 2.0. + */ + itkSetMacro(SmoothingVariance, RealType); + itkGetConstMacro(SmoothingVariance, RealType); + + /** + * Epsilon for minimum value of mean and variance at a pixel. + * Default = 0.00001. + */ + itkSetMacro(Epsilon, RealType); + itkGetConstMacro(Epsilon, RealType); + + /** + * Mean threshold. + * Default = 0.95. + */ + itkSetMacro(MeanThreshold, RealType); + itkGetConstMacro(MeanThreshold, RealType); + + /** + * Variance threshold. + * Default = 0.5. + */ + itkSetMacro(VarianceThreshold, RealType); + itkGetConstMacro(VarianceThreshold, RealType); + + /** + * Neighborhood for computing local mean and variance images. + * Default = 1x1x... + */ + itkSetMacro(NeighborhoodRadiusForLocalMeanAndVariance, NeighborhoodRadiusType); + itkGetConstMacro(NeighborhoodRadiusForLocalMeanAndVariance, NeighborhoodRadiusType); protected: AdaptiveNonLocalMeansDenoisingImageFilter(); @@ -66,21 +176,48 @@ class AdaptiveNonLocalMeansDenoisingImageFilter : public ImageToImageFilter ) ); -#endif + AdaptiveNonLocalMeansDenoisingImageFilter(const Self &) = delete; + void + operator=(const Self &) = delete; + + RealType CalculateCorrectionFactor(RealType); + + bool m_UseRicianNoiseModel; + + ModifiedBesselCalculatorType m_ModifiedBesselCalculator; + + RealType m_Epsilon; + RealType m_MeanThreshold; + RealType m_VarianceThreshold; + RealType m_SmoothingFactor; + RealType m_SmoothingVariance; + + RealType m_MaximumInputPixelIntensity; + RealType m_MinimumInputPixelIntensity; + + RealImagePointer m_MeanImage; + RealImagePointer m_RicianBiasImage; + RealImagePointer m_VarianceImage; + RealImagePointer m_ThreadContributionCountImage; + RealImagePointer m_IntensitySquaredDistanceImage; + + NeighborhoodRadiusType m_NeighborhoodRadiusForLocalMeanAndVariance; }; -} // namespace itk + +} // end namespace itk #ifndef ITK_MANUAL_INSTANTIATION # include "itkAdaptiveNonLocalMeansDenoisingImageFilter.hxx" #endif -#endif // itkAdaptiveNonLocalMeansDenoisingImageFilter +#endif diff --git a/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.hxx b/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.hxx index d407607e35a6..84c578924d5b 100644 --- a/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.hxx +++ b/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.hxx @@ -1,6 +1,6 @@ /*========================================================================= * - * Copyright NumFOCUS + * Copyright Insight Software Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,44 +20,506 @@ #include "itkAdaptiveNonLocalMeansDenoisingImageFilter.h" -#include "itkImageRegionIterator.h" +#include "itkArray.h" +#include "itkDiscreteGaussianImageFilter.h" #include "itkImageRegionConstIterator.h" +#include "itkImageRegionIterator.h" +#include "itkImageRegionIteratorWithIndex.h" +#include "itkMath.h" +#include "itkMeanImageFilter.h" +#include "itkNeighborhoodIterator.h" +#include "itkProgressReporter.h" +#include "itkStatisticsImageFilter.h" +#include "itkVarianceImageFilter.h" + +#include namespace itk { -template -AdaptiveNonLocalMeansDenoisingImageFilter::AdaptiveNonLocalMeansDenoisingImageFilter() -{} +template +AdaptiveNonLocalMeansDenoisingImageFilter:: + AdaptiveNonLocalMeansDenoisingImageFilter() + : m_UseRicianNoiseModel(true) + , m_Epsilon(0.00001) + , m_MeanThreshold(0.95) + , m_VarianceThreshold(0.5) + , m_SmoothingFactor(1.0) + , m_SmoothingVariance(2.0) + , m_MaximumInputPixelIntensity(NumericTraits::NonpositiveMin()) + , m_MinimumInputPixelIntensity(NumericTraits::max()) +{ + this->SetNumberOfRequiredInputs(1); + this->m_MeanImage = nullptr; + this->m_VarianceImage = nullptr; + this->m_IntensitySquaredDistanceImage = nullptr; + this->m_ThreadContributionCountImage = nullptr; + + this->m_RicianBiasImage = nullptr; + + this->m_NeighborhoodRadiusForLocalMeanAndVariance.Fill(1); + this->DynamicMultiThreadingOff(); +} -template +template void -AdaptiveNonLocalMeansDenoisingImageFilter::PrintSelf(std::ostream & os, Indent indent) const +AdaptiveNonLocalMeansDenoisingImageFilter::BeforeThreadedGenerateData() { - Superclass::PrintSelf(os, indent); + Superclass::BeforeThreadedGenerateData(); + + const InputImageType * inputImage = this->GetInput(); + + typedef MeanImageFilter MeanImageFilterType; + typename MeanImageFilterType::Pointer meanImageFilter = MeanImageFilterType::New(); + meanImageFilter->SetInput(inputImage); + meanImageFilter->SetRadius(this->GetNeighborhoodRadiusForLocalMeanAndVariance()); + + this->m_MeanImage = meanImageFilter->GetOutput(); + this->m_MeanImage->Update(); + this->m_MeanImage->DisconnectPipeline(); + + typedef VarianceImageFilter VarianceImageFilterType; + typename VarianceImageFilterType::Pointer varianceImageFilter = VarianceImageFilterType::New(); + varianceImageFilter->SetInput(inputImage); + varianceImageFilter->SetRadius(this->GetNeighborhoodRadiusForLocalMeanAndVariance()); + + this->m_VarianceImage = varianceImageFilter->GetOutput(); + this->m_VarianceImage->Update(); + this->m_VarianceImage->DisconnectPipeline(); + + typedef StatisticsImageFilter StatsFilterType; + typename StatsFilterType::Pointer statsFilter = StatsFilterType::New(); + statsFilter->SetInput(inputImage); + statsFilter->Update(); + + this->m_MaximumInputPixelIntensity = static_cast(statsFilter->GetMaximum()); + this->m_MinimumInputPixelIntensity = static_cast(statsFilter->GetMinimum()); + + this->m_ThreadContributionCountImage = RealImageType::New(); + this->m_ThreadContributionCountImage->CopyInformation(inputImage); + this->m_ThreadContributionCountImage->SetRegions(inputImage->GetRequestedRegion()); + this->m_ThreadContributionCountImage->Allocate(true); + + if (this->m_UseRicianNoiseModel) + { + this->m_RicianBiasImage = RealImageType::New(); + this->m_RicianBiasImage->CopyInformation(inputImage); + this->m_RicianBiasImage->SetRegions(inputImage->GetRequestedRegion()); + this->m_RicianBiasImage->Allocate(true); + } + + this->AllocateOutputs(); + // Output buffer needs to be zero initialized + this->GetOutput()->FillBuffer(0.0); } +template +void +AdaptiveNonLocalMeansDenoisingImageFilter::ThreadedGenerateData( + const RegionType & region, + ThreadIdType threadId) +{ + ProgressReporter progress(this, threadId, region.GetNumberOfPixels(), 100); + + const InputImageType * inputImage = this->GetInput(); + const MaskImageType * maskImage = this->GetMaskImage(); + + OutputImageType * outputImage = this->GetOutput(); + RegionType targetImageRegion = this->GetTargetImageRegion(); + + NeighborhoodOffsetListType neighborhoodPatchOffsetList = this->GetNeighborhoodPatchOffsetList(); + + NeighborhoodRadiusType neighborhoodSearchRadius = this->GetNeighborhoodSearchRadius(); + + ConstNeighborhoodIterator ItV(neighborhoodSearchRadius, this->m_VarianceImage, region); + ConstNeighborhoodIterator ItM(neighborhoodSearchRadius, this->m_MeanImage, region); + + const unsigned int neighborhoodSearchSize = this->GetNeighborhoodSearchSize(); + const unsigned int neighborhoodPatchSize = this->GetNeighborhoodPatchSize(); + + Array weightedAverageIntensities(neighborhoodPatchSize); + + ItM.GoToBegin(); + ItV.GoToBegin(); + + while (!ItM.IsAtEnd()) + { + typename InputImageType::IndexType centerIndex = ItM.GetIndex(); + + InputPixelType inputCenterPixel = inputImage->GetPixel(centerIndex); + RealType meanCenterPixel = this->m_MeanImage->GetPixel(centerIndex); + RealType varianceCenterPixel = this->m_VarianceImage->GetPixel(centerIndex); + + RealType maxWeight = NumericTraits::ZeroValue(); + RealType sumOfWeights = NumericTraits::ZeroValue(); + + weightedAverageIntensities.Fill(NumericTraits::ZeroValue()); + + RealType meanNeighborhoodPixel = NumericTraits::ZeroValue(); + RealType varianceNeighborhoodPixel = NumericTraits::ZeroValue(); + + if (inputCenterPixel > 0 && meanCenterPixel > this->m_Epsilon && varianceCenterPixel > this->m_Epsilon && + (!maskImage || maskImage->GetPixel(centerIndex) != NumericTraits::ZeroValue())) + { + // Calculate the minimum distance + + RealType minimumDistance = NumericTraits::max(); + for (unsigned int m = 0; m < neighborhoodSearchSize; m++) + { + if (!ItM.IndexInBounds(m) || m == static_cast(0.5 * neighborhoodSearchSize)) + { + continue; + } + + IndexType neighborhoodIndex = ItM.GetIndex(m); + + if (inputImage->GetPixel(neighborhoodIndex) <= 0) + { + continue; + } + + meanNeighborhoodPixel = this->m_MeanImage->GetPixel(neighborhoodIndex); + varianceNeighborhoodPixel = this->m_VarianceImage->GetPixel(neighborhoodIndex); + + if (meanNeighborhoodPixel <= this->m_Epsilon || varianceNeighborhoodPixel <= this->m_Epsilon) + { + continue; + } + + const RealType meanRatio = meanCenterPixel / meanNeighborhoodPixel; + const RealType meanRatioInverse = (this->m_MaximumInputPixelIntensity - meanCenterPixel) / + (this->m_MaximumInputPixelIntensity - meanNeighborhoodPixel); + + const RealType varianceRatio = varianceCenterPixel / varianceNeighborhoodPixel; + + if (((meanRatio > this->m_MeanThreshold && + meanRatio < itk::NumericTraits::OneValue() / this->m_MeanThreshold) || + (meanRatioInverse > this->m_MeanThreshold && + meanRatioInverse < itk::NumericTraits::OneValue() / this->m_MeanThreshold)) && + varianceRatio > this->m_VarianceThreshold && + varianceRatio < itk::NumericTraits::OneValue() / this->m_VarianceThreshold) + { + + RealType averageDistance = itk::NumericTraits::ZeroValue(); + RealType count = itk::NumericTraits::ZeroValue(); + + for (unsigned int n = 0; n < neighborhoodPatchSize; n++) + { + IndexType neighborhoodPatchIndex = neighborhoodIndex + neighborhoodPatchOffsetList[n]; + + if (!targetImageRegion.IsInside(neighborhoodPatchIndex)) + { + continue; + } + RealType neighborhoodInputImagePixel = static_cast(inputImage->GetPixel(neighborhoodPatchIndex)); + RealType neighborhoodMeanImagePixel = this->m_MeanImage->GetPixel(neighborhoodPatchIndex); + averageDistance += itk::Math::sqr(neighborhoodInputImagePixel - neighborhoodMeanImagePixel); + + count += itk::NumericTraits::OneValue(); + } + averageDistance /= count; + minimumDistance = std::min(averageDistance, minimumDistance); + } + } + + if (itk::Math::AlmostEquals(minimumDistance, NumericTraits::ZeroValue())) + { + minimumDistance = NumericTraits::OneValue(); + } + + // Rician correction + + if (this->m_UseRicianNoiseModel) + { + for (unsigned int n = 0; n < neighborhoodPatchSize; n++) + { + IndexType neighborhoodPatchIndex = centerIndex + neighborhoodPatchOffsetList[n]; + if (!targetImageRegion.IsInside(neighborhoodPatchIndex)) + { + continue; + } + + if (itk::Math::AlmostEquals(minimumDistance, NumericTraits::max())) + { + this->m_RicianBiasImage->SetPixel(neighborhoodPatchIndex, 0.0); + } + else + { + this->m_RicianBiasImage->SetPixel(neighborhoodPatchIndex, minimumDistance); + } + } + } -template + // Patch filtering + + for (unsigned int m = 0; m < neighborhoodSearchSize; m++) + { + if (!ItM.IndexInBounds(m) || m == static_cast(0.5 * neighborhoodSearchSize)) + { + continue; + } + + IndexType neighborhoodIndex = ItM.GetIndex(m); + + if (inputImage->GetPixel(neighborhoodIndex) <= 0) + { + continue; + } + + meanNeighborhoodPixel = this->m_MeanImage->GetPixel(neighborhoodIndex); + varianceNeighborhoodPixel = this->m_VarianceImage->GetPixel(neighborhoodIndex); + + if (meanNeighborhoodPixel <= this->m_Epsilon || varianceNeighborhoodPixel <= this->m_Epsilon) + { + continue; + } + + const RealType meanRatio = meanCenterPixel / meanNeighborhoodPixel; + const RealType meanRatioInverse = (this->m_MaximumInputPixelIntensity - meanCenterPixel) / + (this->m_MaximumInputPixelIntensity - meanNeighborhoodPixel); + + const RealType varianceRatio = varianceCenterPixel / varianceNeighborhoodPixel; + + if (((meanRatio > this->m_MeanThreshold && + meanRatio < itk::NumericTraits::OneValue() / this->m_MeanThreshold) || + (meanRatioInverse > this->m_MeanThreshold && + meanRatioInverse < itk::NumericTraits::OneValue() / this->m_MeanThreshold)) && + varianceRatio > this->m_VarianceThreshold && + varianceRatio < itk::NumericTraits::OneValue() / this->m_VarianceThreshold) + { + + RealType averageDistance = 0.0; + RealType count = 0.0; + for (unsigned int n = 0; n < neighborhoodPatchSize; n++) + { + IndexType searchNeighborhoodPatchIndex = neighborhoodIndex + neighborhoodPatchOffsetList[n]; + IndexType centerNeighborhoodPatchIndex = centerIndex + neighborhoodPatchOffsetList[n]; + if (!targetImageRegion.IsInside(searchNeighborhoodPatchIndex) || + !targetImageRegion.IsInside(centerNeighborhoodPatchIndex)) + { + continue; + } + RealType distance1 = inputImage->GetPixel(searchNeighborhoodPatchIndex) - + this->m_MeanImage->GetPixel(searchNeighborhoodPatchIndex); + RealType distance2 = inputImage->GetPixel(centerNeighborhoodPatchIndex) - + this->m_MeanImage->GetPixel(centerNeighborhoodPatchIndex); + averageDistance += itk::Math::sqr(distance1 - distance2); + count += itk::NumericTraits::OneValue(); + } + averageDistance /= count; + + RealType weight = itk::NumericTraits::ZeroValue(); + if (averageDistance <= static_cast(3.0) * minimumDistance) + { + weight = std::exp(-averageDistance / minimumDistance); + } + if (weight > maxWeight) + { + maxWeight = weight; + } + + if (weight > itk::NumericTraits::ZeroValue()) + { + for (unsigned int n = 0; n < neighborhoodPatchSize; n++) + { + IndexType neighborhoodPatchIndex = neighborhoodIndex + neighborhoodPatchOffsetList[n]; + if (!targetImageRegion.IsInside(neighborhoodPatchIndex)) + { + continue; + } + if (this->m_UseRicianNoiseModel) + { + weightedAverageIntensities[n] += weight * itk::Math::sqr(inputImage->GetPixel(neighborhoodPatchIndex)); + } + else + { + weightedAverageIntensities[n] += weight * inputImage->GetPixel(neighborhoodPatchIndex); + } + } + sumOfWeights += weight; + } + } + } + + if (itk::Math::AlmostEquals(maxWeight, NumericTraits::ZeroValue())) + { + maxWeight = NumericTraits::OneValue(); + } + } + else + { + maxWeight = NumericTraits::OneValue(); + } + + for (unsigned int n = 0; n < neighborhoodPatchSize; n++) + { + IndexType neighborhoodPatchIndex = centerIndex + neighborhoodPatchOffsetList[n]; + if (!targetImageRegion.IsInside(neighborhoodPatchIndex)) + { + continue; + } + if (this->m_UseRicianNoiseModel) + { + weightedAverageIntensities[n] += maxWeight * itk::Math::sqr(inputImage->GetPixel(neighborhoodPatchIndex)); + } + else + { + weightedAverageIntensities[n] += maxWeight * inputImage->GetPixel(neighborhoodPatchIndex); + } + } + sumOfWeights += maxWeight; + + if (sumOfWeights > itk::NumericTraits::ZeroValue()) + { + for (unsigned int n = 0; n < neighborhoodPatchSize; n++) + { + IndexType neighborhoodPatchIndex = centerIndex + neighborhoodPatchOffsetList[n]; + if (!targetImageRegion.IsInside(neighborhoodPatchIndex)) + { + continue; + } + typename OutputImageType::PixelType estimate = outputImage->GetPixel(neighborhoodPatchIndex); + estimate += (weightedAverageIntensities[n] / sumOfWeights); + + outputImage->SetPixel(neighborhoodPatchIndex, estimate); + this->m_ThreadContributionCountImage->SetPixel( + neighborhoodPatchIndex, this->m_ThreadContributionCountImage->GetPixel(neighborhoodPatchIndex) + 1); + } + } + + ++ItM; + ++ItV; + + progress.CompletedPixel(); + } +} + +template void -AdaptiveNonLocalMeansDenoisingImageFilter::DynamicThreadedGenerateData( - const OutputRegionType & outputRegion) +AdaptiveNonLocalMeansDenoisingImageFilter::AfterThreadedGenerateData() +{ + const MaskImageType * maskImage = this->GetMaskImage(); + + if (this->m_UseRicianNoiseModel) + { + typedef DiscreteGaussianImageFilter SmootherType; + typename SmootherType::Pointer smoother = SmootherType::New(); + smoother->SetInput(this->m_RicianBiasImage); + smoother->SetVariance(this->m_SmoothingVariance); + smoother->SetUseImageSpacingOn(); + smoother->Update(); + + ImageRegionConstIterator ItS(smoother->GetOutput(), smoother->GetOutput()->GetRequestedRegion()); + ImageRegionConstIteratorWithIndex ItM(this->m_MeanImage, this->m_MeanImage->GetRequestedRegion()); + ImageRegionIterator ItB(this->m_RicianBiasImage, this->m_RicianBiasImage->GetRequestedRegion()); + ItS.GoToBegin(); + ItM.GoToBegin(); + ItB.GoToBegin(); + + while (!ItS.IsAtEnd()) + { + if (ItS.Get() > itk::NumericTraits::ZeroValue() && + (!maskImage || maskImage->GetPixel(ItM.GetIndex()) != NumericTraits::ZeroValue())) + { + const RealType snr = ItM.Get() / std::sqrt(ItS.Get()); + + RealType bias = static_cast(2.0) * ItS.Get() / this->CalculateCorrectionFactor(snr); + + if (std::isnan(bias) || std::isinf(bias)) + { + bias = itk::NumericTraits::ZeroValue(); + } + ItB.Set(bias); + } + + ++ItS; + ++ItM; + ++ItB; + } + } + + ImageRegionIteratorWithIndex ItO(this->GetOutput(), this->GetOutput()->GetRequestedRegion()); + ImageRegionConstIterator ItL(this->m_ThreadContributionCountImage, + this->m_ThreadContributionCountImage->GetRequestedRegion()); + + for (ItO.GoToBegin(), ItL.GoToBegin(); !ItO.IsAtEnd(); ++ItO, ++ItL) + { + RealType estimate = ItO.Get(); + + if (itk::Math::FloatAlmostEqual(ItL.Get(), itk::NumericTraits::ZeroValue())) + { + continue; + } + + estimate /= ItL.Get(); + + if (this->m_UseRicianNoiseModel) + { + RealType bias = this->m_RicianBiasImage->GetPixel(ItO.GetIndex()); + + estimate -= bias; + if (estimate < itk::NumericTraits::ZeroValue()) + { + estimate = itk::NumericTraits::ZeroValue(); + } + estimate = std::sqrt(estimate); + } + + ItO.Set(estimate); + } +} + +template +typename AdaptiveNonLocalMeansDenoisingImageFilter::RealType +AdaptiveNonLocalMeansDenoisingImageFilter::CalculateCorrectionFactor( + RealType snr) { - OutputImageType * output = this->GetOutput(); - const InputImageType * input = this->GetInput(); - using InputRegionType = typename InputImageType::RegionType; - InputRegionType inputRegion = InputRegionType(outputRegion.GetSize()); + const RealType snrSquared = itk::Math::sqr(snr); - itk::ImageRegionConstIterator in(input, inputRegion); - itk::ImageRegionIterator out(output, outputRegion); + RealType value = + static_cast(2.0) + snrSquared - + static_cast(0.125) * static_cast(Math::pi) * + static_cast(std::exp(static_cast(-0.5) * snrSquared)) * + itk::Math::sqr((static_cast(2.0) + snrSquared) * + static_cast( + this->m_ModifiedBesselCalculator.ModifiedBesselI0(static_cast(0.25) * snrSquared)) + + snrSquared * static_cast(this->m_ModifiedBesselCalculator.ModifiedBesselI1( + static_cast(0.25) * snrSquared))); - for (in.GoToBegin(), out.GoToBegin(); !in.IsAtEnd() && !out.IsAtEnd(); ++in, ++out) + if (value < static_cast(0.001) || value > static_cast(10.0)) { - out.Set(in.Get()); + value = itk::NumericTraits::OneValue(); } + return value; +} + +template +void +AdaptiveNonLocalMeansDenoisingImageFilter::PrintSelf(std::ostream & os, + Indent indent) const +{ + Superclass::PrintSelf(os, indent); + + if (this->m_UseRicianNoiseModel) + { + os << indent << "Using Rician noise model." << std::endl; + } + else + { + os << indent << "Using Gaussian noise model." << std::endl; + } + + os << indent << "Epsilon = " << this->m_Epsilon << std::endl; + os << indent << "Mean threshold = " << this->m_MeanThreshold << std::endl; + os << indent << "Variance threshold = " << this->m_VarianceThreshold << std::endl; + os << indent << "Smoothing variance = " << this->m_SmoothingVariance << std::endl; + + os << indent + << "Neighborhood radius for local mean and variance = " << this->m_NeighborhoodRadiusForLocalMeanAndVariance + << std::endl; } } // end namespace itk -#endif // itkAdaptiveNonLocalMeansDenoisingImageFilter_hxx +#endif diff --git a/Modules/Filtering/AdaptiveDenoising/include/itkMinimalStandardRandomVariateGenerator.h b/Modules/Filtering/AdaptiveDenoising/include/itkMinimalStandardRandomVariateGenerator.h deleted file mode 100644 index 3a6be913d94a..000000000000 --- a/Modules/Filtering/AdaptiveDenoising/include/itkMinimalStandardRandomVariateGenerator.h +++ /dev/null @@ -1,96 +0,0 @@ -/*========================================================================= - * - * 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 - * - * http://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 itkMinimalStandardRandomVariateGenerator_h -#define itkMinimalStandardRandomVariateGenerator_h - -#include "itkIntTypes.h" -#include "itkObjectFactory.h" -#include "itkRandomVariateGeneratorBase.h" -#include "AdaptiveDenoisingExport.h" -#include "itkNormalVariateGenerator.h" - -namespace itk -{ -namespace Statistics -{ -/** \class MinimalStandardRandomVariateGenerator - * \brief Linear congruential random random variate generator. - * - * This is a pseudo-random number generator for unsigned integers following - * - * \f[ - * X_{n+1} = (a X_n + c) \mod m - * \f] - * - * where \f$a\f$ is the Multiplier \f$c\f$ is the Increment and \f$m\f$ is - * the Modulus. - * - * http://en.wikipedia.com/wiki/Linear_congruential_generator - * - * The random numbers generated have a period \f$m\f$. - * - * This class uses \f$a = 48271\f$, \f$c = 0\f$, \f$m = 2^31 -1 = - * 2147483647\f$, the Minimial Standard configuration recommended by Park, - * Miller and Stockmeyer in 1993. - * - * \ingroup AdaptiveDenoising - */ -class AdaptiveDenoising_EXPORT MinimalStandardRandomVariateGenerator : public RandomVariateGeneratorBase -{ -public: - ITK_DISALLOW_COPY_AND_ASSIGN(MinimalStandardRandomVariateGenerator); - - /** Standard class typedefs. */ - using Self = MinimalStandardRandomVariateGenerator; - using Superclass = RandomVariateGeneratorBase; - using Pointer = SmartPointer; - using ConstPointer = SmartPointer; - - using IntegerType = uint32_t; - - using NormalGeneratorType = itk::Statistics::NormalVariateGenerator; - - /** Run-time type information (and related methods). */ - itkTypeMacro(MinimalStandardRandomVariateGenerator, RandomVariateGeneratorBase); - - /** Method for creation through the object factory. */ - itkNewMacro(Self); - - /** initialize with a simple IntegerType */ - void - Initialize(int randomSeed); - - /** Get a variate in the range [0, 1] */ - double - GetVariate() override; - -protected: - MinimalStandardRandomVariateGenerator(); - ~MinimalStandardRandomVariateGenerator() override = default; - - void - PrintSelf(std::ostream & os, Indent indent) const override; - -private: - NormalGeneratorType::Pointer m_NormalGenerator; -}; - -} // end of namespace Statistics -} // end of namespace itk - -#endif // itkMinimalStandardRandomVariateGenerator_h diff --git a/Modules/Filtering/AdaptiveDenoising/src/itkNonLocalPatchBasedImageFilter.h b/Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.h similarity index 100% rename from Modules/Filtering/AdaptiveDenoising/src/itkNonLocalPatchBasedImageFilter.h rename to Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.h diff --git a/Modules/Filtering/AdaptiveDenoising/src/itkNonLocalPatchBasedImageFilter.hxx b/Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.hxx similarity index 100% rename from Modules/Filtering/AdaptiveDenoising/src/itkNonLocalPatchBasedImageFilter.hxx rename to Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.hxx diff --git a/Modules/Filtering/AdaptiveDenoising/src/itkVarianceImageFilter.h b/Modules/Filtering/AdaptiveDenoising/include/itkVarianceImageFilter.h similarity index 100% rename from Modules/Filtering/AdaptiveDenoising/src/itkVarianceImageFilter.h rename to Modules/Filtering/AdaptiveDenoising/include/itkVarianceImageFilter.h diff --git a/Modules/Filtering/AdaptiveDenoising/src/itkVarianceImageFilter.hxx b/Modules/Filtering/AdaptiveDenoising/include/itkVarianceImageFilter.hxx similarity index 100% rename from Modules/Filtering/AdaptiveDenoising/src/itkVarianceImageFilter.hxx rename to Modules/Filtering/AdaptiveDenoising/include/itkVarianceImageFilter.hxx diff --git a/Modules/Filtering/AdaptiveDenoising/itk-module.cmake b/Modules/Filtering/AdaptiveDenoising/itk-module.cmake index de3b940c428a..2f10fe55feac 100644 --- a/Modules/Filtering/AdaptiveDenoising/itk-module.cmake +++ b/Modules/Filtering/AdaptiveDenoising/itk-module.cmake @@ -12,7 +12,9 @@ itk_module( AdaptiveDenoising DEPENDS ITKCommon + ITKSmoothing ITKStatistics + ITKImageStatistics COMPILE_DEPENDS ITKImageSources TEST_DEPENDS diff --git a/Modules/Filtering/AdaptiveDenoising/src/CMakeLists.txt b/Modules/Filtering/AdaptiveDenoising/src/CMakeLists.txt deleted file mode 100644 index 77d4bd24ee3e..000000000000 --- a/Modules/Filtering/AdaptiveDenoising/src/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -set(AdaptiveDenoising_SRCS - itkMinimalStandardRandomVariateGenerator.cxx - ) - -itk_module_add_library(AdaptiveDenoising ${AdaptiveDenoising_SRCS}) diff --git a/Modules/Filtering/AdaptiveDenoising/src/itkAdaptiveNonLocalMeansDenoisingImageFilter.h b/Modules/Filtering/AdaptiveDenoising/src/itkAdaptiveNonLocalMeansDenoisingImageFilter.h deleted file mode 100644 index 463e11004489..000000000000 --- a/Modules/Filtering/AdaptiveDenoising/src/itkAdaptiveNonLocalMeansDenoisingImageFilter.h +++ /dev/null @@ -1,223 +0,0 @@ -/*========================================================================= - * - * Copyright Insight Software Consortium - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0.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 itkAdaptiveNonLocalMeansDenoisingImageFilter_h -#define itkAdaptiveNonLocalMeansDenoisingImageFilter_h - -#include "itkNonLocalPatchBasedImageFilter.h" - -#include "itkConstNeighborhoodIterator.h" -#include "itkGaussianOperator.h" - -namespace itk -{ - -/** - * \class AdaptiveNonLocalMeansDenoisingImageFilter - * \brief Implementation of a denoising image filter. - * - * \author Jose V. Manjon with ITK porting by Nick Tustison - * - * Contributed by - * - * \par REFERENCE - * - * J. V. Manjon, P. Coupe, Luis Marti-Bonmati, D. L. Collins, - * and M. Robles. "Adaptive Non-Local Means Denoising of MR Images With - * Spatially Varying Noise Levels, Journal of Magnetic Resonance Imaging, - * 31:192-203, June 2010. - * - * \ingroup ITKNoiseFiltering - */ - -template > -class AdaptiveNonLocalMeansDenoisingImageFilter final : public NonLocalPatchBasedImageFilter -{ -public: - /** Standard class typedefs. */ - typedef AdaptiveNonLocalMeansDenoisingImageFilter Self; - typedef NonLocalPatchBasedImageFilter Superclass; - typedef SmartPointer Pointer; - typedef SmartPointer ConstPointer; - - /** Runtime information support. */ - itkTypeMacro(AdaptiveNonLocalMeansDenoisingImageFilter, NonLocalPatchBasedImageFilter); - - /** Standard New method. */ - itkNewMacro(Self); - - /** ImageDimension constants */ - itkStaticConstMacro(ImageDimension, unsigned int, TInputImage::ImageDimension); - - /** Some convenient typedefs. */ - typedef TInputImage InputImageType; - typedef typename InputImageType::PixelType InputPixelType; - typedef TOutputImage OutputImageType; - typedef typename Superclass::RegionType RegionType; - - typedef TMaskImage MaskImageType; - typedef typename MaskImageType::PixelType MaskPixelType; - typedef typename MaskImageType::PixelType LabelType; - - typedef typename Superclass::RealType RealType; - typedef typename Superclass::RealImageType RealImageType; - typedef typename Superclass::RealImagePointer RealImagePointer; - typedef typename Superclass::IndexType IndexType; - - typedef typename Superclass::ConstNeighborhoodIteratorType ConstNeighborhoodIteratorType; - typedef typename Superclass::NeighborhoodRadiusType NeighborhoodRadiusType; - typedef typename Superclass::NeighborhoodOffsetType NeighborhoodOffsetType; - typedef typename Superclass::NeighborhoodOffsetListType NeighborhoodOffsetListType; - - typedef GaussianOperator ModifiedBesselCalculatorType; - - /** - * The image expected for input for noise correction. - */ - void - SetInput1(const InputImageType * image) - { - this->SetInput(image); - } - - /** - * Set mask image function. If a binary mask image is specified, only - * those input image voxels corresponding with the mask image. - */ - void - SetMaskImage(const MaskImageType * mask) - { - this->SetNthInput(1, const_cast(mask)); - } - void - SetInput2(const MaskImageType * mask) - { - this->SetMaskImage(mask); - } - - /** - * Get mask image function. If a binary mask image is specified, only - * those input image voxels corresponding with the mask image. - */ - const MaskImageType * - GetMaskImage() const - { - return static_cast(this->ProcessObject::GetInput(1)); - } - - /** - * Employ Rician noise model. Otherwise use a Gaussian noise model. - * Default = true. - */ - itkSetMacro(UseRicianNoiseModel, bool); - itkGetConstMacro(UseRicianNoiseModel, bool); - itkBooleanMacro(UseRicianNoiseModel); - - /** - * Smoothing factor for noise. Default = 1.0. - */ - itkSetMacro(SmoothingFactor, RealType); - itkGetConstMacro(SmoothingFactor, RealType); - - /** - * Smoothing variance for Rician noise. Default = 2.0. - */ - itkSetMacro(SmoothingVariance, RealType); - itkGetConstMacro(SmoothingVariance, RealType); - - /** - * Epsilon for minimum value of mean and variance at a pixel. - * Default = 0.00001. - */ - itkSetMacro(Epsilon, RealType); - itkGetConstMacro(Epsilon, RealType); - - /** - * Mean threshold. - * Default = 0.95. - */ - itkSetMacro(MeanThreshold, RealType); - itkGetConstMacro(MeanThreshold, RealType); - - /** - * Variance threshold. - * Default = 0.5. - */ - itkSetMacro(VarianceThreshold, RealType); - itkGetConstMacro(VarianceThreshold, RealType); - - /** - * Neighborhood for computing local mean and variance images. - * Default = 1x1x... - */ - itkSetMacro(NeighborhoodRadiusForLocalMeanAndVariance, NeighborhoodRadiusType); - itkGetConstMacro(NeighborhoodRadiusForLocalMeanAndVariance, NeighborhoodRadiusType); - -protected: - AdaptiveNonLocalMeansDenoisingImageFilter(); - ~AdaptiveNonLocalMeansDenoisingImageFilter() override = default; - - void - PrintSelf(std::ostream & os, Indent indent) const override; - - void - ThreadedGenerateData(const RegionType &, ThreadIdType) override; - - void - BeforeThreadedGenerateData() override; - - void - AfterThreadedGenerateData() override; - -private: - AdaptiveNonLocalMeansDenoisingImageFilter(const Self &) = delete; - void - operator=(const Self &) = delete; - - RealType CalculateCorrectionFactor(RealType); - - bool m_UseRicianNoiseModel; - - ModifiedBesselCalculatorType m_ModifiedBesselCalculator; - - RealType m_Epsilon; - RealType m_MeanThreshold; - RealType m_VarianceThreshold; - RealType m_SmoothingFactor; - RealType m_SmoothingVariance; - - RealType m_MaximumInputPixelIntensity; - RealType m_MinimumInputPixelIntensity; - - RealImagePointer m_MeanImage; - RealImagePointer m_RicianBiasImage; - RealImagePointer m_VarianceImage; - RealImagePointer m_ThreadContributionCountImage; - RealImagePointer m_IntensitySquaredDistanceImage; - - NeighborhoodRadiusType m_NeighborhoodRadiusForLocalMeanAndVariance; -}; - -} // end namespace itk - -#ifndef ITK_MANUAL_INSTANTIATION -# include "itkAdaptiveNonLocalMeansDenoisingImageFilter.hxx" -#endif - -#endif diff --git a/Modules/Filtering/AdaptiveDenoising/src/itkAdaptiveNonLocalMeansDenoisingImageFilter.hxx b/Modules/Filtering/AdaptiveDenoising/src/itkAdaptiveNonLocalMeansDenoisingImageFilter.hxx deleted file mode 100644 index 84c578924d5b..000000000000 --- a/Modules/Filtering/AdaptiveDenoising/src/itkAdaptiveNonLocalMeansDenoisingImageFilter.hxx +++ /dev/null @@ -1,525 +0,0 @@ -/*========================================================================= - * - * Copyright Insight Software Consortium - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0.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 itkAdaptiveNonLocalMeansDenoisingImageFilter_hxx -#define itkAdaptiveNonLocalMeansDenoisingImageFilter_hxx - -#include "itkAdaptiveNonLocalMeansDenoisingImageFilter.h" - -#include "itkArray.h" -#include "itkDiscreteGaussianImageFilter.h" -#include "itkImageRegionConstIterator.h" -#include "itkImageRegionIterator.h" -#include "itkImageRegionIteratorWithIndex.h" -#include "itkMath.h" -#include "itkMeanImageFilter.h" -#include "itkNeighborhoodIterator.h" -#include "itkProgressReporter.h" -#include "itkStatisticsImageFilter.h" -#include "itkVarianceImageFilter.h" - -#include - -namespace itk -{ - -template -AdaptiveNonLocalMeansDenoisingImageFilter:: - AdaptiveNonLocalMeansDenoisingImageFilter() - : m_UseRicianNoiseModel(true) - , m_Epsilon(0.00001) - , m_MeanThreshold(0.95) - , m_VarianceThreshold(0.5) - , m_SmoothingFactor(1.0) - , m_SmoothingVariance(2.0) - , m_MaximumInputPixelIntensity(NumericTraits::NonpositiveMin()) - , m_MinimumInputPixelIntensity(NumericTraits::max()) -{ - this->SetNumberOfRequiredInputs(1); - - this->m_MeanImage = nullptr; - this->m_VarianceImage = nullptr; - this->m_IntensitySquaredDistanceImage = nullptr; - this->m_ThreadContributionCountImage = nullptr; - - this->m_RicianBiasImage = nullptr; - - this->m_NeighborhoodRadiusForLocalMeanAndVariance.Fill(1); - this->DynamicMultiThreadingOff(); -} - -template -void -AdaptiveNonLocalMeansDenoisingImageFilter::BeforeThreadedGenerateData() -{ - Superclass::BeforeThreadedGenerateData(); - - const InputImageType * inputImage = this->GetInput(); - - typedef MeanImageFilter MeanImageFilterType; - typename MeanImageFilterType::Pointer meanImageFilter = MeanImageFilterType::New(); - meanImageFilter->SetInput(inputImage); - meanImageFilter->SetRadius(this->GetNeighborhoodRadiusForLocalMeanAndVariance()); - - this->m_MeanImage = meanImageFilter->GetOutput(); - this->m_MeanImage->Update(); - this->m_MeanImage->DisconnectPipeline(); - - typedef VarianceImageFilter VarianceImageFilterType; - typename VarianceImageFilterType::Pointer varianceImageFilter = VarianceImageFilterType::New(); - varianceImageFilter->SetInput(inputImage); - varianceImageFilter->SetRadius(this->GetNeighborhoodRadiusForLocalMeanAndVariance()); - - this->m_VarianceImage = varianceImageFilter->GetOutput(); - this->m_VarianceImage->Update(); - this->m_VarianceImage->DisconnectPipeline(); - - typedef StatisticsImageFilter StatsFilterType; - typename StatsFilterType::Pointer statsFilter = StatsFilterType::New(); - statsFilter->SetInput(inputImage); - statsFilter->Update(); - - this->m_MaximumInputPixelIntensity = static_cast(statsFilter->GetMaximum()); - this->m_MinimumInputPixelIntensity = static_cast(statsFilter->GetMinimum()); - - this->m_ThreadContributionCountImage = RealImageType::New(); - this->m_ThreadContributionCountImage->CopyInformation(inputImage); - this->m_ThreadContributionCountImage->SetRegions(inputImage->GetRequestedRegion()); - this->m_ThreadContributionCountImage->Allocate(true); - - if (this->m_UseRicianNoiseModel) - { - this->m_RicianBiasImage = RealImageType::New(); - this->m_RicianBiasImage->CopyInformation(inputImage); - this->m_RicianBiasImage->SetRegions(inputImage->GetRequestedRegion()); - this->m_RicianBiasImage->Allocate(true); - } - - this->AllocateOutputs(); - // Output buffer needs to be zero initialized - this->GetOutput()->FillBuffer(0.0); -} - -template -void -AdaptiveNonLocalMeansDenoisingImageFilter::ThreadedGenerateData( - const RegionType & region, - ThreadIdType threadId) -{ - ProgressReporter progress(this, threadId, region.GetNumberOfPixels(), 100); - - const InputImageType * inputImage = this->GetInput(); - const MaskImageType * maskImage = this->GetMaskImage(); - - OutputImageType * outputImage = this->GetOutput(); - RegionType targetImageRegion = this->GetTargetImageRegion(); - - NeighborhoodOffsetListType neighborhoodPatchOffsetList = this->GetNeighborhoodPatchOffsetList(); - - NeighborhoodRadiusType neighborhoodSearchRadius = this->GetNeighborhoodSearchRadius(); - - ConstNeighborhoodIterator ItV(neighborhoodSearchRadius, this->m_VarianceImage, region); - ConstNeighborhoodIterator ItM(neighborhoodSearchRadius, this->m_MeanImage, region); - - const unsigned int neighborhoodSearchSize = this->GetNeighborhoodSearchSize(); - const unsigned int neighborhoodPatchSize = this->GetNeighborhoodPatchSize(); - - Array weightedAverageIntensities(neighborhoodPatchSize); - - ItM.GoToBegin(); - ItV.GoToBegin(); - - while (!ItM.IsAtEnd()) - { - typename InputImageType::IndexType centerIndex = ItM.GetIndex(); - - InputPixelType inputCenterPixel = inputImage->GetPixel(centerIndex); - RealType meanCenterPixel = this->m_MeanImage->GetPixel(centerIndex); - RealType varianceCenterPixel = this->m_VarianceImage->GetPixel(centerIndex); - - RealType maxWeight = NumericTraits::ZeroValue(); - RealType sumOfWeights = NumericTraits::ZeroValue(); - - weightedAverageIntensities.Fill(NumericTraits::ZeroValue()); - - RealType meanNeighborhoodPixel = NumericTraits::ZeroValue(); - RealType varianceNeighborhoodPixel = NumericTraits::ZeroValue(); - - if (inputCenterPixel > 0 && meanCenterPixel > this->m_Epsilon && varianceCenterPixel > this->m_Epsilon && - (!maskImage || maskImage->GetPixel(centerIndex) != NumericTraits::ZeroValue())) - { - // Calculate the minimum distance - - RealType minimumDistance = NumericTraits::max(); - for (unsigned int m = 0; m < neighborhoodSearchSize; m++) - { - if (!ItM.IndexInBounds(m) || m == static_cast(0.5 * neighborhoodSearchSize)) - { - continue; - } - - IndexType neighborhoodIndex = ItM.GetIndex(m); - - if (inputImage->GetPixel(neighborhoodIndex) <= 0) - { - continue; - } - - meanNeighborhoodPixel = this->m_MeanImage->GetPixel(neighborhoodIndex); - varianceNeighborhoodPixel = this->m_VarianceImage->GetPixel(neighborhoodIndex); - - if (meanNeighborhoodPixel <= this->m_Epsilon || varianceNeighborhoodPixel <= this->m_Epsilon) - { - continue; - } - - const RealType meanRatio = meanCenterPixel / meanNeighborhoodPixel; - const RealType meanRatioInverse = (this->m_MaximumInputPixelIntensity - meanCenterPixel) / - (this->m_MaximumInputPixelIntensity - meanNeighborhoodPixel); - - const RealType varianceRatio = varianceCenterPixel / varianceNeighborhoodPixel; - - if (((meanRatio > this->m_MeanThreshold && - meanRatio < itk::NumericTraits::OneValue() / this->m_MeanThreshold) || - (meanRatioInverse > this->m_MeanThreshold && - meanRatioInverse < itk::NumericTraits::OneValue() / this->m_MeanThreshold)) && - varianceRatio > this->m_VarianceThreshold && - varianceRatio < itk::NumericTraits::OneValue() / this->m_VarianceThreshold) - { - - RealType averageDistance = itk::NumericTraits::ZeroValue(); - RealType count = itk::NumericTraits::ZeroValue(); - - for (unsigned int n = 0; n < neighborhoodPatchSize; n++) - { - IndexType neighborhoodPatchIndex = neighborhoodIndex + neighborhoodPatchOffsetList[n]; - - if (!targetImageRegion.IsInside(neighborhoodPatchIndex)) - { - continue; - } - RealType neighborhoodInputImagePixel = static_cast(inputImage->GetPixel(neighborhoodPatchIndex)); - RealType neighborhoodMeanImagePixel = this->m_MeanImage->GetPixel(neighborhoodPatchIndex); - averageDistance += itk::Math::sqr(neighborhoodInputImagePixel - neighborhoodMeanImagePixel); - - count += itk::NumericTraits::OneValue(); - } - averageDistance /= count; - minimumDistance = std::min(averageDistance, minimumDistance); - } - } - - if (itk::Math::AlmostEquals(minimumDistance, NumericTraits::ZeroValue())) - { - minimumDistance = NumericTraits::OneValue(); - } - - // Rician correction - - if (this->m_UseRicianNoiseModel) - { - for (unsigned int n = 0; n < neighborhoodPatchSize; n++) - { - IndexType neighborhoodPatchIndex = centerIndex + neighborhoodPatchOffsetList[n]; - if (!targetImageRegion.IsInside(neighborhoodPatchIndex)) - { - continue; - } - - if (itk::Math::AlmostEquals(minimumDistance, NumericTraits::max())) - { - this->m_RicianBiasImage->SetPixel(neighborhoodPatchIndex, 0.0); - } - else - { - this->m_RicianBiasImage->SetPixel(neighborhoodPatchIndex, minimumDistance); - } - } - } - - // Patch filtering - - for (unsigned int m = 0; m < neighborhoodSearchSize; m++) - { - if (!ItM.IndexInBounds(m) || m == static_cast(0.5 * neighborhoodSearchSize)) - { - continue; - } - - IndexType neighborhoodIndex = ItM.GetIndex(m); - - if (inputImage->GetPixel(neighborhoodIndex) <= 0) - { - continue; - } - - meanNeighborhoodPixel = this->m_MeanImage->GetPixel(neighborhoodIndex); - varianceNeighborhoodPixel = this->m_VarianceImage->GetPixel(neighborhoodIndex); - - if (meanNeighborhoodPixel <= this->m_Epsilon || varianceNeighborhoodPixel <= this->m_Epsilon) - { - continue; - } - - const RealType meanRatio = meanCenterPixel / meanNeighborhoodPixel; - const RealType meanRatioInverse = (this->m_MaximumInputPixelIntensity - meanCenterPixel) / - (this->m_MaximumInputPixelIntensity - meanNeighborhoodPixel); - - const RealType varianceRatio = varianceCenterPixel / varianceNeighborhoodPixel; - - if (((meanRatio > this->m_MeanThreshold && - meanRatio < itk::NumericTraits::OneValue() / this->m_MeanThreshold) || - (meanRatioInverse > this->m_MeanThreshold && - meanRatioInverse < itk::NumericTraits::OneValue() / this->m_MeanThreshold)) && - varianceRatio > this->m_VarianceThreshold && - varianceRatio < itk::NumericTraits::OneValue() / this->m_VarianceThreshold) - { - - RealType averageDistance = 0.0; - RealType count = 0.0; - for (unsigned int n = 0; n < neighborhoodPatchSize; n++) - { - IndexType searchNeighborhoodPatchIndex = neighborhoodIndex + neighborhoodPatchOffsetList[n]; - IndexType centerNeighborhoodPatchIndex = centerIndex + neighborhoodPatchOffsetList[n]; - if (!targetImageRegion.IsInside(searchNeighborhoodPatchIndex) || - !targetImageRegion.IsInside(centerNeighborhoodPatchIndex)) - { - continue; - } - RealType distance1 = inputImage->GetPixel(searchNeighborhoodPatchIndex) - - this->m_MeanImage->GetPixel(searchNeighborhoodPatchIndex); - RealType distance2 = inputImage->GetPixel(centerNeighborhoodPatchIndex) - - this->m_MeanImage->GetPixel(centerNeighborhoodPatchIndex); - averageDistance += itk::Math::sqr(distance1 - distance2); - count += itk::NumericTraits::OneValue(); - } - averageDistance /= count; - - RealType weight = itk::NumericTraits::ZeroValue(); - if (averageDistance <= static_cast(3.0) * minimumDistance) - { - weight = std::exp(-averageDistance / minimumDistance); - } - if (weight > maxWeight) - { - maxWeight = weight; - } - - if (weight > itk::NumericTraits::ZeroValue()) - { - for (unsigned int n = 0; n < neighborhoodPatchSize; n++) - { - IndexType neighborhoodPatchIndex = neighborhoodIndex + neighborhoodPatchOffsetList[n]; - if (!targetImageRegion.IsInside(neighborhoodPatchIndex)) - { - continue; - } - if (this->m_UseRicianNoiseModel) - { - weightedAverageIntensities[n] += weight * itk::Math::sqr(inputImage->GetPixel(neighborhoodPatchIndex)); - } - else - { - weightedAverageIntensities[n] += weight * inputImage->GetPixel(neighborhoodPatchIndex); - } - } - sumOfWeights += weight; - } - } - } - - if (itk::Math::AlmostEquals(maxWeight, NumericTraits::ZeroValue())) - { - maxWeight = NumericTraits::OneValue(); - } - } - else - { - maxWeight = NumericTraits::OneValue(); - } - - for (unsigned int n = 0; n < neighborhoodPatchSize; n++) - { - IndexType neighborhoodPatchIndex = centerIndex + neighborhoodPatchOffsetList[n]; - if (!targetImageRegion.IsInside(neighborhoodPatchIndex)) - { - continue; - } - if (this->m_UseRicianNoiseModel) - { - weightedAverageIntensities[n] += maxWeight * itk::Math::sqr(inputImage->GetPixel(neighborhoodPatchIndex)); - } - else - { - weightedAverageIntensities[n] += maxWeight * inputImage->GetPixel(neighborhoodPatchIndex); - } - } - sumOfWeights += maxWeight; - - if (sumOfWeights > itk::NumericTraits::ZeroValue()) - { - for (unsigned int n = 0; n < neighborhoodPatchSize; n++) - { - IndexType neighborhoodPatchIndex = centerIndex + neighborhoodPatchOffsetList[n]; - if (!targetImageRegion.IsInside(neighborhoodPatchIndex)) - { - continue; - } - typename OutputImageType::PixelType estimate = outputImage->GetPixel(neighborhoodPatchIndex); - estimate += (weightedAverageIntensities[n] / sumOfWeights); - - outputImage->SetPixel(neighborhoodPatchIndex, estimate); - this->m_ThreadContributionCountImage->SetPixel( - neighborhoodPatchIndex, this->m_ThreadContributionCountImage->GetPixel(neighborhoodPatchIndex) + 1); - } - } - - ++ItM; - ++ItV; - - progress.CompletedPixel(); - } -} - -template -void -AdaptiveNonLocalMeansDenoisingImageFilter::AfterThreadedGenerateData() -{ - const MaskImageType * maskImage = this->GetMaskImage(); - - if (this->m_UseRicianNoiseModel) - { - typedef DiscreteGaussianImageFilter SmootherType; - typename SmootherType::Pointer smoother = SmootherType::New(); - smoother->SetInput(this->m_RicianBiasImage); - smoother->SetVariance(this->m_SmoothingVariance); - smoother->SetUseImageSpacingOn(); - smoother->Update(); - - ImageRegionConstIterator ItS(smoother->GetOutput(), smoother->GetOutput()->GetRequestedRegion()); - ImageRegionConstIteratorWithIndex ItM(this->m_MeanImage, this->m_MeanImage->GetRequestedRegion()); - ImageRegionIterator ItB(this->m_RicianBiasImage, this->m_RicianBiasImage->GetRequestedRegion()); - ItS.GoToBegin(); - ItM.GoToBegin(); - ItB.GoToBegin(); - - while (!ItS.IsAtEnd()) - { - if (ItS.Get() > itk::NumericTraits::ZeroValue() && - (!maskImage || maskImage->GetPixel(ItM.GetIndex()) != NumericTraits::ZeroValue())) - { - const RealType snr = ItM.Get() / std::sqrt(ItS.Get()); - - RealType bias = static_cast(2.0) * ItS.Get() / this->CalculateCorrectionFactor(snr); - - if (std::isnan(bias) || std::isinf(bias)) - { - bias = itk::NumericTraits::ZeroValue(); - } - ItB.Set(bias); - } - - ++ItS; - ++ItM; - ++ItB; - } - } - - ImageRegionIteratorWithIndex ItO(this->GetOutput(), this->GetOutput()->GetRequestedRegion()); - ImageRegionConstIterator ItL(this->m_ThreadContributionCountImage, - this->m_ThreadContributionCountImage->GetRequestedRegion()); - - for (ItO.GoToBegin(), ItL.GoToBegin(); !ItO.IsAtEnd(); ++ItO, ++ItL) - { - RealType estimate = ItO.Get(); - - if (itk::Math::FloatAlmostEqual(ItL.Get(), itk::NumericTraits::ZeroValue())) - { - continue; - } - - estimate /= ItL.Get(); - - if (this->m_UseRicianNoiseModel) - { - RealType bias = this->m_RicianBiasImage->GetPixel(ItO.GetIndex()); - - estimate -= bias; - if (estimate < itk::NumericTraits::ZeroValue()) - { - estimate = itk::NumericTraits::ZeroValue(); - } - estimate = std::sqrt(estimate); - } - - ItO.Set(estimate); - } -} - -template -typename AdaptiveNonLocalMeansDenoisingImageFilter::RealType -AdaptiveNonLocalMeansDenoisingImageFilter::CalculateCorrectionFactor( - RealType snr) -{ - const RealType snrSquared = itk::Math::sqr(snr); - - RealType value = - static_cast(2.0) + snrSquared - - static_cast(0.125) * static_cast(Math::pi) * - static_cast(std::exp(static_cast(-0.5) * snrSquared)) * - itk::Math::sqr((static_cast(2.0) + snrSquared) * - static_cast( - this->m_ModifiedBesselCalculator.ModifiedBesselI0(static_cast(0.25) * snrSquared)) + - snrSquared * static_cast(this->m_ModifiedBesselCalculator.ModifiedBesselI1( - static_cast(0.25) * snrSquared))); - - if (value < static_cast(0.001) || value > static_cast(10.0)) - { - value = itk::NumericTraits::OneValue(); - } - return value; -} - -template -void -AdaptiveNonLocalMeansDenoisingImageFilter::PrintSelf(std::ostream & os, - Indent indent) const -{ - Superclass::PrintSelf(os, indent); - - if (this->m_UseRicianNoiseModel) - { - os << indent << "Using Rician noise model." << std::endl; - } - else - { - os << indent << "Using Gaussian noise model." << std::endl; - } - - os << indent << "Epsilon = " << this->m_Epsilon << std::endl; - os << indent << "Mean threshold = " << this->m_MeanThreshold << std::endl; - os << indent << "Variance threshold = " << this->m_VarianceThreshold << std::endl; - os << indent << "Smoothing variance = " << this->m_SmoothingVariance << std::endl; - - os << indent - << "Neighborhood radius for local mean and variance = " << this->m_NeighborhoodRadiusForLocalMeanAndVariance - << std::endl; -} - -} // end namespace itk - -#endif diff --git a/Modules/Filtering/AdaptiveDenoising/src/itkMinimalStandardRandomVariateGenerator.cxx b/Modules/Filtering/AdaptiveDenoising/src/itkMinimalStandardRandomVariateGenerator.cxx deleted file mode 100644 index 6c5cc9d7006c..000000000000 --- a/Modules/Filtering/AdaptiveDenoising/src/itkMinimalStandardRandomVariateGenerator.cxx +++ /dev/null @@ -1,52 +0,0 @@ -/*========================================================================= - * - * 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 - * - * http://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 "itkMinimalStandardRandomVariateGenerator.h" - -namespace itk -{ -namespace Statistics -{ - -MinimalStandardRandomVariateGenerator ::MinimalStandardRandomVariateGenerator() -{ - this->m_NormalGenerator = NormalGeneratorType::New(); - this->Initialize(1); -} - -void -MinimalStandardRandomVariateGenerator ::Initialize(int randomSeed) -{ - this->m_NormalGenerator->Initialize(randomSeed); -} - - -double -MinimalStandardRandomVariateGenerator ::GetVariate() -{ - return this->m_NormalGenerator->GetVariate(); -} - - -void -MinimalStandardRandomVariateGenerator ::PrintSelf(std::ostream & os, Indent indent) const -{ - Superclass::PrintSelf(os, indent); -} - -} // end namespace Statistics -} // end namespace itk diff --git a/Modules/Filtering/AdaptiveDenoising/test/Baseline/itkAdaptiveNonLocalMeansDenoisingImageFilterTestOutput.mha.sha512 b/Modules/Filtering/AdaptiveDenoising/test/Baseline/itkAdaptiveNonLocalMeansDenoisingImageFilterTestOutput.mha.sha512 deleted file mode 100644 index c811785f3e70..000000000000 --- a/Modules/Filtering/AdaptiveDenoising/test/Baseline/itkAdaptiveNonLocalMeansDenoisingImageFilterTestOutput.mha.sha512 +++ /dev/null @@ -1 +0,0 @@ -34cdd2aafce413dcf7efc692a707d53b7b57ebb006d0fbc20ecb42343f8a078b2252eff2137b17d3ab583d133f780438e247241ebf213c3289bd9ba1525081b7 diff --git a/Modules/Filtering/AdaptiveDenoising/test/CMakeLists.txt b/Modules/Filtering/AdaptiveDenoising/test/CMakeLists.txt index 753b6c440b34..77ee30f24604 100644 --- a/Modules/Filtering/AdaptiveDenoising/test/CMakeLists.txt +++ b/Modules/Filtering/AdaptiveDenoising/test/CMakeLists.txt @@ -1,27 +1,21 @@ itk_module_test() -set( - AdaptiveDenoisingTests - itkMinimalStandardRandomVariateGeneratorTest.cxx - itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx -) +set(AdaptiveDenoisingTests itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx) createtestdriver(AdaptiveDenoising "${AdaptiveDenoising-Test_LIBRARIES}" "${AdaptiveDenoisingTests}") itk_add_test( - NAME itkMinimalStandardRandomVariateGeneratorTest + NAME itkAdaptiveNonLocalMeansDenoisingImageFilterTest1 COMMAND AdaptiveDenoisingTestDriver - itkMinimalStandardRandomVariateGeneratorTest -) - -itk_add_test( - NAME itkAdaptiveNonLocalMeansDenoisingImageFilterTest - COMMAND - AdaptiveDenoisingTestDriver - --compare - DATA{Baseline/itkAdaptiveNonLocalMeansDenoisingImageFilterTestOutput.mha} - ${ITK_TEST_OUTPUT_DIR}/itkAdaptiveNonLocalMeansDenoisingImageFilterTestOutput.mha itkAdaptiveNonLocalMeansDenoisingImageFilterTest - ${ITK_TEST_OUTPUT_DIR}/itkAdaptiveNonLocalMeansDenoisingImageFilterTestOutput.mha ) + +# itk_add_test(NAME itkAdaptiveNonLocalMeansDenoisingImageFilterTest +# COMMAND AdaptiveDenoisingTestDriver +# --compare +# DATA{Baseline/itkAdaptiveNonLocalMeansDenoisingImageFilterTestOutput.mha} +# ${ITK_TEST_OUTPUT_DIR}/itkAdaptiveNonLocalMeansDenoisingImageFilterTestOutput.mha +# itkAdaptiveNonLocalMeansDenoisingImageFilterTest +# ${ITK_TEST_OUTPUT_DIR}/itkAdaptiveNonLocalMeansDenoisingImageFilterTestOutput.mha +# ) diff --git a/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx b/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx index 9d40c4ac97dc..ac3105dfebc2 100644 --- a/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx +++ b/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx @@ -1,56 +1,71 @@ -/*========================================================================= - * - * 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 - * - * http://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 "itkImageFileReader.h" +#include "itkImageFileWriter.h" #include "itkAdaptiveNonLocalMeansDenoisingImageFilter.h" -#include "itkCommand.h" -#include "itkImageFileWriter.h" -#include "itkTestingMacros.h" +// template +// class CommandProgressUpdate : public itk::Command +// { +// public: +// using Self = CommandProgressUpdate; +// using Superclass = itk::Command; +// using Pointer = itk::SmartPointer >; +// itkNewMacro( CommandProgressUpdate ); +// protected: -namespace -{ -class ShowProgress : public itk::Command -{ -public: - itkNewMacro(ShowProgress); +// CommandProgressUpdate() = default; - void - Execute(itk::Object * caller, const itk::EventObject & event) override - { - Execute((const itk::Object *)caller, event); - } +// using FilterType = TFilter; - void - Execute(const itk::Object * caller, const itk::EventObject & event) override - { - if (!itk::ProgressEvent().CheckEvent(&event)) - { - return; - } - const auto * processObject = dynamic_cast(caller); - if (!processObject) - { - return; - } - std::cout << " " << processObject->GetProgress(); - } -}; -} // namespace +// unsigned int m_CurrentProgress{ 0 }; + +// public: + +// void Execute(itk::Object *caller, const itk::EventObject & event) override +// { +// auto *po = dynamic_cast( caller ); +// if (! po) return; +// if( typeid( event ) == typeid ( itk::ProgressEvent ) ) +// { +// if( this->m_CurrentProgress < 99 ) +// { +// this->m_CurrentProgress++; +// if( this->m_CurrentProgress % 10 == 0 ) +// { +// std::cout << this->m_CurrentProgress << std::flush; +// } +// else +// { +// std::cout << "*" << std::flush; +// } +// } +// } +// } + +// void Execute(const itk::Object * object, const itk::EventObject & event) override +// { +// auto *po = dynamic_cast( +// const_cast( object ) ); +// if (! po) return; + +// if( typeid( event ) == typeid ( itk::ProgressEvent ) ) +// { +// if( this->m_CurrentProgress < 99 ) +// { +// this->m_CurrentProgress++; +// if( this->m_CurrentProgress % 10 == 0 ) +// { +// std::cout << this->m_CurrentProgress << std::flush; +// } +// else +// { +// std::cout << "*" << std::flush; +// } +// } +// } +// } +// }; int itkAdaptiveNonLocalMeansDenoisingImageFilterTest(int argc, char * argv[]) @@ -58,43 +73,71 @@ itkAdaptiveNonLocalMeansDenoisingImageFilterTest(int argc, char * argv[]) if (argc < 2) { std::cerr << "Missing parameters." << std::endl; - std::cerr << "Usage: " << itkNameOfTestExecutableMacro(argv); - std::cerr << " outputImage"; + std::cerr << "Usage: " << argv[0]; + std::cerr << " inputImage"; + std::cerr << " outputImage"; std::cerr << std::endl; return EXIT_FAILURE; } - const char * outputImageFileName = argv[1]; constexpr unsigned int Dimension = 2; using PixelType = float; using ImageType = itk::Image; - using FilterType = itk::AdaptiveNonLocalMeansDenoisingImageFilter; - FilterType::Pointer filter = FilterType::New(); + using ReaderType = itk::ImageFileReader; + ReaderType::Pointer reader = ReaderType::New(); + reader->SetFileName(argv[1]); - ITK_EXERCISE_BASIC_OBJECT_METHODS(filter, AdaptiveNonLocalMeansDenoisingImageFilter, ImageToImageFilter); + using DenoiserType = itk::AdaptiveNonLocalMeansDenoisingImageFilter; + DenoiserType::Pointer filter = DenoiserType::New(); - // Create input image to avoid test dependencies. - ImageType::SizeType size; - size.Fill(128); - ImageType::Pointer image = ImageType::New(); - image->SetRegions(size); - image->Allocate(); - image->FillBuffer(1.1f); + // ITK_EXERCISE_BASIC_OBJECT_METHODS( filter, AdaptiveNonLocalMeansDenoisingImageFilter, ImageToImageFilter ); - ShowProgress::Pointer showProgress = ShowProgress::New(); - filter->AddObserver(itk::ProgressEvent(), showProgress); - filter->SetInput(image); + filter->SetInput(reader->GetOutput()); + filter->SetUseRicianNoiseModel(false); + // ITK_TEST_SET_GET_VALUE( false, filter->GetUseRicianNoiseModel() ); + + DenoiserType::NeighborhoodRadiusType neighborhoodPatchRadius; + DenoiserType::NeighborhoodRadiusType neighborhoodSearchRadius; + + neighborhoodPatchRadius.Fill(1); + neighborhoodSearchRadius.Fill(2); + + filter->SetNeighborhoodSearchRadius(neighborhoodSearchRadius); + filter->SetNeighborhoodPatchRadius(neighborhoodPatchRadius); + + DenoiserType::NeighborhoodRadiusType neighborhoodRadiusForLocalMeanAndVariance; + neighborhoodRadiusForLocalMeanAndVariance.Fill(1); + + filter->SetNeighborhoodRadiusForLocalMeanAndVariance(neighborhoodRadiusForLocalMeanAndVariance); + + filter->SetEpsilon(0.00001); + // ITK_TEST_SET_GET_VALUE( 0.00001, filter->GetEpsilon() ); + + filter->SetMeanThreshold(0.95); + // ITK_TEST_SET_GET_VALUE( 0.95, filter->GetMeanThreshold() ); + + filter->SetVarianceThreshold(0.5); + // ITK_TEST_SET_GET_VALUE( 0.5, filter->GetVarianceThreshold() ); + + filter->SetSmoothingFactor(1.0); + // ITK_TEST_SET_GET_VALUE( 1.0, filter->GetSmoothingFactor() ); + + filter->SetSmoothingVariance(2.0); + // ITK_TEST_SET_GET_VALUE( 2.0, filter->GetSmoothingVariance() ); + + // using CommandType = CommandProgressUpdate; + // CommandType::Pointer observer = CommandType::New(); + // filter->AddObserver( itk::ProgressEvent(), observer ); + + // ITK_TRY_EXPECT_NO_EXCEPTION(filter->Update()); using WriterType = itk::ImageFileWriter; WriterType::Pointer writer = WriterType::New(); - writer->SetFileName(outputImageFileName); + writer->SetFileName(argv[2]); writer->SetInput(filter->GetOutput()); - writer->SetUseCompression(true); - - ITK_TRY_EXPECT_NO_EXCEPTION(writer->Update()); + // ITK_TRY_EXPECT_NO_EXCEPTION( writer->Update() ); - std::cout << "Test finished." << std::endl; return EXIT_SUCCESS; } diff --git a/Modules/Filtering/AdaptiveDenoising/test/itkMinimalStandardRandomVariateGeneratorTest.cxx b/Modules/Filtering/AdaptiveDenoising/test/itkMinimalStandardRandomVariateGeneratorTest.cxx deleted file mode 100644 index 3bb91a1d3f16..000000000000 --- a/Modules/Filtering/AdaptiveDenoising/test/itkMinimalStandardRandomVariateGeneratorTest.cxx +++ /dev/null @@ -1,37 +0,0 @@ -/*========================================================================= - * - * 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 - * - * http://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 "itkMinimalStandardRandomVariateGenerator.h" - -#include "itkTestingMacros.h" -#include "itkMath.h" - -int -itkMinimalStandardRandomVariateGeneratorTest(int, char *[]) -{ - typedef itk::Statistics::MinimalStandardRandomVariateGenerator GeneratorType; - GeneratorType::Pointer generator = GeneratorType::New(); - - ITK_EXERCISE_BASIC_OBJECT_METHODS(generator, MinimalStandardRandomVariateGenerator, RandomVariateGeneratorBase); - - generator->Initialize(324); - - ITK_TEST_EXPECT_TRUE(itk::Math::FloatAlmostEqual(generator->GetVariate(), 1.35581, 4, 0.0001)); - - return EXIT_SUCCESS; -} diff --git a/Modules/Filtering/AdaptiveDenoising/wrapping/CMakeLists.txt b/Modules/Filtering/AdaptiveDenoising/wrapping/CMakeLists.txt index 4b5b7b9b2aad..4d4ec66b8da0 100644 --- a/Modules/Filtering/AdaptiveDenoising/wrapping/CMakeLists.txt +++ b/Modules/Filtering/AdaptiveDenoising/wrapping/CMakeLists.txt @@ -1,3 +1,6 @@ itk_wrap_module(AdaptiveDenoising) + +set(WRAPPER_SUBMODULE_ORDER itkAdaptiveNonLocalMeansDenoisingImageFilter) + itk_auto_load_submodules() itk_end_wrap_module() From 983af8cc3e603c0e1b9c745291a775c798459de6 Mon Sep 17 00:00:00 2001 From: Nick Tustison Date: Sat, 26 Sep 2020 13:44:17 -0700 Subject: [PATCH 03/31] BUG: Header mismatch. --- .../include/itkAdaptiveNonLocalMeansDenoisingImageFilter.h | 2 +- .../include/itkAdaptiveNonLocalMeansDenoisingImageFilter.hxx | 2 +- .../include/itkNonLocalPatchBasedImageFilter.h | 2 +- .../include/itkNonLocalPatchBasedImageFilter.hxx | 2 +- .../AdaptiveDenoising/include/itkVarianceImageFilter.h | 2 +- .../AdaptiveDenoising/include/itkVarianceImageFilter.hxx | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.h b/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.h index 463e11004489..15143a5036fb 100644 --- a/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.h +++ b/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.h @@ -1,6 +1,6 @@ /*========================================================================= * - * Copyright Insight Software Consortium + * Copyright NumFOCUS * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.hxx b/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.hxx index 84c578924d5b..a3be9f04a615 100644 --- a/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.hxx +++ b/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.hxx @@ -1,6 +1,6 @@ /*========================================================================= * - * Copyright Insight Software Consortium + * Copyright NumFOCUS * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.h b/Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.h index 527b0361e877..01cdcd0a331f 100644 --- a/Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.h +++ b/Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.h @@ -1,6 +1,6 @@ /*========================================================================= * - * Copyright Insight Software Consortium + * Copyright NumFOCUS * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.hxx b/Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.hxx index 24df7705ac13..d9d98439b95b 100644 --- a/Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.hxx +++ b/Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.hxx @@ -1,6 +1,6 @@ /*========================================================================= * - * Copyright Insight Software Consortium + * Copyright NumFOCUS * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Modules/Filtering/AdaptiveDenoising/include/itkVarianceImageFilter.h b/Modules/Filtering/AdaptiveDenoising/include/itkVarianceImageFilter.h index 620a31fce5b8..4592fb32d6c1 100644 --- a/Modules/Filtering/AdaptiveDenoising/include/itkVarianceImageFilter.h +++ b/Modules/Filtering/AdaptiveDenoising/include/itkVarianceImageFilter.h @@ -1,6 +1,6 @@ /*========================================================================= * - * Copyright Insight Software Consortium + * Copyright NumFOCUS * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/Modules/Filtering/AdaptiveDenoising/include/itkVarianceImageFilter.hxx b/Modules/Filtering/AdaptiveDenoising/include/itkVarianceImageFilter.hxx index cacc5e3cad2b..dc1f43a149fd 100644 --- a/Modules/Filtering/AdaptiveDenoising/include/itkVarianceImageFilter.hxx +++ b/Modules/Filtering/AdaptiveDenoising/include/itkVarianceImageFilter.hxx @@ -1,6 +1,6 @@ /*========================================================================= * - * Copyright Insight Software Consortium + * Copyright NumFOCUS * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. From 1879b60c262f335d0a415606b40a4a54de07b4f8 Mon Sep 17 00:00:00 2001 From: Nick Tustison Date: Sat, 26 Sep 2020 13:45:15 -0700 Subject: [PATCH 04/31] ENH: Reinstate testing. --- ...eNonLocalMeansDenoisingImageFilterTest.cxx | 146 +++++++++--------- 1 file changed, 74 insertions(+), 72 deletions(-) diff --git a/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx b/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx index ac3105dfebc2..ba37a968765b 100644 --- a/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx +++ b/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx @@ -4,68 +4,70 @@ #include "itkAdaptiveNonLocalMeansDenoisingImageFilter.h" -// template -// class CommandProgressUpdate : public itk::Command -// { -// public: -// using Self = CommandProgressUpdate; -// using Superclass = itk::Command; -// using Pointer = itk::SmartPointer >; -// itkNewMacro( CommandProgressUpdate ); -// protected: - -// CommandProgressUpdate() = default; - -// using FilterType = TFilter; - -// unsigned int m_CurrentProgress{ 0 }; - -// public: - -// void Execute(itk::Object *caller, const itk::EventObject & event) override -// { -// auto *po = dynamic_cast( caller ); -// if (! po) return; -// if( typeid( event ) == typeid ( itk::ProgressEvent ) ) -// { -// if( this->m_CurrentProgress < 99 ) -// { -// this->m_CurrentProgress++; -// if( this->m_CurrentProgress % 10 == 0 ) -// { -// std::cout << this->m_CurrentProgress << std::flush; -// } -// else -// { -// std::cout << "*" << std::flush; -// } -// } -// } -// } - -// void Execute(const itk::Object * object, const itk::EventObject & event) override -// { -// auto *po = dynamic_cast( -// const_cast( object ) ); -// if (! po) return; - -// if( typeid( event ) == typeid ( itk::ProgressEvent ) ) -// { -// if( this->m_CurrentProgress < 99 ) -// { -// this->m_CurrentProgress++; -// if( this->m_CurrentProgress % 10 == 0 ) -// { -// std::cout << this->m_CurrentProgress << std::flush; -// } -// else -// { -// std::cout << "*" << std::flush; -// } -// } -// } -// } -// }; +template +class CommandProgressUpdate : public itk::Command +{ +public: + using Self = CommandProgressUpdate; + using Superclass = itk::Command; + using Pointer = itk::SmartPointer>; + itkNewMacro(CommandProgressUpdate); + +protected: + CommandProgressUpdate() = default; + + using FilterType = TFilter; + + unsigned int m_CurrentProgress{ 0 }; + +public: + void + Execute(itk::Object * caller, const itk::EventObject & event) override + { + auto * po = dynamic_cast(caller); + if (!po) + return; + if (typeid(event) == typeid(itk::ProgressEvent)) + { + if (this->m_CurrentProgress < 99) + { + this->m_CurrentProgress++; + if (this->m_CurrentProgress % 10 == 0) + { + std::cout << this->m_CurrentProgress << std::flush; + } + else + { + std::cout << "*" << std::flush; + } + } + } + } + + void + Execute(const itk::Object * object, const itk::EventObject & event) override + { + auto * po = dynamic_cast(const_cast(object)); + if (!po) + return; + + if (typeid(event) == typeid(itk::ProgressEvent)) + { + if (this->m_CurrentProgress < 99) + { + this->m_CurrentProgress++; + if (this->m_CurrentProgress % 10 == 0) + { + std::cout << this->m_CurrentProgress << std::flush; + } + else + { + std::cout << "*" << std::flush; + } + } + } + } +}; int itkAdaptiveNonLocalMeansDenoisingImageFilterTest(int argc, char * argv[]) @@ -112,32 +114,32 @@ itkAdaptiveNonLocalMeansDenoisingImageFilterTest(int argc, char * argv[]) filter->SetNeighborhoodRadiusForLocalMeanAndVariance(neighborhoodRadiusForLocalMeanAndVariance); filter->SetEpsilon(0.00001); - // ITK_TEST_SET_GET_VALUE( 0.00001, filter->GetEpsilon() ); + ITK_TEST_SET_GET_VALUE(0.00001, filter->GetEpsilon()); filter->SetMeanThreshold(0.95); - // ITK_TEST_SET_GET_VALUE( 0.95, filter->GetMeanThreshold() ); + ITK_TEST_SET_GET_VALUE(0.95, filter->GetMeanThreshold()); filter->SetVarianceThreshold(0.5); - // ITK_TEST_SET_GET_VALUE( 0.5, filter->GetVarianceThreshold() ); + ITK_TEST_SET_GET_VALUE(0.5, filter->GetVarianceThreshold()); filter->SetSmoothingFactor(1.0); - // ITK_TEST_SET_GET_VALUE( 1.0, filter->GetSmoothingFactor() ); + ITK_TEST_SET_GET_VALUE(1.0, filter->GetSmoothingFactor()); filter->SetSmoothingVariance(2.0); - // ITK_TEST_SET_GET_VALUE( 2.0, filter->GetSmoothingVariance() ); + ITK_TEST_SET_GET_VALUE(2.0, filter->GetSmoothingVariance()); - // using CommandType = CommandProgressUpdate; - // CommandType::Pointer observer = CommandType::New(); - // filter->AddObserver( itk::ProgressEvent(), observer ); + using CommandType = CommandProgressUpdate; + CommandType::Pointer observer = CommandType::New(); + filter->AddObserver(itk::ProgressEvent(), observer); - // ITK_TRY_EXPECT_NO_EXCEPTION(filter->Update()); + ITK_TRY_EXPECT_NO_EXCEPTION(filter->Update()); using WriterType = itk::ImageFileWriter; WriterType::Pointer writer = WriterType::New(); writer->SetFileName(argv[2]); writer->SetInput(filter->GetOutput()); - // ITK_TRY_EXPECT_NO_EXCEPTION( writer->Update() ); + ITK_TRY_EXPECT_NO_EXCEPTION(writer->Update()); return EXIT_SUCCESS; } From f2b1be4904309526977fa6c9330060e16d6a2e0a Mon Sep 17 00:00:00 2001 From: Nick Tustison Date: Sat, 26 Sep 2020 14:01:26 -0700 Subject: [PATCH 05/31] BUG: More fixes. --- .../itkAdaptiveNonLocalMeansDenoisingImageFilter.h | 1 - .../include/itkNonLocalPatchBasedImageFilter.h | 1 - .../AdaptiveDenoising/include/itkVarianceImageFilter.h | 10 ++-------- ...tkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx | 4 ++-- .../itkMinimalStandardRandomVariateGenerator.wrap | 1 - 5 files changed, 4 insertions(+), 13 deletions(-) delete mode 100644 Modules/Filtering/AdaptiveDenoising/wrapping/itkMinimalStandardRandomVariateGenerator.wrap diff --git a/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.h b/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.h index 15143a5036fb..791df7bb4de8 100644 --- a/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.h +++ b/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.h @@ -41,7 +41,6 @@ namespace itk * Spatially Varying Noise Levels, Journal of Magnetic Resonance Imaging, * 31:192-203, June 2010. * - * \ingroup ITKNoiseFiltering */ template diff --git a/Modules/Filtering/AdaptiveDenoising/include/itkVarianceImageFilter.h b/Modules/Filtering/AdaptiveDenoising/include/itkVarianceImageFilter.h index 4592fb32d6c1..2042e08bde94 100644 --- a/Modules/Filtering/AdaptiveDenoising/include/itkVarianceImageFilter.h +++ b/Modules/Filtering/AdaptiveDenoising/include/itkVarianceImageFilter.h @@ -24,6 +24,7 @@ namespace itk { + /** \class VarianceImageFilter * \brief Applies an averaging filter to an image * @@ -32,18 +33,11 @@ namespace itk * * A variacne filter is one of the family of linear filters. * - * \sa Image - * \sa Neighborhood - * \sa NeighborhoodOperator - * \sa NeighborhoodIterator - * - * \ingroup IntensityImageFilters - * \ingroup ITKSmoothing * * \wiki - * \wikiexample{Smoothing/VarianceImageFilter,Variance filter an image} * \endwiki */ + template class VarianceImageFilter final : public BoxImageFilter { diff --git a/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx b/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx index ba37a968765b..c550a59e14b8 100644 --- a/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx +++ b/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx @@ -93,11 +93,11 @@ itkAdaptiveNonLocalMeansDenoisingImageFilterTest(int argc, char * argv[]) using DenoiserType = itk::AdaptiveNonLocalMeansDenoisingImageFilter; DenoiserType::Pointer filter = DenoiserType::New(); - // ITK_EXERCISE_BASIC_OBJECT_METHODS( filter, AdaptiveNonLocalMeansDenoisingImageFilter, ImageToImageFilter ); + ITK_EXERCISE_BASIC_OBJECT_METHODS(filter, AdaptiveNonLocalMeansDenoisingImageFilter, ImageToImageFilter); filter->SetInput(reader->GetOutput()); filter->SetUseRicianNoiseModel(false); - // ITK_TEST_SET_GET_VALUE( false, filter->GetUseRicianNoiseModel() ); + ITK_TEST_SET_GET_VALUE(false, filter->GetUseRicianNoiseModel()); DenoiserType::NeighborhoodRadiusType neighborhoodPatchRadius; DenoiserType::NeighborhoodRadiusType neighborhoodSearchRadius; diff --git a/Modules/Filtering/AdaptiveDenoising/wrapping/itkMinimalStandardRandomVariateGenerator.wrap b/Modules/Filtering/AdaptiveDenoising/wrapping/itkMinimalStandardRandomVariateGenerator.wrap deleted file mode 100644 index e13dd73db38f..000000000000 --- a/Modules/Filtering/AdaptiveDenoising/wrapping/itkMinimalStandardRandomVariateGenerator.wrap +++ /dev/null @@ -1 +0,0 @@ -itk_wrap_simple_class("itk::Statistics::MinimalStandardRandomVariateGenerator" POINTER) From f947fddc32874d03ac65c260e5f211995d766c5e Mon Sep 17 00:00:00 2001 From: Nick Tustison Date: Sat, 26 Sep 2020 14:23:06 -0700 Subject: [PATCH 06/31] BUG: More fixes. --- Modules/Filtering/AdaptiveDenoising/CMakeLists.txt | 11 +---------- .../itkAdaptiveNonLocalMeansDenoisingImageFilter.h | 1 + .../include/itkNonLocalPatchBasedImageFilter.h | 1 + .../include/itkVarianceImageFilter.h | 6 +----- 4 files changed, 4 insertions(+), 15 deletions(-) diff --git a/Modules/Filtering/AdaptiveDenoising/CMakeLists.txt b/Modules/Filtering/AdaptiveDenoising/CMakeLists.txt index e683ff492f87..794430a57b99 100644 --- a/Modules/Filtering/AdaptiveDenoising/CMakeLists.txt +++ b/Modules/Filtering/AdaptiveDenoising/CMakeLists.txt @@ -1,12 +1,3 @@ project(AdaptiveDenoising) -set(AdaptiveDenoising_LIBRARIES AdaptiveDenoising) - -if(NOT ITK_SOURCE_DIR) - find_package(ITK REQUIRED) - list(APPEND CMAKE_MODULE_PATH ${ITK_CMAKE_DIR}) - include(ITKModuleExternal) -else() - set(ITK_DIR ${CMAKE_BINARY_DIR}) - itk_module_impl() -endif() +itk_module_impl() diff --git a/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.h b/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.h index 791df7bb4de8..78bc2db36677 100644 --- a/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.h +++ b/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.h @@ -41,6 +41,7 @@ namespace itk * Spatially Varying Noise Levels, Journal of Magnetic Resonance Imaging, * 31:192-203, June 2010. * + * \ingroup AdaptiveDenoising */ template diff --git a/Modules/Filtering/AdaptiveDenoising/include/itkVarianceImageFilter.h b/Modules/Filtering/AdaptiveDenoising/include/itkVarianceImageFilter.h index 2042e08bde94..8713ec4f150a 100644 --- a/Modules/Filtering/AdaptiveDenoising/include/itkVarianceImageFilter.h +++ b/Modules/Filtering/AdaptiveDenoising/include/itkVarianceImageFilter.h @@ -24,7 +24,6 @@ namespace itk { - /** \class VarianceImageFilter * \brief Applies an averaging filter to an image * @@ -33,11 +32,8 @@ namespace itk * * A variacne filter is one of the family of linear filters. * - * - * \wiki - * \endwiki + * \ingroup AdaptiveDenoising */ - template class VarianceImageFilter final : public BoxImageFilter { From 6cb0819d11eacfc3ec595728adef0a907f1edd08 Mon Sep 17 00:00:00 2001 From: Nick Tustison Date: Sat, 26 Sep 2020 15:04:59 -0700 Subject: [PATCH 07/31] BUG: Missing header. --- .../test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx | 1 + 1 file changed, 1 insertion(+) diff --git a/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx b/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx index c550a59e14b8..4d9742e479d1 100644 --- a/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx +++ b/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx @@ -1,6 +1,7 @@ #include "itkImageFileReader.h" #include "itkImageFileWriter.h" +#include "itkTestingMacros.h" #include "itkAdaptiveNonLocalMeansDenoisingImageFilter.h" From e84199196b9785eeb4efdcec81f603e77661b1c8 Mon Sep 17 00:00:00 2001 From: Nick Tustison Date: Sat, 26 Sep 2020 15:20:50 -0700 Subject: [PATCH 08/31] BUG: ITK_TEMPLATE_EXPORT --- ...daptiveNonLocalMeansDenoisingImageFilter.h | 3 ++- .../itkNonLocalPatchBasedImageFilter.h | 4 ++-- .../include/itkVarianceImageFilter.h | 2 +- ...eNonLocalMeansDenoisingImageFilterTest.cxx | 20 ++++++++++++++++++- 4 files changed, 24 insertions(+), 5 deletions(-) diff --git a/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.h b/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.h index 78bc2db36677..13634bd03125 100644 --- a/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.h +++ b/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.h @@ -47,7 +47,8 @@ namespace itk template > -class AdaptiveNonLocalMeansDenoisingImageFilter final : public NonLocalPatchBasedImageFilter +class ITK_TEMPLATE_EXPORT AdaptiveNonLocalMeansDenoisingImageFilter final + : public NonLocalPatchBasedImageFilter { public: /** Standard class typedefs. */ diff --git a/Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.h b/Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.h index b2a41de430ab..0142051b81b2 100644 --- a/Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.h +++ b/Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.h @@ -27,13 +27,13 @@ namespace itk /** * \class NonLocalPatchBasedImageFilter - * \brief Implementation of a non-local upsampling (i.e., superresolution) image filter. + * \brief Implementation of a non-local image filter. * * \ingroup AdaptiveDenoising */ template -class NonLocalPatchBasedImageFilter : public ImageToImageFilter +class ITK_TEMPLATE_EXPORT NonLocalPatchBasedImageFilter : public ImageToImageFilter { public: /** Standard class typedefs. */ diff --git a/Modules/Filtering/AdaptiveDenoising/include/itkVarianceImageFilter.h b/Modules/Filtering/AdaptiveDenoising/include/itkVarianceImageFilter.h index 8713ec4f150a..5aaf8dcc070c 100644 --- a/Modules/Filtering/AdaptiveDenoising/include/itkVarianceImageFilter.h +++ b/Modules/Filtering/AdaptiveDenoising/include/itkVarianceImageFilter.h @@ -35,7 +35,7 @@ namespace itk * \ingroup AdaptiveDenoising */ template -class VarianceImageFilter final : public BoxImageFilter +class ITK_TEMPLATE_EXPORT VarianceImageFilter final : public BoxImageFilter { public: /** Extract dimension from input and output image. */ diff --git a/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx b/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx index 4d9742e479d1..19087b4611bc 100644 --- a/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx +++ b/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx @@ -1,9 +1,27 @@ +/*========================================================================= + * + * 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 + * + * http://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 "itkAdaptiveNonLocalMeansDenoisingImageFilter.h" + #include "itkImageFileReader.h" #include "itkImageFileWriter.h" #include "itkTestingMacros.h" -#include "itkAdaptiveNonLocalMeansDenoisingImageFilter.h" template class CommandProgressUpdate : public itk::Command From 5754deb259bd145fda492182758c5610cfa294ed Mon Sep 17 00:00:00 2001 From: Nick Tustison Date: Sat, 26 Sep 2020 17:28:08 -0700 Subject: [PATCH 09/31] STYLE: Header mismatch." --- .../test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx | 1 - 1 file changed, 1 deletion(-) diff --git a/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx b/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx index 19087b4611bc..4ffc999ddb8b 100644 --- a/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx +++ b/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx @@ -1,4 +1,3 @@ - /*========================================================================= * * Copyright NumFOCUS From 41af4b7315bd43c0a3a126606b3cc33b8897eda5 Mon Sep 17 00:00:00 2001 From: Nick Tustison Date: Sat, 26 Sep 2020 17:51:46 -0700 Subject: [PATCH 10/31] ENH: Add testing data. --- .../AdaptiveDenoising/test/CMakeLists.txt | 16 ++++++---------- ...tiveNonLocalMeansDenoisingImageFilterTest.cxx | 2 +- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/Modules/Filtering/AdaptiveDenoising/test/CMakeLists.txt b/Modules/Filtering/AdaptiveDenoising/test/CMakeLists.txt index 77ee30f24604..c43c9178b9e0 100644 --- a/Modules/Filtering/AdaptiveDenoising/test/CMakeLists.txt +++ b/Modules/Filtering/AdaptiveDenoising/test/CMakeLists.txt @@ -5,17 +5,13 @@ set(AdaptiveDenoisingTests itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx) createtestdriver(AdaptiveDenoising "${AdaptiveDenoising-Test_LIBRARIES}" "${AdaptiveDenoisingTests}") itk_add_test( - NAME itkAdaptiveNonLocalMeansDenoisingImageFilterTest1 + NAME AdaptiveNonLocalMeansDenoisingImageFilterTest1 COMMAND AdaptiveDenoisingTestDriver + --compare + DATA{Baseline/r16denoised.nrrd} + ${ITK_TEST_OUTPUT_DIR}/r16denoised.nrrd itkAdaptiveNonLocalMeansDenoisingImageFilterTest + DATA{Input/r16slice.nrrd} + ${ITK_TEST_OUTPUT_DIR}/r16denoised.nrrd ) - -# itk_add_test(NAME itkAdaptiveNonLocalMeansDenoisingImageFilterTest -# COMMAND AdaptiveDenoisingTestDriver -# --compare -# DATA{Baseline/itkAdaptiveNonLocalMeansDenoisingImageFilterTestOutput.mha} -# ${ITK_TEST_OUTPUT_DIR}/itkAdaptiveNonLocalMeansDenoisingImageFilterTestOutput.mha -# itkAdaptiveNonLocalMeansDenoisingImageFilterTest -# ${ITK_TEST_OUTPUT_DIR}/itkAdaptiveNonLocalMeansDenoisingImageFilterTestOutput.mha -# ) diff --git a/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx b/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx index 4ffc999ddb8b..5e0242767ae0 100644 --- a/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx +++ b/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx @@ -90,7 +90,7 @@ class CommandProgressUpdate : public itk::Command int itkAdaptiveNonLocalMeansDenoisingImageFilterTest(int argc, char * argv[]) { - if (argc < 2) + if (argc < 3) { std::cerr << "Missing parameters." << std::endl; std::cerr << "Usage: " << argv[0]; From f5d11b9a310ad4912bc180ca3a0cc218dbb06d48 Mon Sep 17 00:00:00 2001 From: Nick Tustison Date: Sat, 26 Sep 2020 18:39:28 -0700 Subject: [PATCH 11/31] BUG: Testing superclass::name --- Modules/Filtering/AdaptiveDenoising/test/CMakeLists.txt | 2 +- .../test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/Filtering/AdaptiveDenoising/test/CMakeLists.txt b/Modules/Filtering/AdaptiveDenoising/test/CMakeLists.txt index c43c9178b9e0..09e581e2a331 100644 --- a/Modules/Filtering/AdaptiveDenoising/test/CMakeLists.txt +++ b/Modules/Filtering/AdaptiveDenoising/test/CMakeLists.txt @@ -5,7 +5,7 @@ set(AdaptiveDenoisingTests itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx) createtestdriver(AdaptiveDenoising "${AdaptiveDenoising-Test_LIBRARIES}" "${AdaptiveDenoisingTests}") itk_add_test( - NAME AdaptiveNonLocalMeansDenoisingImageFilterTest1 + NAME AdaptiveNonLocalMeansDenoisingImageFilterTest COMMAND AdaptiveDenoisingTestDriver --compare diff --git a/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx b/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx index 5e0242767ae0..803ebfcddcc3 100644 --- a/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx +++ b/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx @@ -111,7 +111,7 @@ itkAdaptiveNonLocalMeansDenoisingImageFilterTest(int argc, char * argv[]) using DenoiserType = itk::AdaptiveNonLocalMeansDenoisingImageFilter; DenoiserType::Pointer filter = DenoiserType::New(); - ITK_EXERCISE_BASIC_OBJECT_METHODS(filter, AdaptiveNonLocalMeansDenoisingImageFilter, ImageToImageFilter); + // ITK_EXERCISE_BASIC_OBJECT_METHODS( filter, AdaptiveNonLocalMeansDenoisingImageFilter, ImageToImageFilter ); filter->SetInput(reader->GetOutput()); filter->SetUseRicianNoiseModel(false); From 9771166c1d79017d431b3d142e465561cc0e79a1 Mon Sep 17 00:00:00 2001 From: Nick Tustison Date: Sat, 26 Sep 2020 18:46:24 -0700 Subject: [PATCH 12/31] ENH: Refactor testing. --- ...ptiveNonLocalMeansDenoisingImageFilterTest.cxx | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx b/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx index 803ebfcddcc3..f5358d3e08ea 100644 --- a/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx +++ b/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx @@ -20,7 +20,7 @@ #include "itkImageFileReader.h" #include "itkImageFileWriter.h" #include "itkTestingMacros.h" - +#include "itkMath.h" template class CommandProgressUpdate : public itk::Command @@ -132,19 +132,19 @@ itkAdaptiveNonLocalMeansDenoisingImageFilterTest(int argc, char * argv[]) filter->SetNeighborhoodRadiusForLocalMeanAndVariance(neighborhoodRadiusForLocalMeanAndVariance); filter->SetEpsilon(0.00001); - ITK_TEST_SET_GET_VALUE(0.00001, filter->GetEpsilon()); + ITK_TEST_EXPECT_TRUE(itk::Math::FloatAlmostEqual(0.00001, filter->GetEpsilon())); filter->SetMeanThreshold(0.95); - ITK_TEST_SET_GET_VALUE(0.95, filter->GetMeanThreshold()); + ITK_TEST_EXPECT_TRUE(itk::Math::FloatAlmostEqual(0.95, filter->GetMeanThreshold())); filter->SetVarianceThreshold(0.5); - ITK_TEST_SET_GET_VALUE(0.5, filter->GetVarianceThreshold()); + ITK_TEST_EXPECT_TRUE(itk::Math::FloatAlmostEqual(0.5, filter->GetVarianceThreshold())); filter->SetSmoothingFactor(1.0); - ITK_TEST_SET_GET_VALUE(1.0, filter->GetSmoothingFactor()); + ITK_TEST_EXPECT_TRUE(itk::Math::FloatAlmostEqual(1.0, filter->GetSmoothingFactor())); filter->SetSmoothingVariance(2.0); - ITK_TEST_SET_GET_VALUE(2.0, filter->GetSmoothingVariance()); + ITK_TEST_EXPECT_TRUE(itk::Math::FloatAlmostEqual(2.0, filter->GetSmoothingVariance())); using CommandType = CommandProgressUpdate; CommandType::Pointer observer = CommandType::New(); @@ -156,8 +156,7 @@ itkAdaptiveNonLocalMeansDenoisingImageFilterTest(int argc, char * argv[]) WriterType::Pointer writer = WriterType::New(); writer->SetFileName(argv[2]); writer->SetInput(filter->GetOutput()); - - ITK_TRY_EXPECT_NO_EXCEPTION(writer->Update()); + writer->Update(); return EXIT_SUCCESS; } From ca01e22f7173f61d056c5470a25f0516216a8553 Mon Sep 17 00:00:00 2001 From: Nick Tustison Date: Sat, 26 Sep 2020 18:52:33 -0700 Subject: [PATCH 13/31] BUG: explicit float. --- ...eNonLocalMeansDenoisingImageFilterTest.cxx | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx b/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx index f5358d3e08ea..85193c09994a 100644 --- a/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx +++ b/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx @@ -131,20 +131,20 @@ itkAdaptiveNonLocalMeansDenoisingImageFilterTest(int argc, char * argv[]) filter->SetNeighborhoodRadiusForLocalMeanAndVariance(neighborhoodRadiusForLocalMeanAndVariance); - filter->SetEpsilon(0.00001); - ITK_TEST_EXPECT_TRUE(itk::Math::FloatAlmostEqual(0.00001, filter->GetEpsilon())); + filter->SetEpsilon(0.00001f); + ITK_TEST_EXPECT_TRUE(itk::Math::FloatAlmostEqual(0.00001f, filter->GetEpsilon())); - filter->SetMeanThreshold(0.95); - ITK_TEST_EXPECT_TRUE(itk::Math::FloatAlmostEqual(0.95, filter->GetMeanThreshold())); + filter->SetMeanThreshold(0.95f); + ITK_TEST_EXPECT_TRUE(itk::Math::FloatAlmostEqual(0.95f, filter->GetMeanThreshold())); - filter->SetVarianceThreshold(0.5); - ITK_TEST_EXPECT_TRUE(itk::Math::FloatAlmostEqual(0.5, filter->GetVarianceThreshold())); + filter->SetVarianceThreshold(0.5f); + ITK_TEST_EXPECT_TRUE(itk::Math::FloatAlmostEqual(0.5f, filter->GetVarianceThreshold())); - filter->SetSmoothingFactor(1.0); - ITK_TEST_EXPECT_TRUE(itk::Math::FloatAlmostEqual(1.0, filter->GetSmoothingFactor())); + filter->SetSmoothingFactor(1.0f); + ITK_TEST_EXPECT_TRUE(itk::Math::FloatAlmostEqual(1.0f, filter->GetSmoothingFactor())); - filter->SetSmoothingVariance(2.0); - ITK_TEST_EXPECT_TRUE(itk::Math::FloatAlmostEqual(2.0, filter->GetSmoothingVariance())); + filter->SetSmoothingVariance(2.0f); + ITK_TEST_EXPECT_TRUE(itk::Math::FloatAlmostEqual(2.0f, filter->GetSmoothingVariance())); using CommandType = CommandProgressUpdate; CommandType::Pointer observer = CommandType::New(); From d06ae939133f14ac91cbbc06ec148a4a33b8b54e Mon Sep 17 00:00:00 2001 From: Nick Tustison Date: Sat, 26 Sep 2020 20:54:45 -0700 Subject: [PATCH 14/31] ENH: Add wrapping. --- .../Filtering/AdaptiveDenoising/wrapping/CMakeLists.txt | 7 ++++++- .../wrapping/itkNonLocalPatchBasedImageFilter.wrap | 3 +++ .../AdaptiveDenoising/wrapping/itkVarianceImageFilter.wrap | 3 +++ 3 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 Modules/Filtering/AdaptiveDenoising/wrapping/itkNonLocalPatchBasedImageFilter.wrap create mode 100644 Modules/Filtering/AdaptiveDenoising/wrapping/itkVarianceImageFilter.wrap diff --git a/Modules/Filtering/AdaptiveDenoising/wrapping/CMakeLists.txt b/Modules/Filtering/AdaptiveDenoising/wrapping/CMakeLists.txt index 4d4ec66b8da0..c2e65ecce777 100644 --- a/Modules/Filtering/AdaptiveDenoising/wrapping/CMakeLists.txt +++ b/Modules/Filtering/AdaptiveDenoising/wrapping/CMakeLists.txt @@ -1,6 +1,11 @@ itk_wrap_module(AdaptiveDenoising) -set(WRAPPER_SUBMODULE_ORDER itkAdaptiveNonLocalMeansDenoisingImageFilter) +set( + WRAPPER_SUBMODULE_ORDER + itkVarianceImageFilter + itkNonLocalPatchBasedImageFilter + itkAdaptiveNonLocalMeansDenoisingImageFilter +) itk_auto_load_submodules() itk_end_wrap_module() diff --git a/Modules/Filtering/AdaptiveDenoising/wrapping/itkNonLocalPatchBasedImageFilter.wrap b/Modules/Filtering/AdaptiveDenoising/wrapping/itkNonLocalPatchBasedImageFilter.wrap new file mode 100644 index 000000000000..92f6174d0033 --- /dev/null +++ b/Modules/Filtering/AdaptiveDenoising/wrapping/itkNonLocalPatchBasedImageFilter.wrap @@ -0,0 +1,3 @@ +itk_wrap_class("itk::NonLocalPatchBasedImageFilter" POINTER) +itk_wrap_image_filter("${WRAP_ITK_SCALAR}" 2) +itk_end_wrap_class() diff --git a/Modules/Filtering/AdaptiveDenoising/wrapping/itkVarianceImageFilter.wrap b/Modules/Filtering/AdaptiveDenoising/wrapping/itkVarianceImageFilter.wrap new file mode 100644 index 000000000000..ffc8554bdd4a --- /dev/null +++ b/Modules/Filtering/AdaptiveDenoising/wrapping/itkVarianceImageFilter.wrap @@ -0,0 +1,3 @@ +itk_wrap_class("itk::VarianceImageFilter" POINTER) +itk_wrap_image_filter("${WRAP_ITK_SCALAR}" 2) +itk_end_wrap_class() From 54d8575043837aeb0ad0094e93c6ea0fb83df102 Mon Sep 17 00:00:00 2001 From: Nick Tustison Date: Sun, 27 Sep 2020 14:28:14 -0700 Subject: [PATCH 15/31] ENH: Uncomment test. --- .../test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx b/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx index 85193c09994a..a8320b6671d0 100644 --- a/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx +++ b/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx @@ -111,7 +111,7 @@ itkAdaptiveNonLocalMeansDenoisingImageFilterTest(int argc, char * argv[]) using DenoiserType = itk::AdaptiveNonLocalMeansDenoisingImageFilter; DenoiserType::Pointer filter = DenoiserType::New(); - // ITK_EXERCISE_BASIC_OBJECT_METHODS( filter, AdaptiveNonLocalMeansDenoisingImageFilter, ImageToImageFilter ); + ITK_EXERCISE_BASIC_OBJECT_METHODS(filter, AdaptiveNonLocalMeansDenoisingImageFilter, NonLocalPatchBasedImageFilter); filter->SetInput(reader->GetOutput()); filter->SetUseRicianNoiseModel(false); From 7e7f4e723bd556b257ece39559ce60aafdc2f5e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20Haitz=20Legarreta=20Gorro=C3=B1o?= Date: Fri, 2 Oct 2020 17:45:58 -0400 Subject: [PATCH 16/31] COMP: Use and move ITK_DISALLOW_COPY_AND_ASSIGN calls to public section. Use the `ITK_DISALLOW_COPY_AND_ASSIGN` macro to enhance consistency across the toolkit when disallowing the copy constructor and the assign operator. Move the `ITK_DISALLOW_COPY_AND_ASSIGN` calls to the `public` section following the discussion in https://discourse.itk.org/t/itk-disallow-copy-and-assign/648 --- .../itkAdaptiveNonLocalMeansDenoisingImageFilter.h | 6 ++---- .../include/itkNonLocalPatchBasedImageFilter.h | 8 ++------ .../AdaptiveDenoising/include/itkVarianceImageFilter.h | 7 ++----- 3 files changed, 6 insertions(+), 15 deletions(-) diff --git a/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.h b/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.h index 13634bd03125..a9cc7e41b46f 100644 --- a/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.h +++ b/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.h @@ -51,6 +51,8 @@ class ITK_TEMPLATE_EXPORT AdaptiveNonLocalMeansDenoisingImageFilter final : public NonLocalPatchBasedImageFilter { public: + ITK_DISALLOW_COPY_AND_ASSIGN(AdaptiveNonLocalMeansDenoisingImageFilter); + /** Standard class typedefs. */ typedef AdaptiveNonLocalMeansDenoisingImageFilter Self; typedef NonLocalPatchBasedImageFilter Superclass; @@ -187,10 +189,6 @@ class ITK_TEMPLATE_EXPORT AdaptiveNonLocalMeansDenoisingImageFilter final AfterThreadedGenerateData() override; private: - AdaptiveNonLocalMeansDenoisingImageFilter(const Self &) = delete; - void - operator=(const Self &) = delete; - RealType CalculateCorrectionFactor(RealType); bool m_UseRicianNoiseModel; diff --git a/Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.h b/Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.h index 0142051b81b2..3e5e48422d2d 100644 --- a/Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.h +++ b/Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.h @@ -36,6 +36,8 @@ template class ITK_TEMPLATE_EXPORT NonLocalPatchBasedImageFilter : public ImageToImageFilter { public: + ITK_DISALLOW_COPY_AND_ASSIGN(NonLocalPatchBasedImageFilter); + /** Standard class typedefs. */ using Self = NonLocalPatchBasedImageFilter; using Superclass = ImageToImageFilter; @@ -179,12 +181,6 @@ class ITK_TEMPLATE_EXPORT NonLocalPatchBasedImageFilter : public ImageToImageFil NeighborhoodOffsetListType m_NeighborhoodPatchOffsetList; RegionType m_TargetImageRegion; - - -private: - NonLocalPatchBasedImageFilter(const Self &) = delete; - void - operator=(const Self &) = delete; }; } // end namespace itk diff --git a/Modules/Filtering/AdaptiveDenoising/include/itkVarianceImageFilter.h b/Modules/Filtering/AdaptiveDenoising/include/itkVarianceImageFilter.h index 5aaf8dcc070c..5bb96576f240 100644 --- a/Modules/Filtering/AdaptiveDenoising/include/itkVarianceImageFilter.h +++ b/Modules/Filtering/AdaptiveDenoising/include/itkVarianceImageFilter.h @@ -38,6 +38,8 @@ template class ITK_TEMPLATE_EXPORT VarianceImageFilter final : public BoxImageFilter { public: + ITK_DISALLOW_COPY_AND_ASSIGN(VarianceImageFilter); + /** Extract dimension from input and output image. */ itkStaticConstMacro(InputImageDimension, unsigned int, TInputImage::ImageDimension); itkStaticConstMacro(OutputImageDimension, unsigned int, TOutputImage::ImageDimension); @@ -90,11 +92,6 @@ class ITK_TEMPLATE_EXPORT VarianceImageFilter final : public BoxImageFilter Date: Fri, 2 Oct 2020 19:04:25 -0400 Subject: [PATCH 17/31] ENH: Use strongly typed enums Use strongly type enums. Set `AdaptiveDenoising_LIBRARIES` for external builds too derived from the changes involved by the presence of a C++ implementation file. --- .../AdaptiveDenoising/CMakeLists.txt | 2 + .../itkNonLocalPatchBasedImageFilter.h | 47 ++++++++++++++----- .../itkNonLocalPatchBasedImageFilter.hxx | 10 ++-- .../AdaptiveDenoising/src/CMakeLists.txt | 5 ++ .../itkNonLocalPatchBasedImageFilterEnums.cxx | 42 +++++++++++++++++ ...eNonLocalMeansDenoisingImageFilterTest.cxx | 13 +++++ .../itkNonLocalPatchBasedImageFilter.wrap | 5 ++ 7 files changed, 108 insertions(+), 16 deletions(-) create mode 100644 Modules/Filtering/AdaptiveDenoising/src/CMakeLists.txt create mode 100644 Modules/Filtering/AdaptiveDenoising/src/itkNonLocalPatchBasedImageFilterEnums.cxx diff --git a/Modules/Filtering/AdaptiveDenoising/CMakeLists.txt b/Modules/Filtering/AdaptiveDenoising/CMakeLists.txt index 794430a57b99..e0387995bf4a 100644 --- a/Modules/Filtering/AdaptiveDenoising/CMakeLists.txt +++ b/Modules/Filtering/AdaptiveDenoising/CMakeLists.txt @@ -1,3 +1,5 @@ project(AdaptiveDenoising) +set(AdaptiveDenoising_LIBRARIES AdaptiveDenoising) + itk_module_impl() diff --git a/Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.h b/Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.h index 0142051b81b2..1ecc3b5574a9 100644 --- a/Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.h +++ b/Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.h @@ -18,13 +18,39 @@ #ifndef itkNonLocalPatchBasedImageFilter_h #define itkNonLocalPatchBasedImageFilter_h +#include #include "itkImageToImageFilter.h" +#include "AdaptiveDenoisingExport.h" #include "itkConstNeighborhoodIterator.h" namespace itk { +/** + * \class NonLocalPatchBasedImageFilterEnums + * \brief Non-local patch-based image filter enum classes. + * \ingroup AdaptiveDenoising + */ + +class NonLocalPatchBasedImageFilterEnums +{ +public: + /**\class SimilarityMetric + * \brief Neighborhood patch similarity metric enumerated type. + * \ingroup AdaptiveDenoising + */ + enum class SimilarityMetric : uint8_t + { + PEARSON_CORRELATION = 0, + MEAN_SQUARES = 1 + }; +}; + +extern AdaptiveDenoising_EXPORT std::ostream & +operator<<(std::ostream & out, const NonLocalPatchBasedImageFilterEnums::SimilarityMetric value); + + /** * \class NonLocalPatchBasedImageFilter * \brief Implementation of a non-local image filter. @@ -77,14 +103,13 @@ class ITK_TEMPLATE_EXPORT NonLocalPatchBasedImageFilter : public ImageToImageFil using NeighborhoodOffsetType = typename ConstNeighborhoodIteratorType::OffsetType; using NeighborhoodOffsetListType = std::vector; - /** - * Neighborhood patch similarity metric enumerated type - */ - enum SimilarityMetricType - { - PEARSON_CORRELATION, - MEAN_SQUARES - }; + + using SimilarityMetricEnum = NonLocalPatchBasedImageFilterEnums::SimilarityMetric; +#if !defined(ITK_LEGACY_REMOVE) + using SimilarityMetricType = SimilarityMetricEnum; + static constexpr SimilarityMetricType PEARSON_CORRELATION = SimilarityMetricEnum::PEARSON_CORRELATION; + static constexpr SimilarityMetricType MEAN_SQUARES = SimilarityMetricEnum::MEAN_SQUARES; +#endif /** * Get/set neighborhood search radius. @@ -137,8 +162,8 @@ class ITK_TEMPLATE_EXPORT NonLocalPatchBasedImageFilter : public ImageToImageFil /** * Enumerated type for neighborhood similarity. Default = MEAN_SQUARES */ - itkSetMacro(SimilarityMetric, SimilarityMetricType); - itkGetConstMacro(SimilarityMetric, SimilarityMetricType); + itkSetMacro(SimilarityMetric, SimilarityMetricEnum); + itkGetConstMacro(SimilarityMetric, SimilarityMetricEnum); protected: NonLocalPatchBasedImageFilter(); @@ -168,7 +193,7 @@ class ITK_TEMPLATE_EXPORT NonLocalPatchBasedImageFilter : public ImageToImageFil itkSetMacro(TargetImageRegion, RegionType); itkGetConstMacro(TargetImageRegion, RegionType); - SimilarityMetricType m_SimilarityMetric; + SimilarityMetricEnum m_SimilarityMetric; SizeValueType m_NeighborhoodSearchSize; NeighborhoodRadiusType m_NeighborhoodSearchRadius; diff --git a/Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.hxx b/Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.hxx index d9d98439b95b..aba441886ed6 100644 --- a/Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.hxx +++ b/Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.hxx @@ -28,7 +28,7 @@ namespace itk template NonLocalPatchBasedImageFilter::NonLocalPatchBasedImageFilter() { - this->m_SimilarityMetric = MEAN_SQUARES; + this->m_SimilarityMetric = SimilarityMetricEnum::MEAN_SQUARES; this->m_NeighborhoodPatchRadius.Fill(1); this->m_NeighborhoodPatchOffsetList.clear(); @@ -206,7 +206,7 @@ NonLocalPatchBasedImageFilter::ComputeNeighborhoodPat return NumericTraits::max(); } - if (this->m_SimilarityMetric == PEARSON_CORRELATION) + if (this->m_SimilarityMetric == SimilarityMetricEnum::PEARSON_CORRELATION) { RealType varianceX = sumOfSquaresX - itk::Math::sqr(sumX) / N; varianceX = std::max(varianceX, static_cast(1.0e-6)); @@ -221,7 +221,7 @@ NonLocalPatchBasedImageFilter::ComputeNeighborhoodPat return measure; } } - else if (this->m_SimilarityMetric == MEAN_SQUARES) + else if (this->m_SimilarityMetric == SimilarityMetricEnum::MEAN_SQUARES) { return (sumOfSquaredDifferencesXY / N); } @@ -237,11 +237,11 @@ NonLocalPatchBasedImageFilter::PrintSelf(std::ostream { Superclass::PrintSelf(os, indent); - if (this->m_SimilarityMetric == PEARSON_CORRELATION) + if (this->m_SimilarityMetric == SimilarityMetricEnum::PEARSON_CORRELATION) { os << "Using Pearson correlation to measure the patch similarity." << std::endl; } - else if (this->m_SimilarityMetric == MEAN_SQUARES) + else if (this->m_SimilarityMetric == SimilarityMetricEnum::MEAN_SQUARES) { os << "Using mean squares to measure the patch similarity." << std::endl; } diff --git a/Modules/Filtering/AdaptiveDenoising/src/CMakeLists.txt b/Modules/Filtering/AdaptiveDenoising/src/CMakeLists.txt new file mode 100644 index 000000000000..9aa91bde2932 --- /dev/null +++ b/Modules/Filtering/AdaptiveDenoising/src/CMakeLists.txt @@ -0,0 +1,5 @@ +set(AdaptiveDenoising_SRCS + itkNonLocalPatchBasedImageFilterEnums.cxx +) + +itk_module_add_library(AdaptiveDenoising ${AdaptiveDenoising_SRCS}) diff --git a/Modules/Filtering/AdaptiveDenoising/src/itkNonLocalPatchBasedImageFilterEnums.cxx b/Modules/Filtering/AdaptiveDenoising/src/itkNonLocalPatchBasedImageFilterEnums.cxx new file mode 100644 index 000000000000..e661febdf6f4 --- /dev/null +++ b/Modules/Filtering/AdaptiveDenoising/src/itkNonLocalPatchBasedImageFilterEnums.cxx @@ -0,0 +1,42 @@ +/*========================================================================= + * + * 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 + * + * http://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 "itkNonLocalPatchBasedImageFilter.h" + + +namespace itk +{ + +/** Print enum values */ +std::ostream & +operator<<(std::ostream & out, const NonLocalPatchBasedImageFilterEnums::SimilarityMetric value) +{ + return out << [value] { + switch (value) + { + case NonLocalPatchBasedImageFilterEnums::SimilarityMetric::PEARSON_CORRELATION: + return "itk::NonLocalPatchBasedImageFilterEnums::SimilarityMetric::PEARSON_CORRELATION"; + case NonLocalPatchBasedImageFilterEnums::SimilarityMetric::MEAN_SQUARES: + return "itk::NonLocalPatchBasedImageFilterEnums::SimilarityMetric::MEAN_SQUARES"; + default: + return "INVALID VALUE FOR itk::NonLocalPatchBasedImageFilterEnums::SimilarityMetric"; + } + }(); +} + +} // end namespace itk diff --git a/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx b/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx index a8320b6671d0..7cd897e2bd39 100644 --- a/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx +++ b/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx @@ -15,6 +15,8 @@ * limitations under the License. * *=========================================================================*/ + +#include #include "itkAdaptiveNonLocalMeansDenoisingImageFilter.h" #include "itkImageFileReader.h" @@ -158,5 +160,16 @@ itkAdaptiveNonLocalMeansDenoisingImageFilterTest(int argc, char * argv[]) writer->SetInput(filter->GetOutput()); writer->Update(); + // Test streaming enumeration for NonLocalPatchBasedImageFilterEnums::SimilarityMetric elements + const std::set allSimilarityMetric{ + itk::NonLocalPatchBasedImageFilterEnums::SimilarityMetric::PEARSON_CORRELATION, + itk::NonLocalPatchBasedImageFilterEnums::SimilarityMetric::MEAN_SQUARES + }; + for (const auto & ee : allSimilarityMetric) + { + std::cout << "STREAMED ENUM VALUE NonLocalPatchBasedImageFilterEnums::SimilarityMetric: " << ee << std::endl; + } + + return EXIT_SUCCESS; } diff --git a/Modules/Filtering/AdaptiveDenoising/wrapping/itkNonLocalPatchBasedImageFilter.wrap b/Modules/Filtering/AdaptiveDenoising/wrapping/itkNonLocalPatchBasedImageFilter.wrap index 92f6174d0033..859f4e064c09 100644 --- a/Modules/Filtering/AdaptiveDenoising/wrapping/itkNonLocalPatchBasedImageFilter.wrap +++ b/Modules/Filtering/AdaptiveDenoising/wrapping/itkNonLocalPatchBasedImageFilter.wrap @@ -1,3 +1,8 @@ +set(WRAPPER_AUTO_INCLUDE_HEADERS OFF) +itk_wrap_include("itkNonLocalPatchBasedImageFilter.h") + +itk_wrap_simple_class("itk::NonLocalPatchBasedImageFilterEnums" ENUM) + itk_wrap_class("itk::NonLocalPatchBasedImageFilter" POINTER) itk_wrap_image_filter("${WRAP_ITK_SCALAR}" 2) itk_end_wrap_class() From 81923e9aea6217aa80350c878542cc0ae01d0c11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20Haitz=20Legarreta=20Gorro=C3=B1o?= Date: Sat, 3 Oct 2020 16:34:34 -0400 Subject: [PATCH 18/31] ENH: Test the similarity metric Test the similarity metric. Take advantage of the commit to improve the test style to make a better use of the ITK macros. --- .../AdaptiveDenoising/test/CMakeLists.txt | 22 +++++++++++++++---- ...eNonLocalMeansDenoisingImageFilterTest.cxx | 18 ++++++++++----- 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/Modules/Filtering/AdaptiveDenoising/test/CMakeLists.txt b/Modules/Filtering/AdaptiveDenoising/test/CMakeLists.txt index 09e581e2a331..6bdf0be53c73 100644 --- a/Modules/Filtering/AdaptiveDenoising/test/CMakeLists.txt +++ b/Modules/Filtering/AdaptiveDenoising/test/CMakeLists.txt @@ -5,13 +5,27 @@ set(AdaptiveDenoisingTests itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx) createtestdriver(AdaptiveDenoising "${AdaptiveDenoising-Test_LIBRARIES}" "${AdaptiveDenoisingTests}") itk_add_test( - NAME AdaptiveNonLocalMeansDenoisingImageFilterTest + NAME AdaptiveNonLocalMeansDenoisingImageFilterTest1 COMMAND AdaptiveDenoisingTestDriver --compare - DATA{Baseline/r16denoised.nrrd} - ${ITK_TEST_OUTPUT_DIR}/r16denoised.nrrd + DATA{Baseline/r16denoised_pearson_correlation.nrrd} + ${ITK_TEST_OUTPUT_DIR}/r16denoised_pearson_correlation.nrrd itkAdaptiveNonLocalMeansDenoisingImageFilterTest DATA{Input/r16slice.nrrd} - ${ITK_TEST_OUTPUT_DIR}/r16denoised.nrrd + ${ITK_TEST_OUTPUT_DIR}/r16denoised_pearson_correlation.nrrd + 0 +) + +itk_add_test( + NAME AdaptiveNonLocalMeansDenoisingImageFilterTest2 + COMMAND + AdaptiveDenoisingTestDriver + --compare + DATA{Baseline/r16denoised_mean_squares.nrrd} + ${ITK_TEST_OUTPUT_DIR}/r16denoised_mean_squares.nrrd + itkAdaptiveNonLocalMeansDenoisingImageFilterTest + DATA{Input/r16slice.nrrd} + ${ITK_TEST_OUTPUT_DIR}/r16denoised_mean_squares.nrrd + 1 ) diff --git a/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx b/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx index 7cd897e2bd39..c29001bed46a 100644 --- a/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx +++ b/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx @@ -92,13 +92,12 @@ class CommandProgressUpdate : public itk::Command int itkAdaptiveNonLocalMeansDenoisingImageFilterTest(int argc, char * argv[]) { - if (argc < 3) + if (argc < 4) { std::cerr << "Missing parameters." << std::endl; - std::cerr << "Usage: " << argv[0]; - std::cerr << " inputImage"; - std::cerr << " outputImage"; - std::cerr << std::endl; + std::cerr << "Usage: " << itkNameOfTestExecutableMacro(argv) << " inputImage" + << " outputImage" + << " similarityMetric (0: PEARSON_CORRELATION; 1: MEAN_SQUARES)" << std::endl; return EXIT_FAILURE; } @@ -148,6 +147,10 @@ itkAdaptiveNonLocalMeansDenoisingImageFilterTest(int argc, char * argv[]) filter->SetSmoothingVariance(2.0f); ITK_TEST_EXPECT_TRUE(itk::Math::FloatAlmostEqual(2.0f, filter->GetSmoothingVariance())); + auto similarityMetric = static_cast(std::atoi(argv[3])); + filter->SetSimilarityMetric(similarityMetric); + ITK_TEST_SET_GET_VALUE(similarityMetric, filter->GetSimilarityMetric()) + using CommandType = CommandProgressUpdate; CommandType::Pointer observer = CommandType::New(); filter->AddObserver(itk::ProgressEvent(), observer); @@ -158,7 +161,9 @@ itkAdaptiveNonLocalMeansDenoisingImageFilterTest(int argc, char * argv[]) WriterType::Pointer writer = WriterType::New(); writer->SetFileName(argv[2]); writer->SetInput(filter->GetOutput()); - writer->Update(); + + ITK_TRY_EXPECT_NO_EXCEPTION(writer->Update()); + // Test streaming enumeration for NonLocalPatchBasedImageFilterEnums::SimilarityMetric elements const std::set allSimilarityMetric{ @@ -171,5 +176,6 @@ itkAdaptiveNonLocalMeansDenoisingImageFilterTest(int argc, char * argv[]) } + std::cout << "Test finished" << std::endl; return EXIT_SUCCESS; } From 665e616f8c422474b824fbde57386adc11aaed60 Mon Sep 17 00:00:00 2001 From: Hans Johnson Date: Sat, 26 Dec 2020 17:22:25 -0600 Subject: [PATCH 19/31] COMP: Update to new ITK_DISALLOW_COPY_AND_MOVE macro Replace the deprecated ITK_DISALLOW_COPY_AND_ASSIGN with new better descriptive name ITK_DISALLOW_COPY_AND_MOVE. --- .../include/itkAdaptiveNonLocalMeansDenoisingImageFilter.h | 2 +- .../include/itkNonLocalPatchBasedImageFilter.h | 2 +- .../AdaptiveDenoising/include/itkVarianceImageFilter.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.h b/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.h index a9cc7e41b46f..6dba25b904d3 100644 --- a/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.h +++ b/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.h @@ -51,7 +51,7 @@ class ITK_TEMPLATE_EXPORT AdaptiveNonLocalMeansDenoisingImageFilter final : public NonLocalPatchBasedImageFilter { public: - ITK_DISALLOW_COPY_AND_ASSIGN(AdaptiveNonLocalMeansDenoisingImageFilter); + ITK_DISALLOW_COPY_AND_MOVE(AdaptiveNonLocalMeansDenoisingImageFilter); /** Standard class typedefs. */ typedef AdaptiveNonLocalMeansDenoisingImageFilter Self; diff --git a/Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.h b/Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.h index 8863186ab19c..9414abee9a44 100644 --- a/Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.h +++ b/Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.h @@ -62,7 +62,7 @@ template class ITK_TEMPLATE_EXPORT NonLocalPatchBasedImageFilter : public ImageToImageFilter { public: - ITK_DISALLOW_COPY_AND_ASSIGN(NonLocalPatchBasedImageFilter); + ITK_DISALLOW_COPY_AND_MOVE(NonLocalPatchBasedImageFilter); /** Standard class typedefs. */ using Self = NonLocalPatchBasedImageFilter; diff --git a/Modules/Filtering/AdaptiveDenoising/include/itkVarianceImageFilter.h b/Modules/Filtering/AdaptiveDenoising/include/itkVarianceImageFilter.h index 5bb96576f240..6e4b12dcdbdd 100644 --- a/Modules/Filtering/AdaptiveDenoising/include/itkVarianceImageFilter.h +++ b/Modules/Filtering/AdaptiveDenoising/include/itkVarianceImageFilter.h @@ -38,7 +38,7 @@ template class ITK_TEMPLATE_EXPORT VarianceImageFilter final : public BoxImageFilter { public: - ITK_DISALLOW_COPY_AND_ASSIGN(VarianceImageFilter); + ITK_DISALLOW_COPY_AND_MOVE(VarianceImageFilter); /** Extract dimension from input and output image. */ itkStaticConstMacro(InputImageDimension, unsigned int, TInputImage::ImageDimension); From 8382b39619a0cca8cfe2118b86d04629a17a2030 Mon Sep 17 00:00:00 2001 From: Hans Johnson Date: Sat, 26 Dec 2020 19:38:19 -0600 Subject: [PATCH 20/31] COMP: Add missing ';' at end of macro For consistency, a ';' will be required in a future version of ITK. --- .../test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx b/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx index c29001bed46a..906d748693f6 100644 --- a/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx +++ b/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx @@ -149,7 +149,7 @@ itkAdaptiveNonLocalMeansDenoisingImageFilterTest(int argc, char * argv[]) auto similarityMetric = static_cast(std::atoi(argv[3])); filter->SetSimilarityMetric(similarityMetric); - ITK_TEST_SET_GET_VALUE(similarityMetric, filter->GetSimilarityMetric()) + ITK_TEST_SET_GET_VALUE(similarityMetric, filter->GetSimilarityMetric()); using CommandType = CommandProgressUpdate; CommandType::Pointer observer = CommandType::New(); From da3e4195506619d9beba5eb5b6d93af0571b2adf Mon Sep 17 00:00:00 2001 From: Hans Johnson Date: Thu, 5 Aug 2021 18:12:19 -0500 Subject: [PATCH 21/31] COMP: Replace SetUseImageSpacingOn() with SetUseImageSpacing(true) Use of SetUseImageSpacingOn() is deprecated in the future. 'Set' prefixed functions have an argument that is used to set an ivar. UseImageSpacingOn() is also valid, but is less compatible for older versions of ITK. --- .../include/itkAdaptiveNonLocalMeansDenoisingImageFilter.hxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.hxx b/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.hxx index a3be9f04a615..27c71af846e8 100644 --- a/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.hxx +++ b/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.hxx @@ -407,7 +407,7 @@ AdaptiveNonLocalMeansDenoisingImageFilter typename SmootherType::Pointer smoother = SmootherType::New(); smoother->SetInput(this->m_RicianBiasImage); smoother->SetVariance(this->m_SmoothingVariance); - smoother->SetUseImageSpacingOn(); + smoother->SetUseImageSpacing(true); smoother->Update(); ImageRegionConstIterator ItS(smoother->GetOutput(), smoother->GetOutput()->GetRequestedRegion()); From 78cd8556fa023fe7a063d263ef4c189eade95630 Mon Sep 17 00:00:00 2001 From: Hans Johnson Date: Fri, 17 Dec 2021 09:24:30 -0600 Subject: [PATCH 22/31] COMP: Remove inclusion of .hxx files as headers The ability to include either .h or .hxx files as header files required recursively reading the .h files twice. The added complexity is unnecessary, costly, and can confuse static analysis tools that monitor header guardes (due to reaching the maximum depth of recursion limits for nested #ifdefs in checking). --- .../include/itkAdaptiveNonLocalMeansDenoisingImageFilter.hxx | 1 - .../include/itkNonLocalPatchBasedImageFilter.hxx | 1 - .../AdaptiveDenoising/include/itkVarianceImageFilter.hxx | 1 - 3 files changed, 3 deletions(-) diff --git a/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.hxx b/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.hxx index 27c71af846e8..a9fc05549d43 100644 --- a/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.hxx +++ b/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.hxx @@ -18,7 +18,6 @@ #ifndef itkAdaptiveNonLocalMeansDenoisingImageFilter_hxx #define itkAdaptiveNonLocalMeansDenoisingImageFilter_hxx -#include "itkAdaptiveNonLocalMeansDenoisingImageFilter.h" #include "itkArray.h" #include "itkDiscreteGaussianImageFilter.h" diff --git a/Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.hxx b/Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.hxx index aba441886ed6..ac4bd9485405 100644 --- a/Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.hxx +++ b/Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.hxx @@ -18,7 +18,6 @@ #ifndef itkNonLocalPatchBasedImageFilter_hxx #define itkNonLocalPatchBasedImageFilter_hxx -#include "itkNonLocalPatchBasedImageFilter.h" #include "itkNeighborhood.h" diff --git a/Modules/Filtering/AdaptiveDenoising/include/itkVarianceImageFilter.hxx b/Modules/Filtering/AdaptiveDenoising/include/itkVarianceImageFilter.hxx index dc1f43a149fd..e375a8684b09 100644 --- a/Modules/Filtering/AdaptiveDenoising/include/itkVarianceImageFilter.hxx +++ b/Modules/Filtering/AdaptiveDenoising/include/itkVarianceImageFilter.hxx @@ -17,7 +17,6 @@ *=========================================================================*/ #ifndef itkVarianceImageFilter_hxx #define itkVarianceImageFilter_hxx -#include "itkVarianceImageFilter.h" #include "itkConstNeighborhoodIterator.h" #include "itkNeighborhoodInnerProduct.h" From ac0c82d5d2df6410839aa761846d58cae37a914f Mon Sep 17 00:00:00 2001 From: Hans Johnson Date: Fri, 4 Feb 2022 20:18:59 -0600 Subject: [PATCH 23/31] BUG: ZScore computations invalid for small values Images with small values have standard deviations that could be smaller than 1.0, but be perfectly valid. For the case when the standard deviation is zero, set all the z-score values to zero. --- .../itkNonLocalPatchBasedImageFilter.hxx | 35 ++++++++++--------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.hxx b/Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.hxx index ac4bd9485405..f6a86ba59035 100644 --- a/Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.hxx +++ b/Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.hxx @@ -112,16 +112,21 @@ NonLocalPatchBasedImageFilter::VectorizeImagePatch(co if (normalize) { + // Convert the current image patch to a z-score. RealType mean = 0.0; RealType standardDeviation = 0.0; this->GetMeanAndStandardDeviationOfVectorizedImagePatch(patchVector, mean, standardDeviation); - - standardDeviation = std::max(standardDeviation, NumericTraits::OneValue()); - - typename InputImagePixelVectorType::iterator it; - for (it = patchVector.begin(); it != patchVector.end(); ++it) + if (standardDeviation < NumericTraits::epsilon()) + { + for (auto & it : patchVector) + { + it = 0.; + } + } + const auto inv_standardDeviation = 1. / standardDeviation; + for (auto & it : patchVector) { - *it = (*it - mean) / standardDeviation; + it = (it - mean) * inv_standardDeviation; } } return patchVector; @@ -138,13 +143,13 @@ NonLocalPatchBasedImageFilter::GetMeanAndStandardDevi RealType sumOfSquares = 0.0; RealType count = 0.0; - typename InputImagePixelVectorType::const_iterator it; - for (it = patchVector.begin(); it != patchVector.end(); ++it) + for (const auto it : patchVector) { - if (std::isfinite(*it)) + if (std::isfinite(it)) // Silently skip non-finite values used to indicate + // out-of-bounds. { - sum += *it; - sumOfSquares += itk::Math::sqr(*it); + sum += it; + sumOfSquares += itk::Math::sqr(it); count += itk::NumericTraits::OneValue(); } } @@ -204,13 +209,11 @@ NonLocalPatchBasedImageFilter::ComputeNeighborhoodPat { return NumericTraits::max(); } - if (this->m_SimilarityMetric == SimilarityMetricEnum::PEARSON_CORRELATION) { - RealType varianceX = sumOfSquaresX - itk::Math::sqr(sumX) / N; - varianceX = std::max(varianceX, static_cast(1.0e-6)); - - RealType measure = itk::Math::sqr(sumXY) / varianceX; + const RealType varianceX = sumOfSquaresX - itk::Math::sqr(sumX) / N; + const RealType measure = + (varianceX > std::numeric_limits::epsilon()) ? itk::Math::sqr(sumXY) / varianceX : 0.; if (sumXY > 0) { return -measure; From 73d599408bb3c632e2259de15b72275e23062b00 Mon Sep 17 00:00:00 2001 From: Tom Birdsong Date: Tue, 31 May 2022 13:20:36 -0400 Subject: [PATCH 24/31] ENH: Bump ITK and change http to https --- .../include/itkAdaptiveNonLocalMeansDenoisingImageFilter.h | 2 +- .../include/itkAdaptiveNonLocalMeansDenoisingImageFilter.hxx | 2 +- .../include/itkNonLocalPatchBasedImageFilter.h | 2 +- .../include/itkNonLocalPatchBasedImageFilter.hxx | 2 +- .../AdaptiveDenoising/include/itkVarianceImageFilter.h | 2 +- .../AdaptiveDenoising/include/itkVarianceImageFilter.hxx | 2 +- .../src/itkNonLocalPatchBasedImageFilterEnums.cxx | 2 +- .../test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.h b/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.h index 6dba25b904d3..b26f9138e4c1 100644 --- a/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.h +++ b/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.h @@ -6,7 +6,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0.txt + * 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, diff --git a/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.hxx b/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.hxx index a9fc05549d43..473f1dd8bb85 100644 --- a/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.hxx +++ b/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.hxx @@ -6,7 +6,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0.txt + * 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, diff --git a/Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.h b/Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.h index 9414abee9a44..104a1dd76144 100644 --- a/Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.h +++ b/Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.h @@ -6,7 +6,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0.txt + * 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, diff --git a/Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.hxx b/Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.hxx index f6a86ba59035..5c4cc54888e2 100644 --- a/Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.hxx +++ b/Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.hxx @@ -6,7 +6,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0.txt + * 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, diff --git a/Modules/Filtering/AdaptiveDenoising/include/itkVarianceImageFilter.h b/Modules/Filtering/AdaptiveDenoising/include/itkVarianceImageFilter.h index 6e4b12dcdbdd..70bf5e61d3ce 100644 --- a/Modules/Filtering/AdaptiveDenoising/include/itkVarianceImageFilter.h +++ b/Modules/Filtering/AdaptiveDenoising/include/itkVarianceImageFilter.h @@ -6,7 +6,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0.txt + * 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, diff --git a/Modules/Filtering/AdaptiveDenoising/include/itkVarianceImageFilter.hxx b/Modules/Filtering/AdaptiveDenoising/include/itkVarianceImageFilter.hxx index e375a8684b09..ddb671254854 100644 --- a/Modules/Filtering/AdaptiveDenoising/include/itkVarianceImageFilter.hxx +++ b/Modules/Filtering/AdaptiveDenoising/include/itkVarianceImageFilter.hxx @@ -6,7 +6,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0.txt + * 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, diff --git a/Modules/Filtering/AdaptiveDenoising/src/itkNonLocalPatchBasedImageFilterEnums.cxx b/Modules/Filtering/AdaptiveDenoising/src/itkNonLocalPatchBasedImageFilterEnums.cxx index e661febdf6f4..931c9f320377 100644 --- a/Modules/Filtering/AdaptiveDenoising/src/itkNonLocalPatchBasedImageFilterEnums.cxx +++ b/Modules/Filtering/AdaptiveDenoising/src/itkNonLocalPatchBasedImageFilterEnums.cxx @@ -6,7 +6,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0.txt + * 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, diff --git a/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx b/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx index 906d748693f6..078c731ea5a5 100644 --- a/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx +++ b/Modules/Filtering/AdaptiveDenoising/test/itkAdaptiveNonLocalMeansDenoisingImageFilterTest.cxx @@ -6,7 +6,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0.txt + * 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, From 92005ae3639ab303e06b92a2c00b2e4aec97fd96 Mon Sep 17 00:00:00 2001 From: Hans Johnson Date: Sat, 25 Jan 2025 09:58:26 -0600 Subject: [PATCH 25/31] COMP: Use modern macro for name of class MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When preparing for the future with ITK by setting ITK_FUTURE_LEGACY_REMOVE:BOOL=ON ITK_LEGACY_REMOVEBOOL=ON The future preferred macro should be used │ - itkTypeMacro │ + itkOverrideGetNameOfClassMacro --- .../include/itkAdaptiveNonLocalMeansDenoisingImageFilter.h | 2 +- .../include/itkNonLocalPatchBasedImageFilter.h | 2 +- .../AdaptiveDenoising/include/itkVarianceImageFilter.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.h b/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.h index b26f9138e4c1..cf760b9f5ddc 100644 --- a/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.h +++ b/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.h @@ -60,7 +60,7 @@ class ITK_TEMPLATE_EXPORT AdaptiveNonLocalMeansDenoisingImageFilter final typedef SmartPointer ConstPointer; /** Runtime information support. */ - itkTypeMacro(AdaptiveNonLocalMeansDenoisingImageFilter, NonLocalPatchBasedImageFilter); + itkOverrideGetNameOfClassMacro(AdaptiveNonLocalMeansDenoisingImageFilter); /** Standard New method. */ itkNewMacro(Self); diff --git a/Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.h b/Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.h index 104a1dd76144..f09aae5561d1 100644 --- a/Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.h +++ b/Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.h @@ -71,7 +71,7 @@ class ITK_TEMPLATE_EXPORT NonLocalPatchBasedImageFilter : public ImageToImageFil using ConstPointer = SmartPointer; /** Runtime information support. */ - itkTypeMacro(NonLocalPatchBasedImageFilter, ImageToImageFilter); + itkOverrideGetNameOfClassMacro(NonLocalPatchBasedImageFilter); /** Standard New method. */ itkNewMacro(Self); diff --git a/Modules/Filtering/AdaptiveDenoising/include/itkVarianceImageFilter.h b/Modules/Filtering/AdaptiveDenoising/include/itkVarianceImageFilter.h index 70bf5e61d3ce..a9d1bb01a152 100644 --- a/Modules/Filtering/AdaptiveDenoising/include/itkVarianceImageFilter.h +++ b/Modules/Filtering/AdaptiveDenoising/include/itkVarianceImageFilter.h @@ -58,7 +58,7 @@ class ITK_TEMPLATE_EXPORT VarianceImageFilter final : public BoxImageFilter Date: Sat, 25 Jan 2025 10:29:22 -0600 Subject: [PATCH 26/31] STYLE: Replace itkStaticConstMacro with static constexpr Use static constexpr directly now that C++11 conformance is required by all compilers. :%s/itkStaticConstMacro *( *\([^,]*\),[ \_s]*\([^,]*\),\_s*\([^)]*\)) */static constexpr \2 \1 = \3/ge --- .../include/itkAdaptiveNonLocalMeansDenoisingImageFilter.h | 2 +- .../include/itkNonLocalPatchBasedImageFilter.h | 2 +- .../AdaptiveDenoising/include/itkVarianceImageFilter.h | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.h b/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.h index cf760b9f5ddc..329068276397 100644 --- a/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.h +++ b/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.h @@ -66,7 +66,7 @@ class ITK_TEMPLATE_EXPORT AdaptiveNonLocalMeansDenoisingImageFilter final itkNewMacro(Self); /** ImageDimension constants */ - itkStaticConstMacro(ImageDimension, unsigned int, TInputImage::ImageDimension); + static constexpr unsigned int ImageDimension = TInputImage::ImageDimension; /** Some convenient typedefs. */ typedef TInputImage InputImageType; diff --git a/Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.h b/Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.h index f09aae5561d1..90b00ebaec67 100644 --- a/Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.h +++ b/Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.h @@ -77,7 +77,7 @@ class ITK_TEMPLATE_EXPORT NonLocalPatchBasedImageFilter : public ImageToImageFil itkNewMacro(Self); /** ImageDimension constants */ - itkStaticConstMacro(ImageDimension, unsigned int, TInputImage::ImageDimension); + static constexpr unsigned int ImageDimension = TInputImage::ImageDimension; /** Some convenient typedefs. */ using InputImageType = TInputImage; diff --git a/Modules/Filtering/AdaptiveDenoising/include/itkVarianceImageFilter.h b/Modules/Filtering/AdaptiveDenoising/include/itkVarianceImageFilter.h index a9d1bb01a152..d1df07536172 100644 --- a/Modules/Filtering/AdaptiveDenoising/include/itkVarianceImageFilter.h +++ b/Modules/Filtering/AdaptiveDenoising/include/itkVarianceImageFilter.h @@ -41,8 +41,8 @@ class ITK_TEMPLATE_EXPORT VarianceImageFilter final : public BoxImageFilter Date: Fri, 8 May 2026 06:45:29 -0500 Subject: [PATCH 27/31] ENH: Add AdaptiveDenoising test data .cid stubs Test fixtures for the AdaptiveNonLocalMeansDenoising filter: bafkreiafwnstu4vzkrl7gpt73tl3q53ywpdylbs2d4emezgzutj2thoyfy r16slice.nrrd (test/Input) bafkreigltzq46r5ojiiyel37egvlosnxxgyth6ppwckzjtuxyywtlijoii r16denoised_mean_squares.nrrd (test/Baseline) bafkreickjyvdwmq6eyz76e7cukkegm4dd75raimxj4pag2o6bkanvbofwm r16denoised_pearson_correlation.nrrd (test/Baseline) The blobs are pre-uploaded to ITKTestingData via PR #48; the upstream remote module shipped these as raw .nrrd files inline in git, which were stripped from the rewritten ingest history (no raw binaries in ITK's history) and replaced by these .cid stubs at the ingest tip. CIDs were computed via 'ipfs add --cid-version=1 --raw-leaves'. --- .../test/Baseline/r16denoised_mean_squares.nrrd.cid | 1 + .../test/Baseline/r16denoised_pearson_correlation.nrrd.cid | 1 + Modules/Filtering/AdaptiveDenoising/test/Input/r16slice.nrrd.cid | 1 + 3 files changed, 3 insertions(+) create mode 100644 Modules/Filtering/AdaptiveDenoising/test/Baseline/r16denoised_mean_squares.nrrd.cid create mode 100644 Modules/Filtering/AdaptiveDenoising/test/Baseline/r16denoised_pearson_correlation.nrrd.cid create mode 100644 Modules/Filtering/AdaptiveDenoising/test/Input/r16slice.nrrd.cid diff --git a/Modules/Filtering/AdaptiveDenoising/test/Baseline/r16denoised_mean_squares.nrrd.cid b/Modules/Filtering/AdaptiveDenoising/test/Baseline/r16denoised_mean_squares.nrrd.cid new file mode 100644 index 000000000000..2d29f602e36d --- /dev/null +++ b/Modules/Filtering/AdaptiveDenoising/test/Baseline/r16denoised_mean_squares.nrrd.cid @@ -0,0 +1 @@ +bafkreigltzq46r5ojiiyel37egvlosnxxgyth6ppwckzjtuxyywtlijoii diff --git a/Modules/Filtering/AdaptiveDenoising/test/Baseline/r16denoised_pearson_correlation.nrrd.cid b/Modules/Filtering/AdaptiveDenoising/test/Baseline/r16denoised_pearson_correlation.nrrd.cid new file mode 100644 index 000000000000..dfcb5cf3f880 --- /dev/null +++ b/Modules/Filtering/AdaptiveDenoising/test/Baseline/r16denoised_pearson_correlation.nrrd.cid @@ -0,0 +1 @@ +bafkreickjyvdwmq6eyz76e7cukkegm4dd75raimxj4pag2o6bkanvbofwm diff --git a/Modules/Filtering/AdaptiveDenoising/test/Input/r16slice.nrrd.cid b/Modules/Filtering/AdaptiveDenoising/test/Input/r16slice.nrrd.cid new file mode 100644 index 000000000000..e03b4e30a397 --- /dev/null +++ b/Modules/Filtering/AdaptiveDenoising/test/Input/r16slice.nrrd.cid @@ -0,0 +1 @@ +bafkreiafwnstu4vzkrl7gpt73tl3q53ywpdylbs2d4emezgzutj2thoyfy From 2e7e1cef27d524584d8a277331404f3d902f946e Mon Sep 17 00:00:00 2001 From: "Hans J. Johnson" Date: Fri, 8 May 2026 06:47:24 -0500 Subject: [PATCH 28/31] DOC: Add AdaptiveDenoising README pointing at upstream --- Modules/Filtering/AdaptiveDenoising/README.md | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 Modules/Filtering/AdaptiveDenoising/README.md diff --git a/Modules/Filtering/AdaptiveDenoising/README.md b/Modules/Filtering/AdaptiveDenoising/README.md new file mode 100644 index 000000000000..e93d97bee277 --- /dev/null +++ b/Modules/Filtering/AdaptiveDenoising/README.md @@ -0,0 +1,31 @@ +# AdaptiveDenoising + +In-tree ITK module providing patch-based adaptive denoising filters for +scalar and vector images. The flagship class is +`itk::AdaptiveNonLocalMeansDenoisingImageFilter`, which implements a +non-local-means denoiser whose patch-similarity radius and smoothing +strength adapt to local image content. Supporting infrastructure +includes `itk::NonLocalPatchBasedImageFilter` (the base class for +non-local-means style filters) and `itk::VarianceImageFilter` (a +neighborhood variance estimator used to drive the adaptive parameter +selection). + +## Origin + +Ingested from the standalone remote module +[**ntustison/ITKAdaptiveDenoising**](https://github.com/ntustison/ITKAdaptiveDenoising) +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 `examples/` +directory, which was intentionally left in the upstream archive). + +## References + +- Manjón J.V., Coupé P., Martí-Bonmatí L., Collins D.L., Robles M. + *Adaptive non-local means denoising of MR images with spatially + varying noise levels.* Journal of Magnetic Resonance Imaging. + 2010;31(1):192-203. +- Tustison N., Manjón J.V. *Adaptive Non-Local Means Filtering for + Image Denoising.* The Insight Journal. 2020. + From ea2ef1a100b75c034db596b6dbdde00ae1eb685f Mon Sep 17 00:00:00 2001 From: "Hans J. Johnson" Date: Fri, 8 May 2026 06:47:26 -0500 Subject: [PATCH 29/31] COMP: Remove AdaptiveDenoising .remote.cmake (in-tree) --- Modules/Remote/AdaptiveDenoising.remote.cmake | 61 ------------------- 1 file changed, 61 deletions(-) delete mode 100644 Modules/Remote/AdaptiveDenoising.remote.cmake diff --git a/Modules/Remote/AdaptiveDenoising.remote.cmake b/Modules/Remote/AdaptiveDenoising.remote.cmake deleted file mode 100644 index 289dbdfa9ff9..000000000000 --- a/Modules/Remote/AdaptiveDenoising.remote.cmake +++ /dev/null @@ -1,61 +0,0 @@ -#-- # Grading Level Criteria Report -#-- EVALUATION DATE: 09/28/2020 -#-- EVALUATORS: Nick Tustison -#-- -#-- ## 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 -#-- - [ X ] 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 -#-- - [ X ] Active developer community dedicated to maintaining code-base -#-- - [ ] 75% code coverage demonstrated for testing suite -#-- - [ X ] Continuous integration testing performed -#-- - [ ] All requirements of Levels 3,2,1 -#-- -#-- ## Compliance Level 3 star (Quality beta code) -#-- - [ X ] API | executable interface is considered mostly stable and feature complete -#-- - [ X ] 10% C0-code coverage demonstrated for testing suite -#-- - [ X ] 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 - -itk_fetch_module( - AdaptiveDenoising - "A spatially adaptive denoising image filter using non-local means. - A patch-based framework for new ITK functionality: Joint fusion, denoising, - and non-local super-resolution. - Tustison N., Avants B., Wang H., Xie L., Coupe P., Yushkevich P., Manjon J. - Insight Journal. - https://doi.org/10.54294/ywuouh. - Two Luis Miguel fans walk into a bar in Nagoya ---> (yada, yada, yada) - ---> an ITK-implementation of a popular patch-based denoising filter. - Tustison N., Manjon J.V. - Insight Journal. - https://doi.org/10.54294/9f5wt3. - " - MODULE_COMPLIANCE_LEVEL 3 - GIT_REPOSITORY https://github.com/ntustison/ITKAdaptiveDenoising.git - GIT_TAG 99db4507f05ea933600c41ccf0d53b4202f4cab2 - ) From 741721478a2994cf1608b566b0a2acec470cbda5 Mon Sep 17 00:00:00 2001 From: "Hans J. Johnson" Date: Fri, 8 May 2026 08:40:20 -0500 Subject: [PATCH 30/31] ENH: Enable Module_AdaptiveDenoising in configure-ci --- .../include/itkAdaptiveNonLocalMeansDenoisingImageFilter.hxx | 2 +- Modules/Filtering/AdaptiveDenoising/src/CMakeLists.txt | 4 +--- pyproject.toml | 1 + 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.hxx b/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.hxx index 473f1dd8bb85..f0f76c580739 100644 --- a/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.hxx +++ b/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.hxx @@ -440,7 +440,7 @@ AdaptiveNonLocalMeansDenoisingImageFilter ImageRegionIteratorWithIndex ItO(this->GetOutput(), this->GetOutput()->GetRequestedRegion()); ImageRegionConstIterator ItL(this->m_ThreadContributionCountImage, - this->m_ThreadContributionCountImage->GetRequestedRegion()); + this->m_ThreadContributionCountImage->GetRequestedRegion()); for (ItO.GoToBegin(), ItL.GoToBegin(); !ItO.IsAtEnd(); ++ItO, ++ItL) { diff --git a/Modules/Filtering/AdaptiveDenoising/src/CMakeLists.txt b/Modules/Filtering/AdaptiveDenoising/src/CMakeLists.txt index 9aa91bde2932..b8b206626a5b 100644 --- a/Modules/Filtering/AdaptiveDenoising/src/CMakeLists.txt +++ b/Modules/Filtering/AdaptiveDenoising/src/CMakeLists.txt @@ -1,5 +1,3 @@ -set(AdaptiveDenoising_SRCS - itkNonLocalPatchBasedImageFilterEnums.cxx -) +set(AdaptiveDenoising_SRCS itkNonLocalPatchBasedImageFilterEnums.cxx) itk_module_add_library(AdaptiveDenoising ${AdaptiveDenoising_SRCS}) diff --git a/pyproject.toml b/pyproject.toml index c73ae38c83d7..3f7fc02a387f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -52,6 +52,7 @@ cmd = '''cmake \ -DITK_USE_CCACHE:BOOL=ON \ -DCMAKE_C_COMPILER_LAUNCHER:STRING=ccache \ -DCMAKE_CXX_COMPILER_LAUNCHER:STRING=ccache \ + -DModule_AdaptiveDenoising:BOOL=ON \ -DModule_AnisotropicDiffusionLBR:BOOL=ON \ -DModule_Cuberille:BOOL=ON \ -DModule_Montage:BOOL=ON \ From 9b102e9c923a8164006367b0bb6f1592d1c0cb26 Mon Sep 17 00:00:00 2001 From: "Hans J. Johnson" Date: Fri, 8 May 2026 17:32:04 -0500 Subject: [PATCH 31/31] STYLE: Address Greptile review on AdaptiveDenoising MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit itkNonLocalPatchBasedImageFilter.hxx: wrap z-score normalization in an else-branch so the near-zero standard-deviation path no longer falls through to divide by epsilon and propagate -mean/eps into the output patch. itkVarianceImageFilter.h: correct the doxygen header — the filter computes sample variance (a nonlinear neighborhood operation), not an averaging linear filter; fix the "variacne" typo. itkAdaptiveNonLocalMeansDenoisingImageFilter.h, itkVarianceImageFilter.h: convert remaining typedef declarations to using-aliases per ITK's enforced code style. --- ...daptiveNonLocalMeansDenoisingImageFilter.h | 48 +++++++++---------- .../itkNonLocalPatchBasedImageFilter.hxx | 9 ++-- .../include/itkVarianceImageFilter.h | 32 ++++++------- 3 files changed, 46 insertions(+), 43 deletions(-) diff --git a/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.h b/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.h index 329068276397..55b826aa038c 100644 --- a/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.h +++ b/Modules/Filtering/AdaptiveDenoising/include/itkAdaptiveNonLocalMeansDenoisingImageFilter.h @@ -54,10 +54,10 @@ class ITK_TEMPLATE_EXPORT AdaptiveNonLocalMeansDenoisingImageFilter final ITK_DISALLOW_COPY_AND_MOVE(AdaptiveNonLocalMeansDenoisingImageFilter); /** Standard class typedefs. */ - typedef AdaptiveNonLocalMeansDenoisingImageFilter Self; - typedef NonLocalPatchBasedImageFilter Superclass; - typedef SmartPointer Pointer; - typedef SmartPointer ConstPointer; + using Self = AdaptiveNonLocalMeansDenoisingImageFilter; + using Superclass = NonLocalPatchBasedImageFilter; + using Pointer = SmartPointer; + using ConstPointer = SmartPointer; /** Runtime information support. */ itkOverrideGetNameOfClassMacro(AdaptiveNonLocalMeansDenoisingImageFilter); @@ -69,26 +69,26 @@ class ITK_TEMPLATE_EXPORT AdaptiveNonLocalMeansDenoisingImageFilter final static constexpr unsigned int ImageDimension = TInputImage::ImageDimension; /** Some convenient typedefs. */ - typedef TInputImage InputImageType; - typedef typename InputImageType::PixelType InputPixelType; - typedef TOutputImage OutputImageType; - typedef typename Superclass::RegionType RegionType; - - typedef TMaskImage MaskImageType; - typedef typename MaskImageType::PixelType MaskPixelType; - typedef typename MaskImageType::PixelType LabelType; - - typedef typename Superclass::RealType RealType; - typedef typename Superclass::RealImageType RealImageType; - typedef typename Superclass::RealImagePointer RealImagePointer; - typedef typename Superclass::IndexType IndexType; - - typedef typename Superclass::ConstNeighborhoodIteratorType ConstNeighborhoodIteratorType; - typedef typename Superclass::NeighborhoodRadiusType NeighborhoodRadiusType; - typedef typename Superclass::NeighborhoodOffsetType NeighborhoodOffsetType; - typedef typename Superclass::NeighborhoodOffsetListType NeighborhoodOffsetListType; - - typedef GaussianOperator ModifiedBesselCalculatorType; + using InputImageType = TInputImage; + using InputPixelType = typename InputImageType::PixelType; + using OutputImageType = TOutputImage; + using RegionType = typename Superclass::RegionType; + + using MaskImageType = TMaskImage; + using MaskPixelType = typename MaskImageType::PixelType; + using LabelType = typename MaskImageType::PixelType; + + using RealType = typename Superclass::RealType; + using RealImageType = typename Superclass::RealImageType; + using RealImagePointer = typename Superclass::RealImagePointer; + using IndexType = typename Superclass::IndexType; + + using ConstNeighborhoodIteratorType = typename Superclass::ConstNeighborhoodIteratorType; + using NeighborhoodRadiusType = typename Superclass::NeighborhoodRadiusType; + using NeighborhoodOffsetType = typename Superclass::NeighborhoodOffsetType; + using NeighborhoodOffsetListType = typename Superclass::NeighborhoodOffsetListType; + + using ModifiedBesselCalculatorType = GaussianOperator; /** * The image expected for input for noise correction. diff --git a/Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.hxx b/Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.hxx index 5c4cc54888e2..c16618904408 100644 --- a/Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.hxx +++ b/Modules/Filtering/AdaptiveDenoising/include/itkNonLocalPatchBasedImageFilter.hxx @@ -123,10 +123,13 @@ NonLocalPatchBasedImageFilter::VectorizeImagePatch(co it = 0.; } } - const auto inv_standardDeviation = 1. / standardDeviation; - for (auto & it : patchVector) + else { - it = (it - mean) * inv_standardDeviation; + const auto inv_standardDeviation = 1. / standardDeviation; + for (auto & it : patchVector) + { + it = (it - mean) * inv_standardDeviation; + } } } return patchVector; diff --git a/Modules/Filtering/AdaptiveDenoising/include/itkVarianceImageFilter.h b/Modules/Filtering/AdaptiveDenoising/include/itkVarianceImageFilter.h index d1df07536172..cf5133b15213 100644 --- a/Modules/Filtering/AdaptiveDenoising/include/itkVarianceImageFilter.h +++ b/Modules/Filtering/AdaptiveDenoising/include/itkVarianceImageFilter.h @@ -25,12 +25,12 @@ namespace itk { /** \class VarianceImageFilter - * \brief Applies an averaging filter to an image + * \brief Applies a variance filter to an image * - * Computes an image where a given pixel is the variance value of the - * the pixels in a neighborhood about the corresponding input pixel. + * Computes an image where a given pixel is the sample variance of the + * pixels in a neighborhood about the corresponding input pixel. * - * A variacne filter is one of the family of linear filters. + * A variance filter is a nonlinear (quadratic) neighborhood filter. * * \ingroup AdaptiveDenoising */ @@ -45,14 +45,14 @@ class ITK_TEMPLATE_EXPORT VarianceImageFilter final : public BoxImageFilter Superclass; - typedef SmartPointer Pointer; - typedef SmartPointer ConstPointer; + using Self = VarianceImageFilter; + using Superclass = BoxImageFilter; + using Pointer = SmartPointer; + using ConstPointer = SmartPointer; /** Method for creation through the object factory. */ itkNewMacro(Self); @@ -61,14 +61,14 @@ class ITK_TEMPLATE_EXPORT VarianceImageFilter final : public BoxImageFilter::RealType InputRealType; + using InputPixelType = typename InputImageType::PixelType; + using OutputPixelType = typename OutputImageType::PixelType; + using InputRealType = typename NumericTraits::RealType; - typedef typename InputImageType::RegionType InputImageRegionType; - typedef typename OutputImageType::RegionType OutputImageRegionType; + using InputImageRegionType = typename InputImageType::RegionType; + using OutputImageRegionType = typename OutputImageType::RegionType; - typedef typename InputImageType::SizeType InputSizeType; + using InputSizeType = typename InputImageType::SizeType; #ifdef ITK_USE_CONCEPT_CHECKING // Begin concept checking