VoxelDomain.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_VoxelDomain_H
21 #define MIRTK_VoxelDomain_H
22 
23 
24 namespace mirtk {
25 
26 
27 /**
28  * Types which implement inside/outside image domain checks
29  *
30  * This namespace defines auxiliary types which implement inside/outside image
31  * domain checks for voxels as static methods. These types can be used as
32  * Domain template argument as used by the ForEachVoxelIf and ParallelForEachVoxelIf
33  * template functions to restrict the evaluation of the voxel function to a specific
34  * subdomain of the image(s). Moreover, if it is known how the subdomain is
35  * defined, e.g., by a binary mask, a background value, a lower foreground threshold,
36  * or an interpolation domain, a specialized inside/outside domain check is more
37  * efficient as it only needs to test one particular condition. The more generic
38  * default domain check has to evaluate multiple conditions to first decide
39  * how the domain is being defined and then evaluate the actual inside/outside
40  * condition for this domain. This requires multiple if-statements and can be
41  * expensive when all these if-statements have to be evaluated for each voxel.
42  * Therefore, whenever possible use a specialized domain check to focus on the
43  * condition that matters.
44  *
45  * Example:
46  * \code
47  * #include "mirtk/GenericImage.h"
48  * #include "mirtk/VoxelFunction.h"
49  * #include "mirtk/VoxelDomain.h"
50  *
51  * namespace mirtk {
52  *
53  *
54  * void ProcessImageVoxelByVoxel(GreyImage &image)
55  * {
56  * using namespace ForEachVoxelDomain;
57  * ForEachVoxelIf<AboveBackgroundLevel>(image, func);
58  * }
59  *
60  *
61  * } // namespace mirtk
62  * \endcode
63  *
64  * \note The last image passed to ForEachVoxelIf/ParallelForEachVoxelIf is
65  * the one which defines the image domain over which to iterate as it
66  * is often an output image. Therefore, this last image is passed on
67  * to the domain checks defined within the ImageDomain namespace.
68  *
69  */
70 namespace ForEachVoxelDomain {
71 
72 
73 // -----------------------------------------------------------------------------
74 /**
75  * Checks if voxel is in foreground using BaseImage::IsForeground
76  */
77 struct Foreground
78 {
79  static inline bool IsInside(const BaseImage &image, int idx, const void *)
80  {
81  return image.IsForeground(idx);
82  }
83 
84  static inline bool IsInside(const BaseImage &image, int i, int j, int k, int l, const void *)
85  {
86  return image.IsForeground(i, j, k, l);
87  }
88 };
89 
90 // -----------------------------------------------------------------------------
91 /**
92  * Checks if voxel is in foreground using background value of image
93  */
95 {
96  template <class T>
97  static inline bool IsInside(const BaseImage &image, int, const T *p)
98  {
99  const double bg = image.GetBackgroundValueAsDouble();
100  return (*p != bg) && (bg == bg || *p == *p /*, i.e., not both NaN */);
101  }
102 
103  template <class T>
104  static inline bool IsInside(const BaseImage &image, int, int, int, int, const T *p)
105  {
106  const double bg = image.GetBackgroundValueAsDouble();
107  return (*p != bg) && (bg == bg || *p == *p /*, i.e., not both NaN */);
108  }
109 };
110 
111 // -----------------------------------------------------------------------------
112 /**
113  * Checks if voxel is in foreground using background value of image as threshold
114  */
116 {
117  template <class T>
118  static inline bool IsInside(const BaseImage &image, int, const T *p)
119  {
120  const double bg = image.GetBackgroundValueAsDouble();
121  return (*p > bg) && (bg == bg || *p == *p /*, i.e., not both NaN */);
122  }
123 
124  template <class T>
125  static inline bool IsInside(const BaseImage &image, int, int, int, int, const T *p)
126  {
127  const double bg = image.GetBackgroundValueAsDouble();
128  return (*p > bg) && (bg == bg || *p == *p /*, i.e., not both NaN */);
129  }
130 };
131 
132 // -----------------------------------------------------------------------------
133 /**
134  * Checks if voxel is in background using BaseImage::IsBackground
135  */
137 {
138  static inline bool IsInside(const BaseImage &image, int idx, const void *)
139  {
140  return image.IsBackground(idx);
141  }
142 
143  static inline bool IsInside(const BaseImage &image, int i, int j, int k, int l, const void *)
144  {
145  return image.IsBackground(i, j, k, l);
146  }
147 };
148 
149 // -----------------------------------------------------------------------------
150 /**
151  * Checks if voxel is in background using background value of image
152  */
154 {
155  template <class T>
156  static inline bool IsInside(const BaseImage &image, int, const T *p)
157  {
158  const double bg = image.GetBackgroundValueAsDouble();
159  return (*p == bg) || (bg != bg && *p != *p /*, i.e., both NaN */);
160  }
161 
162  template <class T>
163  static inline bool IsInside(const BaseImage &image, int, int, int, int, const T *p)
164  {
165  const double bg = image.GetBackgroundValueAsDouble();
166  return (*p == bg) || (bg != bg && *p != *p /*, i.e., both NaN */);
167  }
168 };
169 
170 // -----------------------------------------------------------------------------
171 /**
172  * Checks if voxel is in image domain using mask of image
173  */
174 struct InMask
175 {
176  static inline bool IsInside(const BaseImage &image, int idx, const void *)
177  {
178  const BinaryImage * const mask = image.GetMask();
179  if (mask->GetT() > 1) {
180  return (mask->Get(idx) != BinaryPixel(0));
181  } else {
182  return (mask->Get(idx % (image.GetX() * image.GetY() * image.GetZ())) != BinaryPixel(0));
183  }
184  }
185 
186  static inline bool IsInside(const BaseImage &image, int i, int j, int k, int l, const void *)
187  {
188  const BinaryImage * const mask = image.GetMask();
189  return (mask->Get(i, j, k, mask->GetT() > 1 ? l : 0) != BinaryPixel(0));
190  }
191 };
192 
193 // -----------------------------------------------------------------------------
194 /**
195  * Checks if voxel is in image domain using mask of image (BaseImage::GetMask)
196  *
197  * Use this domain check if the foreground mask is never four-dimensional even
198  * when the image itself has multiple frames, channels, or vector components.
199  */
201 {
202  static inline bool IsInside(const BaseImage &image, int idx, const void *)
203  {
204  return (image.GetMask()->Get(idx % (image.GetX() * image.GetY() * image.GetZ())) != BinaryPixel(0));
205  }
206 
207  static inline bool IsInside(const BaseImage &image, int i, int j, int k, int, const void *)
208  {
209  return (image.GetMask()->Get(i, j, k) != BinaryPixel(0));
210  }
211 };
212 
213 
214 } // namespace ForEachVoxelDomain
215 
216 
217 /**
218  * Types which implement inside/outside image interpolation domain checks
219  *
220  * This namespace defines auxiliary types which implement inside/outside
221  * interpolation domain checks for (transformed) voxel coordinates as
222  * static methods. These types can be used, in particular, as InputDomain
223  * template argument of the voxel transformation functions derived from
224  * MultipleVoxelTransformation::BaseTransform.
225  */
226 namespace InterpolationDomain {
227 
228 
229 // -----------------------------------------------------------------------------
230 /**
231  * Wraps call to InterpolateImageFunction::IsForeground
232  *
233  * Checks if voxel coordinates are inside the domain for which the interpolation
234  * is defined and also if all values required for interpolation are part of the
235  * foreground region of the image.
236  */
238 {
239  template <class InterpolateImageFunction>
240  static inline bool IsInside(InterpolateImageFunction *interpolator, const double &x, const double &y, const double &z)
241  {
242  return interpolator->IsForeground(x, y, z);
243  }
244 };
245 
246 // -----------------------------------------------------------------------------
247 /**
248  * Wraps call to InterpolateImageFunction::IsInside
249  *
250  * Use as argument for the InputDomain template parameter of the voxel
251  * transformation functors to interpolate the input at a given transformed
252  * voxel when its coordinates are inside the domain for which the interpolation
253  * is well defined.
254  *
255  * More efficient then the default Foreground domain check, but only ensures that
256  * the transformed coordinates are within the interpolation domain of the input
257  * image(s). Can be used when background value of input images is very dominant,
258  * e.g., minimum negative value supported by scalar type, and thus interpolated
259  * values are below a certain threshold, or if influence of background values
260  * is considered negligible.
261  */
262 struct Inside
263 {
264  template <class InterpolateImageFunction>
265  static inline bool IsInside(InterpolateImageFunction *interpolator, const double &x, const double &y, const double &z)
266  {
267  return interpolator->IsInside(x, y, z);
268  }
269 };
270 
271 
272 } // namespace InterpolationDomain
273 
274 
275 } // namespace mirtk
276 
277 #endif // MIRTK_VoxelDomain_H
double GetBackgroundValueAsDouble() const
Get background value.
Definition: BaseImage.h:1413
bool IsBackground(int) const
Whether voxel is within background without index-out-of-bounds check.
Definition: BaseImage.h:1431
BinaryImage * GetMask(bool=false)
Get foreground mask (optionally, take over ownership)
Definition: BaseImage.h:1369
bool IsForeground(int) const
Whether voxel is within foreground without index-out-of-bounds check.
Definition: BaseImage.h:1455
Definition: IOConfig.h:41
int GetX() const
Returns the number of voxels in the x-direction.
Definition: BaseImage.h:904
int GetT() const
Returns the number of voxels in the t-direction.
Definition: BaseImage.h:922
int GetY() const
Returns the number of voxels in the y-direction.
Definition: BaseImage.h:910
bool IsForeground(double, double) const
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