File: itkImageGridSampler.h

package info (click to toggle)
elastix 5.2.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 42,480 kB
  • sloc: cpp: 68,403; lisp: 4,118; python: 1,013; xml: 182; sh: 177; makefile: 33
file content (259 lines) | stat: -rw-r--r-- 9,361 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
/*=========================================================================
 *
 *  Copyright UMC Utrecht and contributors
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0.txt
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *=========================================================================*/
#ifndef itkImageGridSampler_h
#define itkImageGridSampler_h

#include "itkImageSamplerBase.h"
#include "elxMaskHasSameImageDomain.h"

namespace itk
{

/** \class ImageGridSampler
 *
 * \brief Samples image voxels on a regular grid.
 *
 * This ImageSampler samples voxels that lie on a regular grid.
 * The grid can be specified by an integer downsampling factor for
 * each dimension.
 *
 * \parameter SampleGridSpacing: This parameter controls the spacing
 *    of the uniform grid in all dimensions. This should be given in
 *    index coordinates. \n
 *    example: <tt>(SampleGridSpacing 4 4 4)</tt> \n
 *    Default is 2 in each dimension.
 *
 * \ingroup ImageSamplers
 */

template <class TInputImage>
class ITK_TEMPLATE_EXPORT ImageGridSampler : public ImageSamplerBase<TInputImage>
{
public:
  ITK_DISALLOW_COPY_AND_MOVE(ImageGridSampler);

  /** Standard ITK-stuff. */
  using Self = ImageGridSampler;
  using Superclass = ImageSamplerBase<TInputImage>;
  using Pointer = SmartPointer<Self>;
  using ConstPointer = SmartPointer<const Self>;

  /** Method for creation through the object factory. */
  itkNewMacro(Self);

  /** Run-time type information (and related methods). */
  itkTypeMacro(ImageGridSampler, ImageSamplerBase);

  /** Typedefs inherited from the superclass. */
  using typename Superclass::DataObjectPointer;
  using typename Superclass::OutputVectorContainerType;
  using typename Superclass::OutputVectorContainerPointer;
  using typename Superclass::InputImageType;
  using typename Superclass::InputImagePointer;
  using typename Superclass::InputImageConstPointer;
  using typename Superclass::InputImageRegionType;
  using typename Superclass::InputImagePixelType;
  using typename Superclass::ImageSampleType;
  using typename Superclass::ImageSampleContainerType;
  using typename Superclass::ImageSampleContainerPointer;

  // Clang/macos-12/Xcode_14.2 does not like `using typename Superclass::MaskType`, saying "error: 'MaskType' is not a
  // class, namespace, or enumeration"
  using MaskType = typename Superclass::MaskType;

  /** The input image dimension. */
  itkStaticConstMacro(InputImageDimension, unsigned int, Superclass::InputImageDimension);

  /** Other typdefs. */
  using typename Superclass::InputImageIndexType;
  // using typename Superclass::InputImageSpacingType;
  using typename Superclass::InputImagePointType;

  /** Typedefs for support of user defined grid spacing for the spatial samples. */
  using SampleGridSpacingType = typename InputImageType::OffsetType;
  using SampleGridSpacingValueType = typename SampleGridSpacingType::OffsetValueType;
  using SampleGridSizeType = typename InputImageType::SizeType;
  using SampleGridIndexType = InputImageIndexType;
  using InputImageSizeType = typename InputImageType::SizeType;

  /** Set/Get the sample grid spacing for each dimension (only integer factors)
   * This function overrules previous calls to SetNumberOfSamples.
   * Moreover, it calls SetNumberOfSamples(0) (see below), to make sure
   * that the user-set sample grid spacing is never overruled.
   */
  void
  SetSampleGridSpacing(const SampleGridSpacingType & arg);

  itkGetConstReferenceMacro(SampleGridSpacing, SampleGridSpacingType);

  /** Define an isotropic SampleGridSpacing such that the desired number
   * of samples is approximately realized. The following formula is used:
   *
   * spacing = max[ 1, round( (availablevoxels / nrofsamples)^(1/dimension) ) ],
   * with
   * availablevoxels = nr of voxels in bounding box of the mask.
   *
   * The InputImageRegion needs to be specified beforehand.
   * However, the sample grid spacing is recomputed in the update phase, when the
   * bounding box of the mask is known. Supplying nrofsamples=0 turns off the
   * (re)computation of the SampleGridSpacing. Once nrofsamples=0 has been given,
   * the last computed SampleGridSpacing is simply considered as a user parameter,
   * which is not modified automatically anymore.
   *
   * This function overrules any previous calls to SetSampleGridSpacing.
   */
  void
  SetNumberOfSamples(unsigned long nrofsamples) override;

