[ VIGRA Homepage | Function Index | Class Index | Namespaces | File List | Main Page ]

splineimageview.hxx
1 /************************************************************************/
2 /* */
3 /* Copyright 1998-2004 by Ullrich Koethe */
4 /* */
5 /* This file is part of the VIGRA computer vision library. */
6 /* The VIGRA Website is */
7 /* http://hci.iwr.uni-heidelberg.de/vigra/ */
8 /* Please direct questions, bug reports, and contributions to */
9 /* ullrich.koethe@iwr.uni-heidelberg.de or */
10 /* vigra@informatik.uni-hamburg.de */
11 /* */
12 /* Permission is hereby granted, free of charge, to any person */
13 /* obtaining a copy of this software and associated documentation */
14 /* files (the "Software"), to deal in the Software without */
15 /* restriction, including without limitation the rights to use, */
16 /* copy, modify, merge, publish, distribute, sublicense, and/or */
17 /* sell copies of the Software, and to permit persons to whom the */
18 /* Software is furnished to do so, subject to the following */
19 /* conditions: */
20 /* */
21 /* The above copyright notice and this permission notice shall be */
22 /* included in all copies or substantial portions of the */
23 /* Software. */
24 /* */
25 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND */
26 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES */
27 /* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */
28 /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT */
29 /* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
30 /* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */
31 /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */
32 /* OTHER DEALINGS IN THE SOFTWARE. */
33 /* */
34 /************************************************************************/
35 
36 #ifndef VIGRA_SPLINEIMAGEVIEW_HXX
37 #define VIGRA_SPLINEIMAGEVIEW_HXX
38 
39 #include "mathutil.hxx"
40 #include "recursiveconvolution.hxx"
41 #include "splines.hxx"
42 #include "array_vector.hxx"
43 #include "basicimage.hxx"
44 #include "copyimage.hxx"
45 #include "tinyvector.hxx"
46 #include "fixedpoint.hxx"
47 #include "multi_array.hxx"
48 
49 namespace vigra {
50 
51 /********************************************************/
52 /* */
53 /* SplineImageView */
54 /* */
55 /********************************************************/
56 /** \brief Create a continuous view onto a discrete image using splines.
57 
58  This class is very useful if image values or derivatives at arbitrary
59  real-valued coordinates are needed. Access at such coordinates is implemented by
60  interpolating the given discrete image values with a spline of the
61  specified <tt>ORDER</TT>. Continuous derivatives are available up to
62  degree <tt>ORDER-1</TT>. If the requested coordinates are near the image border,
63  reflective boundary conditions are applied. In principle, this class can also be used
64  for image resizing, but here the functions from the <tt>resize...</tt> family are
65  more efficient, since they exploit the regularity of the sampling grid.
66 
67  The <tt>SplineImageView</tt> template is explicitly specialized to make it as efficient as possible.
68  In particular, unnecessary copying of the image is avoided when the iterators passed
69  in the constructor originate from a \ref vigra::BasicImage. In addition, these specializations
70  provide function <tt>unchecked(...)</tt> that do not perform bounds checking. If the original image
71  is not a variant of \ref vigra::BasicImage, one can customize the internal representation by
72  using \ref vigra::SplineImageView0 or \ref vigra::SplineImageView1.
73 
74  <b>Usage:</b>
75 
76  <b>\#include</b> <vigra/splineimageview.hxx><br>
77  Namespace: vigra
78 
79  \code
80  BImage img(w,h);
81  ... // fill img
82 
83  // construct spline view for quadratic interpolation
84  SplineImageView<2, double> spi2(srcImageRange(img));
85 
86  double x = ..., y = ...;
87  double v2 = spi2(x, y);
88 
89  // construct spline view for linear interpolation
90  SplineImageView<1, UInt32> spi1(srcImageRange(img));
91 
92  UInt32 v1 = spi1(x, y);
93 
94  FixedPoint<16, 15> fx(...), fy(...);
95  UInt32 vf = spi1.unchecked(fx, fy); // caller is sure that (fx, fy) are valid coordinates
96  \endcode
97 */
98 template <int ORDER, class VALUETYPE>
100 {
101  typedef typename NumericTraits<VALUETYPE>::RealPromote InternalValue;
102 
103  public:
104 
105  /** The view's value type (return type of access and derivative functions).
106  */
107  typedef VALUETYPE value_type;
108 
109  /** The view's squared norm type (return type of g2() etc.).
110  */
111  typedef typename NormTraits<VALUETYPE>::SquaredNormType SquaredNormType;
112 
113  /** The view's size type.
114  */
115  typedef Size2D size_type;
116 
117  /** The view's difference type.
118  */
120 
121  /** The order of the spline used.
122  */
123  enum StaticOrder { order = ORDER };
124 
125  /** The type of the internal image holding the spline coefficients.
126  */
128 
129  private:
131  typedef typename InternalTraverser::row_iterator InternalRowIterator;
134 
135  enum { ksize_ = ORDER + 1, kcenter_ = ORDER / 2 };
136 
137  public:
138  /** Construct SplineImageView for the given image.
139 
140  If <tt>skipPrefiltering = true</tt> (default: <tt>false</tt>), the recursive
141  prefilter of the cardinal spline function is not applied, resulting
142  in an approximating (smoothing) rather than interpolating spline. This is
143  especially useful if customized prefilters are to be applied.
144  */
145  template <class SrcIterator, class SrcAccessor>
146  SplineImageView(SrcIterator is, SrcIterator iend, SrcAccessor sa, bool skipPrefiltering = false)
147  : w_(iend.x - is.x), h_(iend.y - is.y), w1_(w_-1), h1_(h_-1),
148  x0_(kcenter_), x1_(w_ - kcenter_ - 2), y0_(kcenter_), y1_(h_ - kcenter_ - 2),
149  image_(w_, h_),
150  x_(-1.0), y_(-1.0),
151  u_(-1.0), v_(-1.0)
152  {
153  copyImage(srcIterRange(is, iend, sa), destImage(image_));
154  if(!skipPrefiltering)
155  init();
156  }
157 
158  /** Construct SplineImageView for the given image.
159 
160  If <tt>skipPrefiltering = true</tt> (default: <tt>false</tt>), the recursive
161  prefilter of the cardinal spline function is not applied, resulting
162  in an approximating (smoothing) rather than interpolating spline. This is
163  especially useful if customized prefilters are to be applied.
164  */
165  template <class SrcIterator, class SrcAccessor>
166  SplineImageView(triple<SrcIterator, SrcIterator, SrcAccessor> s, bool skipPrefiltering = false)
167  : w_(s.second.x - s.first.x), h_(s.second.y - s.first.y), w1_(w_-1), h1_(h_-1),
168  x0_(kcenter_), x1_(w_ - kcenter_ - 2), y0_(kcenter_), y1_(h_ - kcenter_ - 2),
169  image_(w_, h_),
170  x_(-1.0), y_(-1.0),
171  u_(-1.0), v_(-1.0)
172  {
173  copyImage(srcIterRange(s.first, s.second, s.third), destImage(image_));
174  if(!skipPrefiltering)
175  init();
176  }
177 
178  /** Access interpolated function at real-valued coordinate <tt>(x, y)</tt>.
179  If <tt>(x, y)</tt> is near the image border or outside the image, the value
180  is calculated with reflective boundary conditions. An exception is thrown if the
181  coordinate is outside the first reflection.
182  */
183  value_type operator()(double x, double y) const;
184 
185  /** Access derivative of order <tt>(dx, dy)</tt> at real-valued coordinate <tt>(x, y)</tt>.
186  If <tt>(x, y)</tt> is near the image border or outside the image, the value
187  is calculated with reflective boundary conditions. An exception is thrown if the
188  coordinate is outside the first reflection.
189  */
190  value_type operator()(double x, double y, unsigned int dx, unsigned int dy) const;
191 
192  /** Access 1st derivative in x-direction at real-valued coordinate <tt>(x, y)</tt>.
193  Equivalent to <tt>splineView(x, y, 1, 0)</tt>.
194  */
195  value_type dx(double x, double y) const
196  { return operator()(x, y, 1, 0); }
197 
198  /** Access 1st derivative in y-direction at real-valued coordinate <tt>(x, y)</tt>.
199  Equivalent to <tt>splineView(x, y, 0, 1)</tt>.
200  */
201  value_type dy(double x, double y) const
202  { return operator()(x, y, 0, 1); }
203 
204  /** Access 2nd derivative in x-direction at real-valued coordinate <tt>(x, y)</tt>.
205  Equivalent to <tt>splineView(x, y, 2, 0)</tt>.
206  */
207  value_type dxx(double x, double y) const
208  { return operator()(x, y, 2, 0); }
209 
210  /** Access mixed 2nd derivative at real-valued coordinate <tt>(x, y)</tt>.
211  Equivalent to <tt>splineView(x, y, 1, 1)</tt>.
212  */
213  value_type dxy(double x, double y) const
214  { return operator()(x, y, 1, 1); }
215 
216  /** Access 2nd derivative in y-direction at real-valued coordinate <tt>(x, y)</tt>.
217  Equivalent to <tt>splineView(x, y, 0, 2)</tt>.
218  */
219  value_type dyy(double x, double y) const
220  { return operator()(x, y, 0, 2); }
221 
222  /** Access 3rd derivative in x-direction at real-valued coordinate <tt>(x, y)</tt>.
223  Equivalent to <tt>splineView(x, y, 3, 0)</tt>.
224  */
225  value_type dx3(double x, double y) const
226  { return operator()(x, y, 3, 0); }
227 
228  /** Access 3rd derivative in y-direction at real-valued coordinate <tt>(x, y)</tt>.
229  Equivalent to <tt>splineView(x, y, 0, 3)</tt>.
230  */
231  value_type dy3(double x, double y) const
232  { return operator()(x, y, 0, 3); }
233 
234  /** Access mixed 3rd derivative dxxy at real-valued coordinate <tt>(x, y)</tt>.
235  Equivalent to <tt>splineView(x, y, 2, 1)</tt>.
236  */
237  value_type dxxy(double x, double y) const
238  { return operator()(x, y, 2, 1); }
239 
240  /** Access mixed 3rd derivative dxyy at real-valued coordinate <tt>(x, y)</tt>.
241  Equivalent to <tt>splineView(x, y, 1, 2)</tt>.
242  */
243  value_type dxyy(double x, double y) const
244  { return operator()(x, y, 1, 2); }
245 
246  /** Access interpolated function at real-valued coordinate <tt>d</tt>.
247  Equivalent to <tt>splineView(d[0], d[1])</tt>.
248  */
250  { return operator()(d[0], d[1]); }
251 
252  /** Access derivative of order <tt>(dx, dy)</tt> at real-valued coordinate <tt>d</tt>.
253  Equivalent to <tt>splineView(d[0], d[1], dx, dy)</tt>.
254  */
255  value_type operator()(difference_type const & d, unsigned int dx, unsigned int dy) const
256  { return operator()(d[0], d[1], dx, dy); }
257 
258  /** Access 1st derivative in x-direction at real-valued coordinate <tt>d</tt>.
259  Equivalent to <tt>splineView.dx(d[0], d[1])</tt>.
260  */
261  value_type dx(difference_type const & d) const
262  { return dx(d[0], d[1]); }
263 
264  /** Access 1st derivative in y-direction at real-valued coordinate <tt>d</tt>.
265  Equivalent to <tt>splineView.dy(d[0], d[1])</tt>.
266  */
267  value_type dy(difference_type const & d) const
268  { return dy(d[0], d[1]); }
269 
270  /** Access 2nd derivative in x-direction at real-valued coordinate <tt>d</tt>.
271  Equivalent to <tt>splineView.dxx(d[0], d[1])</tt>.
272  */
273  value_type dxx(difference_type const & d) const
274  { return dxx(d[0], d[1]); }
275 
276  /** Access mixed 2nd derivative at real-valued coordinate <tt>d</tt>.
277  Equivalent to <tt>splineView.dxy(d[0], d[1])</tt>.
278  */
279  value_type dxy(difference_type const & d) const
280  { return dxy(d[0], d[1]); }
281 
282  /** Access 2nd derivative in y-direction at real-valued coordinate <tt>d</tt>.
283  Equivalent to <tt>splineView.dyy(d[0], d[1])</tt>.
284  */
285  value_type dyy(difference_type const & d) const
286  { return dyy(d[0], d[1]); }
287 
288  /** Access 3rd derivative in x-direction at real-valued coordinate <tt>d</tt>.
289  Equivalent to <tt>splineView.dx3(d[0], d[1])</tt>.
290  */
291  value_type dx3(difference_type const & d) const
292  { return dx3(d[0], d[1]); }
293 
294  /** Access 3rd derivative in y-direction at real-valued coordinate <tt>d</tt>.
295  Equivalent to <tt>splineView.dy3(d[0], d[1])</tt>.
296  */
297  value_type dy3(difference_type const & d) const
298  { return dy3(d[0], d[1]); }
299 
300  /** Access mixed 3rd derivative dxxy at real-valued coordinate <tt>d</tt>.
301  Equivalent to <tt>splineView.dxxy(d[0], d[1])</tt>.
302  */
303  value_type dxxy(difference_type const & d) const
304  { return dxxy(d[0], d[1]); }
305 
306  /** Access mixed 3rd derivative dxyy at real-valued coordinate <tt>d</tt>.
307  Equivalent to <tt>splineView.dxyy(d[0], d[1])</tt>.
308  */
309  value_type dxyy(difference_type const & d) const
310  { return dxyy(d[0], d[1]); }
311 
312  /** Access gradient squared magnitude at real-valued coordinate <tt>(x, y)</tt>.
313  */
314  SquaredNormType g2(double x, double y) const;
315 
316  /** Access 1st derivative in x-direction of gradient squared magnitude
317  at real-valued coordinate <tt>(x, y)</tt>.
318  */
319  SquaredNormType g2x(double x, double y) const;
320 
321  /** Access 1st derivative in y-direction of gradient squared magnitude
322  at real-valued coordinate <tt>(x, y)</tt>.
323  */
324  SquaredNormType g2y(double x, double y) const;
325 
326  /** Access 2nd derivative in x-direction of gradient squared magnitude
327  at real-valued coordinate <tt>(x, y)</tt>.
328  */
329  SquaredNormType g2xx(double x, double y) const;
330 
331  /** Access mixed 2nd derivative of gradient squared magnitude
332  at real-valued coordinate <tt>(x, y)</tt>.
333  */
334  SquaredNormType g2xy(double x, double y) const;
335 
336  /** Access 2nd derivative in y-direction of gradient squared magnitude
337  at real-valued coordinate <tt>(x, y)</tt>.
338  */
339  SquaredNormType g2yy(double x, double y) const;
340 
341  /** Access gradient squared magnitude at real-valued coordinate <tt>d</tt>.
342  */
344  { return g2(d[0], d[1]); }
345 
346  /** Access 1st derivative in x-direction of gradient squared magnitude
347  at real-valued coordinate <tt>d</tt>.
348  */
350  { return g2x(d[0], d[1]); }
351 
352  /** Access 1st derivative in y-direction of gradient squared magnitude
353  at real-valued coordinate <tt>d</tt>.
354  */
356  { return g2y(d[0], d[1]); }
357 
358  /** Access 2nd derivative in x-direction of gradient squared magnitude
359  at real-valued coordinate <tt>d</tt>.
360  */
362  { return g2xx(d[0], d[1]); }
363 
364  /** Access mixed 2nd derivative of gradient squared magnitude
365  at real-valued coordinate <tt>d</tt>.
366  */
368  { return g2xy(d[0], d[1]); }
369 
370  /** Access 2nd derivative in y-direction of gradient squared magnitude
371  at real-valued coordinate <tt>d</tt>.
372  */
374  { return g2yy(d[0], d[1]); }
375 
376  /** The width of the image.
377  <tt>0 <= x <= width()-1</tt> is required for all access functions.
378  */
379  unsigned int width() const
380  { return w_; }
381 
382  /** The height of the image.
383  <tt>0 <= y <= height()-1</tt> is required for all access functions.
384  */
385  unsigned int height() const
386  { return h_; }
387 
388  /** The size of the image.
389  <tt>0 <= x <= size().x-1</tt> and <tt>0 <= y <= size().y-1</tt>
390  are required for all access functions.
391  */
392  size_type size() const
393  { return size_type(w_, h_); }
394 
395  /** The shape of the image.
396  Same as size(), except for the return type.
397  */
399  { return TinyVector<unsigned int, 2>(w_, h_); }
400 
401  /** The internal image holding the spline coefficients.
402  */
403  InternalImage const & image() const
404  {
405  return image_;
406  }
407 
408  /** Get the array of polynomial coefficients for the facet containing
409  the point <tt>(x, y)</tt>. The array <tt>res</tt> must have
410  dimension <tt>(ORDER+1)x(ORDER+1)</tt>. From these coefficients, the
411  value of the interpolated function can be calculated by the following
412  algorithm
413 
414  \code
415  SplineImageView<ORDER, float> view(...);
416  double x = ..., y = ...;
417  double dx, dy;
418 
419  // calculate the local facet coordinates of x and y
420  if(ORDER % 2)
421  {
422  // odd order => facet coordinates between 0 and 1
423  dx = x - floor(x);
424  dy = y - floor(y);
425  }
426  else
427  {
428  // even order => facet coordinates between -0.5 and 0.5
429  dx = x - floor(x + 0.5);
430  dy = y - floor(y + 0.5);
431  }
432 
433  BasicImage<float> coefficients;
434  view.coefficientArray(x, y, coefficients);
435 
436  float f_x_y = 0.0;
437  for(int ny = 0; ny < ORDER + 1; ++ny)
438  for(int nx = 0; nx < ORDER + 1; ++nx)
439  f_x_y += pow(dx, nx) * pow(dy, ny) * coefficients(nx, ny);
440 
441  assert(abs(f_x_y - view(x, y)) < 1e-6);
442  \endcode
443  */
444  template <class Array>
445  void coefficientArray(double x, double y, Array & res) const;
446 
447  /** Check if x is in the original image range.
448  Equivalent to <tt>0 <= x <= width()-1</tt>.
449  */
450  bool isInsideX(double x) const
451  {
452  return x >= 0.0 && x <= width()-1.0;
453  }
454 
455  /** Check if y is in the original image range.
456  Equivalent to <tt>0 <= y <= height()-1</tt>.
457  */
458  bool isInsideY(double y) const
459  {
460  return y >= 0.0 && y <= height()-1.0;
461  }
462 
463  /** Check if x and y are in the original image range.
464  Equivalent to <tt>0 <= x <= width()-1</tt> and <tt>0 <= y <= height()-1</tt>.
465  */
466  bool isInside(double x, double y) const
467  {
468  return isInsideX(x) && isInsideY(y);
469  }
470 
471  /** Check if x and y are in the valid range. Points outside the original image range are computed
472  by reflective boundary conditions, but only within the first reflection.
473  Equivalent to <tt>-width() + ORDER/2 + 2 < x < 2*width() - ORDER/2 - 2</tt> and
474  <tt>-height() + ORDER/2 + 2 < y < 2*height() - ORDER/2 - 2</tt>.
475  */
476  bool isValid(double x, double y) const
477  {
478  return x < w1_ + x1_ && x > -x1_ && y < h1_ + y1_ && y > -y1_;
479  }
480 
481  /** Check whether the points <tt>(x0, y0)</tt> and <tt>(x1, y1)</tt> are in
482  the same spline facet. For odd order splines, facets span the range
483  <tt>(floor(x), floor(x)+1) x (floor(y), floor(y)+1)</tt> (i.e. we have
484  integer facet borders), whereas even order splines have facet between
485  half integer values
486  <tt>(floor(x)-0.5, floor(x)+0.5) x (floor(y)-0.5, floor(y)+0.5)</tt>.
487  */
488  bool sameFacet(double x0, double y0, double x1, double y1) const
489  {
490  x0 = VIGRA_CSTD::floor((ORDER % 2) ? x0 : x0 + 0.5);
491  y0 = VIGRA_CSTD::floor((ORDER % 2) ? y0 : y0 + 0.5);
492  x1 = VIGRA_CSTD::floor((ORDER % 2) ? x1 : x1 + 0.5);
493  y1 = VIGRA_CSTD::floor((ORDER % 2) ? y1 : y1 + 0.5);
494  return x0 == x1 && y0 == y1;
495  }
496 
497  protected:
498 
499  void init();
500  void calculateIndices(double x, double y) const;
501  void coefficients(double t, double * const & c) const;
502  void derivCoefficients(double t, unsigned int d, double * const & c) const;
503  value_type convolve() const;
504 
505  unsigned int w_, h_;
506  int w1_, h1_;
507  double x0_, x1_, y0_, y1_;
508  InternalImage image_;
509  Spline k_;
510  mutable double x_, y_, u_, v_, kx_[ksize_], ky_[ksize_];
511  mutable int ix_[ksize_], iy_[ksize_];
512 };
513 
514 template <int ORDER, class VALUETYPE>
515 void SplineImageView<ORDER, VALUETYPE>::init()
516 {
517  ArrayVector<double> const & b = k_.prefilterCoefficients();
518 
519  for(unsigned int i=0; i<b.size(); ++i)
520  {
521  recursiveFilterX(srcImageRange(image_), destImage(image_), b[i], BORDER_TREATMENT_REFLECT);
522  recursiveFilterY(srcImageRange(image_), destImage(image_), b[i], BORDER_TREATMENT_REFLECT);
523  }
524 }
525 
526 namespace detail
527 {
528 
529 template <int i>
530 struct SplineImageViewUnrollLoop1
531 {
532  template <class Array>
533  static void exec(int c0, Array c)
534  {
535  SplineImageViewUnrollLoop1<i-1>::exec(c0, c);
536  c[i] = c0 + i;
537  }
538 };
539 
540 template <>
541 struct SplineImageViewUnrollLoop1<0>
542 {
543  template <class Array>
544  static void exec(int c0, Array c)
545  {
546  c[0] = c0;
547  }
548 };
549 
550 template <int i, class ValueType>
551 struct SplineImageViewUnrollLoop2
552 {
553  template <class Array1, class RowIterator, class Array2>
554  static ValueType
555  exec(Array1 k, RowIterator r, Array2 x)
556  {
557  return ValueType(k[i] * r[x[i]]) + SplineImageViewUnrollLoop2<i-1, ValueType>::exec(k, r, x);
558  }
559 };
560 
561 template <class ValueType>
562 struct SplineImageViewUnrollLoop2<0, ValueType>
563 {
564  template <class Array1, class RowIterator, class Array2>
565  static ValueType
566  exec(Array1 k, RowIterator r, Array2 x)
567  {
568  return ValueType(k[0] * r[x[0]]);
569  }
570 };
571 
572 } // namespace detail
573 
574 template <int ORDER, class VALUETYPE>
575 void
576 SplineImageView<ORDER, VALUETYPE>::calculateIndices(double x, double y) const
577 {
578  if(x == x_ && y == y_)
579  return; // still in cache
580 
581  if(x > x0_ && x < x1_ && y > y0_ && y < y1_)
582  {
583  detail::SplineImageViewUnrollLoop1<ORDER>::exec(
584  (ORDER % 2) ? int(x - kcenter_) : int(x + 0.5 - kcenter_), ix_);
585  detail::SplineImageViewUnrollLoop1<ORDER>::exec(
586  (ORDER % 2) ? int(y - kcenter_) : int(y + 0.5 - kcenter_), iy_);
587 
588  u_ = x - ix_[kcenter_];
589  v_ = y - iy_[kcenter_];
590  }
591  else
592  {
593  vigra_precondition(isValid(x,y),
594  "SplineImageView::calculateIndices(): coordinates out of range.");
595 
596  int xCenter = (ORDER % 2) ?
597  (int)VIGRA_CSTD::floor(x) :
598  (int)VIGRA_CSTD::floor(x + 0.5);
599  int yCenter = (ORDER % 2) ?
600  (int)VIGRA_CSTD::floor(y) :
601  (int)VIGRA_CSTD::floor(y + 0.5);
602 
603  if(x >= x1_)
604  {
605  for(int i = 0; i < ksize_; ++i)
606  ix_[i] = w1_ - vigra::abs(w1_ - xCenter - (i - kcenter_));
607  }
608  else
609  {
610  for(int i = 0; i < ksize_; ++i)
611  ix_[i] = vigra::abs(xCenter - (kcenter_ - i));
612  }
613  if(y >= y1_)
614  {
615  for(int i = 0; i < ksize_; ++i)
616  iy_[i] = h1_ - vigra::abs(h1_ - yCenter - (i - kcenter_));
617  }
618  else
619  {
620  for(int i = 0; i < ksize_; ++i)
621  iy_[i] = vigra::abs(yCenter - (kcenter_ - i));
622  }
623  u_ = x - xCenter;
624  v_ = y - yCenter;
625  }
626  x_ = x;
627  y_ = y;
628 }
629 
630 template <int ORDER, class VALUETYPE>
631 void SplineImageView<ORDER, VALUETYPE>::coefficients(double t, double * const & c) const
632 {
633  t += kcenter_;
634  for(int i = 0; i<ksize_; ++i)
635  c[i] = k_(t-i);
636 }
637 
638 template <int ORDER, class VALUETYPE>
639 void SplineImageView<ORDER, VALUETYPE>::derivCoefficients(double t,
640  unsigned int d, double * const & c) const
641 {
642  t += kcenter_;
643  for(int i = 0; i<ksize_; ++i)
644  c[i] = k_(t-i, d);
645 }
646 
647 template <int ORDER, class VALUETYPE>
648 VALUETYPE SplineImageView<ORDER, VALUETYPE>::convolve() const
649 {
650  typedef typename NumericTraits<VALUETYPE>::RealPromote RealPromote;
651  RealPromote sum;
652  sum = RealPromote(
653  ky_[0]*detail::SplineImageViewUnrollLoop2<ORDER, RealPromote>::exec(kx_, image_.rowBegin(iy_[0]), ix_));
654 
655  for(int j=1; j<ksize_; ++j)
656  {
657  sum += RealPromote(
658  ky_[j]*detail::SplineImageViewUnrollLoop2<ORDER, RealPromote>::exec(kx_, image_.rowBegin(iy_[j]), ix_));
659  }
660  return detail::RequiresExplicitCast<VALUETYPE>::cast(sum);
661 }
662 
663 template <int ORDER, class VALUETYPE>
664 template <class Array>
665 void
666 SplineImageView<ORDER, VALUETYPE>::coefficientArray(double x, double y, Array & res) const
667 {
668  typedef typename Array::value_type ResType;
669  typename Spline::WeightMatrix & weights = Spline::weights();
670  ResType tmp[ksize_][ksize_];
671 
672  calculateIndices(x, y);
673  for(int j=0; j<ksize_; ++j)
674  {
675  for(int i=0; i<ksize_; ++i)
676  {
677  tmp[i][j] = ResType();
678  for(int k=0; k<ksize_; ++k)
679  {
680  tmp[i][j] += weights[i][k]*image_(ix_[k], iy_[j]);
681  }
682  }
683  }
684  for(int j=0; j<ksize_; ++j)
685  {
686  for(int i=0; i<ksize_; ++i)
687  {
688  res(i,j) = ResType();
689  for(int k=0; k<ksize_; ++k)
690  {
691  res(i,j) += weights[j][k]*tmp[i][k];
692  }
693  }
694  }
695 }
696 
697 template <int ORDER, class VALUETYPE>
698 VALUETYPE SplineImageView<ORDER, VALUETYPE>::operator()(double x, double y) const
699 {
700  calculateIndices(x, y);
701  coefficients(u_, kx_);
702  coefficients(v_, ky_);
703  return convolve();
704 }
705 
706 template <int ORDER, class VALUETYPE>
708  unsigned int dx, unsigned int dy) const
709 {
710  calculateIndices(x, y);
711  derivCoefficients(u_, dx, kx_);
712  derivCoefficients(v_, dy, ky_);
713  return convolve();
714 }
715 
716 template <int ORDER, class VALUETYPE>
718 SplineImageView<ORDER, VALUETYPE>::g2(double x, double y) const
719 {
720  return squaredNorm(dx(x,y)) + squaredNorm(dy(x,y));
721 }
722 
723 template <int ORDER, class VALUETYPE>
725 SplineImageView<ORDER, VALUETYPE>::g2x(double x, double y) const
726 {
727  return SquaredNormType(2.0)*(dot(dx(x,y), dxx(x,y)) + dot(dy(x,y), dxy(x,y)));
728 }
729 
730 template <int ORDER, class VALUETYPE>
732 SplineImageView<ORDER, VALUETYPE>::g2y(double x, double y) const
733 {
734  return SquaredNormType(2.0)*(dot(dx(x,y), dxy(x,y)) + dot(dy(x,y), dyy(x,y)));
735 }
736 
737 template <int ORDER, class VALUETYPE>
740 {
741  return SquaredNormType(2.0)*(squaredNorm(dxx(x,y)) + dot(dx(x,y), dx3(x,y)) +
742  squaredNorm(dxy(x,y)) + dot(dy(x,y), dxxy(x,y)));
743 }
744 
745 template <int ORDER, class VALUETYPE>
748 {
749  return SquaredNormType(2.0)*(squaredNorm(dxy(x,y)) + dot(dx(x,y), dxyy(x,y)) +
750  squaredNorm(dyy(x,y)) + dot(dy(x,y), dy3(x,y)));
751 }
752 
753 template <int ORDER, class VALUETYPE>
756 {
757  return SquaredNormType(2.0)*(dot(dx(x,y), dxxy(x,y)) + dot(dy(x,y), dxyy(x,y)) +
758  dot(dxy(x,y), dxx(x,y) + dyy(x,y)));
759 }
760 
761 /********************************************************/
762 /* */
763 /* SplineImageView0 */
764 /* */
765 /********************************************************/
766 template <class VALUETYPE, class INTERNAL_INDEXER>
767 class SplineImageView0Base
768 {
769  typedef typename INTERNAL_INDEXER::value_type InternalValue;
770  public:
771  typedef VALUETYPE value_type;
772  typedef typename NormTraits<VALUETYPE>::SquaredNormType SquaredNormType;
773  typedef Size2D size_type;
774  typedef TinyVector<double, 2> difference_type;
775  enum StaticOrder { order = 0 };
776 
777  public:
778 
779  SplineImageView0Base(unsigned int w, unsigned int h)
780  : w_(w), h_(h)
781  {}
782 
783  SplineImageView0Base(int w, int h, INTERNAL_INDEXER i)
784  : w_(w), h_(h), internalIndexer_(i)
785  {}
786 
787  template <unsigned IntBits1, unsigned FractionalBits1,
788  unsigned IntBits2, unsigned FractionalBits2>
789  value_type unchecked(FixedPoint<IntBits1, FractionalBits1> x,
790  FixedPoint<IntBits2, FractionalBits2> y) const
791  {
792  return internalIndexer_(round(x), round(y));
793  }
794 
795  template <unsigned IntBits1, unsigned FractionalBits1,
796  unsigned IntBits2, unsigned FractionalBits2>
797  value_type unchecked(FixedPoint<IntBits1, FractionalBits1> x,
798  FixedPoint<IntBits2, FractionalBits2> y,
799  unsigned int dx, unsigned int dy) const
800  {
801  if((dx != 0) || (dy != 0))
802  return NumericTraits<VALUETYPE>::zero();
803  return unchecked(x, y);
804  }
805 
806  value_type unchecked(double x, double y) const
807  {
808  return internalIndexer_((int)(x + 0.5), (int)(y + 0.5));
809  }
810 
811  value_type unchecked(double x, double y, unsigned int dx, unsigned int dy) const
812  {
813  if((dx != 0) || (dy != 0))
814  return NumericTraits<VALUETYPE>::zero();
815  return unchecked(x, y);
816  }
817 
818  value_type operator()(double x, double y) const
819  {
820  int ix, iy;
821  if(x < 0.0)
822  {
823  ix = (int)(-x + 0.5);
824  vigra_precondition(ix <= (int)w_ - 1,
825  "SplineImageView::operator(): coordinates out of range.");
826  }
827  else
828  {
829  ix = (int)(x + 0.5);
830  if(ix >= (int)w_)
831  {
832  ix = 2*w_-2-ix;
833  vigra_precondition(ix >= 0,
834  "SplineImageView::operator(): coordinates out of range.");
835  }
836  }
837  if(y < 0.0)
838  {
839  iy = (int)(-y + 0.5);
840  vigra_precondition(iy <= (int)h_ - 1,
841  "SplineImageView::operator(): coordinates out of range.");
842  }
843  else
844  {
845  iy = (int)(y + 0.5);
846  if(iy >= (int)h_)
847  {
848  iy = 2*h_-2-iy;
849  vigra_precondition(iy >= 0,
850  "SplineImageView::operator(): coordinates out of range.");
851  }
852  }
853  return internalIndexer_(ix, iy);
854  }
855 
856  value_type operator()(double x, double y, unsigned int dx, unsigned int dy) const
857  {
858  if((dx != 0) || (dy != 0))
859  return NumericTraits<VALUETYPE>::zero();
860  return operator()(x, y);
861  }
862 
863  value_type dx(double x, double y) const
864  { return NumericTraits<VALUETYPE>::zero(); }
865 
866  value_type dy(double x, double y) const
867  { return NumericTraits<VALUETYPE>::zero(); }
868 
869  value_type dxx(double x, double y) const
870  { return NumericTraits<VALUETYPE>::zero(); }
871 
872  value_type dxy(double x, double y) const
873  { return NumericTraits<VALUETYPE>::zero(); }
874 
875  value_type dyy(double x, double y) const
876  { return NumericTraits<VALUETYPE>::zero(); }
877 
878  value_type dx3(double x, double y) const
879  { return NumericTraits<VALUETYPE>::zero(); }
880 
881  value_type dy3(double x, double y) const
882  { return NumericTraits<VALUETYPE>::zero(); }
883 
884  value_type dxxy(double x, double y) const
885  { return NumericTraits<VALUETYPE>::zero(); }
886 
887  value_type dxyy(double x, double y) const
888  { return NumericTraits<VALUETYPE>::zero(); }
889 
890  value_type operator()(difference_type const & d) const
891  { return operator()(d[0], d[1]); }
892 
893  value_type operator()(difference_type const & d, unsigned int dx, unsigned int dy) const
894  { return operator()(d[0], d[1], dx, dy); }
895 
896  value_type dx(difference_type const & d) const
897  { return NumericTraits<VALUETYPE>::zero(); }
898 
899  value_type dy(difference_type const & d) const
900  { return NumericTraits<VALUETYPE>::zero(); }
901 
902  value_type dxx(difference_type const & d) const
903  { return NumericTraits<VALUETYPE>::zero(); }
904 
905  value_type dxy(difference_type const & d) const
906  { return NumericTraits<VALUETYPE>::zero(); }
907 
908  value_type dyy(difference_type const & d) const
909  { return NumericTraits<VALUETYPE>::zero(); }
910 
911  value_type dx3(difference_type const & d) const
912  { return NumericTraits<VALUETYPE>::zero(); }
913 
914  value_type dy3(difference_type const & d) const
915  { return NumericTraits<VALUETYPE>::zero(); }
916 
917  value_type dxxy(difference_type const & d) const
918  { return NumericTraits<VALUETYPE>::zero(); }
919 
920  value_type dxyy(difference_type const & d) const
921  { return NumericTraits<VALUETYPE>::zero(); }
922 
923  SquaredNormType g2(double x, double y) const
924  { return NumericTraits<SquaredNormType>::zero(); }
925 
926  SquaredNormType g2x(double x, double y) const
927  { return NumericTraits<SquaredNormType>::zero(); }
928 
929  SquaredNormType g2y(double x, double y) const
930  { return NumericTraits<SquaredNormType>::zero(); }
931 
932  SquaredNormType g2xx(double x, double y) const
933  { return NumericTraits<SquaredNormType>::zero(); }
934 
935  SquaredNormType g2xy(double x, double y) const
936  { return NumericTraits<SquaredNormType>::zero(); }
937 
938  SquaredNormType g2yy(double x, double y) const
939  { return NumericTraits<SquaredNormType>::zero(); }
940 
941  SquaredNormType g2(difference_type const & d) const
942  { return NumericTraits<SquaredNormType>::zero(); }
943 
944  SquaredNormType g2x(difference_type const & d) const
945  { return NumericTraits<SquaredNormType>::zero(); }
946 
947  SquaredNormType g2y(difference_type const & d) const
948  { return NumericTraits<SquaredNormType>::zero(); }
949 
950  SquaredNormType g2xx(difference_type const & d) const
951  { return NumericTraits<SquaredNormType>::zero(); }
952 
953  SquaredNormType g2xy(difference_type const & d) const
954  { return NumericTraits<SquaredNormType>::zero(); }
955 
956  SquaredNormType g2yy(difference_type const & d) const
957  { return NumericTraits<SquaredNormType>::zero(); }
958 
959  unsigned int width() const
960  { return w_; }
961 
962  unsigned int height() const
963  { return h_; }
964 
965  size_type size() const
966  { return size_type(w_, h_); }
967 
968  TinyVector<unsigned int, 2> shape() const
969  { return TinyVector<unsigned int, 2>(w_, h_); }
970 
971  template <class Array>
972  void coefficientArray(double x, double y, Array & res) const
973  {
974  res(0, 0) = operator()(x,y);
975  }
976 
977  bool isInsideX(double x) const
978  {
979  return x >= 0.0 && x <= width() - 1.0;
980  }
981 
982  bool isInsideY(double y) const
983  {
984  return y >= 0.0 && y <= height() - 1.0;
985  }
986 
987  bool isInside(double x, double y) const
988  {
989  return isInsideX(x) && isInsideY(y);
990  }
991 
992  bool isValid(double x, double y) const
993  {
994  return x < 2.0*w_-2.0 && x > 1.0-w_ && y < 2.0*h_-2.0 && y > 1.0-h_;
995  }
996 
997  bool sameFacet(double x0, double y0, double x1, double y1) const
998  {
999  x0 = VIGRA_CSTD::floor(x0 + 0.5);
1000  y0 = VIGRA_CSTD::floor(y0 + 0.5);
1001  x1 = VIGRA_CSTD::floor(x1 + 0.5);
1002  y1 = VIGRA_CSTD::floor(y1 + 0.5);
1003  return x0 == x1 && y0 == y1;
1004  }
1005 
1006  protected:
1007  unsigned int w_, h_;
1008  INTERNAL_INDEXER internalIndexer_;
1009 };
1010 
1011 /** \brief Create an image view for nearest-neighbor interpolation.
1012 
1013  This class behaves like \ref vigra::SplineImageView&lt;0, ...&gt;, but one can pass
1014  an additional template argument that determined the internal representation of the image.
1015  If this is equal to the argument type passed in the constructor, the image is not copied.
1016  By default, this works for \ref vigra::BasicImage, \ref vigra::BasicImageView,
1017  \ref vigra::MultiArray&lt;2, ...&gt;, and \ref vigra::MultiArrayView&lt;2, ...&gt;.
1018 
1019 */
1020 template <class VALUETYPE, class INTERNAL_TRAVERSER = typename BasicImage<VALUETYPE>::const_traverser>
1022 : public SplineImageView0Base<VALUETYPE, INTERNAL_TRAVERSER>
1023 {
1024  typedef SplineImageView0Base<VALUETYPE, INTERNAL_TRAVERSER> Base;
1025  public:
1026  typedef typename Base::value_type value_type;
1027  typedef typename Base::SquaredNormType SquaredNormType;
1028  typedef typename Base::size_type size_type;
1029  typedef typename Base::difference_type difference_type;
1030  enum StaticOrder { order = Base::order };
1032 
1033  protected:
1034  typedef typename IteratorTraits<INTERNAL_TRAVERSER>::mutable_iterator InternalTraverser;
1036  typedef typename IteratorTraits<INTERNAL_TRAVERSER>::const_iterator InternalConstTraverser;
1038 
1039  public:
1040 
1041  /* when traverser and accessor types passed to the constructor are the same as the corresponding
1042  internal types, we need not copy the image (speed up)
1043  */
1044  SplineImageView0(InternalTraverser is, InternalTraverser iend, InternalAccessor sa)
1045  : Base(iend.x - is.x, iend.y - is.y, is)
1046  {}
1047 
1048  SplineImageView0(triple<InternalTraverser, InternalTraverser, InternalAccessor> s)
1049  : Base(s.second.x - s.first.x, s.second.y - s.first.y, s.first)
1050  {}
1051 
1052  SplineImageView0(InternalConstTraverser is, InternalConstTraverser iend, InternalConstAccessor sa)
1053  : Base(iend.x - is.x, iend.y - is.y, is)
1054  {}
1055 
1056  SplineImageView0(triple<InternalConstTraverser, InternalConstTraverser, InternalConstAccessor> s)
1057  : Base(s.second.x - s.first.x, s.second.y - s.first.y, s.first)
1058  {}
1059 
1060  template<class T, class SU>
1062  : Base(i.shape(0), i.shape(1)),
1063  image_(i.shape(0), i.shape(1))
1064  {
1065  for(unsigned int y=0; y<this->height(); ++y)
1066  for(unsigned int x=0; x<this->width(); ++x)
1067  image_(x,y) = detail::RequiresExplicitCast<VALUETYPE>::cast(i(x,y));
1068  this->internalIndexer_ = image_.upperLeft();
1069  }
1070 
1071  template <class SrcIterator, class SrcAccessor>
1072  SplineImageView0(SrcIterator is, SrcIterator iend, SrcAccessor sa)
1073  : Base(iend.x - is.x, iend.y - is.y),
1074  image_(iend - is)
1075  {
1076  copyImage(srcIterRange(is, iend, sa), destImage(image_));
1077  this->internalIndexer_ = image_.upperLeft();
1078  }
1079 
1080  template <class SrcIterator, class SrcAccessor>
1081  SplineImageView0(triple<SrcIterator, SrcIterator, SrcAccessor> s)
1082  : Base(s.second.x - s.first.x, s.second.y - s.first.y),
1083  image_(s.second - s.first)
1084  {
1085  copyImage(s, destImage(image_));
1086  this->internalIndexer_ = image_.upperLeft();
1087  }
1088 
1089  InternalImage const & image() const
1090  { return image_; }
1091 
1092  protected:
1093  InternalImage image_;
1094 };
1095 
1096 template <class VALUETYPE, class StridedOrUnstrided>
1097 class SplineImageView0<VALUETYPE, MultiArrayView<2, VALUETYPE, StridedOrUnstrided> >
1098 : public SplineImageView0Base<VALUETYPE, MultiArrayView<2, VALUETYPE, StridedOrUnstrided> >
1099 {
1100  typedef SplineImageView0Base<VALUETYPE, MultiArrayView<2, VALUETYPE, StridedOrUnstrided> > Base;
1101  public:
1102  typedef typename Base::value_type value_type;
1103  typedef typename Base::SquaredNormType SquaredNormType;
1104  typedef typename Base::size_type size_type;
1105  typedef typename Base::difference_type difference_type;
1106  enum StaticOrder { order = Base::order };
1107  typedef BasicImage<VALUETYPE> InternalImage;
1108 
1109  protected:
1110  typedef MultiArrayView<2, VALUETYPE, StridedOrUnstrided> InternalIndexer;
1111 
1112  public:
1113 
1114  /* when traverser and accessor types passed to the constructor are the same as the corresponding
1115  internal types, we need not copy the image (speed up)
1116  */
1117  SplineImageView0(InternalIndexer const & i)
1118  : Base(i.shape(0), i.shape(1), i)
1119  {}
1120 
1121  template<class T, class SU>
1122  SplineImageView0(MultiArrayView<2, T, SU> const & i)
1123  : Base(i.shape(0), i.shape(1)),
1124  image_(i.shape(0), i.shape(1))
1125  {
1126  for(unsigned int y=0; y<this->height(); ++y)
1127  for(unsigned int x=0; x<this->width(); ++x)
1128  image_(x,y) = detail::RequiresExplicitCast<VALUETYPE>::cast(i(x,y));
1129  this->internalIndexer_ = InternalIndexer(typename InternalIndexer::difference_type(this->width(), this->height()),
1130  image_.data());
1131  }
1132 
1133  template <class SrcIterator, class SrcAccessor>
1134  SplineImageView0(SrcIterator is, SrcIterator iend, SrcAccessor sa)
1135  : Base(iend.x - is.x, iend.y - is.y),
1136  image_(iend-is)
1137  {
1138  copyImage(srcIterRange(is, iend, sa), destImage(image_));
1139  this->internalIndexer_ = InternalIndexer(typename InternalIndexer::difference_type(this->width(), this->height()),
1140  image_.data());
1141  }
1142 
1143  template <class SrcIterator, class SrcAccessor>
1144  SplineImageView0(triple<SrcIterator, SrcIterator, SrcAccessor> s)
1145  : Base(s.second.x - s.first.x, s.second.y - s.first.y),
1146  image_(s.second - s.first)
1147  {
1148  copyImage(s, destImage(image_));
1149  this->internalIndexer_ = InternalIndexer(typename InternalIndexer::difference_type(this->width(), this->height()),
1150  image_.data());
1151  }
1152 
1153  InternalImage const & image() const
1154  { return image_; }
1155 
1156  protected:
1157  InternalImage image_;
1158 };
1159 
1160 template <class VALUETYPE>
1161 class SplineImageView<0, VALUETYPE>
1162 : public SplineImageView0<VALUETYPE>
1163 {
1164  typedef SplineImageView0<VALUETYPE> Base;
1165  public:
1166  typedef typename Base::value_type value_type;
1167  typedef typename Base::SquaredNormType SquaredNormType;
1168  typedef typename Base::size_type size_type;
1169  typedef typename Base::difference_type difference_type;
1170  enum StaticOrder { order = Base::order };
1171  typedef typename Base::InternalImage InternalImage;
1172 
1173  protected:
1174  typedef typename Base::InternalTraverser InternalTraverser;
1175  typedef typename Base::InternalAccessor InternalAccessor;
1176  typedef typename Base::InternalConstTraverser InternalConstTraverser;
1177  typedef typename Base::InternalConstAccessor InternalConstAccessor;
1178 
1179 public:
1180 
1181  /* when traverser and accessor types passed to the constructor are the same as the corresponding
1182  internal types, we need not copy the image (speed up)
1183  */
1184  SplineImageView(InternalTraverser is, InternalTraverser iend, InternalAccessor sa, bool /* unused */ = false)
1185  : Base(is, iend, sa)
1186  {}
1187 
1188  SplineImageView(triple<InternalTraverser, InternalTraverser, InternalAccessor> s, bool /* unused */ = false)
1189  : Base(s)
1190  {}
1191 
1192  SplineImageView(InternalConstTraverser is, InternalConstTraverser iend, InternalConstAccessor sa, bool /* unused */ = false)
1193  : Base(is, iend, sa)
1194  {}
1195 
1196  SplineImageView(triple<InternalConstTraverser, InternalConstTraverser, InternalConstAccessor> s, bool /* unused */ = false)
1197  : Base(s)
1198  {}
1199 
1200  template <class SrcIterator, class SrcAccessor>
1201  SplineImageView(SrcIterator is, SrcIterator iend, SrcAccessor sa, bool /* unused */ = false)
1202  : Base(is, iend, sa)
1203  {
1204  copyImage(srcIterRange(is, iend, sa), destImage(this->image_));
1205  }
1206 
1207  template <class SrcIterator, class SrcAccessor>
1208  SplineImageView(triple<SrcIterator, SrcIterator, SrcAccessor> s, bool /* unused */ = false)
1209  : Base(s)
1210  {
1211  copyImage(s, destImage(this->image_));
1212  }
1213 };
1214 
1215 /********************************************************/
1216 /* */
1217 /* SplineImageView1 */
1218 /* */
1219 /********************************************************/
1220 template <class VALUETYPE, class INTERNAL_INDEXER>
1221 class SplineImageView1Base
1222 {
1223  typedef typename INTERNAL_INDEXER::value_type InternalValue;
1224  public:
1225  typedef VALUETYPE value_type;
1226  typedef Size2D size_type;
1227  typedef typename NormTraits<VALUETYPE>::SquaredNormType SquaredNormType;
1228  typedef TinyVector<double, 2> difference_type;
1229  enum StaticOrder { order = 1 };
1230 
1231  public:
1232 
1233  SplineImageView1Base(unsigned int w, unsigned int h)
1234  : w_(w), h_(h)
1235  {}
1236 
1237  SplineImageView1Base(int w, int h, INTERNAL_INDEXER i)
1238  : w_(w), h_(h), internalIndexer_(i)
1239  {}
1240 
1241  template <unsigned IntBits1, unsigned FractionalBits1,
1242  unsigned IntBits2, unsigned FractionalBits2>
1243  value_type unchecked(FixedPoint<IntBits1, FractionalBits1> x,
1244  FixedPoint<IntBits2, FractionalBits2> y) const
1245  {
1246  int ix = floor(x);
1247  FixedPoint<0, FractionalBits1> tx = frac(x - FixedPoint<IntBits1, FractionalBits1>(ix));
1248  FixedPoint<0, FractionalBits1> dtx = dual_frac(tx);
1249  if(ix == (int)w_ - 1)
1250  {
1251  --ix;
1252  tx.value = FixedPoint<0, FractionalBits1>::ONE;
1253  dtx.value = 0;
1254  }
1255  int iy = floor(y);
1256  FixedPoint<0, FractionalBits2> ty = frac(y - FixedPoint<IntBits2, FractionalBits2>(iy));
1257  FixedPoint<0, FractionalBits2> dty = dual_frac(ty);
1258  if(iy == (int)h_ - 1)
1259  {
1260  --iy;
1261  ty.value = FixedPoint<0, FractionalBits2>::ONE;
1262  dty.value = 0;
1263  }
1264  return fixed_point_cast<value_type>(
1265  dty*(dtx*fixedPoint(internalIndexer_(ix,iy)) +
1266  tx*fixedPoint(internalIndexer_(ix+1,iy))) +
1267  ty *(dtx*fixedPoint(internalIndexer_(ix,iy+1)) +
1268  tx*fixedPoint(internalIndexer_(ix+1,iy+1))));
1269  }
1270 
1271  template <unsigned IntBits1, unsigned FractionalBits1,
1272  unsigned IntBits2, unsigned FractionalBits2>
1273  value_type unchecked(FixedPoint<IntBits1, FractionalBits1> x,
1274  FixedPoint<IntBits2, FractionalBits2> y,
1275  unsigned int dx, unsigned int dy) const
1276  {
1277  int ix = floor(x);
1278  FixedPoint<0, FractionalBits1> tx = frac(x - FixedPoint<IntBits1, FractionalBits1>(ix));
1279  FixedPoint<0, FractionalBits1> dtx = dual_frac(tx);
1280  if(ix == (int)w_ - 1)
1281  {
1282  --ix;
1283  tx.value = FixedPoint<0, FractionalBits1>::ONE;
1284  dtx.value = 0;
1285  }
1286  int iy = floor(y);
1287  FixedPoint<0, FractionalBits2> ty = frac(y - FixedPoint<IntBits2, FractionalBits2>(iy));
1288  FixedPoint<0, FractionalBits2> dty = dual_frac(ty);
1289  if(iy == (int)h_ - 1)
1290  {
1291  --iy;
1292  ty.value = FixedPoint<0, FractionalBits2>::ONE;
1293  dty.value = 0;
1294  }
1295  switch(dx)
1296  {
1297  case 0:
1298  switch(dy)
1299  {
1300  case 0:
1301  return fixed_point_cast<value_type>(
1302  dty*(dtx*fixedPoint(internalIndexer_(ix,iy)) +
1303  tx*fixedPoint(internalIndexer_(ix+1,iy))) +
1304  ty *(dtx*fixedPoint(internalIndexer_(ix,iy+1)) +
1305  tx*fixedPoint(internalIndexer_(ix+1,iy+1))));
1306  case 1:
1307  return fixed_point_cast<value_type>(
1308  (dtx*fixedPoint(internalIndexer_(ix,iy+1)) + tx*fixedPoint(internalIndexer_(ix+1,iy+1))) -
1309  (dtx*fixedPoint(internalIndexer_(ix,iy)) + tx*fixedPoint(internalIndexer_(ix+1,iy))));
1310  default:
1311  return NumericTraits<VALUETYPE>::zero();
1312  }
1313  case 1:
1314  switch(dy)
1315  {
1316  case 0:
1317  return fixed_point_cast<value_type>(
1318  dty*(fixedPoint(internalIndexer_(ix+1,iy)) - fixedPoint(internalIndexer_(ix,iy))) +
1319  ty *(fixedPoint(internalIndexer_(ix+1,iy+1)) - fixedPoint(internalIndexer_(ix,iy+1))));
1320  case 1:
1321  return detail::RequiresExplicitCast<value_type>::cast(
1322  (internalIndexer_(ix+1,iy+1) - internalIndexer_(ix,iy+1)) -
1323  (internalIndexer_(ix+1,iy) - internalIndexer_(ix,iy)));
1324  default:
1325  return NumericTraits<VALUETYPE>::zero();
1326  }
1327  default:
1328  return NumericTraits<VALUETYPE>::zero();
1329  }
1330  }
1331 
1332  value_type unchecked(double x, double y) const
1333  {
1334  int ix = (int)std::floor(x);
1335  if(ix == (int)w_ - 1)
1336  --ix;
1337  double tx = x - ix;
1338  int iy = (int)std::floor(y);
1339  if(iy == (int)h_ - 1)
1340  --iy;
1341  double ty = y - iy;
1342  return NumericTraits<value_type>::fromRealPromote(
1343  (1.0-ty)*((1.0-tx)*internalIndexer_(ix,iy) + tx*internalIndexer_(ix+1,iy)) +
1344  ty *((1.0-tx)*internalIndexer_(ix,iy+1) + tx*internalIndexer_(ix+1,iy+1)));
1345  }
1346 
1347  value_type unchecked(double x, double y, unsigned int dx, unsigned int dy) const
1348  {
1349  int ix = (int)std::floor(x);
1350  if(ix == (int)w_ - 1)
1351  --ix;
1352  double tx = x - ix;
1353  int iy = (int)std::floor(y);
1354  if(iy == (int)h_ - 1)
1355  --iy;
1356  double ty = y - iy;
1357  switch(dx)
1358  {
1359  case 0:
1360  switch(dy)
1361  {
1362  case 0:
1363  return detail::RequiresExplicitCast<value_type>::cast(
1364  (1.0-ty)*((1.0-tx)*internalIndexer_(ix,iy) + tx*internalIndexer_(ix+1,iy)) +
1365  ty *((1.0-tx)*internalIndexer_(ix,iy+1) + tx*internalIndexer_(ix+1,iy+1)));
1366  case 1:
1367  return detail::RequiresExplicitCast<value_type>::cast(
1368  ((1.0-tx)*internalIndexer_(ix,iy+1) + tx*internalIndexer_(ix+1,iy+1)) -
1369  ((1.0-tx)*internalIndexer_(ix,iy) + tx*internalIndexer_(ix+1,iy)));
1370  default:
1371  return NumericTraits<VALUETYPE>::zero();
1372  }
1373  case 1:
1374  switch(dy)
1375  {
1376  case 0:
1377  return detail::RequiresExplicitCast<value_type>::cast(
1378  (1.0-ty)*(internalIndexer_(ix+1,iy) - internalIndexer_(ix,iy)) +
1379  ty *(internalIndexer_(ix+1,iy+1) - internalIndexer_(ix,iy+1)));
1380  case 1:
1381  return detail::RequiresExplicitCast<value_type>::cast(
1382  (internalIndexer_(ix+1,iy+1) - internalIndexer_(ix,iy+1)) -
1383  (internalIndexer_(ix+1,iy) - internalIndexer_(ix,iy)));
1384  default:
1385  return NumericTraits<VALUETYPE>::zero();
1386  }
1387  default:
1388  return NumericTraits<VALUETYPE>::zero();
1389  }
1390  }
1391 
1392  value_type operator()(double x, double y) const
1393  {
1394  return operator()(x, y, 0, 0);
1395  }
1396 
1397  value_type operator()(double x, double y, unsigned int dx, unsigned int dy) const
1398  {
1399  value_type mul = NumericTraits<value_type>::one();
1400  if(x < 0.0)
1401  {
1402  x = -x;
1403  vigra_precondition(x <= w_ - 1.0,
1404  "SplineImageView::operator(): coordinates out of range.");
1405  if(dx % 2)
1406  mul = -mul;
1407  }
1408  else if(x > w_ - 1.0)
1409  {
1410  x = 2.0*w_-2.0-x;
1411  vigra_precondition(x >= 0.0,
1412  "SplineImageView::operator(): coordinates out of range.");
1413  if(dx % 2)
1414  mul = -mul;
1415  }
1416  if(y < 0.0)
1417  {
1418  y = -y;
1419  vigra_precondition(y <= h_ - 1.0,
1420  "SplineImageView::operator(): coordinates out of range.");
1421  if(dy % 2)
1422  mul = -mul;
1423  }
1424  else if(y > h_ - 1.0)
1425  {
1426  y = 2.0*h_-2.0-y;
1427  vigra_precondition(y >= 0.0,
1428  "SplineImageView::operator(): coordinates out of range.");
1429  if(dy % 2)
1430  mul = -mul;
1431  }
1432  return mul*unchecked(x, y, dx, dy);
1433  }
1434 
1435  value_type dx(double x, double y) const
1436  { return operator()(x, y, 1, 0); }
1437 
1438  value_type dy(double x, double y) const
1439  { return operator()(x, y, 0, 1); }
1440 
1441  value_type dxx(double x, double y) const
1442  { return NumericTraits<VALUETYPE>::zero(); }
1443 
1444  value_type dxy(double x, double y) const
1445  { return operator()(x, y, 1, 1); }
1446 
1447  value_type dyy(double x, double y) const
1448  { return NumericTraits<VALUETYPE>::zero(); }
1449 
1450  value_type dx3(double x, double y) const
1451  { return NumericTraits<VALUETYPE>::zero(); }
1452 
1453  value_type dy3(double x, double y) const
1454  { return NumericTraits<VALUETYPE>::zero(); }
1455 
1456  value_type dxxy(double x, double y) const
1457  { return NumericTraits<VALUETYPE>::zero(); }
1458 
1459  value_type dxyy(double x, double y) const
1460  { return NumericTraits<VALUETYPE>::zero(); }
1461 
1462  value_type operator()(difference_type const & d) const
1463  { return operator()(d[0], d[1]); }
1464 
1465  value_type operator()(difference_type const & d, unsigned int dx, unsigned int dy) const
1466  { return operator()(d[0], d[1], dx, dy); }
1467 
1468  value_type dx(difference_type const & d) const
1469  { return operator()(d[0], d[1], 1, 0); }
1470 
1471  value_type dy(difference_type const & d) const
1472  { return operator()(d[0], d[1], 0, 1); }
1473 
1474  value_type dxx(difference_type const & d) const
1475  { return NumericTraits<VALUETYPE>::zero(); }
1476 
1477  value_type dxy(difference_type const & d) const
1478  { return operator()(d[0], d[1], 1, 1); }
1479 
1480  value_type dyy(difference_type const & d) const
1481  { return NumericTraits<VALUETYPE>::zero(); }
1482 
1483  value_type dx3(difference_type const & d) const
1484  { return NumericTraits<VALUETYPE>::zero(); }
1485 
1486  value_type dy3(difference_type const & d) const
1487  { return NumericTraits<VALUETYPE>::zero(); }
1488 
1489  value_type dxxy(difference_type const & d) const
1490  { return NumericTraits<VALUETYPE>::zero(); }
1491 
1492  value_type dxyy(difference_type const & d) const
1493  { return NumericTraits<VALUETYPE>::zero(); }
1494 
1495  SquaredNormType g2(double x, double y) const
1496  { return squaredNorm(dx(x,y)) + squaredNorm(dy(x,y)); }
1497 
1498  SquaredNormType g2x(double x, double y) const
1499  { return NumericTraits<SquaredNormType>::zero(); }
1500 
1501  SquaredNormType g2y(double x, double y) const
1502  { return NumericTraits<SquaredNormType>::zero(); }
1503 
1504  SquaredNormType g2xx(double x, double y) const
1505  { return NumericTraits<SquaredNormType>::zero(); }
1506 
1507  SquaredNormType g2xy(double x, double y) const
1508  { return NumericTraits<SquaredNormType>::zero(); }
1509 
1510  SquaredNormType g2yy(double x, double y) const
1511  { return NumericTraits<SquaredNormType>::zero(); }
1512 
1513  SquaredNormType g2(difference_type const & d) const
1514  { return g2(d[0], d[1]); }
1515 
1516  SquaredNormType g2x(difference_type const & d) const
1517  { return NumericTraits<SquaredNormType>::zero(); }
1518 
1519  SquaredNormType g2y(difference_type const & d) const
1520  { return NumericTraits<SquaredNormType>::zero(); }
1521 
1522  SquaredNormType g2xx(difference_type const & d) const
1523  { return NumericTraits<SquaredNormType>::zero(); }
1524 
1525  SquaredNormType g2xy(difference_type const & d) const
1526  { return NumericTraits<SquaredNormType>::zero(); }
1527 
1528  SquaredNormType g2yy(difference_type const & d) const
1529  { return NumericTraits<SquaredNormType>::zero(); }
1530 
1531  unsigned int width() const
1532  { return w_; }
1533 
1534  unsigned int height() const
1535  { return h_; }
1536 
1537  size_type size() const
1538  { return size_type(w_, h_); }
1539 
1540  TinyVector<unsigned int, 2> shape() const
1541  { return TinyVector<unsigned int, 2>(w_, h_); }
1542 
1543  template <class Array>
1544  void coefficientArray(double x, double y, Array & res) const;
1545 
1546  void calculateIndices(double x, double y, int & ix, int & iy, int & ix1, int & iy1) const;
1547 
1548  bool isInsideX(double x) const
1549  {
1550  return x >= 0.0 && x <= width() - 1.0;
1551  }
1552 
1553  bool isInsideY(double y) const
1554  {
1555  return y >= 0.0 && y <= height() - 1.0;
1556  }
1557 
1558  bool isInside(double x, double y) const
1559  {
1560  return isInsideX(x) && isInsideY(y);
1561  }
1562 
1563  bool isValid(double x, double y) const
1564  {
1565  return x < 2.0*w_-2.0 && x > 1.0-w_ && y < 2.0*h_-2.0 && y > 1.0-h_;
1566  }
1567 
1568  bool sameFacet(double x0, double y0, double x1, double y1) const
1569  {
1570  x0 = VIGRA_CSTD::floor(x0);
1571  y0 = VIGRA_CSTD::floor(y0);
1572  x1 = VIGRA_CSTD::floor(x1);
1573  y1 = VIGRA_CSTD::floor(y1);
1574  return x0 == x1 && y0 == y1;
1575  }
1576 
1577  protected:
1578  unsigned int w_, h_;
1579  INTERNAL_INDEXER internalIndexer_;
1580 };
1581 
1582 template <class VALUETYPE, class INTERNAL_INDEXER>
1583 template <class Array>
1584 void SplineImageView1Base<VALUETYPE, INTERNAL_INDEXER>::coefficientArray(double x, double y, Array & res) const
1585 {
1586  int ix, iy, ix1, iy1;
1587  calculateIndices(x, y, ix, iy, ix1, iy1);
1588  res(0,0) = internalIndexer_(ix,iy);
1589  res(1,0) = internalIndexer_(ix1,iy) - internalIndexer_(ix,iy);
1590  res(0,1) = internalIndexer_(ix,iy1) - internalIndexer_(ix,iy);
1591  res(1,1) = internalIndexer_(ix,iy) - internalIndexer_(ix1,iy) -
1592  internalIndexer_(ix,iy1) + internalIndexer_(ix1,iy1);
1593 }
1594 
1595 template <class VALUETYPE, class INTERNAL_INDEXER>
1596 void SplineImageView1Base<VALUETYPE, INTERNAL_INDEXER>::calculateIndices(double x, double y, int & ix, int & iy, int & ix1, int & iy1) const
1597 {
1598  if(x < 0.0)
1599  {
1600  x = -x;
1601  vigra_precondition(x <= w_ - 1.0,
1602  "SplineImageView::calculateIndices(): coordinates out of range.");
1603  ix = (int)VIGRA_CSTD::ceil(x);
1604  ix1 = ix - 1;
1605  }
1606  else if(x >= w_ - 1.0)
1607  {
1608  x = 2.0*w_-2.0-x;
1609  vigra_precondition(x > 0.0,
1610  "SplineImageView::calculateIndices(): coordinates out of range.");
1611  ix = (int)VIGRA_CSTD::ceil(x);
1612  ix1 = ix - 1;
1613  }
1614  else
1615  {
1616  ix = (int)VIGRA_CSTD::floor(x);
1617  ix1 = ix + 1;
1618  }
1619  if(y < 0.0)
1620  {
1621  y = -y;
1622  vigra_precondition(y <= h_ - 1.0,
1623  "SplineImageView::calculateIndices(): coordinates out of range.");
1624  iy = (int)VIGRA_CSTD::ceil(y);
1625  iy1 = iy - 1;
1626  }
1627  else if(y >= h_ - 1.0)
1628  {
1629  y = 2.0*h_-2.0-y;
1630  vigra_precondition(y > 0.0,
1631  "SplineImageView::calculateIndices(): coordinates out of range.");
1632  iy = (int)VIGRA_CSTD::ceil(y);
1633  iy1 = iy - 1;
1634  }
1635  else
1636  {
1637  iy = (int)VIGRA_CSTD::floor(y);
1638  iy1 = iy + 1;
1639  }
1640 }
1641 
1642 /** \brief Create an image view for bi-linear interpolation.
1643 
1644  This class behaves like \ref vigra::SplineImageView&lt;1, ...&gt;, but one can pass
1645  an additional template argument that determined the internal representation of the image.
1646  If this is equal to the argument type passed in the constructor, the image is not copied.
1647  By default, this works for \ref vigra::BasicImage, \ref vigra::BasicImageView,
1648  \ref vigra::MultiArray&lt;2, ...&gt;, and \ref vigra::MultiArrayView&lt;2, ...&gt;.
1649 
1650  In addition to the function provided by \ref vigra::SplineImageView, there are functions
1651  <tt>unchecked(x,y)</tt> and <tt>unchecked(x,y, xorder, yorder)</tt> which improve speed by
1652  not applying bounds checking and reflective border treatment (<tt>isInside(x, y)</tt> must
1653  be <tt>true</tt>), but otherwise behave identically to their checked counterparts.
1654  In addition, <tt>x</tt> and <tt>y</tt> can have type \ref vigra::FixedPoint instead of
1655  <tt>double</tt>.
1656 */
1657 template <class VALUETYPE, class INTERNAL_TRAVERSER = typename BasicImage<VALUETYPE>::const_traverser>
1659 : public SplineImageView1Base<VALUETYPE, INTERNAL_TRAVERSER>
1660 {
1661  typedef SplineImageView1Base<VALUETYPE, INTERNAL_TRAVERSER> Base;
1662  public:
1663  typedef typename Base::value_type value_type;
1664  typedef typename Base::SquaredNormType SquaredNormType;
1665  typedef typename Base::size_type size_type;
1666  typedef typename Base::difference_type difference_type;
1667  enum StaticOrder { order = Base::order };
1669 
1670  protected:
1671  typedef typename IteratorTraits<INTERNAL_TRAVERSER>::mutable_iterator InternalTraverser;
1673  typedef typename IteratorTraits<INTERNAL_TRAVERSER>::const_iterator InternalConstTraverser;
1675 
1676  public:
1677 
1678  /* when traverser and accessor types passed to the constructor are the same as the corresponding
1679  internal types, we need not copy the image (speed up)
1680  */
1681  SplineImageView1(InternalTraverser is, InternalTraverser iend, InternalAccessor sa)
1682  : Base(iend.x - is.x, iend.y - is.y, is)
1683  {}
1684 
1685  SplineImageView1(triple<InternalTraverser, InternalTraverser, InternalAccessor> s)
1686  : Base(s.second.x - s.first.x, s.second.y - s.first.y, s.first)
1687  {}
1688 
1689  SplineImageView1(InternalConstTraverser is, InternalConstTraverser iend, InternalConstAccessor sa)
1690  : Base(iend.x - is.x, iend.y - is.y, is)
1691  {}
1692 
1693  SplineImageView1(triple<InternalConstTraverser, InternalConstTraverser, InternalConstAccessor> s)
1694  : Base(s.second.x - s.first.x, s.second.y - s.first.y, s.first)
1695  {}
1696 
1697  template<class T, class SU>
1699  : Base(i.shape(0), i.shape(1)),
1700  image_(i.shape(0), i.shape(1))
1701  {
1702  for(unsigned int y=0; y<this->height(); ++y)
1703  for(unsigned int x=0; x<this->width(); ++x)
1704  image_(x,y) = detail::RequiresExplicitCast<VALUETYPE>::cast(i(x,y));
1705  this->internalIndexer_ = image_.upperLeft();
1706  }
1707 
1708  template <class SrcIterator, class SrcAccessor>
1709  SplineImageView1(SrcIterator is, SrcIterator iend, SrcAccessor sa)
1710  : Base(iend.x - is.x, iend.y - is.y),
1711  image_(iend - is)
1712  {
1713  copyImage(srcIterRange(is, iend, sa), destImage(image_));
1714  this->internalIndexer_ = image_.upperLeft();
1715  }
1716 
1717  template <class SrcIterator, class SrcAccessor>
1718  SplineImageView1(triple<SrcIterator, SrcIterator, SrcAccessor> s)
1719  : Base(s.second.x - s.first.x, s.second.y - s.first.y),
1720  image_(s.second - s.first)
1721  {
1722  copyImage(s, destImage(image_));
1723  this->internalIndexer_ = image_.upperLeft();
1724  }
1725 
1726  InternalImage const & image() const
1727  { return image_; }
1728 
1729  protected:
1730  InternalImage image_;
1731 };
1732 
1733 template <class VALUETYPE, class StridedOrUnstrided>
1734 class SplineImageView1<VALUETYPE, MultiArrayView<2, VALUETYPE, StridedOrUnstrided> >
1735 : public SplineImageView1Base<VALUETYPE, MultiArrayView<2, VALUETYPE, StridedOrUnstrided> >
1736 {
1737  typedef SplineImageView1Base<VALUETYPE, MultiArrayView<2, VALUETYPE, StridedOrUnstrided> > Base;
1738  public:
1739  typedef typename Base::value_type value_type;
1740  typedef typename Base::SquaredNormType SquaredNormType;
1741  typedef typename Base::size_type size_type;
1742  typedef typename Base::difference_type difference_type;
1743  enum StaticOrder { order = Base::order };
1744  typedef BasicImage<VALUETYPE> InternalImage;
1745 
1746  protected:
1747  typedef MultiArrayView<2, VALUETYPE, StridedOrUnstrided> InternalIndexer;
1748 
1749  public:
1750 
1751  /* when traverser and accessor types passed to the constructor are the same as the corresponding
1752  internal types, we need not copy the image (speed up)
1753  */
1754  SplineImageView1(InternalIndexer const & i)
1755  : Base(i.shape(0), i.shape(1), i)
1756  {}
1757 
1758  template<class T, class SU>
1759  SplineImageView1(MultiArrayView<2, T, SU> const & i)
1760  : Base(i.shape(0), i.shape(1)),
1761  image_(i.shape(0), i.shape(1))
1762  {
1763  for(unsigned int y=0; y<this->height(); ++y)
1764  for(unsigned int x=0; x<this->width(); ++x)
1765  image_(x,y) = detail::RequiresExplicitCast<VALUETYPE>::cast(i(x,y));
1766  this->internalIndexer_ = InternalIndexer(typename InternalIndexer::difference_type(this->width(), this->height()),
1767  image_.data());
1768  }
1769 
1770  template <class SrcIterator, class SrcAccessor>
1771  SplineImageView1(SrcIterator is, SrcIterator iend, SrcAccessor sa)
1772  : Base(iend.x - is.x, iend.y - is.y),
1773  image_(iend-is)
1774  {
1775  copyImage(srcIterRange(is, iend, sa), destImage(image_));
1776  this->internalIndexer_ = InternalIndexer(typename InternalIndexer::difference_type(this->width(), this->height()),
1777  image_.data());
1778  }
1779 
1780  template <class SrcIterator, class SrcAccessor>
1781  SplineImageView1(triple<SrcIterator, SrcIterator, SrcAccessor> s)
1782  : Base(s.second.x - s.first.x, s.second.y - s.first.y),
1783  image_(s.second - s.first)
1784  {
1785  copyImage(s, destImage(image_));
1786  this->internalIndexer_ = InternalIndexer(typename InternalIndexer::difference_type(this->width(), this->height()),
1787  image_.data());
1788  }
1789 
1790  InternalImage const & image() const
1791  { return image_; }
1792 
1793  protected:
1794  InternalImage image_;
1795 };
1796 
1797 template <class VALUETYPE>
1798 class SplineImageView<1, VALUETYPE>
1799 : public SplineImageView1<VALUETYPE>
1800 {
1801  typedef SplineImageView1<VALUETYPE> Base;
1802  public:
1803  typedef typename Base::value_type value_type;
1804  typedef typename Base::SquaredNormType SquaredNormType;
1805  typedef typename Base::size_type size_type;
1806  typedef typename Base::difference_type difference_type;
1807  enum StaticOrder { order = Base::order };
1808  typedef typename Base::InternalImage InternalImage;
1809 
1810  protected:
1811  typedef typename Base::InternalTraverser InternalTraverser;
1812  typedef typename Base::InternalAccessor InternalAccessor;
1813  typedef typename Base::InternalConstTraverser InternalConstTraverser;
1814  typedef typename Base::InternalConstAccessor InternalConstAccessor;
1815 
1816 public:
1817 
1818  /* when traverser and accessor types passed to the constructor are the same as the corresponding
1819  internal types, we need not copy the image (speed up)
1820  */
1821  SplineImageView(InternalTraverser is, InternalTraverser iend, InternalAccessor sa, bool /* unused */ = false)
1822  : Base(is, iend, sa)
1823  {}
1824 
1825  SplineImageView(triple<InternalTraverser, InternalTraverser, InternalAccessor> s, bool /* unused */ = false)
1826  : Base(s)
1827  {}
1828 
1829  SplineImageView(InternalConstTraverser is, InternalConstTraverser iend, InternalConstAccessor sa, bool /* unused */ = false)
1830  : Base(is, iend, sa)
1831  {}
1832 
1833  SplineImageView(triple<InternalConstTraverser, InternalConstTraverser, InternalConstAccessor> s, bool /* unused */ = false)
1834  : Base(s)
1835  {}
1836 
1837  template <class SrcIterator, class SrcAccessor>
1838  SplineImageView(SrcIterator is, SrcIterator iend, SrcAccessor sa, bool /* unused */ = false)
1839  : Base(is, iend, sa)
1840  {
1841  copyImage(srcIterRange(is, iend, sa), destImage(this->image_));
1842  }
1843 
1844  template <class SrcIterator, class SrcAccessor>
1845  SplineImageView(triple<SrcIterator, SrcIterator, SrcAccessor> s, bool /* unused */ = false)
1846  : Base(s)
1847  {
1848  copyImage(s, destImage(this->image_));
1849  }
1850 };
1851 
1852 } // namespace vigra
1853 
1854 
1855 #endif /* VIGRA_SPLINEIMAGEVIEW_HXX */

© Ullrich Köthe (ullrich.koethe@iwr.uni-heidelberg.de)
Heidelberg Collaboratory for Image Processing, University of Heidelberg, Germany

html generated using doxygen and Python
vigra 1.9.0 (Wed Feb 27 2013)