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

resizeimage.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 
37 #ifndef VIGRA_RESIZEIMAGE_HXX
38 #define VIGRA_RESIZEIMAGE_HXX
39 
40 #include <vector>
41 #include "utilities.hxx"
42 #include "numerictraits.hxx"
43 #include "stdimage.hxx"
44 #include "recursiveconvolution.hxx"
45 #include "separableconvolution.hxx"
46 #include "resampling_convolution.hxx"
47 #include "splines.hxx"
48 
49 namespace vigra {
50 
51 /*****************************************************************/
52 /* */
53 /* CoscotFunction */
54 /* */
55 /*****************************************************************/
56 
57 /*! The Coscot interpolation function.
58 
59  Implements the Coscot interpolation function proposed by Maria Magnusson Seger
60  (maria@isy.liu.se) in the context of tomographic reconstruction. It provides a fast
61  transition between the pass- and stop-bands and minimal ripple outside the transition
62  region. Both properties are important for this application and can be tuned by the parameters
63  <i>m</i> and <i>h</i> (with defaults 3 and 0.5). The function is defined by
64 
65  \f[ f_{m,h}(x) = \left\{ \begin{array}{ll}
66  \frac{1}{2m}\sin(\pi x)\cot(\pi x / (2 m))(h + (1-h)\cos(\pi x/m)) & |x| \leq m \\
67  0 & \mbox{otherwise}
68  \end{array}\right.
69  \f]
70 
71  It can be used as a functor, and as a kernel for
72  \ref resamplingConvolveImage() to create a differentiable interpolant
73  of an image.
74 
75  <b>\#include</b> <vigra/resizeimage.hxx><br>
76  Namespace: vigra
77 
78  \ingroup MathFunctions
79 */
80 template <class T>
82 {
83  public:
84 
85  /** the kernel's value type
86  */
87  typedef T value_type;
88  /** the unary functor's argument type
89  */
90  typedef T argument_type;
91  /** the splines polynomial order
92  */
93  typedef T result_type;
94 
95  CoscotFunction(unsigned int m = 3, double h = 0.5)
96  : m_(m),
97  h_(h)
98  {}
99 
100  /** function (functor) call
101  */
103  {
104  return x == 0.0 ?
105  1.0
106  : abs(x) < m_ ?
107  VIGRA_CSTD::sin(M_PI*x) / VIGRA_CSTD::tan(M_PI * x / 2.0 / m_) *
108  (h_ + (1.0 - h_) * VIGRA_CSTD::cos(M_PI * x / m_)) / 2.0 / m_
109  : 0.0;
110  }
111 
112  /** index operator -- same as operator()
113  */
115  { return operator()(x); }
116 
117  /** Radius of the function's support.
118  Needed for \ref resamplingConvolveImage(), equals m.
119  */
120  double radius() const
121  { return m_; }
122 
123  /** Derivative order of the function: always 0.
124  */
125  unsigned int derivativeOrder() const
126  { return 0; }
127 
128  /** Prefilter coefficients for compatibility with \ref vigra::BSpline.
129  (array has zero length, since prefiltering is not necessary).
130  */
132  {
133  static ArrayVector<double> b;
134  return b;
135  }
136 
137  protected:
138 
139  unsigned int m_;
140  double h_;
141 };
142 
143 /** \addtogroup GeometricTransformations Geometric Transformations
144  Zoom up and down by repeating pixels, or using various interpolation schemes.
145 
146  See also: \ref resamplingConvolveImage(), \ref resampleImage(), \ref resizeMultiArraySplineInterpolation()
147 
148  <b>\#include</b> <vigra/stdimagefunctions.hxx><br>
149  <b>or</b><br>
150  <b>\#include</b> <vigra/resizeimage.hxx><br>
151 */
152 //@{
153 
154 /********************************************************/
155 /* */
156 /* resizeLineNoInterpolation */
157 /* */
158 /********************************************************/
159 
160 template <class SrcIterator, class SrcAccessor,
161  class DestIterator, class DestAccessor>
162 void
163 resizeLineNoInterpolation(SrcIterator i1, SrcIterator iend, SrcAccessor as,
164  DestIterator id, DestIterator idend, DestAccessor ad)
165 {
166  int wold = iend - i1;
167  int wnew = idend - id;
168 
169  if(wnew == 1)
170  {
171  ad.set(as(i1), id);
172  return;
173  }
174 
175  double dx = (double)(wold - 1) / (wnew - 1);
176  double x = 0.5;
177  for(; id != idend; ++id, x += dx)
178  {
179  int ix = (int)x;
180  ad.set(as(i1, ix), id);
181  }
182 }
183 
184 /********************************************************/
185 /* */
186 /* resizeImageNoInterpolation */
187 /* */
188 /********************************************************/
189 
190 /** \brief Resize image by repeating the nearest pixel values.
191 
192  This algorithm is very fast and does not require any arithmetic on
193  the pixel types.
194 
195  The range of both the input and output images (resp. regions) must
196  be given. Both images must have a size of at least 2x2 pixels. The
197  scaling factors are then calculated accordingly. Destination
198  pixels are directly copied from the appropriate source pixels.
199 
200  The function uses accessors.
201 
202  <b> Declarations:</b>
203 
204  pass arguments explicitly:
205  \code
206  namespace vigra {
207  template <class SrcImageIterator, class SrcAccessor,
208  class DestImageIterator, class DestAccessor>
209  void
210  resizeImageNoInterpolation(
211  SrcImageIterator is, SrcImageIterator iend, SrcAccessor sa,
212  DestImageIterator id, DestImageIterator idend, DestAccessor da)
213  }
214  \endcode
215 
216 
217  use argument objects in conjunction with \ref ArgumentObjectFactories :
218  \code
219  namespace vigra {
220  template <class SrcImageIterator, class SrcAccessor,
221  class DestImageIterator, class DestAccessor>
222  void
223  resizeImageNoInterpolation(
224  triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
225  triple<DestImageIterator, DestImageIterator, DestAccessor> dest)
226  }
227  \endcode
228 
229  <b> Usage:</b>
230 
231  <b>\#include</b> <vigra/resizeimage.hxx><br>
232  Namespace: vigra
233 
234  \code
235  vigra::resizeImageNoInterpolation(
236  src.upperLeft(), src.lowerRight(), src.accessor(),
237  dest.upperLeft(), dest.lowerRight(), dest.accessor());
238 
239  \endcode
240 
241  <b> Required Interface:</b>
242 
243  \code
244  SrcImageIterator src_upperleft, src_lowerright;
245  DestImageIterator dest_upperleft, src_lowerright;
246 
247  SrcAccessor src_accessor;
248  DestAccessor dest_accessor;
249 
250  dest_accessor.set(src_accessor(src_upperleft), dest_upperleft);
251 
252  \endcode
253 
254  <b> Preconditions:</b>
255 
256  \code
257  src_lowerright.x - src_upperleft.x > 1
258  src_lowerright.y - src_upperleft.y > 1
259  dest_lowerright.x - dest_upperleft.x > 1
260  dest_lowerright.y - dest_upperleft.y > 1
261  \endcode
262 
263 */
264 doxygen_overloaded_function(template <...> void resizeImageNoInterpolation)
265 
266 template <class SrcIterator, class SrcAccessor,
267  class DestIterator, class DestAccessor>
268 void
269 resizeImageNoInterpolation(SrcIterator is, SrcIterator iend, SrcAccessor sa,
270  DestIterator id, DestIterator idend, DestAccessor da)
271 {
272  int w = iend.x - is.x;
273  int h = iend.y - is.y;
274 
275  int wnew = idend.x - id.x;
276  int hnew = idend.y - id.y;
277 
278  vigra_precondition((w > 1) && (h > 1),
279  "resizeImageNoInterpolation(): "
280  "Source image too small.\n");
281  vigra_precondition((wnew > 1) && (hnew > 1),
282  "resizeImageNoInterpolation(): "
283  "Destination image too small.\n");
284 
285  typedef BasicImage<typename SrcAccessor::value_type> TmpImage;
286  typedef typename TmpImage::traverser TmpImageIterator;
287 
288  TmpImage tmp(w, hnew);
289 
290  TmpImageIterator yt = tmp.upperLeft();
291 
292  for(int x=0; x<w; ++x, ++is.x, ++yt.x)
293  {
294  typename SrcIterator::column_iterator c1 = is.columnIterator();
295  typename TmpImageIterator::column_iterator ct = yt.columnIterator();
296 
297  resizeLineNoInterpolation(c1, c1 + h, sa, ct, ct + hnew, tmp.accessor());
298  }
299 
300  yt = tmp.upperLeft();
301 
302  for(int y=0; y < hnew; ++y, ++yt.y, ++id.y)
303  {
304  typename DestIterator::row_iterator rd = id.rowIterator();
305  typename TmpImageIterator::row_iterator rt = yt.rowIterator();
306 
307  resizeLineNoInterpolation(rt, rt + w, tmp.accessor(), rd, rd + wnew, da);
308  }
309 }
310 
311 template <class SrcIterator, class SrcAccessor,
312  class DestIterator, class DestAccessor>
313 inline
314 void
315 resizeImageNoInterpolation(triple<SrcIterator, SrcIterator, SrcAccessor> src,
316  triple<DestIterator, DestIterator, DestAccessor> dest)
317 {
318  resizeImageNoInterpolation(src.first, src.second, src.third,
319  dest.first, dest.second, dest.third);
320 }
321 
322 /********************************************************/
323 /* */
324 /* resizeLineLinearInterpolation */
325 /* */
326 /********************************************************/
327 
328 template <class SrcIterator, class SrcAccessor,
329  class DestIterator, class DestAccessor>
330 void
331 resizeLineLinearInterpolation(SrcIterator i1, SrcIterator iend, SrcAccessor as,
332  DestIterator id, DestIterator idend, DestAccessor ad)
333 {
334  int wold = iend - i1;
335  int wnew = idend - id;
336 
337  if((wold <= 1) || (wnew <= 1)) return; // oder error ?
338 
339  typedef
340  NumericTraits<typename DestAccessor::value_type> DestTraits;
341  typedef typename DestTraits::RealPromote RealPromote;
342 
343  ad.set(DestTraits::fromRealPromote(as(i1)), id);
344  ++id;
345 
346  --iend, --idend;
347  ad.set(DestTraits::fromRealPromote(as(iend)), idend);
348 
349  double dx = (double)(wold - 1) / (wnew - 1);
350  double x = dx;
351 
352  for(; id != idend; ++id, x += dx)
353  {
354  if(x >= 1.0)
355  {
356  int xx = (int)x;
357  i1 += xx;
358  x -= (double)xx;
359  }
360  double x1 = 1.0 - x;
361 
362  ad.set(DestTraits::fromRealPromote(RealPromote(x1 * as(i1) + x * as(i1, 1))), id);
363  }
364 }
365 
366 /********************************************************/
367 /* */
368 /* resizeImageLinearInterpolation */
369 /* */
370 /********************************************************/
371 
372 /** \brief Resize image using linear interpolation.
373 
374  The function uses the standard separable bilinear interpolation algorithm to
375  obtain a good compromise between quality and speed.
376 
377  The range must of both the input and output images (resp. regions)
378  must be given. Both images must have a size of at
379  least 2x2. The scaling factors are then calculated
380  accordingly. If the source image is larger than the destination, it
381  is smoothed (band limited) using a recursive
382  exponential filter. The source value_type (SrcAccessor::value_type) must
383  be a linear space, i.e. it must support addition, multiplication
384  with a scalar real number and \ref NumericTraits "NumericTraits".
385  The function uses accessors.
386 
387  <b> Declarations:</b>
388 
389  pass arguments explicitly:
390  \code
391  namespace vigra {
392  template <class SrcImageIterator, class SrcAccessor,
393  class DestImageIterator, class DestAccessor>
394  void
395  resizeImageLinearInterpolation(
396  SrcImageIterator is, SrcImageIterator iend, SrcAccessor sa,
397  DestImageIterator id, DestImageIterator idend, DestAccessor da)
398  }
399  \endcode
400 
401 
402  use argument objects in conjunction with \ref ArgumentObjectFactories :
403  \code
404  namespace vigra {
405  template <class SrcImageIterator, class SrcAccessor,
406  class DestImageIterator, class DestAccessor>
407  void
408  resizeImageLinearInterpolation(
409  triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
410  triple<DestImageIterator, DestImageIterator, DestAccessor> dest)
411  }
412  \endcode
413 
414  <b> Usage:</b>
415 
416  <b>\#include</b> <vigra/resizeimage.hxx><br>
417  Namespace: vigra
418 
419  \code
420  vigra::resizeImageLinearInterpolation(
421  src.upperLeft(), src.lowerRight(), src.accessor(),
422  dest.upperLeft(), dest.lowerRight(), dest.accessor());
423 
424  \endcode
425 
426  <b> Required Interface:</b>
427 
428  \code
429  SrcImageIterator src_upperleft, src_lowerright;
430  DestImageIterator dest_upperleft, src_lowerright;
431 
432  SrcAccessor src_accessor;
433  DestAccessor dest_accessor;
434 
435  NumericTraits<SrcAccessor::value_type>::RealPromote
436  u = src_accessor(src_upperleft),
437  v = src_accessor(src_upperleft, 1);
438  double d;
439 
440  u = d * v;
441  u = u + v;
442 
443  dest_accessor.set(
444  NumericTraits<DestAccessor::value_type>::fromRealPromote(u),
445  dest_upperleft);
446 
447  \endcode
448 
449  <b> Preconditions:</b>
450 
451  \code
452  src_lowerright.x - src_upperleft.x > 1
453  src_lowerright.y - src_upperleft.y > 1
454  dest_lowerright.x - dest_upperleft.x > 1
455  dest_lowerright.y - dest_upperleft.y > 1
456  \endcode
457 
458 */
459 doxygen_overloaded_function(template <...> void resizeImageLinearInterpolation)
460 
461 template <class SrcIterator, class SrcAccessor,
462  class DestIterator, class DestAccessor>
463 void
464 resizeImageLinearInterpolation(SrcIterator is, SrcIterator iend, SrcAccessor sa,
465  DestIterator id, DestIterator idend, DestAccessor da)
466 {
467  int w = iend.x - is.x;
468  int h = iend.y - is.y;
469 
470  int wnew = idend.x - id.x;
471  int hnew = idend.y - id.y;
472 
473  vigra_precondition((w > 1) && (h > 1),
474  "resizeImageLinearInterpolation(): "
475  "Source image too small.\n");
476  vigra_precondition((wnew > 1) && (hnew > 1),
477  "resizeImageLinearInterpolation(): "
478  "Destination image too small.\n");
479 
480  double const scale = 2.0;
481 
482  typedef typename SrcAccessor::value_type SRCVT;
483  typedef typename NumericTraits<SRCVT>::RealPromote TMPTYPE;
484  typedef BasicImage<TMPTYPE> TmpImage;
485  typedef typename TmpImage::traverser TmpImageIterator;
486 
487  BasicImage<TMPTYPE> tmp(w, hnew);
488  BasicImage<TMPTYPE> line((h > w) ? h : w, 1);
489 
490  int x,y;
491 
492  typename BasicImage<TMPTYPE>::Iterator yt = tmp.upperLeft();
493  typename TmpImageIterator::row_iterator lt = line.upperLeft().rowIterator();
494 
495  for(x=0; x<w; ++x, ++is.x, ++yt.x)
496  {
497  typename SrcIterator::column_iterator c1 = is.columnIterator();
498  typename TmpImageIterator::column_iterator ct = yt.columnIterator();
499 
500  if(hnew < h)
501  {
502  recursiveSmoothLine(c1, c1 + h, sa,
503  lt, line.accessor(), (double)h/hnew/scale);
504 
505  resizeLineLinearInterpolation(lt, lt + h, line.accessor(),
506  ct, ct + hnew, tmp.accessor());
507  }
508  else
509  {
510  resizeLineLinearInterpolation(c1, c1 + h, sa,
511  ct, ct + hnew, tmp.accessor());
512  }
513  }
514 
515  yt = tmp.upperLeft();
516 
517  for(y=0; y < hnew; ++y, ++yt.y, ++id.y)
518  {
519  typename DestIterator::row_iterator rd = id.rowIterator();
520  typename TmpImageIterator::row_iterator rt = yt.rowIterator();
521 
522  if(wnew < w)
523  {
524  recursiveSmoothLine(rt, rt + w, tmp.accessor(),
525  lt, line.accessor(), (double)w/wnew/scale);
526 
527  resizeLineLinearInterpolation(lt, lt + w, line.accessor(),
528  rd, rd + wnew, da);
529  }
530  else
531  {
532  resizeLineLinearInterpolation(rt, rt + w, tmp.accessor(),
533  rd, rd + wnew, da);
534  }
535  }
536 }
537 
538 template <class SrcIterator, class SrcAccessor,
539  class DestIterator, class DestAccessor>
540 inline
541 void
542 resizeImageLinearInterpolation(triple<SrcIterator, SrcIterator, SrcAccessor> src,
543  triple<DestIterator, DestIterator, DestAccessor> dest)
544 {
545  resizeImageLinearInterpolation(src.first, src.second, src.third,
546  dest.first, dest.second, dest.third);
547 }
548 
549 /***************************************************************/
550 /* */
551 /* resizeImageSplineInterpolation */
552 /* */
553 /***************************************************************/
554 
555 /** \brief Resize image using B-spline interpolation.
556 
557  The function implements separable spline interpolation algorithm described in
558 
559  M. Unser, A. Aldroubi, M. Eden, <i>"B-Spline Signal Processing"</i>
560  IEEE Transactions on Signal Processing, vol. 41, no. 2, pp. 821-833 (part I),
561  pp. 834-848 (part II), 1993.
562 
563  to obtain optimal interpolation quality and speed. You may pass the function
564  a spline of arbitrary order (e.g. <TT>BSpline<ORDER, double></tt> or
565  <TT>CatmullRomSpline<double></tt>). The default is a third order spline
566  which gives a twice continuously differentiable interpolant.
567  The implementation ensures that image values are interpolated rather
568  than smoothed by first calling a recursive (sharpening) prefilter as
569  described in the above paper. Then the actual interpolation is done
570  using \ref resamplingConvolveLine().
571 
572  The range of both the input and output images (resp. regions)
573  must be given. The input image must have a size of at
574  least 4x4, the destination of at least 2x2. The scaling factors are then calculated
575  accordingly. If the source image is larger than the destination, it
576  is smoothed (band limited) using a recursive
577  exponential filter. The source value_type (SrcAccessor::value_type) must
578  be a linear algebra, i.e. it must support addition, subtraction,
579  and multiplication (+, -, *), multiplication with a scalar
580  real number and \ref NumericTraits "NumericTraits".
581  The function uses accessors.
582 
583  <b> Declarations:</b>
584 
585  pass arguments explicitly:
586  \code
587  namespace vigra {
588  template <class SrcImageIterator, class SrcAccessor,
589  class DestImageIterator, class DestAccessor,
590  class SPLINE>
591  void
592  resizeImageSplineInterpolation(
593  SrcImageIterator is, SrcImageIterator iend, SrcAccessor sa,
594  DestImageIterator id, DestImageIterator idend, DestAccessor da,
595  SPLINE spline = BSpline<3, double>())
596  }
597  \endcode
598 
599 
600  use argument objects in conjunction with \ref ArgumentObjectFactories :
601  \code
602  namespace vigra {
603  template <class SrcImageIterator, class SrcAccessor,
604  class DestImageIterator, class DestAccessor,
605  class SPLINE>
606  void
607  resizeImageSplineInterpolation(
608  triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
609  triple<DestImageIterator, DestImageIterator, DestAccessor> dest,
610  SPLINE spline = BSpline<3, double>())
611  }
612  \endcode
613 
614  <b> Usage:</b>
615 
616  <b>\#include</b> <vigra/resizeimage.hxx><br>
617  Namespace: vigra
618 
619  \code
620  vigra::resizeImageSplineInterpolation(
621  src.upperLeft(), src.lowerRight(), src.accessor(),
622  dest.upperLeft(), dest.lowerRight(), dest.accessor());
623 
624  \endcode
625 
626  <b> Required Interface:</b>
627 
628  \code
629  SrcImageIterator src_upperleft, src_lowerright;
630  DestImageIterator dest_upperleft, src_lowerright;
631 
632  SrcAccessor src_accessor;
633  DestAccessor dest_accessor;
634 
635  NumericTraits<SrcAccessor::value_type>::RealPromote
636  u = src_accessor(src_upperleft),
637  v = src_accessor(src_upperleft, 1);
638  double d;
639 
640  u = d * v;
641  u = u + v;
642  u = u - v;
643  u = u * v;
644  u += v;
645  u -= v;
646 
647  dest_accessor.set(
648  NumericTraits<DestAccessor::value_type>::fromRealPromote(u),
649  dest_upperleft);
650 
651  \endcode
652 
653  <b> Preconditions:</b>
654 
655  \code
656  src_lowerright.x - src_upperleft.x > 3
657  src_lowerright.y - src_upperleft.y > 3
658  dest_lowerright.x - dest_upperleft.x > 1
659  dest_lowerright.y - dest_upperleft.y > 1
660  \endcode
661 
662 */
663 doxygen_overloaded_function(template <...> void resizeImageSplineInterpolation)
664 
665 template <class SrcIterator, class SrcAccessor,
666  class DestIterator, class DestAccessor,
667  class SPLINE>
668 void
670  SrcIterator src_iter, SrcIterator src_iter_end, SrcAccessor src_acc,
671  DestIterator dest_iter, DestIterator dest_iter_end, DestAccessor dest_acc,
672  SPLINE const & spline)
673 {
674 
675  int width_old = src_iter_end.x - src_iter.x;
676  int height_old = src_iter_end.y - src_iter.y;
677 
678  int width_new = dest_iter_end.x - dest_iter.x;
679  int height_new = dest_iter_end.y - dest_iter.y;
680 
681  vigra_precondition((width_old > 1) && (height_old > 1),
682  "resizeImageSplineInterpolation(): "
683  "Source image too small.\n");
684 
685  vigra_precondition((width_new > 1) && (height_new > 1),
686  "resizeImageSplineInterpolation(): "
687  "Destination image too small.\n");
688 
689  Rational<int> xratio(width_new - 1, width_old - 1);
690  Rational<int> yratio(height_new - 1, height_old - 1);
691  Rational<int> offset(0);
692  resampling_detail::MapTargetToSourceCoordinate xmapCoordinate(xratio, offset);
693  resampling_detail::MapTargetToSourceCoordinate ymapCoordinate(yratio, offset);
694  int xperiod = lcm(xratio.numerator(), xratio.denominator());
695  int yperiod = lcm(yratio.numerator(), yratio.denominator());
696 
697  double const scale = 2.0;
698 
699  typedef typename SrcAccessor::value_type SRCVT;
700  typedef typename NumericTraits<SRCVT>::RealPromote TMPTYPE;
701  typedef BasicImage<TMPTYPE> TmpImage;
702  typedef typename TmpImage::traverser TmpImageIterator;
703 
704  BasicImage<TMPTYPE> tmp(width_old, height_new);
705 
706  BasicImage<TMPTYPE> line((height_old > width_old) ? height_old : width_old, 1);
707  typename BasicImage<TMPTYPE>::Accessor tmp_acc = tmp.accessor();
708  ArrayVector<double> const & prefilterCoeffs = spline.prefilterCoefficients();
709 
710  int x,y;
711 
712  ArrayVector<Kernel1D<double> > kernels(yperiod);
713  createResamplingKernels(spline, ymapCoordinate, kernels);
714 
715  typename BasicImage<TMPTYPE>::Iterator y_tmp = tmp.upperLeft();
716  typename TmpImageIterator::row_iterator line_tmp = line.upperLeft().rowIterator();
717 
718  for(x=0; x<width_old; ++x, ++src_iter.x, ++y_tmp.x)
719  {
720 
721  typename SrcIterator::column_iterator c_src = src_iter.columnIterator();
722  typename TmpImageIterator::column_iterator c_tmp = y_tmp.columnIterator();
723 
724  if(prefilterCoeffs.size() == 0)
725  {
726  if(height_new >= height_old)
727  {
728  resamplingConvolveLine(c_src, c_src + height_old, src_acc,
729  c_tmp, c_tmp + height_new, tmp_acc,
730  kernels, ymapCoordinate);
731  }
732  else
733  {
734  recursiveSmoothLine(c_src, c_src + height_old, src_acc,
735  line_tmp, line.accessor(), (double)height_old/height_new/scale);
736  resamplingConvolveLine(line_tmp, line_tmp + height_old, line.accessor(),
737  c_tmp, c_tmp + height_new, tmp_acc,
738  kernels, ymapCoordinate);
739  }
740  }
741  else
742  {
743  recursiveFilterLine(c_src, c_src + height_old, src_acc,
744  line_tmp, line.accessor(),
745  prefilterCoeffs[0], BORDER_TREATMENT_REFLECT);
746  for(unsigned int b = 1; b < prefilterCoeffs.size(); ++b)
747  {
748  recursiveFilterLine(line_tmp, line_tmp + height_old, line.accessor(),
749  line_tmp, line.accessor(),
750  prefilterCoeffs[b], BORDER_TREATMENT_REFLECT);
751  }
752  if(height_new < height_old)
753  {
754  recursiveSmoothLine(line_tmp, line_tmp + height_old, line.accessor(),
755  line_tmp, line.accessor(), (double)height_old/height_new/scale);
756  }
757  resamplingConvolveLine(line_tmp, line_tmp + height_old, line.accessor(),
758  c_tmp, c_tmp + height_new, tmp_acc,
759  kernels, ymapCoordinate);
760  }
761  }
762 
763  y_tmp = tmp.upperLeft();
764 
765  kernels.resize(xperiod);
766  createResamplingKernels(spline, xmapCoordinate, kernels);
767 
768  for(y=0; y < height_new; ++y, ++y_tmp.y, ++dest_iter.y)
769  {
770  typename DestIterator::row_iterator r_dest = dest_iter.rowIterator();
771  typename TmpImageIterator::row_iterator r_tmp = y_tmp.rowIterator();
772 
773  if(prefilterCoeffs.size() == 0)
774  {
775  if(width_new >= width_old)
776  {
777  resamplingConvolveLine(r_tmp, r_tmp + width_old, tmp.accessor(),
778  r_dest, r_dest + width_new, dest_acc,
779  kernels, xmapCoordinate);
780  }
781  else
782  {
783  recursiveSmoothLine(r_tmp, r_tmp + width_old, tmp.accessor(),
784  line_tmp, line.accessor(), (double)width_old/width_new/scale);
785  resamplingConvolveLine(line_tmp, line_tmp + width_old, line.accessor(),
786  r_dest, r_dest + width_new, dest_acc,
787  kernels, xmapCoordinate);
788  }
789  }
790  else
791  {
792  recursiveFilterLine(r_tmp, r_tmp + width_old, tmp.accessor(),
793  line_tmp, line.accessor(),
794  prefilterCoeffs[0], BORDER_TREATMENT_REFLECT);
795  for(unsigned int b = 1; b < prefilterCoeffs.size(); ++b)
796  {
797  recursiveFilterLine(line_tmp, line_tmp + width_old, line.accessor(),
798  line_tmp, line.accessor(),
799  prefilterCoeffs[b], BORDER_TREATMENT_REFLECT);
800  }
801  if(width_new < width_old)
802  {
803  recursiveSmoothLine(line_tmp, line_tmp + width_old, line.accessor(),
804  line_tmp, line.accessor(), (double)width_old/width_new/scale);
805  }
806  resamplingConvolveLine(line_tmp, line_tmp + width_old, line.accessor(),
807  r_dest, r_dest + width_new, dest_acc,
808  kernels, xmapCoordinate);
809  }
810  }
811 }
812 
813 template <class SrcIterator, class SrcAccessor,
814  class DestIterator, class DestAccessor,
815  class SPLINE>
816 inline
817 void
818 resizeImageSplineInterpolation(triple<SrcIterator, SrcIterator, SrcAccessor> src,
819  triple<DestIterator, DestIterator, DestAccessor> dest,
820  SPLINE const & spline)
821 {
822  resizeImageSplineInterpolation(src.first, src.second, src.third,
823  dest.first, dest.second, dest.third, spline);
824 }
825 
826 template <class SrcIterator, class SrcAccessor,
827  class DestIterator, class DestAccessor>
828 void
829 resizeImageSplineInterpolation(SrcIterator is, SrcIterator iend, SrcAccessor sa,
830  DestIterator id, DestIterator idend, DestAccessor da)
831 {
832  resizeImageSplineInterpolation(is, iend, sa, id, idend, da, BSpline<3, double>());
833 }
834 
835 template <class SrcIterator, class SrcAccessor,
836  class DestIterator, class DestAccessor>
837 inline
838 void
839 resizeImageSplineInterpolation(triple<SrcIterator, SrcIterator, SrcAccessor> src,
840  triple<DestIterator, DestIterator, DestAccessor> dest)
841 {
842  resizeImageSplineInterpolation(src.first, src.second, src.third,
843  dest.first, dest.second, dest.third);
844 }
845 
846 /*****************************************************************/
847 /* */
848 /* resizeImageCatmullRomInterpolation */
849 /* */
850 /*****************************************************************/
851 
852 /** \brief Resize image using the Catmull/Rom interpolation function.
853 
854  The function calls like \ref resizeImageSplineInterpolation() with
855  \ref vigra::CatmullRomSpline as an interpolation kernel.
856  The interpolated function has one continuous derivative.
857  (See \ref resizeImageSplineInterpolation() for more documentation)
858 
859  <b> Declarations:</b>
860 
861  pass arguments explicitly:
862  \code
863  namespace vigra {
864  template <class SrcIterator, class SrcAccessor,
865  class DestIterator, class DestAccessor>
866  void
867  resizeImageCatmullRomInterpolation(SrcIterator src_iter, SrcIterator src_iter_end, SrcAccessor src_acc,
868  DestIterator dest_iter, DestIterator dest_iter_end, DestAccessor dest_acc);
869  }
870  \endcode
871 
872 
873  use argument objects in conjunction with \ref ArgumentObjectFactories :
874  \code
875  namespace vigra {
876  template <class SrcIterator, class SrcAccessor,
877  class DestIterator, class DestAccessor>
878  void
879  resizeImageCatmullRomInterpolation(triple<SrcIterator, SrcIterator, SrcAccessor> src,
880  triple<DestIterator, DestIterator, DestAccessor> dest);
881  }
882  \endcode
883 
884 
885  <b>\#include</b> <vigra/resizeimage.hxx><br>
886  Namespace: vigra
887 
888 */
889 doxygen_overloaded_function(template <...> void resizeImageCatmullRomInterpolation)
890 
891 template <class SrcIterator, class SrcAccessor,
892  class DestIterator, class DestAccessor>
893 inline void
894 resizeImageCatmullRomInterpolation(SrcIterator src_iter, SrcIterator src_iter_end, SrcAccessor src_acc,
895  DestIterator dest_iter, DestIterator dest_iter_end, DestAccessor dest_acc)
896 {
897  resizeImageSplineInterpolation(src_iter, src_iter_end, src_acc, dest_iter, dest_iter_end, dest_acc,
898  CatmullRomSpline<double>());
899 }
900 
901 template <class SrcIterator, class SrcAccessor,
902  class DestIterator, class DestAccessor>
903 inline
904 void
905 resizeImageCatmullRomInterpolation(triple<SrcIterator, SrcIterator, SrcAccessor> src,
906  triple<DestIterator, DestIterator, DestAccessor> dest)
907 {
908  resizeImageCatmullRomInterpolation(src.first, src.second, src.third,
909  dest.first, dest.second, dest.third);
910 }
911 
912 #if 0
913 /*****************************************************************/
914 /* */
915 /* resizeImageCubicInterpolation */
916 /* */
917 /*****************************************************************/
918 
919 /** \brief Resize image using the cardinal B-spline interpolation function.
920 
921  The function calls like \ref resizeImageSplineInterpolation() with
922  \ref vigra::BSpline<3, double> and prefiltering as an interpolation kernel.
923  The interpolated function has two continuous derivatives.
924  (See \ref resizeImageSplineInterpolation() for more documentation)
925 
926  <b>\#include</b> <vigra/resizeimage.hxx><br>
927  Namespace: vigra
928 
929 */
930 template <class SrcIterator, class SrcAccessor,
931  class DestIterator, class DestAccessor>
932 void
933 resizeImageCubicInterpolation(SrcIterator src_iter, SrcIterator src_iter_end, SrcAccessor src_acc,
934  DestIterator dest_iter, DestIterator dest_iter_end, DestAccessor dest_acc)
935 {
936  resizeImageSplineInterpolation(src_iter, src_iter_end, src_acc, dest_iter, dest_iter_end, dest_acc,
937  BSpline<3, double>());
938 }
939 
940 template <class SrcIterator, class SrcAccessor,
941  class DestIterator, class DestAccessor>
942 inline
943 void
944 resizeImageCubicInterpolation(triple<SrcIterator, SrcIterator, SrcAccessor> src,
945  triple<DestIterator, DestIterator, DestAccessor> dest)
946 {
947  resizeImageCubicInterpolation(src.first, src.second, src.third,
948  dest.first, dest.second, dest.third);
949 }
950 #endif
951 
952 /*****************************************************************/
953 /* */
954 /* resizeImageCoscotInterpolation */
955 /* */
956 /*****************************************************************/
957 
958 /** \brief Resize image using the Coscot interpolation function.
959 
960  The function calls \ref resizeImageSplineInterpolation() with
961  \ref vigra::CoscotFunction as an interpolation kernel.
962  The interpolated function has one continuous derivative.
963  (See \ref resizeImageSplineInterpolation() for more documentation)
964 
965  <b> Declarations:</b>
966 
967  pass arguments explicitly:
968  \code
969  namespace vigra {
970  template <class SrcIterator, class SrcAccessor,
971  class DestIterator, class DestAccessor>
972  void
973  resizeImageCoscotInterpolation(SrcIterator src_iter, SrcIterator src_iter_end, SrcAccessor src_acc,
974  DestIterator dest_iter, DestIterator dest_iter_end, DestAccessor dest_acc);
975  }
976  \endcode
977 
978 
979  use argument objects in conjunction with \ref ArgumentObjectFactories :
980  \code
981  namespace vigra {
982  template <class SrcIterator, class SrcAccessor,
983  class DestIterator, class DestAccessor>
984  void
985  resizeImageCoscotInterpolation(triple<SrcIterator, SrcIterator, SrcAccessor> src,
986  triple<DestIterator, DestIterator, DestAccessor> dest);
987  }
988  \endcode
989 
990 
991  <b>\#include</b> <vigra/resizeimage.hxx><br>
992  Namespace: vigra
993 
994 */
995 doxygen_overloaded_function(template <...> void resizeImageCoscotInterpolation)
996 
997 template <class SrcIterator, class SrcAccessor,
998  class DestIterator, class DestAccessor>
999 void
1000 resizeImageCoscotInterpolation(SrcIterator src_iter, SrcIterator src_iter_end, SrcAccessor src_acc,
1001  DestIterator dest_iter, DestIterator dest_iter_end, DestAccessor dest_acc)
1002 {
1003  resizeImageSplineInterpolation(src_iter, src_iter_end, src_acc, dest_iter, dest_iter_end, dest_acc,
1004  CoscotFunction<double>());
1005 }
1006 
1007 template <class SrcIterator, class SrcAccessor,
1008  class DestIterator, class DestAccessor>
1009 inline
1010 void
1011 resizeImageCoscotInterpolation(triple<SrcIterator, SrcIterator, SrcAccessor> src,
1012  triple<DestIterator, DestIterator, DestAccessor> dest)
1013 {
1014  resizeImageCoscotInterpolation(src.first, src.second, src.third,
1015  dest.first, dest.second, dest.third);
1016 }
1017 
1018 
1019 #if 0 // old version of the spline interpolation algorithm
1020 
1021 /********************************************************/
1022 /* */
1023 /* resizeCalculateSplineCoefficients */
1024 /* (internally used by resize functions) */
1025 /* */
1026 /********************************************************/
1027 
1028 template <class SrcIterator, class SrcAccessor, class VALUETYPE>
1029 void
1030 resizeCalculateSplineCoefficients(SrcIterator i1, SrcIterator iend,
1031  SrcAccessor a, VALUETYPE * i2)
1032 {
1033  int n = iend - i1;
1034 
1035  if(n <= 0) return;
1036 
1037  VALUETYPE zero = NumericTraits<VALUETYPE>::zero();
1038  VALUETYPE two = 2.0 * NumericTraits<VALUETYPE>::one();
1039  VALUETYPE half = 0.5 * NumericTraits<VALUETYPE>::one();
1040 
1041  *i2 = zero;
1042  if(n == 1) return;
1043 
1044  std::vector<VALUETYPE> vec(n);
1045  typename std::vector<VALUETYPE>::iterator u = vec.begin();
1046 
1047  *u = zero;
1048 
1049  for(++i1, ++i2, ++u, --iend; i1 != iend; ++i1, ++i2, ++u)
1050  {
1051  VALUETYPE p = 0.5 * i2[-1] + two;
1052  *i2 = half / p;
1053  *u = 3.0 *(a(i1,1) - 2.0 * a(i1) + a(i1, -1)) - 0.5 * u[-1] / p;
1054  }
1055 
1056  *i2 = zero;
1057 
1058  for(--i2, --u; u != vec; --u, --i2)
1059  {
1060  *i2 = *i2 * i2[1] + *u;
1061  }
1062 }
1063 
1064 /********************************************************/
1065 /* */
1066 /* resizeImageInternalSplineGradient */
1067 /* */
1068 /********************************************************/
1069 
1070 template <class SrcIterator, class SrcAccessor,
1071  class DoubleIterator, class TempIterator, class DestIterator>
1072 void
1073 resizeImageInternalSplineGradient(SrcIterator in, SrcIterator inend, SrcAccessor sa,
1074  DoubleIterator tmp, TempIterator r, DestIterator id)
1075 {
1076  int w = inend - in;
1077 
1078  int x;
1079 
1080  typedef typename SrcAccessor::value_type SRCVT;
1081  typedef typename NumericTraits<SRCVT>::RealPromote TMPTYPE;
1082 
1083  // calculate border derivatives
1084  SrcIterator xs = in;
1085  TMPTYPE p0 = -11.0/6.0 * sa(xs); ++xs;
1086  p0 += 3.0 * sa(xs); ++xs;
1087  p0 += -1.5 * sa(xs); ++xs;
1088  p0 += 1.0/3.0 * sa(xs);
1089 
1090  xs = in + w-1;
1091  TMPTYPE pw = 11.0/6.0 * sa(xs); --xs;
1092  pw += -3.0 * sa(xs); --xs;
1093  pw += 1.5 * sa(xs); --xs;
1094  pw += -1.0/3.0 * sa(xs);
1095 
1096  xs = in + 2;
1097  SrcIterator xs1 = in;
1098 
1099  for(x=1; x<w-1; ++x, ++xs, ++xs1)
1100  {
1101  r[x] = 3.0 * (sa(xs) - sa(xs1));
1102  }
1103 
1104  r[1] -= p0;
1105  r[w-2] -= pw;
1106 
1107  double q = 0.25;
1108 
1109  id[0] = p0;
1110  id[w-1] = pw;
1111  id[1] = 0.25 * r[1];
1112 
1113  for(x=2; x<w-1; ++x)
1114  {
1115  tmp[x] = q;
1116  q = 1.0 / (4.0 - q);
1117  id[x] = q * (r[x] - id[x-1]);
1118  }
1119 
1120  for(x=w-3; x>=1; --x)
1121  {
1122  id[x] -= tmp[x+1]*id[x+1];
1123  }
1124 }
1125 
1126 /********************************************************/
1127 /* */
1128 /* resizeImageInternalSplineInterpolation */
1129 /* */
1130 /********************************************************/
1131 
1132 template <class SrcIterator, class SrcAccessor,
1133  class DestIterator, class DestAccessor>
1134 void
1135 resizeImageInternalSplineInterpolation(SrcIterator is, SrcIterator iend, SrcAccessor sa,
1136  DestIterator id, DestIterator idend, DestAccessor da)
1137 {
1138  int w = iend.x - is.x;
1139  int h = iend.y - is.y;
1140 
1141  int wnew = idend.x - id.x;
1142  int hnew = idend.y - id.y;
1143 
1144  typedef typename SrcAccessor::value_type SRCVT;
1145  typedef typename NumericTraits<SRCVT>::RealPromote TMPTYPE;
1146  typedef typename BasicImage<TMPTYPE>::Iterator TMPITER;
1147  typedef
1148  NumericTraits<typename DestAccessor::value_type> DestTraits;
1149 
1150  BasicImage<TMPTYPE> dx(w,h);
1151  BasicImage<TMPTYPE> dy(w,h);
1152  BasicImage<TMPTYPE> dxy(w,h);
1153  BasicImage<TMPTYPE> W(4,4), W1(4,4);
1154  std::vector<TMPTYPE> R(w > h ? w : h);
1155  std::vector<double> tmp(w > h ? w : h);
1156 
1157  typename BasicImage<TMPTYPE>::Accessor ta;
1158 
1159  SrcIterator in = is;
1160 
1161  TMPITER idx = dx.upperLeft();
1162  TMPITER idy = dy.upperLeft();
1163  TMPITER idxy = dxy.upperLeft();
1164  typename std::vector<TMPTYPE>::iterator r = R.begin();
1165  typename std::vector<double>::iterator it = tmp.begin();
1166 
1167  double ig[] = { 1.0, 0.0, -3.0, 2.0,
1168  0.0, 1.0, -2.0, 1.0,
1169  0.0, 0.0, 3.0, -2.0,
1170  0.0, 0.0, -1.0, 1.0 };
1171 
1172  int x, y, i, j, k;
1173 
1174 
1175  // calculate x derivatives
1176  for(y=0; y<h; ++y, ++in.y, ++idx.y)
1177  {
1178  typename SrcIterator::row_iterator sr = in.rowIterator();
1179  typename TMPITER::row_iterator dr = idx.rowIterator();
1180  resizeImageInternalSplineGradient(sr, sr+w, sa,
1181  it, r, dr);
1182  }
1183 
1184  in = is;
1185 
1186  // calculate y derivatives
1187  for(x=0; x<w; ++x, ++in.x, ++idy.x)
1188  {
1189  typename SrcIterator::column_iterator sc = in.columnIterator();
1190  typename TMPITER::column_iterator dc = idy.columnIterator();
1191  resizeImageInternalSplineGradient(sc, sc+h, sa,
1192  it, r, dc);
1193  }
1194 
1195  in = is;
1196  idy = dy.upperLeft();
1197 
1198  // calculate mixed derivatives
1199  for(y=0; y<h; ++y, ++idy.y, ++idxy.y)
1200  {
1201  typename TMPITER::row_iterator sr = idy.rowIterator();
1202  typename TMPITER::row_iterator dr = idxy.rowIterator();
1203  resizeImageInternalSplineGradient(sr, sr+w, ta,
1204  it, r, dr);
1205  }
1206 
1207  double du = (double)(w-1) / (wnew-1);
1208  double dv = (double)(h-1) / (hnew-1);
1209  double ov = 0.0;
1210  int oy = 0;
1211  int yy = oy;
1212 
1213  DestIterator xxd = id, yyd = id;
1214 
1215  static Diff2D down(0,1), right(1,0), downright(1,1);
1216 
1217  for(y=0; y<h-1; ++y, ++in.y, ov -= 1.0)
1218  {
1219  if(y < h-2 && ov >= 1.0) continue;
1220  int y1 = y+1;
1221  double v = ov;
1222  double ou = 0.0;
1223  int ox = 0;
1224  int xx = ox;
1225 
1226  SrcIterator xs = in;
1227  for(x=0; x<w-1; ++x, ++xs.x, ou -= 1.0)
1228  {
1229  if(x < w-2 && ou >= 1.0) continue;
1230  int x1 = x+1;
1231  double u = ou;
1232 
1233  DestIterator xd = id + Diff2D(ox,oy);
1234  W[0][0] = sa(xs);
1235  W[0][1] = dy(x, y);
1236  W[0][2] = sa(xs, down);
1237  W[0][3] = dy(x, y1);
1238  W[1][0] = dx(x, y);
1239  W[1][1] = dxy(x, y);
1240  W[1][2] = dx(x, y1);
1241  W[1][3] = dxy(x, y1);
1242  W[2][0] = sa(xs, right);
1243  W[2][1] = dy(x1,y);
1244  W[2][2] = sa(xs, downright);
1245  W[2][3] = dy(x1, y1);
1246  W[3][0] = dx(x1, y);
1247  W[3][1] = dxy(x1, y);
1248  W[3][2] = dx(x1, y1);
1249  W[3][3] = dxy(x1, y1);
1250 
1251  for(i=0; i<4; ++i)
1252  {
1253  for(j=0; j<4; ++j)
1254  {
1255  W1[j][i] = ig[j] * W[0][i];
1256  for(k=1; k<4; ++k)
1257  {
1258  W1[j][i] += ig[j+4*k] * W[k][i];
1259  }
1260  }
1261  }
1262  for(i=0; i<4; ++i)
1263  {
1264  for(j=0; j<4; ++j)
1265  {
1266  W[j][i] = ig[i] * W1[j][0];
1267  for(k=1; k<4; ++k)
1268  {
1269  W[j][i] += ig[4*k+i] * W1[j][k];
1270  }
1271  }
1272  }
1273 
1274  TMPTYPE a1,a2,a3,a4;
1275 
1276  yyd = xd;
1277  for(v=ov, yy=oy; v<1.0; v+=dv, ++yyd.y, ++yy)
1278  {
1279  a1 = W[0][0] + v * (W[0][1] +
1280  v * (W[0][2] + v * W[0][3]));
1281  a2 = W[1][0] + v * (W[1][1] +
1282  v * (W[1][2] + v * W[1][3]));
1283  a3 = W[2][0] + v * (W[2][1] +
1284  v * (W[2][2] + v * W[2][3]));
1285  a4 = W[3][0] + v * (W[3][1] +
1286  v * (W[3][2] + v * W[3][3]));
1287 
1288  xxd = yyd;
1289  for(u=ou, xx=ox; u<1.0; u+=du, ++xxd.x, ++xx)
1290  {
1291  da.set(DestTraits::fromRealPromote(a1 + u * (a2 + u * (a3 + u * a4))), xxd);
1292  }
1293 
1294  if(xx == wnew-1)
1295  {
1296  da.set(DestTraits::fromRealPromote(a1 + a2 + a3 + a4), xxd);
1297  }
1298  }
1299 
1300  if(yy == hnew-1)
1301  {
1302  a1 = W[0][0] + W[0][1] + W[0][2] + W[0][3];
1303  a2 = W[1][0] + W[1][1] + W[1][2] + W[1][3];
1304  a3 = W[2][0] + W[2][1] + W[2][2] + W[2][3];
1305  a4 = W[3][0] + W[3][1] + W[3][2] + W[3][3];
1306 
1307  DestIterator xxd = yyd;
1308  for(u=ou, xx=ox; u<1.0; u+=du, ++xxd.x, ++xx)
1309  {
1310  da.set(DestTraits::fromRealPromote(a1 + u * (a2 + u * (a3 + u * a4))), xxd);
1311  }
1312 
1313  if(xx == wnew-1)
1314  {
1315  da.set(DestTraits::fromRealPromote(a1 + a2 + a3 + a4), xxd);
1316  }
1317  }
1318 
1319  ou = u;
1320  ox = xx;
1321  }
1322  ov = v;
1323  oy = yy;
1324  }
1325 }
1326 
1327 template <class SrcIterator, class SrcAccessor,
1328  class DestIterator, class DestAccessor>
1329 void
1330 resizeImageSplineInterpolation(SrcIterator is, SrcIterator iend, SrcAccessor sa,
1331  DestIterator id, DestIterator idend, DestAccessor da)
1332 {
1333  int w = iend.x - is.x;
1334  int h = iend.y - is.y;
1335 
1336  int wnew = idend.x - id.x;
1337  int hnew = idend.y - id.y;
1338 
1339  vigra_precondition((w > 3) && (h > 3),
1340  "resizeImageSplineInterpolation(): "
1341  "Source image too small.\n");
1342  vigra_precondition((wnew > 1) && (hnew > 1),
1343  "resizeImageSplineInterpolation(): "
1344  "Destination image too small.\n");
1345 
1346  double scale = 2.0;
1347 
1348  if(wnew < w || hnew < h)
1349  {
1350  typedef typename SrcAccessor::value_type SRCVT;
1351  typedef typename NumericTraits<SRCVT>::RealPromote TMPTYPE;
1352  typedef typename BasicImage<TMPTYPE>::Iterator TMPITER;
1353 
1354  BasicImage<TMPTYPE> t(w,h);
1355  TMPITER it = t.upperLeft();
1356 
1357  if(wnew < w)
1358  {
1359  recursiveSmoothX(is, iend, sa,
1360  it, t.accessor(), (double)w/wnew/scale);
1361 
1362  if(hnew < h)
1363  {
1364  recursiveSmoothY(it, t.lowerRight(), t.accessor(),
1365  it, t.accessor(), (double)h/hnew/scale);
1366  }
1367  }
1368  else
1369  {
1370  recursiveSmoothY(is, iend, sa,
1371  it, t.accessor(), (double)h/hnew/scale);
1372  }
1373 
1374  resizeImageInternalSplineInterpolation(it, t.lowerRight(), t.accessor(),
1375  id, idend, da);
1376  }
1377  else
1378  {
1379  resizeImageInternalSplineInterpolation(is, iend, sa, id, idend, da);
1380  }
1381 }
1382 
1383 template <class SrcIterator, class SrcAccessor,
1384  class DestIterator, class DestAccessor>
1385 inline
1386 void
1387 resizeImageSplineInterpolation(triple<SrcIterator, SrcIterator, SrcAccessor> src,
1388  triple<DestIterator, DestIterator, DestAccessor> dest)
1389 {
1390  resizeImageSplineInterpolation(src.first, src.second, src.third,
1391  dest.first, dest.second, dest.third);
1392 }
1393 #endif // old algorithm version
1394 
1395 //@}
1396 
1397 } // namespace vigra
1398 
1399 #endif // VIGRA_RESIZEIMAGE_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 (Sat Oct 5 2013)