  /** Selecting new samples makes no sense if nothing changed. The same samples would be selected anyway. */
  bool
  SelectNewSamplesOnUpdate() override
  {
    return false;
  }


  /** Returns whether the sampler supports SelectNewSamplesOnUpdate(). */
  bool
  SelectingNewSamplesOnUpdateSupported() const override
  {
    return false;
  }


protected:
  /** The constructor. */
  ImageGridSampler() = default;

  /** The destructor. */
  ~ImageGridSampler() override = default;

  /** PrintSelf. */
  void
  PrintSelf(std::ostream & os, Indent indent) const override;

  /** Function that does the work. */
  void
  GenerateData() override;

private:
  struct WorkUnit
  {
    const SampleGridIndexType GridIndex{};
    const SampleGridSizeType  GridSize{};

    // Should point to the first sample for this specific work unit.
    ImageSampleType * const Samples{};

    // The number of samples retrieved by this work unit. Only used when a mask is specified.
    size_t NumberOfSamples{};
  };

  struct UserData
  {
    ITK_DISALLOW_COPY_AND_MOVE(UserData);

    const InputImageType &      InputImage;
    const MaskType * const      Mask{};
    const SampleGridSpacingType GridSpacing{};
    std::vector<WorkUnit>       WorkUnits{};
  };

  template <elastix::MaskCondition VMaskCondition>
  static ITK_THREAD_RETURN_FUNCTION_CALL_CONVENTION
  ThreaderCallback(void * arg);

  /** Retrieves the sample grid size along the axis, specified by VIndex */
  template <unsigned int VIndex>
  static unsigned int
  GetGridSizeValue(const SampleGridSizeType & gridSize)
  {
    if constexpr (VIndex < InputImageDimension)
    {
      return gridSize[VIndex];
    }
    else
    {
      return 1;
    }
  }

  /** Jumps to the next grid position along the axis, specified by VIndex */
  template <unsigned int VIndex>
  static void
  JumpToNextGridPosition(SampleGridIndexType &         index,
                         const SampleGridIndexType &   gridIndex,
                         const SampleGridSpacingType & gridSpacing)
  {
    static_assert(VIndex > 0);

    if constexpr (VIndex < InputImageDimension)
    {
      index[VIndex - 1] = gridIndex[VIndex - 1];
      index[VIndex] += gridSpacing[VIndex];
    }
  }


  /** Determine the grid. */
  static std::pair<SampleGridIndexType, SampleGridSizeType>
  DetermineGridIndexAndSize(const InputImageRegionType &  croppedInputImageRegion,
                            const SampleGridSpacingType & gridSpacing);

  /** Generates the work units, to be processed when doing multi-threading. */
  static std::vector<WorkUnit>
  GenerateWorkUnits(const ThreadIdType             numberOfWorkUnits,
                    const InputImageRegionType &   croppedInputImageRegion,
                    const SampleGridIndexType      gridIndex,
                    const SampleGridSpacingType    gridSpacing,
                    std::vector<ImageSampleType> & samples);

  static void
  SingleThreadedGenerateData(const TInputImage &            inputImage,
                             const MaskType * const         mask,
                             const InputImageRegionType &   croppedInputImageRegion,
                             const SampleGridSpacingType &  gridSpacing,
                             std::vector<ImageSampleType> & samples);
  static void
  MultiThreadedGenerateData(MultiThreaderBase &            multiThreader,
                            const ThreadIdType             numberOfWorkUnits,
                            const TInputImage &            inputImage,
                            const MaskType * const         mask,
                            const InputImageRegionType &   croppedInputImageRegion,
                            const SampleGridSpacingType &  gridSpacing,
                            std::vector<ImageSampleType> & samples);

  /** Generates the data for one specific work unit. */
  template <elastix::MaskCondition VMaskCondition>
  static void
  GenerateDataForWorkUnit(WorkUnit &, const InputImageType &, const MaskType *, const SampleGridSpacingType &);

  /** An array of integer spacing factors */
  SampleGridSpacingType m_SampleGridSpacing{ itk::MakeFilled<SampleGridSpacingType>(1) };

  /** The number of samples entered in the SetNumberOfSamples method */
  unsigned long m_RequestedNumberOfSamples{ 0 };
};

} // end namespace itk

#ifndef ITK_MANUAL_INSTANTIATION
#  include "itkImageGridSampler.hxx"
#endif

#endif // end #ifndef itkImageGridSampler_h