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

basicgeometry.hxx
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
46namespace 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*/
189doxygen_overloaded_function(template <...> void rotateImage)
190
191template <class SrcIterator, class SrcAccessor,
192 class DestIterator, class DestAccessor>
193void 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
260template <class SrcImageIterator, class SrcAccessor,
261 class DestImageIterator, class DestAccessor>
262inline void
263rotateImage(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
269template <class T1, class S1,
270 class T2, class S2>
271inline void
272rotateImage(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
291enum Reflect {horizontal = 1, vertical = 2};
292
293inline
294Reflect 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*/
382doxygen_overloaded_function(template <...> void reflectImage)
383
384template <class SrcIterator, class SrcAccessor,
385 class DestIterator, class DestAccessor>
386void 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
442template <class SrcImageIterator, class SrcAccessor,
443 class DestImageIterator, class DestAccessor>
444inline void
445reflectImage(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
451template <class T1, class S1,
452 class T2, class S2>
453inline void
454reflectImage(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
469enum 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*/
570doxygen_overloaded_function(template <...> void transposeImage)
571
572template <class SrcIterator, class SrcAccessor,
573 class DestIterator, class DestAccessor>
574void 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
632template <class SrcImageIterator, class SrcAccessor,
633 class DestImageIterator, class DestAccessor>
634inline void
635transposeImage(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
641template <class T1, class S1,
642 class T2, class S2>
643inline void
644transposeImage(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*/
670template <class SrcIterator, class SrcAccessor,
671 class DestIterator, class DestAccessor>
672void 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
727inline 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*/
850doxygen_overloaded_function(template <...> void resampleImage)
851
852template <class SrcIterator, class SrcAccessor,
853 class DestIterator, class DestAccessor>
854void
855resampleImage(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
903template <class SrcIterator, class SrcAccessor,
904 class DestIterator, class DestAccessor>
905void
906resampleImage(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
912template <class SrcImageIterator, class SrcAccessor,
913 class DestImageIterator, class DestAccessor>
914inline void
915resampleImage(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
921template <class SrcImageIterator, class SrcAccessor,
922 class DestImageIterator, class DestAccessor>
923inline void
924resampleImage(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
930template <class T1, class S1,
931 class T2, class S2>
932inline void
933resampleImage(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
946template <class T1, class S1,
947 class T2, class S2>
948inline void
949resampleImage(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 */
Definition basicimage.hxx:265
Fundamental class template for images.
Definition basicimage.hxx:476
Accessor accessor()
Definition basicimage.hxx:1066
traverser upperLeft()
Definition basicimage.hxx:925
int floor(FixedPoint< IntBits, FracBits > v)
rounding down.
Definition fixedpoint.hxx:667
void reflectImage(...)
Reflect image horizontally or vertically.
void resampleImage(...)
Resample image by a given factor.
void transposeImage(...)
Transpose an image over the major or minor diagonal.
int ceil(FixedPoint< IntBits, FracBits > v)
rounding up.
Definition fixedpoint.hxx:675
void copyImage(...)
Copy source image into destination image.

© 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.12.2