BinaryVoxelFunction.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_BinaryVoxelFunction_H
21 #define MIRTK_BinaryVoxelFunction_H
22 
23 #include "mirtk/VoxelFunction.h"
24 
25 #include "mirtk/NeighborhoodOffsets.h"
26 #include "mirtk/InterpolateImageFunction.h"
27 
28 
29 /**
30  * These basic binary voxel functions can be used as VoxelFunc template parameter
31  * of the binary ForEachVoxel function templates as follows:
32  *
33  * \code
34  * // Add one image to another in-place
35  * GreyImage input (attr);
36  * GreyImage output(attr);
37  * // Set image in-place to maximum of both images
38  * BinaryVoxelFunction::Max max;
39  * ForEachVoxel(input, output, max);
40  * BinaryVoxelFunction::Add add;
41  * ParallelForEachVoxel(input, output, add);
42  * // Compute sum-of-squared differences (SSD)
43  * GreyImage target(attr);
44  * GreyImage source(attr);
45  * BinaryVoxelFunction::SSD ssd;
46  * ForEachVoxel(target, source, ssd);
47  * printf("SSD=%f\n", ssd.value);
48  * \endcode
49  *
50  */
51 
52 namespace mirtk { namespace BinaryVoxelFunction {
53 
54 
55 // =============================================================================
56 // Copy
57 // =============================================================================
58 
59 // -----------------------------------------------------------------------------
60 /**
61  * Copies the voxel value of one image to the corresponding voxel of another
62  */
63 struct Copy : public VoxelFunction
64 {
65  template <class T1, class T2>
66  void operator ()(const T1 *in, T2 *out) { *out = *in; }
67 
68  template <class TImage, class T1, class T2>
69  void operator ()(const TImage&, int, const T1 *in, T2 *out)
70  {
71  this->operator ()(in, out);
72  }
73 
74  template <class T1, class T2>
75  void operator ()(int, int, int, int, const T1 *in, T2 *out)
76  {
77  this->operator ()(in, out);
78  }
79 };
80 
81 // =============================================================================
82 // Basic mathematical voxel-wise in-place operations
83 // =============================================================================
84 
85 // -----------------------------------------------------------------------------
86 /**
87  * Add image to another
88  */
89 struct Add : public VoxelFunction
90 {
91  template <class T1, class T2>
92  void operator ()(const T1 *in, T2 *out)
93  {
94  *out = static_cast<T2>(static_cast<double>(*out) + static_cast<double>(*in));
95  }
96 
97  template <class TImage, class T1, class T2>
98  void operator ()(const TImage&, int, const T1 *in, T2 *out)
99  {
100  this->operator ()(in, out);
101  }
102 
103  template <class T1, class T2>
104  void operator ()(int, int, int, int, const T1 *in, T2 *out)
105  {
106  this->operator ()(in, out);
107  }
108 };
109 
110 // -----------------------------------------------------------------------------
111 /**
112  * Subtract image from another
113  */
114 struct Sub : public VoxelFunction
115 {
116  template <class T1, class T2>
117  void operator ()(const T1 *in, T2 *out)
118  {
119  *out = static_cast<T2>(static_cast<double>(*out) - static_cast<double>(*in));
120  }
121 
122  template <class TImage, class T1, class T2>
123  void operator ()(const TImage&, int, const T1 *in, T2 *out)
124  {
125  this->operator ()(in, out);
126  }
127 
128  template <class T1, class T2>
129  void operator ()(int, int, int, int, const T1 *in, T2 *out)
130  {
131  this->operator ()(in, out);
132  }
133 };
134 
135 // -----------------------------------------------------------------------------
136 /**
137  * Multiplies the voxel value of one image by the value of another
138  */
139 struct Mul : public VoxelFunction
140 {
141  template <class T1, class T2>
142  void operator ()(const T1 *in, T2 *out)
143  {
144  *out = static_cast<T2>(static_cast<double>(*out) * static_cast<double>(*in));
145  }
146 
147  template <class TImage, class T1, class T2>
148  void operator ()(const TImage&, int, const T1 *in, T2 *out)
149  {
150  this->operator ()(in, out);
151  }
152 
153  template <class T1, class T2>
154  void operator ()(int, int, int, int, const T1 *in, T2 *out)
155  {
156  this->operator ()(in, out);
157  }
158 };
159 
160 // -----------------------------------------------------------------------------
161 /**
162  * Divides the voxel value of one image by the value of another
163  */
164 struct Div : public VoxelFunction
165 {
166  template <class T1, class T2>
167  void operator ()(const T1 *in, T2 *out)
168  {
169  double divisor = static_cast<double>(*in);
170  if (divisor == .0) {
171  *out = static_cast<T2>(0);
172  } else {
173  *out = static_cast<T2>(static_cast<double>(*out) / divisor);
174  }
175  }
176 
177  template <class TImage, class T1, class T2>
178  void operator ()(const TImage&, int, const T1 *in, T2 *out)
179  {
180  this->operator ()(in, out);
181  }
182 
183  template <class T1, class T2>
184  void operator ()(int, int, int, int, const T1 *in, T2 *out)
185  {
186  this->operator ()(in, out);
187  }
188 };
189 
190 // =============================================================================
191 // Morphological operators
192 // =============================================================================
193 
194 /**
195  * Replace voxel value by minimum of neighboring voxels
196  */
197 class Erode : public VoxelFunction
198 {
199  const NeighborhoodOffsets &_Offsets;
200 
201 public:
202 
203  Erode(const NeighborhoodOffsets &offsets) : _Offsets(offsets) {}
204 
205  template <class T>
206  void operator ()(int i, int j, int k, int, const T *in, T *out)
207  {
208  const T *ptr2offset;
209  T &value = *out;
210  if (_Domain->IsBoundary(i, j, k)) {
211  value = *in;
212  } else {
213  value = *in;
214  for (int n = 0; n < _Offsets.Size(); ++n) {
215  ptr2offset = in + _Offsets(n);
216  if (*ptr2offset < value) value = *ptr2offset;
217  }
218  }
219  }
220 };
221 
222 /**
223  * Replace voxel value by maximum of neighboring voxels
224  */
225 class Dilate : public VoxelFunction
226 {
227  const NeighborhoodOffsets &_Offsets;
228 
229 public:
230 
231  Dilate(const NeighborhoodOffsets &offsets) : _Offsets(offsets) {}
232 
233  template <class T>
234  void operator ()(int i, int j, int k, int, const T *in, T *out)
235  {
236  const T *ptr2offset;
237  T &value = *out;
238  if (_Domain->IsBoundary(i, j, k)) {
239  value = *in;
240  } else {
241  value = *in;
242  for (int n = 0; n < _Offsets.Size(); ++n) {
243  ptr2offset = in + _Offsets(n);
244  if (*ptr2offset > value) value = *ptr2offset;
245  }
246  }
247  }
248 };
249 
250 // =============================================================================
251 // Image similarity measures
252 // =============================================================================
253 
254 // -----------------------------------------------------------------------------
255 /**
256  * Compute sum-of-squared differences (SSD)
257  */
258 struct SSD : public VoxelReduction
259 {
260  double value;
261 
262  SSD() : value(.0) {}
263  SSD(SSD &o) : value(o.value) {}
264 
265  void split(const SSD &) { value = .0; }
266  void join (const SSD &rhs) { value += rhs.value; }
267 
268  template <class T1, class T2>
269  void operator ()(const T1 *in1, const T2 *in2)
270  {
271  double diff = static_cast<double>(*in1) - static_cast<double>(*in2);
272  value += diff * diff;
273  }
274 
275  template <class TImage, class T1, class T2>
276  void operator ()(const TImage&, int, const T1 *in, T2 *out)
277  {
278  this->operator ()(in, out);
279  }
280 
281  template <class T1, class T2>
282  void operator ()(int, int, int, int, const T1 *in, T2 *out)
283  {
284  this->operator ()(in, out);
285  }
286 };
287 
288 // =============================================================================
289 // Composition
290 // =============================================================================
291 
292 // -----------------------------------------------------------------------------
293 /// Compose two 2D displacement fields: D = D1 ° D2
294 template <class TReal, class TInterpolator = InterpolateImageFunction>
296 {
297  // ---------------------------------------------------------------------------
298  ComposeDisplacementFields2D(TInterpolator *d1, const GenericImage<TReal> *d2)
299  :
300  _D1(d1->Input()),
301  _D1Interpolator(d1),
302  _D2(d2),
303  _y(d2->X() * d2->Y())
304  {
305  }
306 
307  // ---------------------------------------------------------------------------
308  void operator()(int i, int j, int k, int, const TReal *d2, TReal *dout)
309  {
310  double d[3]; // 2D displacement field can have constant third component!
311  double x1 = i, y1 = j, z1 = k;
312  _D2->ImageToWorld(x1, y1, z1);
313  double x2 = x1 + d2[_x]; double x = x2;
314  double y2 = y1 + d2[_y]; double y = y2;
315  _D1 ->WorldToImage(x, y, z1);
316  _D1Interpolator->Evaluate (d, x, y, z1);
317  x2 = x2 + d[0];
318  y2 = y2 + d[1];
319  dout[_x] = static_cast<TReal>(x2 - x1);
320  dout[_y] = static_cast<TReal>(y2 - y1);
321  }
322 
323 private:
324  const BaseImage *_D1; ///< First displacement field
325  TInterpolator *_D1Interpolator; ///< Interpolator of first displacement field
326  const GenericImage<TReal> *_D2; ///< Second displacement field
327 
328  static const int _x = 0; ///< Offset of x component
329  int _y; ///< Offset of y component
330 };
331 
332 // -----------------------------------------------------------------------------
333 /// Compose two 3D displacement fields: D = D1 ° D2
334 template <class TReal, class TInterpolator = InterpolateImageFunction>
336 {
337  // ---------------------------------------------------------------------------
338  ComposeDisplacementFields3D(TInterpolator *d1, const GenericImage<TReal> *d2)
339  :
340  _D1(d1->Input()),
341  _D1Interpolator(d1),
342  _D2(d2),
343  _y(d2->X() * d2->Y() * d2->Z()),
344  _z(2 * _y)
345  {
346  }
347 
348  // ---------------------------------------------------------------------------
349  void operator()(int i, int j, int k, int, const TReal *d2, TReal *dout)
350  {
351  double d[3];
352  double x1 = i, y1 = j, z1 = k;
353  _D2->ImageToWorld(x1, y1, z1);
354  double x2 = x1 + d2[_x]; double x = x2;
355  double y2 = y1 + d2[_y]; double y = y2;
356  double z2 = z1 + d2[_z]; double z = z2;
357  _D1 ->WorldToImage(x, y, z);
358  _D1Interpolator->Evaluate (d, x, y, z);
359  x2 = x2 + d[0];
360  y2 = y2 + d[1];
361  z2 = z2 + d[2];
362  dout[_x] = static_cast<TReal>(x2 - x1);
363  dout[_y] = static_cast<TReal>(y2 - y1);
364  dout[_z] = static_cast<TReal>(z2 - z1);
365  }
366 
367 private:
368  const BaseImage *_D1; ///< First displacement field
369  TInterpolator *_D1Interpolator; ///< Interpolator of first displacement field
370  const GenericImage<TReal> *_D2; ///< Second displacement field
371 
372  static const int _x = 0; ///< Offset of x component
373  int _y; ///< Offset of y component
374  int _z; ///< Offset of z component
375 };
376 
377 
378 } } // namespace mirtk::BinaryVoxelFunction
379 
380 #endif
Compose two 2D displacement fields: D = D1 ° D2.
const ImageAttributes * _Domain
Definition: VoxelFunction.h:99
Definition: IOConfig.h:41
Compose two 3D displacement fields: D = D1 ° D2.
void join(VoxelFunction &)
Join results.
int Y() const
Returns the number of voxels in the y-direction.
Definition: BaseImage.h:880
int X() const
Returns the number of voxels in the x-direction.
Definition: BaseImage.h:874
void split(VoxelFunction &)
bool IsBoundary(int) const
Whether voxel index is at boundary of finite image domain.
int Z() const
Returns the number of voxels in the z-direction.
Definition: BaseImage.h:886