ITK  5.0.0
Insight Segmentation and Registration Toolkit
itkVectorGradientMagnitudeImageFilter.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 itkVectorGradientMagnitudeImageFilter_h
19 #define itkVectorGradientMagnitudeImageFilter_h
20 
22 #include "itkImageToImageFilter.h"
23 #include "itkImage.h"
24 #include "itkVector.h"
25 #include "vnl/vnl_matrix.h"
26 #include "vnl/vnl_vector_fixed.h"
27 #include "vnl/algo/vnl_symmetric_eigensystem.h"
28 #include "itkMath.h"
29 
30 namespace itk
31 {
133 template< typename TInputImage,
134  typename TRealType = float,
135  typename TOutputImage = Image< TRealType,
136  TInputImage::ImageDimension >
137  >
138 class ITK_TEMPLATE_EXPORT VectorGradientMagnitudeImageFilter:
139  public ImageToImageFilter< TInputImage, TOutputImage >
140 {
141 public:
142  ITK_DISALLOW_COPY_AND_ASSIGN(VectorGradientMagnitudeImageFilter);
143 
149 
151  itkNewMacro(Self);
152 
155 
158  using OutputPixelType = typename TOutputImage::PixelType;
159  using InputPixelType = typename TInputImage::PixelType;
160 
162  using InputImageType = TInputImage;
163  using OutputImageType = TOutputImage;
164  using InputImagePointer = typename InputImageType::Pointer;
165  using OutputImagePointer = typename OutputImageType::Pointer;
166 
168  static constexpr unsigned int ImageDimension = TOutputImage::ImageDimension;
169 
171  static constexpr unsigned int VectorDimension = InputPixelType::Dimension;
172 
174  using RealType = TRealType;
175  using RealVectorType =
177  using RealVectorImageType =
179 
184 
186  using OutputImageRegionType = typename Superclass::OutputImageRegionType;
187 
196  void GenerateInputRequestedRegion() override;
197 
203  { this->SetUseImageSpacing(true); }
204 
209  { this->SetUseImageSpacing(false); }
210 
213  void SetUseImageSpacing(bool);
214 
215  itkGetConstMacro(UseImageSpacing, bool);
216 
218 
221  itkSetMacro(DerivativeWeights, WeightsType);
222  itkGetConstReferenceMacro(DerivativeWeights, WeightsType);
224 
227  itkSetMacro(ComponentWeights, WeightsType);
228  itkGetConstReferenceMacro(ComponentWeights, WeightsType);
230 
236  itkSetMacro(UsePrincipleComponents, bool);
237  itkGetConstMacro(UsePrincipleComponents, bool);
239  {
240  this->SetUsePrincipleComponents(true);
241  }
243 
245  {
246  this->SetUsePrincipleComponents(false);
247  }
248 
251  static int CubicSolver(double *, double *);
252 
253 #ifdef ITK_USE_CONCEPT_CHECKING
254  // Begin concept checking
255  itkConceptMacro( InputHasNumericTraitsCheck,
257  itkConceptMacro( RealTypeHasNumericTraitsCheck,
259  // End concept checking
260 #endif
261 
262 protected:
264  ~VectorGradientMagnitudeImageFilter() override = default;
265 
269  void BeforeThreadedGenerateData() override;
270 
282  void DynamicThreadedGenerateData(const OutputImageRegionType & outputRegionForThread) override;
283 
284 
285  void PrintSelf(std::ostream & os, Indent indent) const override;
286 
287  using ImageBaseType = typename InputImageType::Superclass;
288 
290  itkGetConstObjectMacro(RealValuedInputImage, ImageBaseType);
291 
293  {
294  unsigned i, j;
295  TRealType dx, sum, accum;
296 
298  for ( i = 0; i < ImageDimension; ++i )
299  {
301  for ( j = 0; j < VectorDimension; ++j )
302  {
303  dx = m_DerivativeWeights[i] * m_SqrtComponentWeights[j]
304  * 0.5 * ( it.GetNext(i)[j] - it.GetPrevious(i)[j] );
305  sum += dx * dx;
306  }
307  accum += sum;
308  }
309  return std::sqrt(accum);
310  }
311 
313  {
314  // WARNING: ONLY CALL THIS METHOD WHEN PROCESSING A 3D IMAGE
315  unsigned int i, j;
316  double Lambda[3];
317  double CharEqn[3];
318  double ans;
319 
320  vnl_matrix< TRealType > g(ImageDimension, ImageDimension);
321  vnl_vector_fixed< TRealType, VectorDimension >
322  d_phi_du[TInputImage::ImageDimension];
323 
324  // Calculate the directional derivatives for each vector component using
325  // central differences.
326  for ( i = 0; i < ImageDimension; i++ )
327  {
328  for ( j = 0; j < VectorDimension; j++ )
329  {
330  d_phi_du[i][j] = m_DerivativeWeights[i] * m_SqrtComponentWeights[j]
331  * 0.5 * ( it.GetNext(i)[j] - it.GetPrevious(i)[j] );
332  }
333  }
334 
335  // Calculate the symmetric metric tensor g
336  for ( i = 0; i < ImageDimension; i++ )
337  {
338  for ( j = i; j < ImageDimension; j++ )
339  {
340  g[j][i] = g[i][j] = dot_product(d_phi_du[i], d_phi_du[j]);
341  }
342  }
343 
344  // Find the coefficients of the characteristic equation det(g - lambda I)=0
345  // CharEqn[3] = 1.0;
346 
347  CharEqn[2] = -( g[0][0] + g[1][1] + g[2][2] );
348 
349  CharEqn[1] = ( g[0][0] * g[1][1] + g[0][0] * g[2][2] + g[1][1] * g[2][2] )
350  - ( g[0][1] * g[1][0] + g[0][2] * g[2][0] + g[1][2] * g[2][1] );
351 
352  CharEqn[0] = g[0][0] * ( g[1][2] * g[2][1] - g[1][1] * g[2][2] )
353  + g[1][0] * ( g[2][2] * g[0][1] - g[0][2] * g[2][1] )
354  + g[2][0] * ( g[1][1] * g[0][2] - g[0][1] * g[1][2] );
355 
356  // Find the eigenvalues of g
357  int numberOfDistinctRoots = this->CubicSolver(CharEqn, Lambda);
358 
359  // Define gradient magnitude as the difference between two largest
360  // eigenvalues. Other definitions may be appropriate here as well.
361  if ( numberOfDistinctRoots == 3 ) // By far the most common case
362  {
363  if ( Lambda[0] > Lambda[1] )
364  {
365  if ( Lambda[1] > Lambda[2] ) // Most common, guaranteed?
366  {
367  ans = Lambda[0] - Lambda[1];
368  }
369  else
370  {
371  if ( Lambda[0] > Lambda[2] )
372  {
373  ans = Lambda[0] - Lambda[2];
374  }
375  else
376  {
377  ans = Lambda[2] - Lambda[0];
378  }
379  }
380  }
381  else
382  {
383  if ( Lambda[0] > Lambda[2] )
384  {
385  ans = Lambda[1] - Lambda[0];
386  }
387  else
388  {
389  if ( Lambda[1] > Lambda[2] )
390  {
391  ans = Lambda[1] - Lambda[2];
392  }
393  else
394  {
395  ans = Lambda[2] - Lambda[1];
396  }
397  }
398  }
399  }
400  else if ( numberOfDistinctRoots == 2 )
401  {
402  if ( Lambda[0] > Lambda[1] )
403  {
404  ans = Lambda[0] - Lambda[1];
405  }
406  else
407  {
408  ans = Lambda[1] - Lambda[0];
409  }
410  }
411  else if ( numberOfDistinctRoots == 1 )
412  {
413  ans = 0.0;
414  }
415  else
416  {
417  itkExceptionMacro(<< "Undefined condition. Cubic root solver returned "
418  << numberOfDistinctRoots << " distinct roots.");
419  }
420 
421  return ans;
422  }
423 
424  // Function is defined here because the templating confuses gcc 2.96 when
425  // defined
426  // in .hxx file. jc 1/29/03
428  {
429  unsigned int i, j;
430 
431  vnl_matrix< TRealType > g(ImageDimension, ImageDimension);
432  vnl_vector_fixed< TRealType, VectorDimension >
433  d_phi_du[TInputImage::ImageDimension];
434 
435  // Calculate the directional derivatives for each vector component using
436  // central differences.
437  for ( i = 0; i < ImageDimension; i++ )
438  {
439  for ( j = 0; j < VectorDimension; j++ )
440  {
441  d_phi_du[i][j] = m_DerivativeWeights[i] * m_SqrtComponentWeights[j]
442  * 0.5 * ( it.GetNext(i)[j] - it.GetPrevious(i)[j] );
443  }
444  }
445 
446  // Calculate the symmetric metric tensor g
447  for ( i = 0; i < ImageDimension; i++ )
448  {
449  for ( j = i; j < ImageDimension; j++ )
450  {
451  g[j][i] = g[i][j] = dot_product(d_phi_du[i], d_phi_du[j]);
452  }
453  }
454 
455  // Find the eigenvalues of g
456  vnl_symmetric_eigensystem< TRealType > E(g);
457 
458  // Return the difference in length between the first two principle axes.
459  // Note that other edge strength metrics may be appropriate here instead..
460  return ( E.get_eigenvalue(ImageDimension - 1) - E.get_eigenvalue(ImageDimension - 2) );
461  }
462 
465 
471 
472 private:
475 
477 
478  typename ImageBaseType::ConstPointer m_RealValuedInputImage;
479 
480 };
481 } // end namespace itk
482 
483 #ifndef ITK_MANUAL_INSTANTIATION
484 #include "itkVectorGradientMagnitudeImageFilter.hxx"
485 #endif
486 
487 #endif
typename OutputImageType::Pointer OutputImagePointer
Define numeric traits for std::vector.
TRealType EvaluateAtNeighborhood3D(const ConstNeighborhoodIteratorType &it) const
The base class for all process objects (source, filters, mappers) in the Insight data processing pipe...
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 ConstNeighborhoodIteratorType::RadiusType RadiusType
Computes a scalar, gradient magnitude image from a multiple channel (pixels are vectors) input...
ITK_ITERATOR_VIRTUAL PixelType GetPrevious(const unsigned axis, NeighborIndexType i) const ITK_ITERATOR_FINAL
typename InputImageType::Pointer InputImagePointer
A templated class holding a n-Dimensional vector.
Definition: itkVector.h:62
typename OutputImageType::RegionType OutputImageRegionType
TOutputImage OutputImageType
TRealType NonPCEvaluateAtNeighborhood(const ConstNeighborhoodIteratorType &it) const
unsigned int ThreadIdType
Definition: itkIntTypes.h:99
Base class for filters that take an image as input and produce an image as output.
ITK_ITERATOR_VIRTUAL PixelType GetNext(const unsigned axis, NeighborIndexType i) const ITK_ITERATOR_FINAL
Control indentation during Print() invocation.
Definition: itkIndent.h:49
typename Superclass::RadiusType RadiusType
#define itkConceptMacro(name, concept)
Templated n-dimensional image class.
Definition: itkImage.h:75
TRealType EvaluateAtNeighborhood(const ConstNeighborhoodIteratorType &it) const