ITK  5.0.0
Insight Segmentation and Registration Toolkit
itkPatchBasedDenoisingImageFilter.h
Go to the documentation of this file.
1 /*=========================================================================
2  *
3  * Copyright Insight Software Consortium
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0.txt
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  *=========================================================================*/
18 #ifndef itkPatchBasedDenoisingImageFilter_h
19 #define itkPatchBasedDenoisingImageFilter_h
20 
22 #include "itkImageRegionIterator.h"
24 #include "itkVector.h"
25 #include "itkVectorImage.h"
26 #include "itkRGBPixel.h"
27 #include "itkRGBAPixel.h"
28 #include "itkDiffusionTensor3D.h"
29 #include "itkFixedArray.h"
30 #include "itkMatrix.h"
32 #include <type_traits>
33 
34 #include <vector>
35 
36 namespace itk
37 {
59 template <typename TInputImage, typename TOutputImage>
60 class ITK_TEMPLATE_EXPORT PatchBasedDenoisingImageFilter :
61  public PatchBasedDenoisingBaseImageFilter<TInputImage, TOutputImage>
62 {
63 public:
64  ITK_DISALLOW_COPY_AND_ASSIGN(PatchBasedDenoisingImageFilter);
65 
71  using OutputImagePointer = typename Superclass::OutputImagePointer;
72 
74  itkNewMacro(Self);
75 
77  itkTypeMacro(PatchBasedDenoisingImageFilter,
79 
81  using InputImageType = typename Superclass::InputImageType;
82  using OutputImageType = typename Superclass::OutputImageType;
83 
85  static constexpr unsigned int ImageDimension = Superclass::ImageDimension;
86 
89 
93 
96  using PixelType = typename Superclass::PixelType;
97  using PixelValueType = typename Superclass::PixelValueType;
98 
104 
106  using ListAdaptorType = typename Superclass::ListAdaptorType;
107  using PatchRadiusType = typename Superclass::PatchRadiusType;
108  using InputImagePatchIterator = typename Superclass::InputImagePatchIterator;
110  using PatchWeightsType = typename Superclass::PatchWeightsType;
111 
117 
125  using EigenValuesCacheType = std::vector<EigenValuesArrayType>;
126  using EigenVectorsCacheType = std::vector<EigenVectorsMatrixType>;
127 
129  {
139  };
140 
145  itkSetMacro(UseSmoothDiscPatchWeights, bool);
146  itkBooleanMacro(UseSmoothDiscPatchWeights);
147  itkGetConstMacro(UseSmoothDiscPatchWeights, bool);
149 
154  void SetKernelBandwidthSigma(const RealArrayType& kernelSigma);
155  itkGetConstMacro(KernelBandwidthSigma, RealArrayType);
157 
162  itkSetClampMacro(KernelBandwidthFractionPixelsForEstimation, double, 0.01, 1.0);
163  itkGetConstReferenceMacro(KernelBandwidthFractionPixelsForEstimation, double);
165 
168  itkSetMacro(ComputeConditionalDerivatives, bool);
169  itkBooleanMacro(ComputeConditionalDerivatives);
170  itkGetConstMacro(ComputeConditionalDerivatives, bool);
172 
186  itkSetMacro(UseFastTensorComputations, bool);
187  itkBooleanMacro(UseFastTensorComputations);
188  itkGetConstMacro(UseFastTensorComputations, bool);
190 
192  static constexpr unsigned int MaxSigmaUpdateIterations = 20;
193 
200  itkSetClampMacro(KernelBandwidthMultiplicationFactor, double, 0.01, 100);
201  itkGetConstReferenceMacro(KernelBandwidthMultiplicationFactor, double);
203 
207  void SetNoiseSigma(const RealType& sigma);
208 
209  itkGetConstMacro(NoiseSigma, RealType);
210 
212  itkSetObjectMacro(Sampler, BaseSamplerType);
213  itkGetModifiableObjectMacro(Sampler, BaseSamplerType);
215 
217  itkGetConstMacro(NumIndependentComponents, unsigned int);
218 
219 protected:
221  ~PatchBasedDenoisingImageFilter() override;
222  void PrintSelf(std::ostream& os, Indent indent) const override;
223 
225  virtual void EmptyCaches();
226 
228  void AllocateUpdateBuffer() override;
229 
230  void CopyInputToOutput() override;
231 
232  void GenerateInputRequestedRegion() override;
233 
234  template<typename T, typename U = void> using DisableIfMultiComponent =
235  typename std::enable_if<std::is_same<T, typename NumericTraits<T>::ValueType>::value, U >;
236 
237  template<typename T, typename U = void> using EnableIfMultiComponent =
238  typename std::enable_if<!std::is_same<T, typename NumericTraits<T>::ValueType>::value, U >;
239 
240 
247  template< typename T>
249  GetComponent(const T pix,
250  unsigned int itkNotUsed( idx ) ) const
251  {
252  // The enable if idiom is used to overload this method for both
253  // scalars and multi-component types. By exploiting that
254  // NumericTraits' ValueType type alias (defines the per-element type
255  // for multi-component types ) is different then the parameterize
256  // type, the bracket operator is used only for multi-component
257  // types.
258  return pix;
259  }
260 
261  template< typename T>
262  typename EnableIfMultiComponent<T, typename NumericTraits<T>::ValueType>::type
263  GetComponent(const T& pix,
264  unsigned int idx ) const
265  {
266  return pix[idx];
267  }
268 
270  template< typename T >
271  void
272  SetComponent( T &pix,
273  unsigned int itkNotUsed( idx ),
275  {
276  pix = val;
277  }
278 
279  template< typename T >
280  void
281  SetComponent( T &pix,
282  unsigned int idx,
284  {
285  pix[idx] = val;
286  }
287 
291  void ComputeMinMax(const Image< DiffusionTensor3D<PixelValueType> , ImageDimension>* img)
292  {
293  if( this->GetComponentSpace() == Superclass::RIEMANNIAN )
294  {
295  DispatchedRiemannianMinMax(img);
296  }
297  else
298  {
299  DispatchedArrayMinMax(img);
300  }
301  }
302 
303  template< typename TImageType >
304  typename DisableIfMultiComponent<typename TImageType::PixelType>::type
305  ComputeMinMax(const TImageType* img)
306  {
307  DispatchedMinMax(img);
308  }
309 
310  template< typename TImageType >
311  typename EnableIfMultiComponent<typename TImageType::PixelType>::type
312  ComputeMinMax(const TImageType* img)
313  {
314  DispatchedArrayMinMax(img);
315  }
316 
327  const RealArrayType& weight,
328  bool useCachedComputations,
329  SizeValueType cacheIndex,
330  EigenValuesCacheType& eigenValsCache,
331  EigenVectorsCacheType& eigenVecsCache,
332  RealType& diff, RealArrayType& norm)
333  {
334  if( this->GetComponentSpace() == Superclass::RIEMANNIAN )
335  {
336  ComputeLogMapAndWeightedSquaredGeodesicDifference(a, b, weight,
337  useCachedComputations, cacheIndex,
338  eigenValsCache, eigenVecsCache,
339  diff, norm);
340  }
341  else
342  {
343  ComputeSignedEuclideanDifferenceAndWeightedSquaredNorm(a, b, weight,
344  useCachedComputations, cacheIndex,
345  eigenValsCache, eigenVecsCache,
346  diff, norm);
347  }
348  }
350 
351  template <typename PixelT>
353  const PixelT& b,
354  const RealArrayType& weight,
355  bool useCachedComputations,
356  SizeValueType cacheIndex,
357  EigenValuesCacheType& eigenValsCache,
358  EigenVectorsCacheType& eigenVecsCache,
359  RealType& diff, RealArrayType& norm)
360  {
361  ComputeSignedEuclideanDifferenceAndWeightedSquaredNorm(a, b, weight,
362  useCachedComputations, cacheIndex,
363  eigenValsCache, eigenVecsCache,
364  diff, norm);
365  }
366 
371  const RealType& b)
372  {
373  if( this->GetComponentSpace() == Superclass::RIEMANNIAN )
374  {
375  return this->AddExponentialMapUpdate(a, b);
376  }
377  else
378  {
379  return this->AddEuclideanUpdate(a, b);
380  }
381  }
383 
384  template <typename RealT>
385  RealType AddUpdate(const RealT& a,
386  const RealType& b)
387  {
388  return this->AddEuclideanUpdate(a, b);
389  }
390 
391  virtual void EnforceConstraints();
392 
393  void Initialize() override;
394 
395  virtual void InitializeKernelSigma();
396 
397  void InitializePatchWeights() override;
398 
399  virtual void InitializePatchWeightsSmoothDisc();
400 
401  void InitializeIteration() override;
402 
403  void ComputeKernelBandwidthUpdate() override; // derived from base class;
404 
405  // define here
406 
407  virtual ThreadDataStruct ThreadedComputeSigmaUpdate(const InputImageRegionType& regionToProcess,
408  const int itkNotUsed(threadId),
409  ThreadDataStruct threadData);
410 
411  virtual RealArrayType ResolveSigmaUpdate();
412 
413  void ComputeImageUpdate() override;
414 
415  virtual ThreadDataStruct ThreadedComputeImageUpdate(const InputImageRegionType& regionToProcess,
416  const int threadId,
417  ThreadDataStruct threadData);
418 
419  virtual RealType ComputeGradientJointEntropy(InstanceIdentifier id,
420  typename ListAdaptorType::Pointer& inList,
421  BaseSamplerPointer& sampler,
422  ThreadDataStruct& threadData);
423 
424  void ApplyUpdate() override;
425 
426  virtual void ThreadedApplyUpdate(const InputImageRegionType& regionToProcess,
427  const int itkNotUsed(threadId) );
428 
429  void PostProcessOutput() override;
430 
431  virtual void SetThreadData(int threadId, const ThreadDataStruct& data);
432 
433  virtual ThreadDataStruct GetThreadData(int threadId);
434 
435 private:
438  static ITK_THREAD_RETURN_FUNCTION_CALL_CONVENTION ComputeSigmaUpdateThreaderCallback( void *arg );
439 
442  static ITK_THREAD_RETURN_FUNCTION_CALL_CONVENTION ComputeImageUpdateThreaderCallback( void *arg );
443 
446  static ITK_THREAD_RETURN_FUNCTION_CALL_CONVENTION ApplyUpdateThreaderCallback( void *arg );
447 
448  template <typename TInputImageType>
449  void DispatchedMinMax(const TInputImageType* img);
450 
451  template <typename TInputImageType>
452  void DispatchedArrayMinMax(const TInputImageType* img);
453 
454  template <typename TInputImageType>
455  void DispatchedVectorMinMax(const TInputImageType* img);
456 
457  template <typename TInputImageType>
458  void DispatchedRiemannianMinMax(const TInputImageType* img);
459 
462  static ITK_THREAD_RETURN_FUNCTION_CALL_CONVENTION RiemannianMinMaxThreaderCallback( void *arg );
463 
464  ThreadDataStruct ThreadedRiemannianMinMax(const InputImageRegionType& regionToProcess,
465  const int itkNotUsed(threadId),
466  const InputImageType* img,
467  ThreadDataStruct threadData);
468 
469  virtual void ResolveRiemannianMinMax();
470 
471  void ComputeSignedEuclideanDifferenceAndWeightedSquaredNorm(const PixelType& a, const PixelType& b,
472  const RealArrayType& weight,
473  bool useCachedComputations,
474  SizeValueType cacheIndex,
475  EigenValuesCacheType& eigenValsCache,
476  EigenVectorsCacheType& eigenVecsCache,
477  RealType& diff, RealArrayType& norm);
478 
480  void ComputeLogMapAndWeightedSquaredGeodesicDifference(const DiffusionTensor3D<PixelValueType>& spdMatrixA,
481  const DiffusionTensor3D<PixelValueType>& spdMatrixB,
482  const RealArrayType& weight,
483  bool useCachedComputations,
484  SizeValueType cacheIndex,
485  EigenValuesCacheType& eigenValsCache,
486  EigenVectorsCacheType& eigenVecsCache,
487  RealType& symMatrixLogMap, RealArrayType& geodesicDist);
488 
489  template <typename TensorValueT>
490  void Compute3x3EigenAnalysis(const DiffusionTensor3D<TensorValueT>& spdMatrix,
492  Matrix< TensorValueT, 3, 3 >& eigenVecs);
493 
494  RealType AddEuclideanUpdate(const RealType& a, const RealType& b);
495 
497  RealType AddExponentialMapUpdate(const DiffusionTensor3D<RealValueType>& spdMatrix,
498  const DiffusionTensor3D<RealValueType>& symMatrix);
499 
501  {
504  };
505 
506  std::vector<ThreadDataStruct> m_ThreadData;
507 
509  typename OutputImageType::Pointer m_UpdateBuffer;
510 
511  unsigned int m_NumPixelComponents{ 0 };
512  unsigned int m_NumIndependentComponents{ 0 };
513  unsigned int m_TotalNumberPixels{ 0 };
514 
515  bool m_UseSmoothDiscPatchWeights{ true };
516 
517  bool m_UseFastTensorComputations{ true };
518 
520  bool m_KernelBandwidthSigmaIsSet{ false };
525  double m_KernelBandwidthFractionPixelsForEstimation{ 0.20 };
526  bool m_ComputeConditionalDerivatives{ false };
527  double m_MinSigma;
530  double m_SigmaUpdateConvergenceTolerance{ 0.01 };
532  double m_KernelBandwidthMultiplicationFactor{ 1.0 };
533 
536  bool m_NoiseSigmaIsSet{ false };
537 
539  typename ListAdaptorType::Pointer m_SearchSpaceList;
540 };
541 } // end namespace itk
542 
543 #ifndef ITK_MANUAL_INSTANTIATION
544 #include "itkPatchBasedDenoisingImageFilter.hxx"
545 #endif
546 
547 #endif
A templated class holding a M x N size Matrix.
Definition: itkMatrix.h:49
Derived class implementing a specific patch-based denoising algorithm, as detailed below...
std::vector< EigenValuesArrayType > EigenValuesCacheType
typename TSample::InstanceIdentifier InstanceIdentifier
typename OutputImageType::Pointer OutputImagePointer
Define numeric traits for std::vector.
void ComputeDifferenceAndWeightedSquaredNorm(const PixelT &a, const PixelT &b, const RealArrayType &weight, bool useCachedComputations, SizeValueType cacheIndex, EigenValuesCacheType &eigenValsCache, EigenVectorsCacheType &eigenVecsCache, RealType &diff, RealArrayType &norm)
void SetComponent(T &pix, unsigned int, typename DisableIfMultiComponent< T, RealValueType >::type val) const
A method to generically set a component.
Base class for patch-based denoising algorithms.
unsigned long SizeValueType
Definition: itkIntTypes.h:83
DisableIfMultiComponent< typename TImageType::PixelType >::type ComputeMinMax(const TImageType *img)
typename Superclass::InputImageType InputImageType
The base class for all process objects (source, filters, mappers) in the Insight data processing pipe...
itk::ITK_THREAD_RETURN_TYPE ITK_THREAD_RETURN_FUNCTION_CALL_CONVENTION
Base class for all process objects that output image data.
Const version of NeighborhoodIterator, defining iteration of a local N-dimensional neighborhood of pi...
typename NumericTraits< PixelType >::RealType RealType
typename std::enable_if<!std::is_same< T, typename NumericTraits< T >::ValueType >::value, U > EnableIfMultiComponent
typename::itk::Statistics::ImageToNeighborhoodSampleAdaptor< OutputImageType, BoundaryConditionType > ListAdaptorType
Simulate a standard C array with copy semnatics.
Definition: itkFixedArray.h:51
typename BaseSamplerType::Pointer BaseSamplerPointer
EnableIfMultiComponent< T, typename NumericTraits< T >::ValueType >::type GetComponent(const T &pix, unsigned int idx) const
typename NumericTraits< PixelType >::ValueType PixelValueType
RealType AddUpdate(const DiffusionTensor3D< RealValueType > &a, const RealType &b)
typename std::enable_if< std::is_same< T, typename NumericTraits< T >::ValueType >::value, U > DisableIfMultiComponent
EnableIfMultiComponent< typename TImageType::PixelType >::type ComputeMinMax(const TImageType *img)
void ComputeMinMax(const Image< DiffusionTensor3D< PixelValueType >, ImageDimension > *img)
This an abstract subsampler that constrains subsamples to be contained within a given image region...
A multi-dimensional iterator templated over image type that walks a region of pixels.
TOutputImage OutputImageType
DisableIfMultiComponent< T, T >::type GetComponent(const T pix, unsigned int) const
A method to generically get a component.
typename InputImageType::RegionType InputImageRegionType
typename NumericTraits< PixelValueType >::RealType RealValueType
void SetComponent(T &pix, unsigned int idx, typename EnableIfMultiComponent< T, RealValueType >::type val) const
Control indentation during Print() invocation.
Definition: itkIndent.h:49
typename ListAdaptorType::NeighborhoodRadiusType PatchRadiusType
void ComputeDifferenceAndWeightedSquaredNorm(const DiffusionTensor3D< PixelValueType > &a, const DiffusionTensor3D< PixelValueType > &b, const RealArrayType &weight, bool useCachedComputations, SizeValueType cacheIndex, EigenValuesCacheType &eigenValsCache, EigenVectorsCacheType &eigenVecsCache, RealType &diff, RealArrayType &norm)
Represent a diffusion tensor as used in DTI images.
std::vector< EigenVectorsMatrixType > EigenVectorsCacheType
Templated n-dimensional image class.
Definition: itkImage.h:75
A multi-dimensional iterator templated over image type that walks a region of pixels.
RealType AddUpdate(const RealT &a, const RealType &b)
typename BaseSamplerType::InstanceIdentifier InstanceIdentifier