UnaryVoxelFunction.h
1 /*
2  * Medical Image Registration ToolKit (MIRTK)
3  *
4  * Copyright 2013-2015 Imperial College London
5  * Copyright 2013-2015 Andreas Schuh
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 
20 #ifndef MIRTK_UnaryVoxelFunction_H
21 #define MIRTK_UnaryVoxelFunction_H
22 
23 #include "mirtk/VoxelFunction.h"
24 
25 #include "mirtk/Assert.h"
26 #include "mirtk/Voxel.h"
27 #include "mirtk/VoxelCast.h"
28 #include "mirtk/BaseImage.h"
29 #include "mirtk/GenericImage.h"
30 #include "mirtk/Math.h"
31 
32 
33 namespace mirtk {
34 
35 
36 // Forward declaration
37 class InterpolateImageFunction;
38 
39 
40 /**
41  * These basic unary voxel functions can be used as VoxelFunc template parameter
42  * of the unary ForEachVoxel function templates as follows:
43  *
44  * \code
45  * GreyImage image(attr);
46  * // Clamp intensities such that they are in the range [0, 255]
47  * UnaryVoxelFunction::Clamp clamp(0, 255);
48  * ForEachVoxel(image, clamp);
49  * // Determine intensity range of grayscale image
50  * UnaryVoxelFunction::GetMinMax minmax;
51  * ParallelForEachVoxel(image, minmax);
52  * double min = minmax.GetMinAsDouble();
53  * double max = minmax.GetMaxAsDouble();
54  * \endcode
55  */
56 namespace UnaryVoxelFunction {
57 
58 
59 // =============================================================================
60 // Minimum/maximum
61 // =============================================================================
62 
63 // -----------------------------------------------------------------------------
64 /**
65  * Finds the minimum intensity in an image
66  */
67 struct GetMin : public VoxelReduction
68 {
69  void Reset() { _Min = voxel_limits<double>::max(); }
70 
71  GetMin() { Reset(); }
72  GetMin(const GetMin &o) : _Min(o._Min) {}
73 
74  void split(const GetMin &rhs) { _Min = rhs._Min; }
75  void join (const GetMin &rhs) { if (rhs._Min < _Min) _Min = rhs._Min; }
76 
77  template <class TImage, class T>
78  void operator ()(const TImage&, int, const T *p)
79  {
80  if (static_cast<double>(*p) < _Min) _Min = static_cast<double>(*p);
81  }
82 
83  template <class T>
84  void operator ()(int, int, int, int, const T *p)
85  {
86  if (static_cast<double>(*p) < _Min) _Min = static_cast<double>(*p);
87  }
88 
89  double GetMinAsDouble() const
90  {
91  if (_Min == voxel_limits<double>::max()) {
92  return numeric_limits<double>::quiet_NaN();
93  }
94  return _Min;
95  }
96 
97 protected:
98  double _Min;
99 };
100 
101 // -----------------------------------------------------------------------------
102 /**
103  * Finds the maximum intensity in an image
104  */
105 struct GetMax : public VoxelReduction
106 {
107  void Reset() { _Max = voxel_limits<double>::min(); }
108 
109  GetMax() { Reset(); }
110  GetMax(const GetMax &o) : _Max(o._Max) {}
111 
112  void split(const GetMax &rhs) { _Max = rhs._Max; }
113  void join (const GetMax &rhs) { if (rhs._Max < _Max) _Max = rhs._Max; }
114 
115  template <class TImage, class T>
116  void operator ()(const TImage&, int, const T *p)
117  {
118  if (static_cast<double>(*p) > _Max) _Max = static_cast<double>(*p);
119  }
120 
121  template <class T>
122  void operator ()(int, int, int, int, const T *p)
123  {
124  if (static_cast<double>(*p) > _Max) _Max = static_cast<double>(*p);
125  }
126 
127  double GetMaxAsDouble() const
128  {
129  if (_Max == voxel_limits<double>::min()) {
130  return numeric_limits<double>::quiet_NaN();
131  }
132  return _Max;
133  }
134 
135 protected:
136  double _Max;
137 };
138 
139 // -----------------------------------------------------------------------------
140 /**
141  * Finds the minimum and maximum intensities in an image
142  */
143 struct GetMinMax : public VoxelReduction
144 {
145  void Reset()
146  {
147  _Min = voxel_limits<double>::max();
148  _Max = voxel_limits<double>::min();
149  }
150 
151  GetMinMax() { Reset(); }
152  GetMinMax(const GetMinMax &o) : _Min(o._Min), _Max(o._Max) {}
153 
154  void split(const GetMinMax &rhs)
155  {
156  _Min = rhs._Min;
157  _Max = rhs._Max;
158  }
159 
160  void join(const GetMinMax &rhs)
161  {
162  if (rhs._Min < _Min) _Min = rhs._Min;
163  if (rhs._Max > _Max) _Max = rhs._Max;
164  }
165 
166  template <class TImage, class T>
167  void operator ()(const TImage&, int, const T *p)
168  {
169  if (static_cast<double>(*p) < _Min) _Min = static_cast<double>(*p);
170  if (static_cast<double>(*p) > _Max) _Max = static_cast<double>(*p);
171  }
172 
173  template <class T>
174  void operator ()(int, int, int, int, const T *p)
175  {
176  if (static_cast<double>(*p) < _Min) _Min = static_cast<double>(*p);
177  if (static_cast<double>(*p) > _Max) _Max = static_cast<double>(*p);
178  }
179 
180  double GetMinAsDouble() const
181  {
182  if (_Min == voxel_limits<double>::max()) {
183  return numeric_limits<double>::quiet_NaN();
184  }
185  return _Min;
186  }
187 
188  double GetMaxAsDouble() const
189  {
190  if (_Max == voxel_limits<double>::min()) {
191  return numeric_limits<double>::quiet_NaN();
192  }
193  return _Max;
194  }
195 
196 protected:
197  double _Min, _Max;
198 };
199 
200 // =============================================================================
201 // Thresholding
202 // =============================================================================
203 
204 // -----------------------------------------------------------------------------
205 /**
206  * Sets all voxel values below a given threshold to this threshold value
207  */
208 template <class T>
210 {
211  LowerThreshold(T threshold) : _LowerThreshold(threshold) {}
212 
213  void operator ()(const GenericImage<T>&, int, T *p)
214  {
215  if (*p < _LowerThreshold) *p = _LowerThreshold;
216  }
217 
218  void operator ()(int, int, int, int, T *p)
219  {
220  if (*p < _LowerThreshold) *p = _LowerThreshold;
221  }
222 
223  T _LowerThreshold; ///< Lower threshold value
224 };
225 
226 // -----------------------------------------------------------------------------
227 /**
228  * Sets all voxel values exceeding a given threshold to this threshold value
229  */
230 template <class T>
232 {
233  UpperThreshold(T threshold) : _UpperThreshold(threshold) {}
234 
235  void operator ()(const GenericImage<T>&, int, T *p)
236  {
237  if (*p > _UpperThreshold) *p = _UpperThreshold;
238  }
239 
240  void operator ()(int, int, int, int, T *p)
241  {
242  if (*p > _UpperThreshold) *p = _UpperThreshold;
243  }
244 
245  T _UpperThreshold; ///< Upper threshold value
246 };
247 
248 // -----------------------------------------------------------------------------
249 /**
250  * Sets voxel values to a minimum/maximum value if below/above minimum/maximum
251  */
252 template <class T>
253 struct Clamp : public VoxelFunction
254 {
255  Clamp(T min, T max) : _LowerThreshold(min), _UpperThreshold(max) {}
256 
257  void operator ()(const GenericImage<T>&, int, T *p)
258  {
259  if (*p < _LowerThreshold) *p = _LowerThreshold;
260  else if (*p > _UpperThreshold) *p = _UpperThreshold;
261  }
262 
263  void operator ()(int, int, int, int, T *p)
264  {
265  if (*p < _LowerThreshold) *p = _LowerThreshold;
266  else if (*p > _UpperThreshold) *p = _UpperThreshold;
267  }
268 
269  T _LowerThreshold; ///< Lower threshold value
270  T _UpperThreshold; ///< Upper threshold value
271 };
272 
273 // =============================================================================
274 // Mathematical operations
275 // =============================================================================
276 
277 // -----------------------------------------------------------------------------
278 /**
279  * Takes the square root of the intensities
280  */
281 struct Sqrt : public VoxelFunction
282 {
283  template <class TImage, class T>
284  void operator ()(const TImage&, int, T *p)
285  {
286  *p = static_cast<T>(sqrt(static_cast<double>(*p)));
287  }
288 
289  template <class T>
290  void operator ()(int, int, int, int, const T *p)
291  {
292  *p = static_cast<T>(sqrt(static_cast<double>(*p)));
293  }
294 };
295 
296 // =============================================================================
297 // Casts
298 // =============================================================================
299 
300 // -----------------------------------------------------------------------------
301 /// Casts intensities to grey values
303 {
304  template <class TImage, class T>
305  void operator ()(const TImage &, int, T *v)
306  {
307  *v = static_cast<GreyPixel>(*v);
308  }
309 };
310 
311 // =============================================================================
312 // Interpolation
313 // =============================================================================
314 
315 // -----------------------------------------------------------------------------
316 /// Interpolate scalar or vector image
317 template <class TInterpolator = InterpolateImageFunction>
319 {
320  const BaseImage *_Input;
321  const TInterpolator *_Interpolator;
322  BaseImage *_Output;
323 
324  InterpolateImage(const TInterpolator *input, BaseImage *output)
325  :
326  _Input (input->Input()),
327  _Interpolator(input),
328  _Output (output)
329  {
330  mirtkAssert(input->Input()->T() == 1 || input->Input()->GetTSize() != .0,
331  "Input image is not a multi-channel image");
332  }
333 
334  InterpolateImage(const InterpolateImage &other)
335  :
336  _Input (other._Input),
337  _Interpolator(other._Interpolator),
338  _Output (other._Output)
339  {}
340 
341  /// Interpolate scalar/vector image
342  template <class T>
343  void operator()(int i, int j, int k, int l, T *o)
344  {
345  // Convert output voxel to world coordinates
346  double x = i, y = j, z = k, t = l;
347  _Output->ImageToWorld(x, y, z);
348  t = _Output->ImageToTime (t);
349  // Convert world coordinates to input voxel coordinates
350  _Input->WorldToImage(x, y, z);
351  t = _Input->TimeToImage (t);
352  // Interpolate input scalar or vector
353  Vector v;
354  _Interpolator->Evaluate(v, x, y, z, t);
355  (*o) = voxel_cast<T>(v); // Convert to output type
356  }
357 };
358 
359 // -----------------------------------------------------------------------------
360 /// Interpolate scalar image
361 template <class TInterpolator = InterpolateImageFunction>
363 {
364  const BaseImage *_Input;
365  const TInterpolator *_Interpolator;
366  BaseImage *_Output;
367 
368  InterpolateScalarImage(const TInterpolator *input, BaseImage *output)
369  :
370  _Input (input->Input()),
371  _Interpolator(input),
372  _Output (output)
373  {
374  mirtkAssert(input->Input()->N() == 1, "Input image has scalar data type");
375  }
376 
378  :
379  _Input (other._Input),
380  _Interpolator(other._Interpolator),
381  _Output (other._Output)
382  {}
383 
384  /// Interpolate scalar at (i, j, k, l)
385  template <class T>
386  void operator()(int i, int j, int k, int l, T *o)
387  {
388  // Convert output voxel to world coordinates
389  double x = i, y = j, z = k, t = l;
390  _Output->ImageToWorld(x, y, z);
391  t = _Output->ImageToTime (t);
392  // Convert world coordinates to input voxel coordinates
393  _Input->WorldToImage(x, y, z);
394  t = _Input->TimeToImage (t);
395  // Interpolate input scalar and convert to output type
396  (*o) = voxel_cast<T>(_Interpolator->Evaluate(x, y, z, t));
397  }
398 };
399 
400 // -----------------------------------------------------------------------------
401 /// Interpolate multi-channel image (3D+c)
402 template <class TInterpolator = InterpolateImageFunction>
404 {
405  const BaseImage *_Input;
406  const TInterpolator *_Interpolator;
407  BaseImage *_Output;
408  int _NumberOfVoxels;
409 
410  InterpolateMultiChannelImage(const TInterpolator *input, BaseImage *output)
411  :
412  _Input (input->Input()),
413  _Interpolator (input),
414  _Output (output),
415  _NumberOfVoxels(output->NumberOfSpatialVoxels())
416  {
417  mirtkAssert(input->Input() != NULL, "Interpolator is initialized");
418  mirtkAssert(output->T() == input->Input()->T(),
419  "Input and output images have same number of channels");
420  }
421 
423  :
424  _Input (other._Input),
425  _Interpolator (other._Interpolator),
426  _Output (other._Output),
427  _NumberOfVoxels(other._NumberOfVoxels)
428  {}
429 
430  /// Interpolate all channels at (i, j, k) at once
431  template <class T>
432  void operator()(int i, int j, int k, int, T *o)
433  {
434  // Convert output voxel to world coordinates
435  double x = i, y = j, z = k;
436  _Output->ImageToWorld(x, y, z);
437  // Convert world coordinates to input voxel coordinates
438  _Input->WorldToImage(x, y, z);
439  // Interpolate input channels
440  double *v = new double[_Output->T()];
441  _Interpolator->Evaluate(v, x, y, z);
442  for (int l = 0; l < _Output->T(); ++l, o += _NumberOfVoxels) {
443  (*o) = voxel_cast<T>(v[l]); // Convert to output type
444  }
445  delete[] v;
446  }
447 
448  /// Interpolate all channels at (i, j, k) at once
449  void operator()(int i, int j, int k, int, double *o)
450  {
451  // Convert output voxel to world coordinates
452  double x = i, y = j, z = k;
453  _Output->ImageToWorld(x, y, z);
454  // Convert world coordinates to input voxel coordinates
455  _Input->WorldToImage(x, y, z);
456  // Interpolate input scalar or vector
457  _Interpolator->Evaluate(o, x, y, z, _NumberOfVoxels);
458  }
459 };
460 
461 // =============================================================================
462 // Downsampling
463 // =============================================================================
464 
465 // -----------------------------------------------------------------------------
466 template <class TVoxel>
467 struct DownsampleX : public VoxelFunction
468 {
469  const GenericImage<TVoxel> *_Input;
470  int _Offset;
471  int _Factor;
472 
473  DownsampleX(const GenericImage<TVoxel> *input, int m)
474  : _Input(input), _Offset((input->GetX() % m) / 2), _Factor(m)
475  {}
476 
477  template <class T>
478  void operator ()(int i, int j, int k, int l, T *out)
479  {
480  *out = _Input->Get(_Offset + i * _Factor, j, k, l);
481  }
482 };
483 
484 // -----------------------------------------------------------------------------
485 template <class TVoxel>
486 struct DownsampleY : public VoxelFunction
487 {
488  const GenericImage<TVoxel> *_Input;
489  int _Offset;
490  int _Factor;
491 
492  DownsampleY(const GenericImage<TVoxel> *input, int m)
493  : _Input(input), _Offset((input->GetY() % m) / 2), _Factor(m)
494  {}
495 
496  template <class T>
497  void operator ()(int i, int j, int k, int l, T *out)
498  {
499  *out = _Input->Get(i, _Offset + j * _Factor, k, l);
500  }
501 };
502 
503 // -----------------------------------------------------------------------------
504 template <class TVoxel>
505 struct DownsampleZ : public VoxelFunction
506 {
507  const GenericImage<TVoxel> *_Input;
508  int _Offset;
509  int _Factor;
510 
511  DownsampleZ(const GenericImage<TVoxel> *input, int m)
512  : _Input(input), _Offset((input->GetZ() % m) / 2), _Factor(m)
513  {}
514 
515  template <class T>
516  void operator ()(int i, int j, int k, int l, T *out)
517  {
518  *out = _Input->Get(i, j, _Offset + k * _Factor, l);
519  }
520 };
521 
522 
523 } } // namespace mirtk::UnaryVoxelFunction
524 
525 #endif // MIRTK_UnaryVoxelFunction_H
void operator()(int i, int j, int k, int l, T *o)
Interpolate scalar at (i, j, k, l)
Dummy type used to distinguish split constructor from copy constructor.
Definition: Parallel.h:143
void operator()(int i, int j, int k, int, double *o)
Interpolate all channels at (i, j, k) at once.
void WorldToImage(double &, double &) const
World to image coordinate conversion with two doubles.
Definition: BaseImage.h:1212
T _UpperThreshold
Upper threshold value.
Casts intensities to grey values.
Interpolate scalar or vector image.
T _LowerThreshold
Lower threshold value.
void operator()(int i, int j, int k, int, T *o)
Interpolate all channels at (i, j, k) at once.
void operator()(int i, int j, int k, int l, T *o)
Interpolate scalar/vector image.
Definition: IOConfig.h:41
int GetX() const
Returns the number of voxels in the x-direction.
Definition: BaseImage.h:904
void ImageToWorld(double &, double &) const
Image to world coordinate conversion with two doubles.
Definition: BaseImage.h:1180
double TimeToImage(double) const
Time to image coordinate conversion.
Definition: BaseImage.h:1262
int GetY() const
Returns the number of voxels in the y-direction.
Definition: BaseImage.h:910
double ImageToTime(double) const
Image to time coordinate conversion.
Definition: BaseImage.h:1256
int T() const
Returns the number of voxels in the t-direction.
Definition: BaseImage.h:892
VoxelType Get(int) const
Function for pixel get access.
Definition: GenericImage.h:573
int GetZ() const
Returns the number of voxels in the z-direction.
Definition: BaseImage.h:916
int NumberOfSpatialVoxels() const
Returns the total number of spatial voxels.
Definition: BaseImage.h:868