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

basicgeometry.hxx VIGRA

1 /************************************************************************/
2 /* */
3 /* Copyright 1998-2002 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_BASICGEOMETRY_HXX
37 #define VIGRA_BASICGEOMETRY_HXX
38 
39 #include "error.hxx"
40 #include "stdimage.hxx"
41 #include "copyimage.hxx"
42 #include "multi_shape.hxx"
43 
44 #include <cmath>
45 
46 namespace vigra {
47 
48 /** \addtogroup GeometricTransformations
49 */
50 //@{
51 
52 /********************************************************/
53 /* */
54 /* rotateImage */
55 /* */
56 /********************************************************/
57 
58 /** \brief Rotate an image by a multiple of 90 degrees or by an arbitrary angle.
59 
60  If you specify the angle as an integer which is a multiple of 90 degrees, rotateImage()
61  just copies the pixels in the appropriate new order. It expects the destination image to
62  have the correct shape for the desired rotation. That is, when the rotation is a multiple
63  of 180 degrees, source and destination must have the same shape, otherwise destination
64  must have the transposed shape of the source.
65 
66  If you want to rotate by an arbitrary angle and around an arbitrary center point,
67  you must specify the source image as a \ref vigra::SplineImageView, which is used for
68  interpolation at the required subpixel positions. If no center point is provided, the image
69  center is used by default. The destination image must have the same size
70  as the source SplineImageView.
71 
72  Positive angles refer to counter-clockwise rotation, negative ones to clockwise rotation.
73  All angles must be given in degrees.
74 
75  <b> Declarations:</b>
76 
77  pass 2D array views:
78  \code
79  namespace vigra {
80  // rotate by a multiple of 90 degrees
81  template <class T1, class S1,
82  class T2, class S2>
83  void
84  rotateImage(MultiArrayView<2, T1, S1> const & src,
85  MultiArrayView<2, T2, S2> dest,
86  int rotation);
87 
88  // rotate by an arbitrary angle around the given center point
89  template <int ORDER, class T,
90  class T2, class S2>
91  void
92  rotateImage(SplineImageView<ORDER, T> const & src,
93  MultiArrayView<2, T2, S2> dest,
94  double angleInDegree,
95  TinyVector<double, 2> const & center = (src.shape() - Shape2(1)) / 2.0);
96  }
97  \endcode
98 
99  \deprecatedAPI{rotateImage}
100  pass \ref ImageIterators and \ref DataAccessors :
101  \code
102  namespace vigra {
103  // rotate by a multiple of 90 degrees
104  template <class SrcIterator, class SrcAccessor,
105  class DestIterator, class DestAccessor>
106  void
107  rotateImage(SrcIterator is, SrcIterator end, SrcAccessor as,
108  DestIterator id, DestAccessor ad, int rotation);
109 
110  // rotate by an arbitrary angle around the given center point
111  template <int ORDER, class T,
112  class DestIterator, class DestAccessor>
113  void rotateImage(SplineImageView<ORDER, T> const & src,
114  DestIterator id, DestAccessor dest,
115  double angleInDegree, TinyVector<double, 2> const & center = (src.shape() - Shape2(1)) / 2.0);
116  }
117  \endcode
118  use argument objects in conjunction with \ref ArgumentObjectFactories :
119  \code
120  namespace vigra {
121  // rotate by a multiple of 90 degrees
122  template <class SrcImageIterator, class SrcAccessor,
123  class DestImageIterator, class DestAccessor>
124  void
125  rotateImage(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
126  pair<DestImageIterator, DestAccessor> dest, int rotation);
127 
128  // rotate by an arbitrary angle around the given center point
129  template <int ORDER, class T,
130  class DestIterator, class DestAccessor>
131  void
132  rotateImage(SplineImageView<ORDER, T> const & src,
133  pair<DestImageIterator, DestAccessor> dest,
134  double angleInDegree, TinyVector<double, 2> const & center = (src.shape() - Shape2(1)) / 2.0);
135  }
136  \endcode
137  \deprecatedEnd
138 
139  <b> Usage:</b>
140 
141  <b>\#include</b> <vigra/basicgeometry.hxx><br>
142  Namespace: vigra
143 
144  \code
145  // rotate counter-clockwise by 90 degrees (no interpolation required)
146  MultiArray<2, float> src(width, height),
147  dest(height, width); // note that width and height are exchanged
148  ... // fill src
149  rotateImage(src, dest, 90);
150 
151  // rotate clockwise by 38.5 degrees, using a SplieImageView for cubic interpolation
152  SplineImageView<3, float> spline(srcImageRange(src));
153  MultiArray<2, float> dest2(src.shape());
154 
155  vigra::rotateImage(spline, dest2, -38.5);
156  \endcode
157 
158  \deprecatedUsage{rotateImage}
159  \code
160  // rotate counter-clockwise by 90 degrees (no interpolation required)
161  BImage src(width, height),
162  dest(height, width); // note that width and height are exchanged
163  ... // fill src
164 
165  rotateImage(srcImageRange(src), destImage(dest), 90);
166 
167  // rotate clockwise by 38.5 degrees, using a SplieImageView for cubic interpolation
168  SplineImageView<3, float> spline(srcImageRange(src));
169  FImage dest2(width, height);
170 
171  rotateImage(spline, destImage(dest), -38.5);
172  \endcode
173  <b> Required Interface:</b>
174  \code
175  SrcImageIterator src_upperleft, src_lowerright;
176  DestImageIterator dest_upperleft;
177 
178  SrcAccessor src_accessor;
179 
180  dest_accessor.set(src_accessor(src_upperleft), dest_upperleft);
181  \endcode
182  \deprecatedEnd
183 
184  <b> Preconditions:</b>
185  \code
186  src.shape(0) > 1 && src.shape(1) > 1
187  \endcode
188 */
189 doxygen_overloaded_function(template <...> void rotateImage)
190 
191 template <class SrcIterator, class SrcAccessor,
192  class DestIterator, class DestAccessor>
193 void rotateImage(SrcIterator is, SrcIterator end, SrcAccessor as,
194  DestIterator id, DestAccessor ad, int rotation)
195 {
196  int x, y;
197  int ws = end.x - is.x;
198  int hs = end.y - is.y;
199 
200  vigra_precondition(rotation % 90 == 0,
201  "rotateImage(): "
202  "This function rotates images only about multiples of 90 degree");
203 
204  rotation = rotation%360;
205  if (rotation < 0)
206  rotation += 360;
207 
208  switch(rotation)
209  {
210  case 0:
211  copyImage(is, end, as, id, ad);
212  break;
213  case 90:
214  is.x += (ws-1);
215  for(x=0; x != ws; x++, is.x--, id.y++)
216  {
217  typename SrcIterator::column_iterator cs = is.columnIterator();
218  typename DestIterator::row_iterator rd = id.rowIterator();
219  for(y=0; y != hs; y++, cs++, rd++)
220  {
221  ad.set(as(cs), rd);
222  }
223 
224  }
225  break;
226 
227  case 180:
228  end.x--;
229  end.y--;
230  for(x=0; x != ws; x++, end.x--, id.x++)
231  {
232  typename SrcIterator::column_iterator cs = end.columnIterator();
233  typename DestIterator::column_iterator cd = id.columnIterator();
234  for(y=0; y != hs; y++, cs--, cd++)
235  {
236  ad.set(as(cs), cd);
237  }
238 
239  }
240  break;
241 
242  case 270:
243  is.y += (hs-1);
244  for(x=0; x != ws; x++, is.x++, id.y++)
245  {
246  typename SrcIterator::column_iterator cs = is.columnIterator();
247  typename DestIterator::row_iterator rd = id.rowIterator();
248  for(y=0; y != hs; y++, cs--, rd++)
249  {
250  ad.set(as(cs), rd);
251  }
252 
253  }
254  break;
255  default: //not needful, because of the exception handig in if-statement
256  vigra_fail("internal error");
257  }
258 }
259 
260 template <class SrcImageIterator, class SrcAccessor,
261  class DestImageIterator, class DestAccessor>
262 inline void
263 rotateImage(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
264  pair<DestImageIterator, DestAccessor> dest, int rotation)
265 {
266  rotateImage(src.first, src.second, src.third, dest.first, dest.second, rotation);
267 }
268 
269 template <class T1, class S1,
270  class T2, class S2>
271 inline void
272 rotateImage(MultiArrayView<2, T1, S1> const & src,
273  MultiArrayView<2, T2, S2> dest,
274  int rotation)
275 {
276  if(rotation % 180 == 0)
277  vigra_precondition(src.shape() == dest.shape(),
278  "rotateImage(): shape mismatch between input and output.");
279  else
280  vigra_precondition(src.shape() == reverse(dest.shape()),
281  "rotateImage(): shape mismatch between input and output.");
282  rotateImage(srcImageRange(src), destImage(dest), rotation);
283 }
284 
285 /********************************************************/
286 /* */
287 /* reflectImage */
288 /* */
289 /********************************************************/
290 
291 enum Reflect {horizontal = 1, vertical = 2};
292 
293 inline
294 Reflect operator|(Reflect l, Reflect r)
295 {
296  return Reflect((unsigned int)l | (unsigned int)r);
297 }
298 
299 /** \brief Reflect image horizontally or vertically.
300 
301  The reflection direction refers to the reflection axis, i.e.
302  horizontal reflection turns the image upside down, vertical reflection
303  changes left for right. The directions are selected by the enum values
304  <tt>vigra::horizontal</tt> and <tt>vigra::vertical</tt>. The two directions
305  can also be "or"ed together to perform both reflections simultaneously
306  (see example below) -- this is the same as a 180 degree rotation.
307 
308  <b> Declarations:</b>
309 
310  pass 2D array views:
311  \code
312  namespace vigra {
313  template <class T1, class S1,
314  class T2, class S2>
315  void
316  reflectImage(MultiArrayView<2, T1, S1> const & src,
317  MultiArrayView<2, T2, S2> dest, Reflect reflect);
318  }
319  \endcode
320 
321  \deprecatedAPI{reflectImage}
322  pass \ref ImageIterators and \ref DataAccessors :
323  \code
324  namespace vigra {
325  template <class SrcIterator, class SrcAccessor,
326  class DestIterator, class DestAccessor>
327  void
328  reflectImage(SrcIterator is, SrcIterator end, SrcAccessor as,
329  DestIterator id, DestAccessor ad, Reflect axis);
330  }
331  \endcode
332  use argument objects in conjunction with \ref ArgumentObjectFactories :
333  \code
334  namespace vigra {
335  template <class SrcImageIterator, class SrcAccessor,
336  class DestImageIterator, class DestAccessor>
337  void
338  reflectImage(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
339  pair<DestImageIterator, DestAccessor> dest, Reflect axis);
340  }
341  \endcode
342  \deprecatedEnd
343 
344  <b> Usage:</b>
345 
346  <b>\#include</b> <vigra/basicgeometry.hxx><br>
347  Namespace: vigra
348 
349  \code
350  MultiArray<2, float> src(width, height),
351  dest(width, height);
352  ... // fill src
353  // reflect about both dimensions
354  vigra::reflectImage(src, dest, vigra::horizontal | vigra::vertical);
355 
356  \endcode
357 
358  \deprecatedUsage{reflectImage}
359  \code
360  BImage src(width, height),
361  dest(width, height);
362  ... // fill src
363 
364  vigra::reflectImage(srcImageRange(src), destImage(dest), vigra::horizontal | vigra::vertical);
365  \endcode
366  <b> Required Interface:</b>
367  \code
368  SrcImageIterator src_upperleft, src_lowerright;
369  DestImageIterator dest_upperleft;
370 
371  SrcAccessor src_accessor;
372 
373  dest_accessor.set(src_accessor(src_upperleft), dest_upperleft);
374  \endcode
375  \deprecatedEnd
376 
377  <b> Preconditions:</b>
378  \code
379  src.shape(0) > 1 && src.shape(1) > 1
380  \endcode
381 */
382 doxygen_overloaded_function(template <...> void reflectImage)
383 
384 template <class SrcIterator, class SrcAccessor,
385  class DestIterator, class DestAccessor>
386 void reflectImage(SrcIterator is, SrcIterator end, SrcAccessor as,
387  DestIterator id, DestAccessor ad, Reflect reflect)
388 {
389 
390  int ws = end.x - is.x;
391  int hs = end.y - is.y;
392 
393  int x, y;
394 
395  if(reflect == horizontal)
396  {//flipImage
397  is.y += (hs-1);
398  for(x=0; x<ws; ++x, ++is.x, ++id.x)
399  {
400  typename SrcIterator::column_iterator cs = is.columnIterator();
401  typename DestIterator::column_iterator cd = id.columnIterator();
402  for(y=0; y!=hs;y++, cs--, cd++)
403  {
404  ad.set(as(cs), cd);
405  }
406  }
407  }
408  else if(reflect == vertical)
409  {//flopImage
410  is.x += (ws-1);
411  for(x=0; x < ws; ++x, --is.x, ++id.x)
412  {
413 
414  typename SrcIterator::column_iterator cs = is.columnIterator();
415  typename DestIterator::column_iterator cd = id.columnIterator();
416  for(y=0; y!=hs;y++, cs++, cd++)
417  {
418  ad.set(as(cs), cd);
419  }
420  }
421  }
422  else if(reflect == (horizontal | vertical))
423  {//flipFlopImage //???
424  end.x--;
425  end.y--;
426  for(x=0; x != ws; x++, end.x--, id.x++)
427  {
428  typename SrcIterator::column_iterator cs = end.columnIterator();
429  typename DestIterator::column_iterator cd = id.columnIterator();
430  for(y=0; y != hs; y++, cs--, cd++)
431  {
432  ad.set(as(cs), cd);
433  }
434  }
435  }
436  else
437  vigra_fail("reflectImage(): "
438  "This function reflects horizontal or vertical,"
439  " 'and' is included");
440 }
441 
442 template <class SrcImageIterator, class SrcAccessor,
443  class DestImageIterator, class DestAccessor>
444 inline void
445 reflectImage(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
446  pair<DestImageIterator, DestAccessor> dest, Reflect reflect)
447 {
448  reflectImage(src.first, src.second, src.third, dest.first, dest.second, reflect);
449 }
450 
451 template <class T1, class S1,
452  class T2, class S2>
453 inline void
454 reflectImage(MultiArrayView<2, T1, S1> const & src,
455  MultiArrayView<2, T2, S2> dest, Reflect reflect)
456 {
457  vigra_precondition(src.shape() == dest.shape(),
458  "reflectImage(): shape mismatch between input and output.");
459  reflectImage(srcImageRange(src), destImage(dest), reflect);
460 }
461 
462 /********************************************************/
463 /* */
464 /* transposeImage */
465 /* */
466 /********************************************************/
467 
468 // names clash with sys/types.h on Mac OS / Darwin, see docs below
469 enum Transpose{major = 1, minor = 2};
470 
471 /** \brief Transpose an image over the major or minor diagonal.
472 
473  The transposition direction refers to the axis, i.e.
474  major transposition turns the upper right corner into the lower left one,
475  whereas minor transposition changes the upper left corner into the lower right one.
476  The directions are selected by the enum values
477  <tt>vigra::major</tt> and <tt>vigra::minor</tt>. The two directions
478  can also be "or"ed together to perform both reflections simultaneously
479  (see example below) -- this is the same as a 180 degree rotation.
480  (Caution: When doing multi-platform development, you should be
481  aware that some <sys/types.h> define major/minor, too. Do not omit
482  the vigra namespace prefix.)
483 
484  Note that a similar effect can be chieved by MultiArrayView::transpose(). However,
485  the latter can only transpose about the major diagonal, and it doesn't rearrange the data
486  - it just creates a view with transposed axis ordering. It depends on the context
487  which function is more appropriate.
488 
489  <b> Declarations:</b>
490 
491  pass 2D array views:
492  \code
493  namespace vigra {
494  template <class T1, class S1,
495  class T2, class S2>
496  void
497  transposeImage(MultiArrayView<2, T1, S1> const & src,
498  MultiArrayView<2, T2, S2> dest, Transpose axis);
499  }
500  \endcode
501 
502  \deprecatedAPI{transposeImage}
503  pass \ref ImageIterators and \ref DataAccessors :
504  \code
505  namespace vigra {
506  template <class SrcIterator, class SrcAccessor,
507  class DestIterator, class DestAccessor>
508  void
509  transposeImage(SrcIterator is, SrcIterator end, SrcAccessor as,
510  DestIterator id, DestAccessor ad, Transpose axis);
511  }
512  \endcode
513  use argument objects in conjunction with \ref ArgumentObjectFactories :
514  \code
515  namespace vigra {
516  template <class SrcImageIterator, class SrcAccessor,
517  class DestImageIterator, class DestAccessor>
518  void
519  transposeImage(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
520  pair<DestImageIterator, DestAccessor> dest, Transpose axis);
521  }
522  \endcode
523  \deprecatedEnd
524 
525  <b> Usage:</b>
526 
527  <b>\#include</b> <vigra/basicgeometry.hxx><br>
528  Namespace: vigra
529 
530  \code
531  MultiArray<2, float> src(width, height),
532  dest(height, width); // note that dimensions are transposed
533  ... // fill src
534 
535  // transpose about the major diagonal
536  vigra::transposeImage(src, dest, vigra::major);
537 
538  // this produces the same data as transposing the view
539  assert(dest == src.transpose());
540 
541  // transposition about the minor diagonal has no correspondence in MultiArrayView
542  vigra::transposeImage(src, dest, vigra::minor);
543  \endcode
544 
545  \deprecatedUsage{transposeImage}
546  \code
547  BImage src(width, height),
548  dest(width, height);
549  ... // fill src
550 
551  // transpose about both diagonals simultaneously
552  vigra::transposeImage(srcImageRange(src), destImage(dest), vigra::major | vigra::minor);
553  \endcode
554  <b> Required Interface:</b>
555  \code
556  SrcImageIterator src_upperleft, src_lowerright;
557  DestImageIterator dest_upperleft;
558 
559  SrcAccessor src_accessor;
560 
561  dest_accessor.set(src_accessor(src_upperleft), dest_upperleft);
562  \endcode
563  \deprecatedEnd
564 
565  <b> Preconditions:</b>
566  \code
567  src.shape(0) > 1 && src.shape(1) > 1
568  \endcode
569 */
570 doxygen_overloaded_function(template <...> void transposeImage)
571 
572 template <class SrcIterator, class SrcAccessor,
573  class DestIterator, class DestAccessor>
574 void transposeImage(SrcIterator is, SrcIterator end, SrcAccessor as,
575  DestIterator id, DestAccessor ad, Transpose transpose)
576 {
577  int ws = end.x - is.x;
578  int hs = end.y - is.y;
579 
580  int x, y;
581 
582  if(transpose == major)
583  {//Die Funktion spiegelt das Bild um (0,0) (1,1) Diagonale
584  for(x=0; x != ws; x++, is.x++, id.y++)
585  {
586 
587  typename SrcIterator::column_iterator cs = is.columnIterator();
588  typename DestIterator::row_iterator rd = id.rowIterator();
589  for(y=0; y != hs; y++, cs++, rd++)
590  {
591  ad.set(as(cs), rd);
592  }
593  }
594  }
595  else if(transpose == minor)
596  {//Die Funktion spiegelt das Bild (1,0) (0,1) Diagonale
597  end.x--;
598  end.y--;
599  for(x=0; x != ws; x++, --end.x, ++id.y)
600  {
601 
602  typename SrcIterator::column_iterator cs = end.columnIterator();
603  typename DestIterator::row_iterator rd = id.rowIterator();
604  for(y=0; y != hs; y++, --cs, ++rd)
605  {
606  ad.set(as(cs), rd);
607  }
608  }
609  }
610  else if(transpose == (major | minor))
611  {//flipFlopImage //???
612  end.x--;
613  end.y--;
614  for(x=0; x != ws; x++, end.x--, id.x++)
615  {
616  typename SrcIterator::column_iterator cs = end.columnIterator();
617  typename DestIterator::column_iterator cd = id.columnIterator();
618  for(y=0; y != hs; y++, cs--, cd++)
619  {
620  ad.set(as(cs), cd);
621  }
622  }
623 
624  }
625  else
626  vigra_fail("transposeImage(): "
627  "This function transposes major or minor,"
628  " 'and' is included");
629 
630 }
631 
632 template <class SrcImageIterator, class SrcAccessor,
633  class DestImageIterator, class DestAccessor>
634 inline void
635 transposeImage(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
636  pair<DestImageIterator, DestAccessor> dest, Transpose transpose)
637 {
638  transposeImage(src.first, src.second, src.third, dest.first, dest.second, transpose);
639 }
640 
641 template <class T1, class S1,
642  class T2, class S2>
643 inline void
644 transposeImage(MultiArrayView<2, T1, S1> const & src,
645  MultiArrayView<2, T2, S2> dest, Transpose transpose)
646 {
647  vigra_precondition(src.shape() == reverse(dest.shape()),
648  "transposeImage(): shape mismatch between input and output.");
649  transposeImage(srcImageRange(src), destImage(dest), transpose);
650 }
651 
652 /********************************************************/
653 /* */
654 /* resampleLine */
655 /* */
656 /********************************************************/
657 
658 /*
659 * Vergroessert eine Linie um einen Faktor.
660 * Ist z.B. der Faktor = 4 so werden in der
661 * neuen Linie(Destination) jedes Pixel genau 4 mal
662 * vorkommen, also es findet auch keine Glaetung
663 * statt (NoInterpolation). Als Parameter sollen
664 * der Anfangs-, der Enditerator und der Accessor
665 * der Ausgangslinie (Source line), der Anfangsiterator
666 * und Accessor der Ziellinie (destination line) und
667 * anschliessend der Faktor um den die Linie (Zeile)
668 * vergroessert bzw. verkleinert werden soll.
669 */
670 template <class SrcIterator, class SrcAccessor,
671  class DestIterator, class DestAccessor>
672 void resampleLine(SrcIterator src_iter, SrcIterator src_iter_end, SrcAccessor src_acc,
673  DestIterator dest_iter, DestAccessor dest_acc, double factor)
674 {
675  // The width of the src line.
676  int src_width = src_iter_end - src_iter;
677 
678  vigra_precondition(src_width > 0,
679  "resampleLine(): input image too small.");
680  vigra_precondition(factor > 0.0,
681  "resampleLine(): factor must be positive.");
682 
683  if (factor >= 1.0)
684  {
685  int int_factor = (int)factor;
686  double dx = factor - int_factor;
687  double saver = dx;
688  for ( ; src_iter != src_iter_end ; ++src_iter, saver += dx)
689  {
690  if (saver >= 1.0)
691  {
692  saver = saver - (int)saver;
693  dest_acc.set(src_acc(src_iter), dest_iter);
694  ++dest_iter;
695  }
696  for(int i = 0 ; i < int_factor ; i++, ++dest_iter)
697  {
698  dest_acc.set(src_acc(src_iter), dest_iter);
699  }
700  }
701  }
702  else
703  {
704  DestIterator dest_end = dest_iter + (int)VIGRA_CSTD::ceil(src_width*factor);
705  factor = 1.0/factor;
706  int int_factor = (int)factor;
707  double dx = factor - int_factor;
708  double saver = dx;
709  src_iter_end -= 1;
710  for ( ; src_iter != src_iter_end && dest_iter != dest_end ;
711  ++dest_iter, src_iter += int_factor, saver += dx)
712  {
713  if (saver >= 1.0)
714  {
715  saver = saver - (int)saver;
716  ++src_iter;
717  }
718  dest_acc.set(src_acc(src_iter), dest_iter);
719  }
720  if (dest_iter != dest_end)
721  {
722  dest_acc.set(src_acc(src_iter_end), dest_iter);
723  }
724  }
725 }
726 
727 inline int sizeForResamplingFactor(int oldsize, double factor)
728 {
729  return (factor < 1.0)
730  ? (int)VIGRA_CSTD::ceil(oldsize * factor)
731  : (int)(oldsize * factor);
732 }
733 
734 
735 /********************************************************/
736 /* */
737 /* resampleImage */
738 /* */
739 /********************************************************/
740 
741 /** \brief Resample image by a given factor.
742 
743  This algorithm is very fast and does not require any arithmetic on the pixel types.
744  The input image must have a size of at
745  least 2x2. Destiniation pixels are directly copied from the appropriate
746  source pixels. The size of the result image is the product of <tt>factor</tt>
747  and the original size, where we round up if <tt>factor < 1.0</tt> and down otherwise.
748  This size calculation is the main difference to the convention used in the similar
749  function \ref resizeImageNoInterpolation():
750  there, the result size is calculated as <tt>n*(old_width-1)+1</tt> and
751  <tt>n*(old_height-1)+1</tt>. This is because \ref resizeImageNoInterpolation()
752  does not replicate the last pixel of every row/column in order to make it compatible
753  with the other functions of the <tt>resizeImage...</tt> family.
754 
755  The function can be called with different resampling factors for x and y, or
756  with a single factor to be used for both directions.
757 
758  It should also be noted that resampleImage() is implemented so that an enlargement followed
759  by the corresponding shrinking reproduces the original image.
760 
761  <b> Declarations:</b>
762 
763  pass 2D array views:
764  \code
765  namespace vigra {
766  template <class T1, class S1,
767  class T2, class S2>
768  void
769  resampleImage(MultiArrayView<2, T1, S1> const & src,
770  MultiArrayView<2, T2, S2> dest, double factor);
771 
772  template <class T1, class S1,
773  class T2, class S2>
774  void
775  resampleImage(MultiArrayView<2, T1, S1> const & src,
776  MultiArrayView<2, T2, S2> dest, double xfactor, double yfactor);
777  }
778  \endcode
779 
780  \deprecatedAPI{resampleImage}
781  pass \ref ImageIterators and \ref DataAccessors :
782  \code
783  namespace vigra {
784  template <class SrcIterator, class SrcAccessor,
785  class DestIterator, class DestAccessor>
786  void
787  resampleImage(SrcIterator is, SrcIterator iend, SrcAccessor sa,
788  DestIterator id, DestAccessor ad, double factor);
789 
790  template <class SrcIterator, class SrcAccessor,
791  class DestIterator, class DestAccessor>
792  void
793  resampleImage(SrcIterator is, SrcIterator iend, SrcAccessor sa,
794  DestIterator id, DestAccessor ad, double xfactor, double yfactor);
795  }
796  \endcode
797  use argument objects in conjunction with \ref ArgumentObjectFactories :
798  \code
799  namespace vigra {
800  template <class SrcImageIterator, class SrcAccessor,
801  class DestImageIterator, class DestAccessor>
802  void
803  resampleImage(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
804  pair<DestImageIterator, DestAccessor> dest, double factor);
805 
806  template <class SrcImageIterator, class SrcAccessor,
807  class DestImageIterator, class DestAccessor>
808  void
809  resampleImage(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
810  pair<DestImageIterator, DestAccessor> dest, double xfactor, double yfactor);
811  }
812  \endcode
813  \deprecatedEnd
814 
815  <b> Usage:</b>
816 
817  <b>\#include</b> <vigra/basicgeometry.hxx><br>
818  Namespace: vigra
819 
820  \code
821  double factor = 2.0;
822  MultiArray<2, float> src(width, height),
823  dest((int)(factor*width), (int)(factor*height)); // enlarge image by factor
824  ... // fill src
825 
826  resampleImage(src, dest, factor);
827  \endcode
828 
829  \deprecatedUsage{resampleImage}
830  \code
831  // use old API
832  vigra::resampleImage(srcImageRange(src), destImage(dest), factor);
833  \endcode
834  <b> Required Interface:</b>
835  \code
836  SrcImageIterator src_upperleft, src_lowerright;
837  DestImageIterator dest_upperleft;
838 
839  SrcAccessor src_accessor;
840 
841  dest_accessor.set(src_accessor(src_upperleft), dest_upperleft);
842  \endcode
843  \deprecatedEnd
844 
845  <b> Preconditions:</b>
846  \code
847  src.shape(0) > 1 && src.shape(1) > 1
848  \endcode
849 */
850 doxygen_overloaded_function(template <...> void resampleImage)
851 
852 template <class SrcIterator, class SrcAccessor,
853  class DestIterator, class DestAccessor>
854 void
855 resampleImage(SrcIterator is, SrcIterator iend, SrcAccessor sa,
856  DestIterator id, DestAccessor ad, double xfactor, double yfactor)
857 {
858  int width_old = iend.x - is.x;
859  int height_old = iend.y - is.y;
860 
861  //Bei Verkleinerung muss das dest-Bild ceiling(src*factor), da z.B.
862  //aus 6x6 grossem Bild wird eins 18x18 grosses gemacht bei Vergroesserungsfaktor 3.1
863  //umgekehrt damit wir vom 18x18 zu 6x6 (und nicht 5x5) bei Vergroesserung von 1/3.1
864  //muss das kleinste Integer das groesser als 18/3.1 ist genommen werden.
865  int height_new = sizeForResamplingFactor(height_old, yfactor);
866  int width_new = sizeForResamplingFactor(width_old, xfactor);
867 
868  vigra_precondition((width_old > 1) && (height_old > 1),
869  "resampleImage(): "
870  "Source image too small.\n");
871  vigra_precondition((width_new > 1) && (height_new > 1),
872  "resampleImage(): "
873  "Destination image too small.\n");
874 
875  typedef typename SrcAccessor::value_type SRCVT;
876  typedef BasicImage<SRCVT> TmpImage;
877  typedef typename TmpImage::traverser TmpImageIterator;
878 
879  BasicImage<SRCVT> tmp(width_old, height_new);
880 
881  int x,y;
882 
883  typename BasicImage<SRCVT>::Iterator yt = tmp.upperLeft();
884 
885  for(x=0; x<width_old; ++x, ++is.x, ++yt.x)
886  {
887  typename SrcIterator::column_iterator c1 = is.columnIterator();
888  typename TmpImageIterator::column_iterator ct = yt.columnIterator();
889  resampleLine(c1, c1 + height_old, sa, ct, tmp.accessor(), yfactor);
890  }
891 
892  yt = tmp.upperLeft();
893 
894  for(y=0; y < height_new; ++y, ++yt.y, ++id.y)
895  {
896  typename DestIterator::row_iterator rd = id.rowIterator();
897  typename TmpImageIterator::row_iterator rt = yt.rowIterator();
898  resampleLine(rt, rt + width_old, tmp.accessor(), rd, ad, xfactor);
899  }
900 
901 }
902 
903 template <class SrcIterator, class SrcAccessor,
904  class DestIterator, class DestAccessor>
905 void
906 resampleImage(SrcIterator is, SrcIterator iend, SrcAccessor sa,
907  DestIterator id, DestAccessor ad, double factor)
908 {
909  resampleImage(is, iend, sa, id, ad, factor, factor);
910 }
911 
912 template <class SrcImageIterator, class SrcAccessor,
913  class DestImageIterator, class DestAccessor>
914 inline void
915 resampleImage(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
916  pair<DestImageIterator, DestAccessor> dest, double factor)
917 {
918  resampleImage(src.first, src.second, src.third, dest.first, dest.second, factor);
919 }
920 
921 template <class SrcImageIterator, class SrcAccessor,
922  class DestImageIterator, class DestAccessor>
923 inline void
924 resampleImage(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
925  pair<DestImageIterator, DestAccessor> dest, double xfactor, double yfactor)
926 {
927  resampleImage(src.first, src.second, src.third, dest.first, dest.second, xfactor, yfactor);
928 }
929 
930 template <class T1, class S1,
931  class T2, class S2>
932 inline void
933 resampleImage(MultiArrayView<2, T1, S1> const & src,
934  MultiArrayView<2, T2, S2> dest, double factor)
935 {
936  if(factor > 1.0)
937  vigra_precondition(floor(factor*src.shape()) == dest.shape(),
938  "resampleImage(): shape mismatch between input and output.");
939  else
940  vigra_precondition(ceil(factor*src.shape()) == dest.shape(),
941  "resampleImage(): shape mismatch between input and output.");
942 
943  resampleImage(srcImageRange(src), destImage(dest), factor);
944 }
945 
946 template <class T1, class S1,
947  class T2, class S2>
948 inline void
949 resampleImage(MultiArrayView<2, T1, S1> const & src,
950  MultiArrayView<2, T2, S2> dest, double xfactor, double yfactor)
951 {
952  if(xfactor > 1.0)
953  vigra_precondition(floor(xfactor*src.shape(0)) == dest.shape(0),
954  "resampleImage(): shape mismatch between input and output.");
955  else
956  vigra_precondition(ceil(xfactor*src.shape(0)) == dest.shape(0),
957  "resampleImage(): shape mismatch between input and output.");
958  if(yfactor > 1.0)
959  vigra_precondition(floor(yfactor*src.shape(1)) == dest.shape(1),
960  "resampleImage(): shape mismatch between input and output.");
961  else
962  vigra_precondition(ceil(yfactor*src.shape(1)) == dest.shape(1),
963  "resampleImage(): shape mismatch between input and output.");
964 
965  resampleImage(srcImageRange(src), destImage(dest), xfactor, yfactor);
966 }
967 
968 //@}
969 
970 } // namespace vigra
971 
972 
973 #endif /* VIGRA_BASICGEOMETRY_HXX */
void transposeImage(...)
Transpose an image over the major or minor diagonal.
doxygen_overloaded_function(template<...> void separableConvolveBlockwise) template< unsigned int N
Separated convolution on ChunkedArrays.
void copyImage(...)
Copy source image into destination image.
void reflectImage(...)
Reflect image horizontally or vertically.
void resampleImage(...)
Resample image by a given factor.
int ceil(FixedPoint< IntBits, FracBits > v)
rounding up.
Definition: fixedpoint.hxx:675
int floor(FixedPoint< IntBits, FracBits > v)
rounding down.
Definition: fixedpoint.hxx:667

© 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.11.1 (Fri May 19 2017)