aimstil  5.0.5
ImageExtrapolator.h
Go to the documentation of this file.
1 #ifndef TIL_IMAGEEXTRAPOLATOR_H
2 #define TIL_IMAGEEXTRAPOLATOR_H
3 
4 // includes from TIL library
5 #include "til/til_common.h"
6 #include "til/imageTools.h"
7 #include "til/labels.h"
8 #include "til/PointerTraits.h"
9 
10 
11 namespace til {
12 
13 // TODO: actually maybe we want to have the test (im.contains) in these classes,
14 // first because then the user does not have to type it, and second, it makes
15 // possible to have an 'unsafe' extrapolation that actually does not extrapolate.
16 // Might be useful to use some functions (e.g. resample) where we know that
17 // with the parameters we give there is no extrapolation to be done.
18 
19 // A macro to shorten declaration of extrapolation classes
20 // NB: to be undefined at the end of the declarations
21 /*
22 #define EXTRAPOL_FUNC \
23 template < typename TImage > \
24 INLINE \
25 static typename TImage::value_type \
26 getValue(const TImage &im, const Vector<int,3> & pos) \
27 { return Self::getValue(im, EXPAND_VECTOR(pos)); } \
28  \
29 template < typename TImage > \
30 INLINE \
31 static typename TImage::value_type \
32 getValue(const TImage &im, int i, int j, int k) \
33 { if (contains(im,i,j,k)) { return im.getUnsafeValue(i,j,k); } \
34  else { return Self::getExtrapolatedValue(im, i, j, k); } } \
35  \
36 template < typename TImage > \
37 INLINE \
38 static typename TImage::value_type \
39 getExtrapolatedValue(const TImage &im, const Vector<int,3> & pos) \
40 { return Self::getExtrapolatedValue(im, EXPAND_VECTOR(pos)); } \
41  \
42 template < typename TImage > \
43 INLINE \
44 static typename TImage::value_type \
45 getExtrapolatedValue(const TImage &im, int i, int j, int k) \
46  \
47 */
48 
49 #define TIL_EXTRAPOL_FUNC(imname, posname) \
50 template < typename TImage > \
51 INLINE \
52 static typename TImage::value_type \
53 getValue(const TImage &im, numeric_array<int,3> pos) \
54 { if (contains(im,pos)) { return im.getUnsafeValue(pos); } \
55  else { return Self::getExtrapolatedValue(im, pos); } } \
56  \
57 template < typename TImage > \
58 INLINE \
59 static typename TImage::value_type \
60 getExtrapolatedValue(const TImage & imname, numeric_array<int,3> posname) \
61 
62 
63 
64 
65 // NB: In all extrapolator classes, it is assumed that the (i,j,k) position
66 // lies outside the image range
67 // In other words, this classes are always called after an explicit range
68 // checking.
69 
70 
72 struct RangeCheckingExtrapolator : public ImageExtrapolator_label
73 {
74 public: // typededs
75 
77 
78 public: // static functions
79 
81  {
82  //throw std::out_of_range(mySprintf("Coordinates out of image range: (%i, %i, %i)", i, j, k));
83  throw std::out_of_range(mySprintf("Coordinates out of image range: (%i, %i, %i)", pos[0], pos[1], pos[2])); }
84 };
85 
86 
88 class ZeroExtrapolator : public ImageExtrapolator_label
89 {
90 public: // typedefs
91 
93 
94 public: // static functions
95 
97  {
98  return typename TImage::value_type();
99  }
100 };
101 
102 
104 class NearestExtrapolator : public ImageExtrapolator_label
105 {
106 public: // typededs
107 
109 
110 public: // static functions
111 
113  {
114  if (pos[0]<0) pos[0]=0; else if (pos[0] >= im.dim()[0]) pos[0] = im.dim()[0]-1;
115  if (pos[1]<0) pos[1]=0; else if (pos[1] >= im.dim()[1]) pos[1] = im.dim()[1]-1;
116  if (pos[2]<0) pos[2]=0; else if (pos[2] >= im.dim()[2]) pos[2] = im.dim()[2]-1;
117  /*
118  if (i<0) i=0; else if (i >= im.dim()[0]) i = im.dim()[0]-1;
119  if (j<0) j=0; else if (j >= im.dim()[1]) j = im.dim()[1]-1;
120  if (k<0) k=0; else if (k >= im.dim()[2]) k = im.dim()[2]-1;*/
121  return im.getUnsafeValue(pos);
122  }
123 };
124 
125 
129 class MirrorExtrapolator : public ImageExtrapolator_label
130 {
131 public: // typededs
132 
134 
135 public: // static functions
136 
138  {
139  Self::mirror(pos[0], im.dim()[0]-1);
140  Self::mirror(pos[1], im.dim()[1]-1);
141  Self::mirror(pos[2], im.dim()[2]-1);
142  return im.getUnsafeValue(pos);
143  }
144 
145 private: // static functions
146 
147  static void mirror(int &i, int n)
148  {
149  i = std::abs(i) % (2*n);
150  if (i > n) i = 2*n - i;
151  }
152 };
153 
154 
155 
157 class CyclicExtrapolator : public ImageExtrapolator_label
158 {
159 public: // typededs
160 
162 
163 public: // static functions
164 
166  {
167  Self::cyclic(pos[0], im.dim()[0]);
168  Self::cyclic(pos[1], im.dim()[1]);
169  Self::cyclic(pos[2], im.dim()[2]);
170  return im.getUnsafeValue(pos);
171  }
172 
173 private: // static functions
174 
175  static void cyclic(int &i, int n)
176  {
177  i = i%n;
178  if (i<0) i+=n;
179  }
180 };
181 
187 class UnsafeNoExtrapolator : public ImageExtrapolator_label
188 {
189 public: // typededs
190 
192 
193 public: // static functions
194 
195  template < typename TImage >
196  inline
197  static typename TImage::value_type
198  getValue(const TImage & im, const numeric_array<int,3> & pos)
199  { return im.getUnsafeValue(pos); }
200 
201  template < typename TImage >
202  inline
203  static typename TImage::value_type
204  getExtrapolatedValue(const TImage &im, const numeric_array<int,3> & pos)
205  { return im.getUnsafeValue(pos); }
206 };
207 
208 
209 #undef TIL_EXTRAPOL_FUNC
210 
212 // still not clear whether it should inherit from image or not.
213 // There are many possibilities to get the extrapolated value of an image.
214 // One could for example code in each image class a getValue<Extrapolator> member.
215 // But then, do we bring really something as opposed to using directly the extrapolation
216 // classes? Not really, because in both cases we assume that the current code and
217 // the person who writes it are aware that at this point in time an Extrapolation
218 // is needed and used.
219 // This class aim at hiding the extrapolation process, by templating on it, so
220 // it brings another layer. It means that we can pass along this object to a function,
221 // and this function will do extrapolation without even knowing it.
222 // Initially this was motivated for image resampling. When we do image resampling
223 // we have to do interpolation of potentially extrapolated value. But of course,
224 // we should not write an interpolation that is aware of extrapolation, because both
225 // problems are distinct. The easiest way would be to proceed in two steps, first
226 // extract potentially extrapolated values, and then interpolate them, but the
227 // extraction of values actually depends on the interpolator, so this job has to be
228 // done by it.
229 // TODO: maybe a mechanism to inhibit from templating on itself
230 template < class TImageExtrapolator, class TImage >
231 class ExtrapolableImage : public TImage, public ExtrapolableImage_label
232 {
233 public: // typedefs
234  typedef typename TImage::value_type value_type;
235 
236 public: // functions
237 
238  value_type getValue(const numeric_array<int,3> & p) const
239  {
240  if (this->contains(p))
241  {
242  return this->getUnsafeValue(p);
243  }
244  else
245  {
246  return TImageExtrapolator::getExtrapolatedValue(*this, p);
247  }
248  }
249 
250 private: // rules
251 
252  typedef typename enable_if<is_Image<TImage> >::type rule1;
253  typedef typename disable_if<is_ExtrapolableImage<TImage> >::type rule2;
254 };
255 
256 template < class TImageExtrapolator, class TImage >
258 extrapolable(const TImage &im)
259 {
261  EImage eim;
262  eim.shallowCopy(im);
263  return eim;
264 }
265 /*
266 template < class TImageExtrapolator, class TImage >
267 ConstPtr<ExtrapolableImage<TImageExtrapolator, TImage> >
268 extrapolable(const ConstPtr<TImage> &im)
269 {
270  typedef ExtrapolableImage<TImageExtrapolator, TImage> EImage;
271  return ConstPtr<EImage>(static_cast<const EImage *>((const TImage *)im));
272 }
273 */
274 
275 
276 } // namespace
277 
278 #endif
279 
static TImage::value_type getExtrapolatedValue(const TImage &im, const numeric_array< int, 3 > &pos)
static TImage::value_type getValue(const TImage &im, const numeric_array< int, 3 > &pos)
ExtrapolableImage< TImageExtrapolator, TImage > extrapolable(const TImage &im)
Enable image extrapolation by overloading the getValue function.
Belongs to package Box Do not include directly, include til/Box.h instead.
Definition: Accumulator.h:10
General macros, definitions and functions.
Small miscellaneous utility functions for images.
Defines empty classes that serves as labels.
Image extrapolation using cyclic symmetry.
This extrapolator actually does NOT extrapolate at all and does not do any range checking.
numeric_array< T, D > abs(const numeric_array< T, D > &a)
Absolute value, element-wise.
value_type getValue(const numeric_array< int, 3 > &p) const
boost::enable_if< is_numeric_container< TStorage >, bool >::type contains(const Box< T, D > &box, const TStorage &v)
Check whether a point lies within box.
Definition: boxTools.h:15
NearestExtrapolator Self
TIL_API char * mySprintf(const char *format,...)
CyclicExtrapolator Self
Image extrapolation using value of nearest image point.
ZeroExtrapolator Self
Extrapolate image with default value of image type (zero for numeric types)
Extrapolation using (thin) mirror symmetry.
TImage::value_type value_type
MirrorExtrapolator Self
No image extrapolation.
RangeCheckingExtrapolator Self