Skip to content

Commit 59418aa

Browse files
committed
ENH: Add VkMultiResolutionPyramidImageFilter
Adds image filter for image pyramid generation making selective use of VkFFT acceleration for FFT-based blurring. Also adds factory override class so that `VkMultiResolutionPyramidImageFilter` can be used as the default implementation of `MultiResolutionPyramidImageFilter` per the ITK object factory.
1 parent bce0b1c commit 59418aa

14 files changed

Lines changed: 790 additions & 3 deletions
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
/*=========================================================================
2+
*
3+
* Copyright NumFOCUS
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 itkVkMultiResolutionPyramidImageFilter_h
19+
#define itkVkMultiResolutionPyramidImageFilter_h
20+
21+
#include "itkMultiResolutionPyramidImageFilter.h"
22+
23+
#include "itkDiscreteGaussianImageFilter.h"
24+
#include "itkFFTDiscreteGaussianImageFilter.h"
25+
#include "itkVector.h"
26+
#include "itkMacro.h"
27+
#include "VkFFTBackendExport.h"
28+
29+
#include <string>
30+
31+
namespace itk
32+
{
33+
34+
/** \class VkMultiResolutionPyramidImageFilter
35+
* \brief Creates a multi-resolution pyramid with FFT acceleration
36+
*
37+
* VkMultiResolutionPyramidImageFilter re-implements a framework
38+
* for creating an image pyramid as laid out in
39+
* MultiResolutionPyramidImageFilter. Conditional logic is added
40+
* to preemptively select the optimal image smoothing pipeline
41+
* that is expected to give the best performance for different
42+
* pyramid levels.
43+
*
44+
* Separable spatial convolution with DiscreteGaussianImageFilter
45+
* runs quickly for small kernel sizes but scales poorly with
46+
* increasing kernel size. By contrast ITK FFT convolution accelerated
47+
* with a VkFFT GPU backend scales slowly with increasing kernel size
48+
* but is typically outperformed by spatial convolution filters
49+
* for small kernel sizes.
50+
*
51+
* VkMultiResolutionPyramidImageFilter allows the user to fix the
52+
* metric threshold at which a performance tradeoff is expected
53+
* between spatial and FFT convolution. The exact threshold depends
54+
* on user hardware and can be estimated through benchmarking with
55+
* scripts in the ITKVkFFTBackend repository.
56+
*
57+
* By mitigating blurring times on levels with large kernel sizes
58+
* VkMultiResolutionPyramidImageFilter has been observed to run in
59+
* as little as 50% of the time of its base class.
60+
*
61+
* See documentation of MultiResolutionPyramidImageFilter
62+
* for information on how to specify a multi-resolution schedule.
63+
*
64+
* \sa MultiResolutionPyramidImageFilter
65+
* \sa DiscreteGaussianImageFilter
66+
* \sa FFTDiscreteGaussianImageFilter
67+
* \sa ShrinkImageFilter
68+
*
69+
* \ingroup VkFFTBackend
70+
* \ingroup PyramidImageFilter
71+
* \ingroup ITKRegistrationCommon
72+
*/
73+
template <typename TInputImage, typename TOutputImage>
74+
class ITK_TEMPLATE_EXPORT VkMultiResolutionPyramidImageFilter
75+
: public MultiResolutionPyramidImageFilter<TInputImage, TOutputImage>
76+
{
77+
public:
78+
ITK_DISALLOW_COPY_AND_MOVE(VkMultiResolutionPyramidImageFilter);
79+
80+
/** Standard class type aliases. */
81+
using Self = VkMultiResolutionPyramidImageFilter;
82+
using Superclass = MultiResolutionPyramidImageFilter<TInputImage, TOutputImage>;
83+
using Pointer = SmartPointer<Self>;
84+
using ConstPointer = SmartPointer<const Self>;
85+
86+
/** Method for creation through the object factory. */
87+
itkNewMacro(Self);
88+
89+
/** Run-time type information (and related methods). */
90+
itkTypeMacro(VkMultiResolutionPyramidImageFilter, MultiResolutionPyramidImageFilter);
91+
92+
/** ImageDimension enumeration. */
93+
static constexpr unsigned int ImageDimension = TInputImage::ImageDimension;
94+
95+
/** Inherit types from Superclass. */
96+
using typename Superclass::InputImageType;
97+
using typename Superclass::OutputImageType;
98+
using typename Superclass::InputImagePointer;
99+
using typename Superclass::OutputImagePointer;
100+
using typename Superclass::InputImageConstPointer;
101+
using InputSizeType = typename InputImageType::SizeType;
102+
using OutputPixelType = typename OutputImageType::PixelType;
103+
using OutputSizeType = typename OutputImageType::SizeType;
104+
using typename Superclass::ScheduleType;
105+
106+
using VarianceType = itk::Vector<double, ImageDimension>;
107+
using KernelSizeType = OutputSizeType;
108+
109+
/** Types for acceleration.
110+
* Assumes and does not verify that FFT backend is accelerated. */
111+
using BaseSmootherType = DiscreteGaussianImageFilter<OutputImageType, OutputImageType>;
112+
using SpatialSmootherType = DiscreteGaussianImageFilter<OutputImageType, OutputImageType>;
113+
using FFTSmootherType = FFTDiscreteGaussianImageFilter<OutputImageType, OutputImageType>;
114+
115+
/** Set the metric threshold to decide between
116+
* accelerated methods such as CPU-based separable smoothing
117+
* versus GPU-based FFT smoothing.
118+
* We can predictively compare spatial and FFT smoothing
119+
* performance using the following metric:
120+
*
121+
* f(i,j,k,x,y,z) = log((i + j + k) * x * y * z)
122+
*
123+
* where i,j,k are the dimensions of the kernel for a given
124+
* pyramid level and x,y,z are the dimensions of the
125+
* output image region.
126+
*
127+
* The equation above approximates the difference in runtime complexity
128+
* between separable spatial Gaussian smoothing and FFT Gaussian smoothing.
129+
* Under separable smoothing each pixel [xi,yi,zi] is used in computation
130+
* approximately (i + j + k) times. FFT smoothing meanwhile has significant
131+
* overhead in setup but scales much more slowly with kernel and image sizes.
132+
* As a result there is an approximate threshold where GPU-accelerated
133+
* smoothing outperforms spatial smoothing for a given pyramid level.
134+
*
135+
* The default threshold value 8.0 has been empirically determined as
136+
* a reasonable approximation such that f(...) < 8.0 indicates that
137+
* spatial convolution will run faster while f(...) > 8.0 indicates that
138+
* FFT convolution will run faster. The threshold value is not universal
139+
* and may need to be adjusted to better match benchmarking results for
140+
* particular hardware and expected image sizes so that nuances such as
141+
* multithreading and GPU performance may be taken into account.
142+
*/
143+
itkSetMacro(MetricThreshold, float);
144+
itkGetMacro(MetricThreshold, float);
145+
146+
/** Set the metric threshold from a certain parameter set describing the input size
147+
* and kernel radius threshold that is expected to be equally fast with separable
148+
* spatial smoothing and FFT smoothing */
149+
void
150+
SetMetricThreshold(const InputSizeType & inputSize, const KernelSizeType & kernelRadius)
151+
{
152+
this->SetMetricThreshold(ComputeMetricValue(inputSize, kernelRadius));
153+
}
154+
155+
float
156+
ComputeMetricValue(const InputSizeType & inputSize, const KernelSizeType & kernelRadius) const;
157+
158+
/** Estimate the kernel radius from ilevel settings */
159+
KernelSizeType
160+
GetKernelRadius(unsigned int ilevel) const;
161+
162+
/** Get the kernel variance for the given pyramid level
163+
* based on the current schedule */
164+
VarianceType
165+
GetVariance(unsigned int ilevel) const;
166+
167+
/** Get whether FFT smoothing will be used for the given
168+
* pyramid level */
169+
bool
170+
GetUseFFT(const KernelSizeType & kernelRadius) const;
171+
172+
protected:
173+
VkMultiResolutionPyramidImageFilter() = default;
174+
~VkMultiResolutionPyramidImageFilter() override = default;
175+
176+
/** Generate the output data. */
177+
void
178+
GenerateData() override;
179+
180+
void
181+
PrintSelf(std::ostream & os, Indent indent) const override;
182+
183+
private:
184+
float m_MetricThreshold = 8.0f;
185+
typename SpatialSmootherType::Pointer spatialSmoother = SpatialSmootherType::New();
186+
typename FFTSmootherType::Pointer fftSmoother = FFTSmootherType::New();
187+
188+
};
189+
} // namespace itk
190+
191+
#ifndef ITK_MANUAL_INSTANTIATION
192+
# include "itkVkMultiResolutionPyramidImageFilter.hxx"
193+
#endif
194+
195+
#endif

0 commit comments

Comments
 (0)