18 #ifndef itkVectorGradientMagnitudeImageFilter_h
19 #define itkVectorGradientMagnitudeImageFilter_h
25 #include "vnl/vnl_matrix.h"
26 #include "vnl/vnl_vector_fixed.h"
27 #include "vnl/algo/vnl_symmetric_eigensystem.h"
106 * The filter requires an image with at least two dimensions and a vector
107 * length of at least 2. The theory supports extension to scalar
images, but
108 * the implementation of the
itk vector classes
do not
110 * The
template parameter TRealType must be floating
point (
float or
double) or
111 * a user-defined
"real" numerical type with arithmetic operations defined
112 * sufficient to compute derivatives.
115 * This filter will automatically multithread
if run with
117 * mode. Unfortunately the ND eigen solver used is not thread safe (a special
118 * 3D solver is), so it cannot multithread
for data other than 3D in
123 * [1] G. Sapiro and D. Ringach,
"Anisotropic Diffusion of Multivalued Images
124 * with Application to Color Filtering," IEEE Transactions on
Image Processing,
125 *
Vol 5, No. 11
pp. 1582-1586, 1996
127 * \ingroup GradientFilters
133 * \ingroup ITKImageGradient
135 template <
typename TInputImage,
136 typename TRealType = float,
168 static constexpr
unsigned int InputImageDimension = TInputImage::ImageDimension;
169 static constexpr
unsigned int ImageDimension = TOutputImage::ImageDimension;
185 using typename Superclass::OutputImageRegionType;
196 GenerateInputRequestedRegion()
override;
204 SetUseImageSpacing(
bool);
205 itkGetConstMacro(UseImageSpacing,
bool);
206 itkBooleanMacro(UseImageSpacing);
209 #if !defined(ITK_FUTURE_LEGACY_REMOVE)
218 this->SetUseImageSpacing(
true);
228 this->SetUseImageSpacing(
false);
234 #if !defined(ITK_LEGACY_REMOVE)
260 #if !defined(ITK_FUTURE_LEGACY_REMOVE)
265 this->SetUsePrincipleComponents(
true);
272 this->SetUsePrincipleComponents(
false);
279 CubicSolver(
const double *,
double *);
281 #ifdef ITK_USE_CONCEPT_CHECKING
297 BeforeThreadedGenerateData()
override;
311 DynamicThreadedGenerateData(
const OutputImageRegionType & outputRegionForThread)
override;
315 PrintSelf(std::ostream & os,
Indent indent)
const override;
329 auto accum = TRealType{};
330 for (i = 0; i < ImageDimension; ++i)
333 for (j = 0; j < VectorDimension; ++j)
335 dx = m_DerivativeWeights[i] * m_SqrtComponentWeights[j] * 0.5 * (it.
GetNext(i)[j] - it.
GetPrevious(i)[j]);
340 return std::sqrt(accum);
353 vnl_matrix<TRealType> g(ImageDimension, ImageDimension);
354 vnl_vector_fixed<TRealType, VectorDimension> d_phi_du[TInputImage::ImageDimension];
358 for (i = 0; i < ImageDimension; ++i)
360 for (j = 0; j < VectorDimension; ++j)
363 m_DerivativeWeights[i] * m_SqrtComponentWeights[j] * 0.5 * (it.
GetNext(i)[j] - it.
GetPrevious(i)[j]);
368 for (i = 0; i < ImageDimension; ++i)
370 for (j = i; j < ImageDimension; ++j)
372 g[j][i] = g[i][j] = dot_product(d_phi_du[i], d_phi_du[j]);
379 CharEqn[2] = -(g[0][0] + g[1][1] + g[2][2]);
381 CharEqn[1] = (g[0][0] * g[1][1] + g[0][0] * g[2][2] + g[1][1] * g[2][2]) -
382 (g[0][1] * g[1][0] + g[0][2] * g[2][0] + g[1][2] * g[2][1]);
384 CharEqn[0] = g[0][0] * (g[1][2] * g[2][1] - g[1][1] * g[2][2]) + g[1][0] * (g[2][2] * g[0][1] - g[0][2] * g[2][1]) +
385 g[2][0] * (g[1][1] * g[0][2] - g[0][1] * g[1][2]);
388 const int numberOfDistinctRoots = this->CubicSolver(CharEqn, Lambda);
392 if (numberOfDistinctRoots == 3)
394 if (Lambda[0] > Lambda[1])
396 if (Lambda[1] > Lambda[2])
398 ans = Lambda[0] - Lambda[1];
402 if (Lambda[0] > Lambda[2])
404 ans = Lambda[0] - Lambda[2];
408 ans = Lambda[2] - Lambda[0];
414 if (Lambda[0] > Lambda[2])
416 ans = Lambda[1] - Lambda[0];
420 if (Lambda[1] > Lambda[2])
422 ans = Lambda[1] - Lambda[2];
426 ans = Lambda[2] - Lambda[1];
431 else if (numberOfDistinctRoots == 2)
433 if (Lambda[0] > Lambda[1])
435 ans = Lambda[0] - Lambda[1];
439 ans = Lambda[1] - Lambda[0];
442 else if (numberOfDistinctRoots == 1)
448 itkExceptionMacro(
"Undefined condition. Cubic root solver returned " << numberOfDistinctRoots
449 <<
" distinct roots.");
464 vnl_matrix<TRealType> g(ImageDimension, ImageDimension);
465 vnl_vector_fixed<TRealType, VectorDimension> d_phi_du[TInputImage::ImageDimension];
469 for (i = 0; i < ImageDimension; ++i)
471 for (j = 0; j < VectorDimension; ++j)
474 m_DerivativeWeights[i] * m_SqrtComponentWeights[j] * 0.5 * (it.
GetNext(i)[j] - it.
GetPrevious(i)[j]);
479 for (i = 0; i < ImageDimension; ++i)
481 for (j = i; j < ImageDimension; ++j)
483 g[j][i] = g[i][j] = dot_product(d_phi_du[i], d_phi_du[j]);
488 const vnl_symmetric_eigensystem<TRealType> E(g);
492 return (E.get_eigenvalue(ImageDimension - 1) - E.get_eigenvalue(ImageDimension - 2));
506 bool m_UseImageSpacing{
true };
507 bool m_UsePrincipleComponents{};
515 #ifndef ITK_MANUAL_INSTANTIATION
516 # include "itkVectorGradientMagnitudeImageFilter.hxx"