Skip to content

Commit

Permalink
ENH: Add kernel helper methods to itk::DiscreteGaussianImageFilter
Browse files Browse the repository at this point in the history
Exposes methods in `itk::DiscreteGaussianImageFilter` public interface
for getting details on the separable Gaussian kernel to be used in
smoothing. This is useful for handling cases such as image padding and
overlap for convolution.
  • Loading branch information
tbirdso authored and hjmjohnson committed May 11, 2022
1 parent f222a5e commit 74d01fa
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -193,19 +193,24 @@ class ITK_TEMPLATE_EXPORT DiscreteGaussianImageFilter : public ImageToImageFilte
}

/** Set the standard deviation of the Gaussian used for smoothing.
* Sigma is measured in the units of image spacing. You may use the method
* SetSigma to set the same value across each axis or use the method
* SetSigmaArray if you need different values along each axis. */
* Sigma is measured in the units of image spacing. */
void
SetSigmaArray(const ArrayType & sigmas)
SetSigma(const ArrayType & sigma)
{
ArrayType variance;
for (unsigned int i = 0; i < ImageDimension; ++i)
{
variance[i] = sigmas[i] * sigmas[i];
variance[i] = sigma[i] * sigma[i];
}
this->SetVariance(variance);
}
/** SetSigmaArray is preserved for interface
* backwards compatibility. */
void
SetSigmaArray(const ArrayType & sigmas)
{
this->SetSigma(sigmas);
}
void
SetSigma(double sigma)
{
Expand Down Expand Up @@ -256,6 +261,19 @@ class ITK_TEMPLATE_EXPORT DiscreteGaussianImageFilter : public ImageToImageFilte
this->SetMaximumError(dv);
}

/** Get the radius of the generated directional kernel */
unsigned int
GetKernelRadius(const unsigned int dimension) const;

/** Get the radius of the separable kernel in each direction */
ArrayType
GetKernelRadius() const;

/** Get the size of the separable kernel in each direction.
* size[i] = radius[i] * 2 + 1 */
ArrayType
GetKernelSize() const;

/** Set/Get whether or not the filter will use the spacing of the input
* image in its calculations. Use On to take the image spacing information
* into account and to specify the Gaussian variance in real world units;
Expand Down Expand Up @@ -343,10 +361,6 @@ class ITK_TEMPLATE_EXPORT DiscreteGaussianImageFilter : public ImageToImageFilte
void
GenerateKernel(const unsigned int dimension, KernelType & oper) const;

/** Get the radius of the generated directional kernel */
unsigned int
GetKernelRadius(const unsigned int dimension) const;

/** Get the variance, optionally adjusted for pixel spacing */
ArrayType
GetKernelVarianceArray() const;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,31 @@ DiscreteGaussianImageFilter<TInputImage, TOutputImage>::GetKernelRadius(const un
return oper.GetRadius(dimension);
}

template <typename TInputImage, typename TOutputImage>
auto
DiscreteGaussianImageFilter<TInputImage, TOutputImage>::GetKernelRadius() const -> ArrayType
{
ArrayType kernelRadius;
for (unsigned int dim = 0; dim < ImageDimension; ++dim)
{
kernelRadius[dim] = this->GetKernelRadius(dim);
}
return kernelRadius;
}


template <typename TInputImage, typename TOutputImage>
auto
DiscreteGaussianImageFilter<TInputImage, TOutputImage>::GetKernelSize() const -> ArrayType
{
ArrayType kernelSize;
for (unsigned int dim = 0; dim < ImageDimension; ++dim)
{
kernelSize[dim] = this->GetKernelRadius(dim) * 2 + 1;
}
return kernelSize;
}

template <typename TInputImage, typename TOutputImage>
typename DiscreteGaussianImageFilter<TInputImage, TOutputImage>::ArrayType
DiscreteGaussianImageFilter<TInputImage, TOutputImage>::GetKernelVarianceArray() const
Expand All @@ -59,7 +84,7 @@ DiscreteGaussianImageFilter<TInputImage, TOutputImage>::GetKernelVarianceArray()
{
if (this->GetInput() == nullptr)
{
itkExceptionMacro("UseImageSpacing is ON but no input image was provided");
itkExceptionMacro("Could not get kernel variance! UseImageSpacing is ON but no input image was provided");
}

ArrayType adjustedVariance;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ itkDiscreteGaussianImageFilterTest(int argc, char * argv[])
filter->SetSigma(sigmaValue);
ITK_TEST_SET_GET_VALUE(sigmaValue, filter->GetSigma());

filter->SetSigma(sigma);
ITK_TEST_SET_GET_VALUE(sigma, filter->GetSigmaArray());

filter->SetSigmaArray(sigma);
ITK_TEST_SET_GET_VALUE(sigma, filter->GetSigmaArray());

Expand Down Expand Up @@ -101,6 +104,25 @@ itkDiscreteGaussianImageFilterTest(int argc, char * argv[])
filter->SetFilterDimensionality(Dimension);
ITK_TEST_SET_GET_VALUE(Dimension, filter->GetFilterDimensionality());

// Verify kernel radius matches expectations for test parameters
filter->SetUseImageSpacingOff();
constexpr unsigned int EXPECTED_RADIUS = 3;
auto radius = filter->GetKernelRadius();
auto kernelSize = filter->GetKernelSize();
for (unsigned int idx = 0; idx < Dimension; ++idx)
{
ITK_TEST_EXPECT_EQUAL(radius[idx], EXPECTED_RADIUS);
ITK_TEST_EXPECT_EQUAL(filter->GetKernelRadius(idx), EXPECTED_RADIUS);
ITK_TEST_EXPECT_EQUAL(kernelSize[idx], EXPECTED_RADIUS * 2 + 1);
}

// Verify filter throws exception when trying to get kernel information
// if UseImageSpacing is ON and an input image is not set
filter->SetUseImageSpacingOn();
ITK_TRY_EXPECT_EXCEPTION(filter->GetKernelRadius());
ITK_TRY_EXPECT_EXCEPTION(filter->GetKernelRadius(0));
ITK_TRY_EXPECT_EXCEPTION(filter->GetKernelSize());

auto useImageSpacing = static_cast<bool>(std::stoi(argv[1]));
#if !defined(ITK_FUTURE_LEGACY_REMOVE)
if (useImageSpacing)
Expand Down

0 comments on commit 74d01fa

Please sign in to comment.