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