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
37 #ifndef VIGRA_TRANSFORMIMAGE_HXX
38 #define VIGRA_TRANSFORMIMAGE_HXX
39
40 #include "utilities.hxx"
41 #include "numerictraits.hxx"
42 #include "iteratortraits.hxx"
43 #include "rgbvalue.hxx"
44 #include "functortraits.hxx"
45 #include "inspectimage.hxx"
46 #include "multi_shape.hxx"
47
48 namespace vigra {
49
50 /** \addtogroup TransformAlgo Algorithms to Transform Images
51 Apply functor to calculate a pixelwise transformation of one image
52
53 @{
54 */
55
56 /********************************************************/
57 /* */
58 /* transformLine */
59 /* */
60 /********************************************************/
61
62 template <class SrcIterator, class SrcAccessor,
63 class DestIterator, class DestAccessor, class Functor>
64 void
transformLine(SrcIterator s,SrcIterator send,SrcAccessor src,DestIterator d,DestAccessor dest,Functor const & f)65 transformLine(SrcIterator s,
66 SrcIterator send, SrcAccessor src,
67 DestIterator d, DestAccessor dest,
68 Functor const & f)
69 {
70 for(; s != send; ++s, ++d)
71 dest.set(f(src(s)), d);
72 }
73
74 template <class SrcIterator, class SrcAccessor,
75 class MaskIterator, class MaskAccessor,
76 class DestIterator, class DestAccessor,
77 class Functor>
78 void
transformLineIf(SrcIterator s,SrcIterator send,SrcAccessor src,MaskIterator m,MaskAccessor mask,DestIterator d,DestAccessor dest,Functor const & f)79 transformLineIf(SrcIterator s,
80 SrcIterator send, SrcAccessor src,
81 MaskIterator m, MaskAccessor mask,
82 DestIterator d, DestAccessor dest,
83 Functor const & f)
84 {
85 for(; s != send; ++s, ++d, ++m)
86 if(mask(m))
87 dest.set(f(src(s)), d);
88 }
89
90 /********************************************************/
91 /* */
92 /* transformImage */
93 /* */
94 /********************************************************/
95
96 /** \brief Apply unary point transformation to each pixel.
97
98 After the introduction of arithmetic and algebraic \ref MultiMathModule "array expressions",
99 this function is rarely needed. Moreover, \ref transformMultiArray() provides the
100 same functionality for arbitrary dimensional arrays.
101
102 The transformation given by the functor is applied to every source
103 pixel and the result written into the corresponding destination pixel.
104 Note that the unary functors of the STL can be used in addition to
105 the functors specifically defined in \ref TransformFunctor.
106 Creation of new functors is easiest by using \ref FunctorExpressions.
107
108 <b> Declarations:</b>
109
110 pass 2D array views:
111 \code
112 namespace vigra {
113 template <class T1, class S1,
114 class T2, class S2, class Functor>
115 void
116 transformImage(MultiArrayView<2, T1, S1> const & src,
117 MultiArrayView<2, T2, S2> dest,
118 Functor const & f);
119 }
120 \endcode
121
122 \deprecatedAPI{transformImage}
123 pass \ref ImageIterators and \ref DataAccessors :
124 \code
125 namespace vigra {
126 template <class SrcImageIterator, class SrcAccessor,
127 class DestImageIterator, class DestAccessor, class Functor>
128 void
129 transformImage(SrcImageIterator src_upperleft,
130 SrcImageIterator src_lowerright, SrcAccessor sa,
131 DestImageIterator dest_upperleft, DestAccessor da,
132 Functor const & f)
133 }
134 \endcode
135 use argument objects in conjunction with \ref ArgumentObjectFactories :
136 \code
137 namespace vigra {
138 template <class SrcImageIterator, class SrcAccessor,
139 class DestImageIterator, class DestAccessor, class Functor>
140 void
141 transformImage(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
142 pair<DestImageIterator, DestAccessor> dest,
143 Functor const & f)
144 }
145 \endcode
146 \deprecatedEnd
147
148 <b> Usage:</b>
149
150 <b>\#include</b> \<vigra/transformimage.hxx\><br>
151 Namespace: vigra
152
153 \code
154 #include <cmath> // for sqrt()
155 MultiArray<2, float> src(100, 200),
156 dest(100, 200);
157 ...
158
159 transformImage(src, dest, &std::sqrt );
160 \endcode
161
162 \deprecatedUsage{transformImage}
163 \code
164 #include <cmath> // for sqrt()
165 FImage src(100, 200),
166 dest(100, 200);
167
168 vigra::transformImage(srcImageRange(src),
169 destImage(dest),
170 (double(*)(double))&std::sqrt );
171
172 \endcode
173 <b> Required Interface:</b>
174 \code
175 SrcImageIterator src_upperleft, src_lowerright;
176 DestImageIterator dest_upperleft;
177 SrcImageIterator::row_iterator sx = src_upperleft.rowIterator();
178 DestImageIterator::row_iterator dx = dest_upperleft.rowIterator();
179
180 SrcAccessor src_accessor;
181 DestAccessor dest_accessor;
182
183 Functor functor;
184
185 dest_accessor.set(functor(src_accessor(sx)), dx);
186
187 \endcode
188 \deprecatedEnd
189
190 \see TransformFunctor, MultiMathModule, \ref FunctorExpressions
191 */
doxygen_overloaded_function(template<...> void transformImage)192 doxygen_overloaded_function(template <...> void transformImage)
193
194 template <class SrcImageIterator, class SrcAccessor,
195 class DestImageIterator, class DestAccessor, class Functor>
196 void
197 transformImage(SrcImageIterator src_upperleft,
198 SrcImageIterator src_lowerright, SrcAccessor sa,
199 DestImageIterator dest_upperleft, DestAccessor da,
200 Functor const & f)
201 {
202 int w = src_lowerright.x - src_upperleft.x;
203
204 for(; src_upperleft.y < src_lowerright.y; ++src_upperleft.y, ++dest_upperleft.y)
205 {
206 transformLine(src_upperleft.rowIterator(),
207 src_upperleft.rowIterator() + w, sa,
208 dest_upperleft.rowIterator(), da, f);
209 }
210 }
211
212 template <class SrcImageIterator, class SrcAccessor,
213 class DestImageIterator, class DestAccessor, class Functor>
214 inline void
transformImage(triple<SrcImageIterator,SrcImageIterator,SrcAccessor> src,pair<DestImageIterator,DestAccessor> dest,Functor const & f)215 transformImage(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
216 pair<DestImageIterator, DestAccessor> dest,
217 Functor const & f)
218 {
219 transformImage(src.first, src.second, src.third,
220 dest.first, dest.second, f);
221 }
222
223 template <class T1, class S1,
224 class T2, class S2, class Functor>
225 inline void
transformImage(MultiArrayView<2,T1,S1> const & src,MultiArrayView<2,T2,S2> dest,Functor const & f)226 transformImage(MultiArrayView<2, T1, S1> const & src,
227 MultiArrayView<2, T2, S2> dest,
228 Functor const & f)
229 {
230 vigra_precondition(src.shape() == dest.shape(),
231 "transformImage(): shape mismatch between input and output.");
232 transformImage(srcImageRange(src),
233 destImage(dest), f);
234 }
235
236 /********************************************************/
237 /* */
238 /* transformImageIf */
239 /* */
240 /********************************************************/
241
242 /** \brief Apply unary point transformation to each pixel within the ROI
243 (i.e., where the mask is non-zero).
244
245 After the introduction of arithmetic and algebraic \ref MultiMathModule "array expressions",
246 this function is rarely needed. Moreover, \ref combineTwoMultiArrays() provides the
247 same functionality for arbitrary dimensional arrays.
248
249 The transformation given by the functor is applied to every source
250 pixel in the ROI (i.e. when the return value of the mask's accessor
251 is not zero)
252 and the result is written into the corresponding destination pixel.
253 The function uses accessors to access the pixel data.
254 Note that the unary functors of the STL can be used in addition to
255 the functors specifically defined in \ref TransformFunctor.
256 Creation of new functors is easiest by using \ref FunctorExpressions.
257
258 <b> Declarations:</b>
259
260 pass 2D array views:
261 \code
262 namespace vigra {
263 template <class T1, class S1,
264 class TM, class SM,
265 class T2, class S2,
266 class Functor>
267 void
268 transformImageIf(MultiArrayView<2, T1, S1> const & src,
269 MultiArrayView<2, TM, SM> const & mask,
270 MultiArrayView<2, T2, S2> dest,
271 Functor const & f);
272 }
273 \endcode
274
275 \deprecatedAPI{transformImageIf}
276 pass \ref ImageIterators and \ref DataAccessors :
277 \code
278 namespace vigra {
279 template <class SrcImageIterator, class SrcAccessor,
280 class MaskImageIterator, class MaskAccessor,
281 class DestImageIterator, clas DestAccessor,
282 class Functor>
283 void
284 transformImageIf(SrcImageIterator src_upperleft,
285 SrcImageIterator src_lowerright, SrcAccessor sa,
286 MaskImageIterator mask_upperleft, MaskAccessor ma,
287 DestImageIterator dest_upperleft, DestAccessor da,
288 Functor const & f)
289 }
290 \endcode
291 use argument objects in conjunction with \ref ArgumentObjectFactories :
292 \code
293 namespace vigra {
294 template <class SrcImageIterator, class SrcAccessor,
295 class MaskImageIterator, class MaskAccessor,
296 class DestImageIterator, clas DestAccessor,
297 class Functor>
298 void
299 transformImageIf(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
300 pair<MaskImageIterator, MaskAccessor> mask,
301 pair<DestImageIterator, DestAccessor> dest,
302 Functor const & f)
303 }
304 \endcode
305 \deprecatedEnd
306
307 <b> Usage:</b>
308
309 <b>\#include</b> \<vigra/transformimage.hxx\><br>
310 Namespace: vigra
311
312 \code
313 #include <cmath> // for sqrt()
314
315 MultiArray<2, unsigned char> mask(100, 200),
316 MultiArray<2, float> src(100, 200),
317 dest(100, 200);
318 ... // fill src and mask
319
320 transformImageIf(src, mask, dest, &std::sqrt );
321 \endcode
322
323 \deprecatedUsage{transformImageIf}
324 \code
325 #include <cmath> // for sqrt()
326
327 vigra::transformImageIf(srcImageRange(src),
328 maskImage(mask),
329 destImage(dest),
330 (double(*)(double))&std::sqrt );
331
332 \endcode
333 <b> Required Interface:</b>
334 \code
335 SrcImageIterator src_upperleft, src_lowerright;
336 DestImageIterator dest_upperleft;
337 MaskImageIterator mask_upperleft;
338 SrcImageIterator::row_iterator sx = src_upperleft.rowIterator();
339 MaskImageIterator::row_iterator mx = mask_upperleft.rowIterator();
340 DestImageIterator::row_iterator dx = dest_upperleft.rowIterator();
341
342 SrcAccessor src_accessor;
343 DestAccessor dest_accessor;
344 MaskAccessor mask_accessor;
345 Functor functor;
346
347 if(mask_accessor(mx))
348 dest_accessor.set(functor(src_accessor(sx)), dx);
349
350 \endcode
351 \deprecatedEnd
352
353 \see TransformFunctor, MultiMathModule, \ref FunctorExpressions
354 */
doxygen_overloaded_function(template<...> void transformImageIf)355 doxygen_overloaded_function(template <...> void transformImageIf)
356
357 template <class SrcImageIterator, class SrcAccessor,
358 class MaskImageIterator, class MaskAccessor,
359 class DestImageIterator, class DestAccessor,
360 class Functor>
361 void
362 transformImageIf(SrcImageIterator src_upperleft,
363 SrcImageIterator src_lowerright, SrcAccessor sa,
364 MaskImageIterator mask_upperleft, MaskAccessor ma,
365 DestImageIterator dest_upperleft, DestAccessor da,
366 Functor const & f)
367 {
368 int w = src_lowerright.x - src_upperleft.x;
369
370 for(; src_upperleft.y < src_lowerright.y;
371 ++src_upperleft.y, ++mask_upperleft.y, ++dest_upperleft.y)
372 {
373 transformLineIf(src_upperleft.rowIterator(),
374 src_upperleft.rowIterator() + w, sa,
375 mask_upperleft.rowIterator(), ma,
376 dest_upperleft.rowIterator(), da, f);
377 }
378 }
379
380 template <class SrcImageIterator, class SrcAccessor,
381 class MaskImageIterator, class MaskAccessor,
382 class DestImageIterator, class DestAccessor,
383 class Functor>
384 inline void
transformImageIf(triple<SrcImageIterator,SrcImageIterator,SrcAccessor> src,pair<MaskImageIterator,MaskAccessor> mask,pair<DestImageIterator,DestAccessor> dest,Functor const & f)385 transformImageIf(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
386 pair<MaskImageIterator, MaskAccessor> mask,
387 pair<DestImageIterator, DestAccessor> dest,
388 Functor const & f)
389 {
390 transformImageIf(src.first, src.second, src.third,
391 mask.first, mask.second,
392 dest.first, dest.second, f);
393 }
394
395 template <class T1, class S1,
396 class TM, class SM,
397 class T2, class S2,
398 class Functor>
399 inline void
transformImageIf(MultiArrayView<2,T1,S1> const & src,MultiArrayView<2,TM,SM> const & mask,MultiArrayView<2,T2,S2> dest,Functor const & f)400 transformImageIf(MultiArrayView<2, T1, S1> const & src,
401 MultiArrayView<2, TM, SM> const & mask,
402 MultiArrayView<2, T2, S2> dest,
403 Functor const & f)
404 {
405 vigra_precondition(src.shape() == mask.shape() && src.shape() == dest.shape(),
406 "transformImageIf(): shape mismatch between input and output.");
407 transformImageIf(srcImageRange(src),
408 maskImage(mask),
409 destImage(dest), f);
410 }
411
412 /********************************************************/
413 /* */
414 /* gradientBasedTransform */
415 /* */
416 /********************************************************/
417
418 /** \brief Calculate a function of the image gradient.
419
420 The gradient and the function represented by <TT>Functor f</TT>
421 are calculated in one go: for each location, the symmetric
422 difference in x- and y-directions (asymmetric difference at the
423 image borders) are passed to the given functor, and the result is
424 written to the destination image. Functors to be used with this
425 function include \ref MagnitudeFunctor and \ref
426 RGBGradientMagnitudeFunctor.
427
428 <b> Declarations:</b>
429
430 pass 2D array views:
431 \code
432 namespace vigra {
433 template <class T1, class S1,
434 class T2, class S2,
435 class Functor>
436 void
437 gradientBasedTransform(MultiArrayView<2, T1, S1> const & src,
438 MultiArrayView<2, T2, S2> dest,
439 Functor const & grad);
440 }
441 \endcode
442
443 \deprecatedAPI{gradientBasedTransform}
444 pass \ref ImageIterators and \ref DataAccessors :
445 \code
446 namespace vigra {
447 template <class SrcImageIterator, class SrcAccessor,
448 class DestImageIterator, class DestAccessor, class Functor>
449 void
450 gradientBasedTransform(SrcImageIterator srcul, SrcImageIterator srclr, SrcAccessor sa,
451 DestImageIterator destul, DestAccessor da, Functor const & f)
452 }
453 \endcode
454 use argument objects in conjunction with \ref ArgumentObjectFactories :
455 \code
456 namespace vigra {
457 template <class SrcImageIterator, class SrcAccessor,
458 class DestImageIterator, class DestAccessor, class Functor>
459 void
460 gradientBasedTransform(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
461 pair<DestImageIterator, DestAccessor> dest, Functor const & const & f)
462 }
463 \endcode
464 \deprecatedEnd
465
466 <b> Usage:</b>
467
468 <b>\#include</b> \<vigra/transformimage.hxx\><br/>
469 Namespace: vigra
470
471 \code
472 MultiArray<2, float> src(w,h), magnitude(w,h);
473 ...
474
475 gradientBasedTransform(src, magnitude,
476 MagnitudeFunctor<float>());
477 \endcode
478
479 \deprecatedUsage{gradientBasedTransform}
480 \code
481 vigra::FImage src(w,h), magnitude(w,h);
482 ...
483
484 gradientBasedTransform(srcImageRange(src), destImage(magnitude),
485 vigra::MagnitudeFunctor<float>());
486 \endcode
487 <b> Required Interface:</b>
488 \code
489 SrcImageIterator is, isend;
490 DestImageIterator id;
491
492 SrcAccessor src_accessor;
493 DestAccessor dest_accessor;
494
495 typename NumericTraits<typename SrcAccessor::value_type>::RealPromote
496 diffx, diffy;
497
498 diffx = src_accessor(is, Diff2D(-1,0)) - src_accessor(is, Diff2D(1,0));
499 diffy = src_accessor(is, Diff2D(0,-1)) - src_accessor(is, Diff2D(0,1));
500
501 Functor f;
502
503 dest_accessor.set(f(diffx, diffy), id);
504
505 \endcode
506 \deprecatedEnd
507
508 \see TransformFunctor, MultiMathModule, \ref FunctorExpressions
509 */
doxygen_overloaded_function(template<...> void gradientBasedTransform)510 doxygen_overloaded_function(template <...> void gradientBasedTransform)
511
512 template <class SrcImageIterator, class SrcAccessor,
513 class DestImageIterator, class DestAccessor, class Functor>
514 void
515 gradientBasedTransform(SrcImageIterator srcul, SrcImageIterator srclr, SrcAccessor sa,
516 DestImageIterator destul, DestAccessor da, Functor const & grad)
517 {
518 int w = srclr.x - srcul.x;
519 int h = srclr.y - srcul.y;
520 int x,y;
521
522 SrcImageIterator sy = srcul;
523 DestImageIterator dy = destul;
524
525 const Diff2D left(-1,0);
526 const Diff2D right(1,0);
527 const Diff2D top(0,-1);
528 const Diff2D bottom(0,1);
529
530 typedef typename NumericTraits<typename SrcAccessor::value_type>::RealPromote TmpType;
531 TmpType diffx, diffy;
532
533 SrcImageIterator sx = sy;
534 DestImageIterator dx = dy;
535
536 diffx = sa(sx) - sa(sx, right);
537 diffy = sa(sx) - sa(sx, bottom);
538 da.set(grad(diffx, diffy), dx);
539
540 for(x=2, ++sx.x, ++dx.x; x<w; ++x, ++sx.x, ++dx.x)
541 {
542 diffx = (sa(sx, left) - sa(sx, right)) / TmpType(2.0);
543 diffy = sa(sx) - sa(sx, bottom);
544 da.set(grad(diffx, diffy), dx);
545 }
546
547 diffx = sa(sx, left) - sa(sx);
548 diffy = sa(sx) - sa(sx, bottom);
549 da.set(grad(diffx, diffy), dx);
550
551 ++sy.y;
552 ++dy.y;
553
554 for(y=2; y<h; ++y, ++sy.y, ++dy.y)
555 {
556 sx = sy;
557 dx = dy;
558
559 diffx = sa(sx) - sa(sx, right);
560 diffy = (sa(sx, top) - sa(sx, bottom)) / TmpType(2.0);
561 da.set(grad(diffx, diffy), dx);
562
563 for(x=2, ++sx.x, ++dx.x; x<w; ++x, ++sx.x, ++dx.x)
564 {
565 diffx = (sa(sx, left) - sa(sx, right)) / TmpType(2.0);
566 diffy = (sa(sx, top) - sa(sx, bottom)) / TmpType(2.0);
567 da.set(grad(diffx, diffy), dx);
568 }
569
570 diffx = sa(sx, left) - sa(sx);
571 diffy = (sa(sx, top) - sa(sx, bottom)) / TmpType(2.0);
572 da.set(grad(diffx, diffy), dx);
573 }
574
575 sx = sy;
576 dx = dy;
577
578 diffx = sa(sx) - sa(sx, right);
579 diffy = sa(sx, top) - sa(sx);
580 da.set(grad(diffx, diffy), dx);
581
582 for(x=2, ++sx.x, ++dx.x; x<w; ++x, ++sx.x, ++dx.x)
583 {
584 diffx = (sa(sx, left) - sa(sx, right)) / TmpType(2.0);
585 diffy = sa(sx, top) - sa(sx);
586 da.set(grad(diffx, diffy), dx);
587 }
588
589 diffx = sa(sx, left) - sa(sx);
590 diffy = sa(sx, top) - sa(sx);
591 da.set(grad(diffx, diffy), dx);
592 }
593
594 template <class SrcImageIterator, class SrcAccessor,
595 class DestImageIterator, class DestAccessor, class Functor>
596 inline void
gradientBasedTransform(triple<SrcImageIterator,SrcImageIterator,SrcAccessor> src,pair<DestImageIterator,DestAccessor> dest,Functor const & grad)597 gradientBasedTransform(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
598 pair<DestImageIterator, DestAccessor> dest, Functor const & grad)
599 {
600 gradientBasedTransform(src.first, src.second, src.third,
601 dest.first, dest.second, grad);
602 }
603
604 template <class T1, class S1,
605 class T2, class S2, class Functor>
606 inline void
gradientBasedTransform(MultiArrayView<2,T1,S1> const & src,MultiArrayView<2,T2,S2> dest,Functor const & grad)607 gradientBasedTransform(MultiArrayView<2, T1, S1> const & src,
608 MultiArrayView<2, T2, S2> dest, Functor const & grad)
609 {
610 vigra_precondition(src.shape() == dest.shape(),
611 "gradientBasedTransform(): shape mismatch between input and output.");
612 gradientBasedTransform(srcImageRange(src),
613 destImage(dest), grad);
614 }
615
616 /** @} */
617 /** \addtogroup TransformFunctor Functors to Transform Images
618
619 Note that the unary functors of the STL can also be used in
620 connection with \ref transformImage().
621 */
622 //@{
623
624 template <class DestValueType, class Multiplier = double>
625 class LinearIntensityTransform
626 {
627 public:
628 /* the functors argument type (actually, since
629 <tt>operator()</tt> is a template, much more types are possible)
630 */
631 typedef DestValueType argument_type;
632
633 /* the functors result type
634 */
635 typedef DestValueType result_type;
636
637 /* \deprecated use argument_type and result_type
638 */
639 typedef DestValueType value_type;
640
641 /* type of the offset (used in internal calculations to prevent
642 overflows and minimize round-off errors).
643 */
644 typedef typename
645 NumericTraits<DestValueType>::RealPromote argument_promote;
646
647 /* type of the scale factor
648 */
649 typedef Multiplier scalar_multiplier_type;
650
651 /* init scale and offset
652 */
LinearIntensityTransform(scalar_multiplier_type scale,argument_promote offset)653 LinearIntensityTransform(scalar_multiplier_type scale, argument_promote offset)
654 : scale_(scale), offset_(offset)
655 {}
656
657 /* calculate transform
658 */
659 template <class SrcValueType>
operator ()(SrcValueType const & s) const660 result_type operator()(SrcValueType const & s) const
661 {
662 return NumericTraits<result_type>::fromRealPromote(scale_ * (s + offset_));
663 }
664
665 private:
666
667 scalar_multiplier_type scale_;
668 argument_promote offset_;
669 };
670
671 template <class DestValueType, class Multiplier>
672 class FunctorTraits<LinearIntensityTransform<DestValueType, Multiplier> >
673 : public FunctorTraitsBase<LinearIntensityTransform<DestValueType, Multiplier> >
674 {
675 public:
676 typedef VigraTrueType isUnaryFunctor;
677 };
678
679 template <class DestValueType, class Multiplier = double>
680 class ScalarIntensityTransform
681 {
682 public:
683 /* the functors argument type (actually, since
684 <tt>operator()</tt> is a template, much more types are possible)
685 */
686 typedef DestValueType argument_type;
687
688 /* the functors result type
689 */
690 typedef DestValueType result_type;
691
692 /* \deprecated use argument_type and result_type
693 */
694 typedef DestValueType value_type;
695
696 /* type of the scale factor
697 */
698 typedef Multiplier scalar_multiplier_type;
699
700 /* init scale
701 */
ScalarIntensityTransform(scalar_multiplier_type scale)702 ScalarIntensityTransform(scalar_multiplier_type scale)
703 : scale_(scale)
704 {}
705
706 /* calculate transform
707 */
708 template <class SrcValueType>
operator ()(SrcValueType const & s) const709 result_type operator()(SrcValueType const & s) const
710 {
711 return NumericTraits<result_type>::fromRealPromote(scale_ * s);
712 }
713
714 private:
715 scalar_multiplier_type scale_;
716 };
717
718 template <class DestValueType, class Multiplier>
719 class FunctorTraits<ScalarIntensityTransform<DestValueType, Multiplier> >
720 : public FunctorTraitsBase<ScalarIntensityTransform<DestValueType, Multiplier> >
721 {
722 public:
723 typedef VigraTrueType isUnaryFunctor;
724 };
725
726 /********************************************************/
727 /* */
728 /* linearIntensityTransform */
729 /* */
730 /********************************************************/
731
732 /** \brief Apply a linear transform to the source pixel values
733
734 Factory function for a functor that linearly transforms the
735 source pixel values. The functor applies the transform
736 '<TT>destvalue = scale * (srcvalue + offset)</TT>' to every pixel.
737 This can, for example, be used to transform images into the visible
738 range 0...255 or to invert an image.
739
740 If you leave out the second parameter / offset, you will get an
741 optimized version of the functor which only scales by the given
742 factor, however you have to make the template parameter (pixel
743 type) explicit then.
744
745 <b> Traits defined:</b>
746
747 <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
748
749 <b> Declaration:</b>
750
751 \code
752 namespace vigra {
753 template <class Multiplier, class DestValueType>
754 LinearIntensityTransform<DestValueType, Multiplier>
755 linearIntensityTransform(Multiplier scale, DestValueType offset);
756
757 template <class DestValueType, class Multiplier>
758 ScalarIntensityTransform<DestValueType, Multiplier>
759 linearIntensityTransform(Multiplier scale);
760 }
761 \endcode
762
763 <b> Usage:</b>
764
765 <b>\#include</b> \<vigra/transformimage.hxx\><br>
766 Namespace: vigra
767
768 \code
769 vigra::IImage src(width, height);
770 vigra::BImage dest(width, height);
771 ...
772 vigra::FindMinMax<IImage::PixelType> minmax; // functor to find range
773
774 vigra::inspectImage(srcImageRange(src), minmax); // find original range
775
776 // transform to range 0...255
777 vigra::transformImage(srcImageRange(src), destImage(dest),
778 linearIntensityTransform(
779 255.0 / (minmax.max - minmax.min), // scaling
780 - minmax.min)); // offset
781 \endcode
782
783 The one-parameter version can be used like this:
784
785 \code
786 // scale from 0..255 to 0..1.0
787 FImage dest(src.size());
788
789 vigra::transformImage(srcImageRange(src), destImage(dest),
790 linearIntensityTransform<float>(1.0 / 255));
791 \endcode
792
793 <b> Required Interface:</b>
794
795 The source and destination value types must be models of \ref LinearSpace in both cases.
796
797 */
798 template <class Multiplier, class DestValueType>
799 LinearIntensityTransform<DestValueType, Multiplier>
linearIntensityTransform(Multiplier scale,DestValueType offset)800 linearIntensityTransform(Multiplier scale, DestValueType offset)
801 {
802 return LinearIntensityTransform<DestValueType, Multiplier>(scale, offset);
803 }
804
805 template <class DestValueType, class Multiplier>
806 ScalarIntensityTransform<DestValueType, Multiplier>
linearIntensityTransform(Multiplier scale)807 linearIntensityTransform(Multiplier scale)
808 {
809 return ScalarIntensityTransform<DestValueType, Multiplier>(scale);
810 }
811
812 /********************************************************/
813 /* */
814 /* linearRangeMapping */
815 /* */
816 /********************************************************/
817
818 /** \brief Map a source intensity range linearly to a destination range.
819
820 Factory function for a functor that linearly transforms the
821 source pixel values. The functor applies the transform
822 '<TT>destvalue = scale * (srcvalue + offset)</TT>' to every pixel,
823 where <tt>scale = (dest_max - dest_min) / (src_max - src_min)</tt>
824 and <tt>offset = dest_min / scale - src_min</tt>. As a result,
825 the pixel values <tt>src_max</tt>, <tt>src_min</tt> in the source image
826 are mapped onto <tt>dest_max</tt>, <tt>dest_min</tt> respectively.
827 This works for scalar as well as vector pixel types. Instead of
828 <tt>src_min</tt> and <tt>src_max</tt>, you may also pass a functor
829 \ref FindMinMax.
830
831 <b> Declaration:</b>
832
833 \code
834 namespace vigra {
835 template <class SrcValueType, class DestValueType>
836 LinearIntensityTransform<DestValueType, typename NumericTraits<DestValueType>::RealPromote>
837 linearRangeMapping(SrcValueType src_min, SrcValueType src_max,
838 DestValueType dest_min, DestValueType dest_max );
839
840 template <class SrcValueType, class DestValueType>
841 LinearIntensityTransform<DestValueType, typename NumericTraits<DestValueType>::RealPromote>
842 linearRangeMapping(SrcValueType src_min, SrcValueType src_max,
843 DestValueType dest_min, DestValueType dest_max );
844 }
845 \endcode
846
847 <b> Usage:</b>
848
849 <b>\#include</b> \<vigra/transformimage.hxx\><br>
850 Namespace: vigra
851
852 \code
853 vigra::IImage src(width, height);
854 vigra::BImage dest(width, height);
855 ...
856 vigra::FindMinMax<IImage::PixelType> minmax; // functor to find range
857
858 vigra::inspectImage(srcImageRange(src), minmax); // find original range
859
860 // transform to range 0...255
861 vigra::transformImage(srcImageRange(src), destImage(dest),
862 linearRangeMapping(
863 minmax.min, minmax.max, // src range
864 0, 255) // dest range
865 );
866
867 // equivalent, but shorter
868 vigra::transformImage(srcImageRange(src), destImage(dest),
869 linearRangeMapping(
870 minmax, // src range
871 0, 255) // dest range
872 );
873 \endcode
874
875 <b> Required Interface:</b>
876
877 The source and destination value types must be models of \ref LinearSpace in both cases.
878
879 */
880 template <class SrcValueType, class DestValueType>
881 LinearIntensityTransform<DestValueType, typename NumericTraits<DestValueType>::RealPromote>
linearRangeMapping(SrcValueType src_min,SrcValueType src_max,DestValueType dest_min,DestValueType dest_max)882 linearRangeMapping(SrcValueType src_min, SrcValueType src_max,
883 DestValueType dest_min, DestValueType dest_max )
884 {
885 return linearRangeMapping(src_min, src_max, dest_min, dest_max,
886 typename NumericTraits<DestValueType>::isScalar());
887 }
888
889 template <class SrcValueType, class DestValueType>
890 LinearIntensityTransform<DestValueType, typename NumericTraits<DestValueType>::RealPromote>
linearRangeMapping(FindMinMax<SrcValueType> const & src,DestValueType dest_min,DestValueType dest_max)891 linearRangeMapping(FindMinMax<SrcValueType> const & src,
892 DestValueType dest_min, DestValueType dest_max )
893 {
894 return linearRangeMapping(src.min, src.max, dest_min, dest_max,
895 typename NumericTraits<DestValueType>::isScalar());
896 }
897
898 template <class SrcValueType, class DestValueType>
899 LinearIntensityTransform<DestValueType, typename NumericTraits<DestValueType>::RealPromote>
linearRangeMapping(SrcValueType src_min,SrcValueType src_max,DestValueType dest_min,DestValueType dest_max,VigraTrueType)900 linearRangeMapping(
901 SrcValueType src_min, SrcValueType src_max,
902 DestValueType dest_min, DestValueType dest_max,
903 VigraTrueType /* isScalar */ )
904 {
905 typedef typename NumericTraits<DestValueType>::RealPromote Multiplier;
906 Multiplier diff = src_max - src_min;
907 Multiplier scale = diff == NumericTraits<Multiplier>::zero()
908 ? NumericTraits<Multiplier>::one()
909 : (dest_max - dest_min) / diff;
910 return LinearIntensityTransform<DestValueType, Multiplier>(
911 scale, dest_min / scale - src_min );
912 }
913
914 template <class SrcValueType, class DestValueType>
915 LinearIntensityTransform<DestValueType, typename NumericTraits<DestValueType>::RealPromote>
linearRangeMapping(SrcValueType src_min,SrcValueType src_max,DestValueType dest_min,DestValueType dest_max,VigraFalseType)916 linearRangeMapping(
917 SrcValueType src_min, SrcValueType src_max,
918 DestValueType dest_min, DestValueType dest_max,
919 VigraFalseType /* isScalar */ )
920 {
921 typedef typename NumericTraits<DestValueType>::RealPromote Multiplier;
922 typedef typename Multiplier::value_type MComponent;
923 Multiplier scale(dest_max), offset(dest_max);
924 for(unsigned int i=0; i<src_min.size(); ++i)
925 {
926 MComponent diff = src_max[i] - src_min[i];
927 scale[i] = diff == NumericTraits<MComponent>::zero()
928 ? NumericTraits<MComponent>::one()
929 : (dest_max[i] - dest_min[i]) / diff;
930 offset[i] = dest_min[i] / scale[i] - src_min[i];
931 }
932 return LinearIntensityTransform<DestValueType, Multiplier>(scale, offset);
933 }
934
935 /********************************************************/
936 /* */
937 /* Threshold */
938 /* */
939 /********************************************************/
940
941 /** \brief Threshold an image.
942
943 <b>Note:</b> Nowadays, it is probably easier to perform thresholding by means of
944 C++ 11 lambda functions or \ref MultiMathModule "array expressions".
945
946 If a source pixel is above or equal the lower and below
947 or equal the higher threshold (i.e. within the closed interval
948 [lower, higher]) the destination pixel is set to 'yesresult',
949 otherwise to 'noresult'.
950
951 <b> Traits defined:</b>
952
953 <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
954
955 <b> Usage:</b>
956
957 <b>\#include</b> \<vigra/transformimage.hxx\><br>
958 Namespace: vigra
959
960 \code
961 vigra::BImage src(width, height), dest(width, height);
962 ...
963 vigra::transformImage(src.upperLeft(), src.lowerRight(), src.accessor(),
964 dest.upperLeft(), dest.accessor(),
965 vigra::Threshold<
966 vigra::BImage::PixelType, vigra::BImage::PixelType>(10, 100, 0, 255));
967
968 \endcode
969
970 <b> Required Interface:</b>
971
972 \code
973
974 SrcValueType src;
975 DestValueType dest, yesresult, noresult;
976
977 dest = ((src < lower) || (higher < src)) ? noresult : yesresult;
978
979 \endcode
980
981 */
982 template <class SrcValueType, class DestValueType>
983 class Threshold
984 {
985 public:
986
987 /** the functor's argument type
988 */
989 typedef SrcValueType argument_type;
990
991 /** the functor's result type
992 */
993 typedef DestValueType result_type;
994
995 /** init thresholds and return values
996 */
Threshold(argument_type lower,argument_type higher,result_type noresult,result_type yesresult)997 Threshold(argument_type lower, argument_type higher,
998 result_type noresult, result_type yesresult)
999 : lower_(lower), higher_(higher),
1000 yesresult_(yesresult), noresult_(noresult)
1001 {}
1002
1003 /** calculate transform
1004 */
operator ()(argument_type s) const1005 result_type operator()(argument_type s) const
1006 {
1007 return ((s < lower_) || (higher_ < s)) ? noresult_ : yesresult_;
1008 }
1009
1010 private:
1011
1012 argument_type lower_, higher_;
1013 result_type yesresult_, noresult_;
1014 };
1015
1016 template <class SrcValueType, class DestValueType>
1017 class FunctorTraits<Threshold<SrcValueType, DestValueType> >
1018 : public FunctorTraitsBase<Threshold<SrcValueType, DestValueType> >
1019 {
1020 public:
1021 typedef VigraTrueType isUnaryFunctor;
1022 };
1023
1024 /********************************************************/
1025 /* */
1026 /* BrightnessContrastFunctor */
1027 /* */
1028 /********************************************************/
1029
1030 /** \brief Adjust brightness and contrast of an image.
1031
1032 This functor applies a gamma correction to each pixel in order to
1033 modify the brightness of the image. To the result of the gamma
1034 correction, another transform is applied that modifies the
1035 contrast. The brightness and contrast parameters must be
1036 positive. Values greater than 1 will increase image brightness or
1037 contrast respectively, values smaller than 1 decrease them. A
1038 value of exactly 1 will have no effect. If contrast is set to 1,
1039 the result is equivalent to that of the GammaFunctor with gamma =
1040 1./brightness.
1041
1042 For \ref RGBValue "RGBValue's", the transforms are applied
1043 component-wise. The pixel values are assumed to lie between the
1044 given minimum and maximum values (in case of RGB, this is again
1045 understood component-wise). In case of <TT>unsigned char</TT>, min
1046 and max default to 0 and 255 respectively. Precisely, the
1047 following transform is applied to each <em> PixelValue</em>:
1048
1049 \f[
1050 \begin{array}{rcl}
1051 V_1 & = & \frac{PixelValue - min}{max - min} \\
1052 V_2 & = & V_1^\frac{1}{brightness} \\
1053 V_3 & = & 2 V_2 - 1 \\
1054 V_4 & = & \left\lbrace
1055 \begin{array}{l}
1056 V_3^\frac{1}{contrast} \mbox{\rm \quad if } V_3 \ge 0 \\
1057 - (-V_3)^\frac{1}{contrast} \mbox{\rm \quad otherwise}
1058 \end{array} \right. \\
1059 Result & = & \frac{V_4 + 1}{2} (max - min) + min
1060 \end{array}
1061 \f]
1062
1063 If the <TT>PixelType</TT> is <TT>unsigned char</TT>, a look-up-table is used
1064 for faster computation.
1065
1066 <b> Traits defined:</b>
1067
1068 <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
1069
1070 <b> Usage:</b>
1071
1072 <b>\#include</b> \<vigra/transformimage.hxx\><br>
1073 Namespace: vigra
1074
1075 \code
1076 vigra::BImage bimage(width, height);
1077 double brightness, contrast;
1078 ...
1079 vigra::transformImage(srcImageRange(bimage), destImage(bimage),
1080 vigra::BrightnessContrastFunctor<unsigned char>(brightness, contrast));
1081
1082
1083
1084 vigra::FImage fimage(width, height);
1085 ...
1086
1087 vigra::FindMinMax<float> minmax;
1088 vigra::inspectImage(srcImageRange(fimage), minmax);
1089
1090 vigra::transformImage(srcImageRange(fimage), destImage(fimage),
1091 vigra::BrightnessContrastFunctor<float>(brightness, contrast, minmax.min, minmax.max));
1092
1093
1094 \endcode
1095
1096 <b> Required Interface:</b>
1097
1098 Scalar types: must be a linear algebra (+, - *, NumericTraits),
1099 strict weakly ordered (<), and <TT>pow()</TT> must be defined.
1100
1101 RGB values: the component type must meet the above requirements.
1102 */
1103 template <class PixelType>
1104 class BrightnessContrastFunctor
1105 {
1106 typedef typename
1107 NumericTraits<PixelType>::RealPromote promote_type;
1108
1109 public:
1110
1111 /** the functor's argument type
1112 */
1113 typedef PixelType argument_type;
1114
1115 /** the functor's result type
1116 */
1117 typedef PixelType result_type;
1118
1119 /** \deprecated use argument_type and result_type
1120 */
1121 typedef PixelType value_type;
1122
1123 /** Init functor for argument range <TT>[min, max]</TT>.
1124 <TT>brightness</TT> and <TT>contrast</TT> values > 1 will
1125 increase brightness and contrast, < 1 will decrease them, and == 1 means
1126 no change.
1127 */
BrightnessContrastFunctor(promote_type brightness,promote_type contrast,argument_type const & min,argument_type const & max)1128 BrightnessContrastFunctor(promote_type brightness, promote_type contrast,
1129 argument_type const & min, argument_type const & max)
1130 : b_(1.0/brightness),
1131 c_(1.0/contrast),
1132 min_(min),
1133 diff_(max - min),
1134 zero_(NumericTraits<promote_type>::zero()),
1135 one_(NumericTraits<promote_type>::one())
1136 {}
1137
1138 /** Calculate modified gray or color value
1139 */
operator ()(argument_type const & v) const1140 result_type operator()(argument_type const & v) const
1141 {
1142 promote_type v1 = (v - min_) / diff_;
1143 promote_type brighter = VIGRA_CSTD::pow(v1, b_);
1144 promote_type v2 = 2.0 * brighter - one_;
1145 promote_type contrasted = (v2 < zero_) ?
1146 -VIGRA_CSTD::pow(-v2, c_) :
1147 VIGRA_CSTD::pow(v2, c_);
1148 return result_type(0.5 * diff_ * (contrasted + one_) + min_);
1149 }
1150
1151 private:
1152 promote_type b_, c_;
1153 argument_type min_;
1154 promote_type diff_, zero_, one_;
1155 };
1156
1157 template <>
1158 class BrightnessContrastFunctor<unsigned char>
1159 {
1160 typedef NumericTraits<unsigned char>::RealPromote promote_type;
1161 unsigned char lut[256];
1162
1163 public:
1164
1165 typedef unsigned char value_type;
1166
BrightnessContrastFunctor(promote_type brightness,promote_type contrast,value_type const & min=0,value_type const & max=255)1167 BrightnessContrastFunctor(promote_type brightness, promote_type contrast,
1168 value_type const & min = 0, value_type const & max = 255)
1169 {
1170 BrightnessContrastFunctor<promote_type> f(brightness, contrast, min, max);
1171
1172 for(int i = min; i <= max; ++i)
1173 {
1174 lut[i] = static_cast<unsigned char>(f(i)+0.5);
1175 }
1176 }
1177
operator ()(value_type const & v) const1178 value_type operator()(value_type const & v) const
1179 {
1180
1181 return lut[v];
1182 }
1183 };
1184
1185 #ifndef NO_PARTIAL_TEMPLATE_SPECIALIZATION
1186
1187 template <class ComponentType>
1188 class BrightnessContrastFunctor<RGBValue<ComponentType> >
1189 {
1190 typedef typename
1191 NumericTraits<ComponentType>::RealPromote promote_type;
1192 BrightnessContrastFunctor<ComponentType> red, green, blue;
1193
1194 public:
1195
1196 typedef RGBValue<ComponentType> value_type;
1197
BrightnessContrastFunctor(promote_type brightness,promote_type contrast,value_type const & min,value_type const & max)1198 BrightnessContrastFunctor(promote_type brightness, promote_type contrast,
1199 value_type const & min, value_type const & max)
1200 : red(brightness, contrast, min.red(), max.red()),
1201 green(brightness, contrast, min.green(), max.green()),
1202 blue(brightness, contrast, min.blue(), max.blue())
1203 {}
1204
operator ()(value_type const & v) const1205 value_type operator()(value_type const & v) const
1206 {
1207
1208 return value_type(red(v.red()), green(v.green()), blue(v.blue()));
1209 }
1210 };
1211
1212 #else // NO_PARTIAL_TEMPLATE_SPECIALIZATION
1213
1214 template <>
1215 class BrightnessContrastFunctor<RGBValue<int> >
1216 {
1217 typedef NumericTraits<int>::RealPromote promote_type;
1218 BrightnessContrastFunctor<int> red, green, blue;
1219
1220 public:
1221
1222 typedef RGBValue<int> value_type;
1223
BrightnessContrastFunctor(promote_type brightness,promote_type contrast,value_type const & min,value_type const & max)1224 BrightnessContrastFunctor(promote_type brightness, promote_type contrast,
1225 value_type const & min, value_type const & max)
1226 : red(brightness, contrast, min.red(), max.red()),
1227 green(brightness, contrast, min.green(), max.green()),
1228 blue(brightness, contrast, min.blue(), max.blue())
1229 {}
1230
operator ()(value_type const & v) const1231 value_type operator()(value_type const & v) const
1232 {
1233
1234 return value_type(red(v.red()), green(v.green()), blue(v.blue()));
1235 }
1236 };
1237
1238 template <>
1239 class BrightnessContrastFunctor<RGBValue<float> >
1240 {
1241 typedef NumericTraits<float>::RealPromote promote_type;
1242 BrightnessContrastFunctor<float> red, green, blue;
1243
1244 public:
1245
1246 typedef RGBValue<float> value_type;
1247
BrightnessContrastFunctor(promote_type brightness,promote_type contrast,value_type const & min,value_type const & max)1248 BrightnessContrastFunctor(promote_type brightness, promote_type contrast,
1249 value_type const & min, value_type const & max)
1250 : red(brightness, contrast, min.red(), max.red()),
1251 green(brightness, contrast, min.green(), max.green()),
1252 blue(brightness, contrast, min.blue(), max.blue())
1253 {}
1254
operator ()(value_type const & v) const1255 value_type operator()(value_type const & v) const
1256 {
1257
1258 return value_type(red(v.red()), green(v.green()), blue(v.blue()));
1259 }
1260 };
1261
1262 template <class PixelType>
1263 class FunctorTraits<BrightnessContrastFunctor<PixelType> >
1264 : public FunctorTraitsBase<BrightnessContrastFunctor<PixelType> >
1265 {
1266 public:
1267 typedef VigraTrueType isUnaryFunctor;
1268 };
1269
1270 #endif // NO_PARTIAL_TEMPLATE_SPECIALIZATION
1271
1272 template <>
1273 class BrightnessContrastFunctor<RGBValue<unsigned char> >
1274 {
1275 typedef NumericTraits<unsigned char>::RealPromote promote_type;
1276 BrightnessContrastFunctor<unsigned char> red, green, blue;
1277
1278 public:
1279
1280 typedef RGBValue<unsigned char> value_type;
1281
BrightnessContrastFunctor(promote_type brightness,promote_type contrast,value_type const & min=value_type (0,0,0),value_type const & max=value_type (255,255,255))1282 BrightnessContrastFunctor(promote_type brightness, promote_type contrast,
1283 value_type const & min = value_type(0,0,0),
1284 value_type const & max = value_type(255, 255, 255))
1285 : red(brightness, contrast, min.red(), max.red()),
1286 green(brightness, contrast, min.green(), max.green()),
1287 blue(brightness, contrast, min.blue(), max.blue())
1288 {}
1289
operator ()(value_type const & v) const1290 value_type operator()(value_type const & v) const
1291 {
1292
1293 return value_type(red(v.red()), green(v.green()), blue(v.blue()));
1294 }
1295 };
1296
1297
1298
1299 /********************************************************/
1300 /* */
1301 /* GammaFunctor */
1302 /* */
1303 /********************************************************/
1304
1305 /** \brief Perform gamma correction of an image.
1306
1307 This functor applies a gamma correction to each pixel in order to
1308 modify the brightness of the image. Gamma values smaller than 1
1309 will increase image brightness, whereas values greater than 1
1310 decrease it. A value of gamma = 1 will have no effect. (See also
1311 BrightnessContrastFunctor, which additionally changes the
1312 contrast.)
1313
1314 For \ref RGBValue "RGBValue's", the transforms are applied
1315 component-wise. For ease of use, the pixel values are assumed to
1316 lie between the given minimum and maximum values (in case of RGB,
1317 this is again understood component-wise). In case of <TT>unsigned
1318 char</TT>, min and max default to 0 and 255 respectively.
1319 Precisely, the following transform is applied to each <em>
1320 PixelValue</em>:
1321
1322 \f[
1323 \begin{array}{rcl}
1324 V_1 & = & \frac{PixelValue - min}{max - min} \\
1325 V_2 & = & V_1^{gamma} \\
1326 Result & = & V_2 (max - min) + min
1327 \end{array}
1328 \f]
1329
1330 If the <TT>PixelType</TT> is <TT>unsigned char</TT>, a
1331 look-up-table is used for faster computation.
1332
1333 <b> Traits defined:</b>
1334
1335 <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
1336
1337 <b> Usage:</b>
1338
1339 <b>\#include</b> \<vigra/transformimage.hxx\><br>
1340 Namespace: vigra
1341
1342 \code
1343 vigra::BImage bimage(width, height);
1344 double gamma;
1345 ...
1346 vigra::transformImage(srcImageRange(bimage), destImage(bimage),
1347 vigra::GammaFunctor<unsigned char>(gamma));
1348
1349
1350
1351 vigra::FImage fimage(width, height);
1352 ...
1353
1354 vigra::FindMinMax<float> minmax;
1355 vigra::inspectImage(srcImageRange(fimage), minmax);
1356
1357 vigra::transformImage(srcImageRange(fimage), destImage(fimage),
1358 vigra::GammaFunctor<float>(gamma, minmax.min, minmax.max));
1359
1360 \endcode
1361
1362 <b> Required Interface:</b>
1363
1364 Scalar types: must be a linear algebra (+, - *, NumericTraits),
1365 strict weakly ordered (<), and <TT>pow()</TT> must be defined.
1366
1367 RGB values: the component type must meet the above requirements.
1368 */
1369 template <class PixelType>
1370 class GammaFunctor
1371 {
1372 typedef typename
1373 NumericTraits<PixelType>::RealPromote promote_type;
1374
1375 public:
1376
1377 /** the functor's argument type
1378 */
1379 typedef PixelType argument_type;
1380
1381 /** the functor's result type
1382 */
1383 typedef PixelType result_type;
1384
1385 /** \deprecated use argument_type and result_type
1386 */
1387 typedef PixelType value_type;
1388
1389 /** Init functor for argument range <TT>[min, max]</TT>.
1390 <TT>gamma</TT> values < 1 will increase brightness, > 1
1391 will decrease it (gamma == 1 means no change).
1392 */
GammaFunctor(double gamma,argument_type const & min,argument_type const & max)1393 GammaFunctor(double gamma,
1394 argument_type const & min, argument_type const & max)
1395 : gamma_((promote_type)gamma),
1396 min_(min),
1397 diff_(max - min),
1398 zero_(NumericTraits<promote_type>::zero()),
1399 one_(NumericTraits<promote_type>::one())
1400 {}
1401
1402 /** Calculate modified gray or color value
1403 */
operator ()(argument_type const & v) const1404 result_type operator()(argument_type const & v) const
1405 {
1406 promote_type v1 = (v - min_) / diff_;
1407 promote_type brighter = VIGRA_CSTD::pow(v1, gamma_);
1408 return result_type(diff_ * brighter + min_);
1409 }
1410
1411 private:
1412 promote_type gamma_;
1413 argument_type min_;
1414 promote_type diff_, zero_, one_;
1415 };
1416
1417 template <>
1418 class GammaFunctor<unsigned char>
1419 {
1420 typedef NumericTraits<unsigned char>::RealPromote promote_type;
1421 unsigned char lut[256];
1422
1423 public:
1424
1425 typedef unsigned char value_type;
1426
GammaFunctor(promote_type gamma,value_type const & min=0,value_type const & max=255)1427 GammaFunctor(promote_type gamma,
1428 value_type const & min = 0, value_type const & max = 255)
1429 {
1430 GammaFunctor<promote_type> f(gamma, min, max);
1431
1432 for(int i = min; i <= max; ++i)
1433 {
1434 lut[i] = static_cast<unsigned char>(f(i)+0.5);
1435 }
1436 }
1437
operator ()(value_type const & v) const1438 value_type operator()(value_type const & v) const
1439 {
1440
1441 return lut[v];
1442 }
1443 };
1444
1445 #ifndef NO_PARTIAL_TEMPLATE_SPECIALIZATION
1446
1447 template <class ComponentType>
1448 class GammaFunctor<RGBValue<ComponentType> >
1449 {
1450 typedef typename
1451 NumericTraits<ComponentType>::RealPromote promote_type;
1452 GammaFunctor<ComponentType> red, green, blue;
1453
1454 public:
1455
1456 typedef RGBValue<ComponentType> value_type;
1457
GammaFunctor(promote_type gamma,value_type const & min,value_type const & max)1458 GammaFunctor(promote_type gamma,
1459 value_type const & min, value_type const & max)
1460 : red(gamma, min.red(), max.red()),
1461 green(gamma, min.green(), max.green()),
1462 blue(gamma, min.blue(), max.blue())
1463 {}
1464
operator ()(value_type const & v) const1465 value_type operator()(value_type const & v) const
1466 {
1467 return value_type(red(v.red()), green(v.green()), blue(v.blue()));
1468 }
1469 };
1470
1471 #else // NO_PARTIAL_TEMPLATE_SPECIALIZATION
1472
1473 template <>
1474 class GammaFunctor<RGBValue<int> >
1475 {
1476 typedef NumericTraits<int>::RealPromote promote_type;
1477 GammaFunctor<int> red, green, blue;
1478
1479 public:
1480
1481 typedef RGBValue<int> value_type;
1482
GammaFunctor(promote_type gamma,value_type const & min,value_type const & max)1483 GammaFunctor(promote_type gamma,
1484 value_type const & min, value_type const & max)
1485 : red(gamma, min.red(), max.red()),
1486 green(gamma, min.green(), max.green()),
1487 blue(gamma, min.blue(), max.blue())
1488 {}
1489
operator ()(value_type const & v) const1490 value_type operator()(value_type const & v) const
1491 {
1492 return value_type(red(v.red()), green(v.green()), blue(v.blue()));
1493 }
1494 };
1495
1496 template <>
1497 class GammaFunctor<RGBValue<float> >
1498 {
1499 typedef NumericTraits<float>::RealPromote promote_type;
1500 GammaFunctor<float> red, green, blue;
1501
1502 public:
1503
1504 typedef RGBValue<float> value_type;
1505
GammaFunctor(promote_type gamma,value_type const & min,value_type const & max)1506 GammaFunctor(promote_type gamma,
1507 value_type const & min, value_type const & max)
1508 : red(gamma, min.red(), max.red()),
1509 green(gamma, min.green(), max.green()),
1510 blue(gamma, min.blue(), max.blue())
1511 {}
1512
operator ()(value_type const & v) const1513 value_type operator()(value_type const & v) const
1514 {
1515 return value_type(red(v.red()), green(v.green()), blue(v.blue()));
1516 }
1517 };
1518
1519 template <class PixelType>
1520 class FunctorTraits<GammaFunctor<PixelType> >
1521 : public FunctorTraitsBase<GammaFunctor<PixelType> >
1522 {
1523 public:
1524 typedef VigraTrueType isUnaryFunctor;
1525 };
1526
1527 #endif // NO_PARTIAL_TEMPLATE_SPECIALIZATION
1528
1529 template <>
1530 class GammaFunctor<RGBValue<unsigned char> >
1531 {
1532 typedef NumericTraits<unsigned char>::RealPromote promote_type;
1533 GammaFunctor<unsigned char> red, green, blue;
1534
1535 public:
1536 typedef RGBValue<unsigned char> value_type;
1537
GammaFunctor(promote_type gamma,value_type const & min=value_type (0,0,0),value_type const & max=value_type (255,255,255))1538 GammaFunctor(promote_type gamma,
1539 value_type const & min = value_type(0,0,0),
1540 value_type const & max = value_type(255, 255, 255))
1541 : red(gamma, min.red(), max.red()),
1542 green(gamma, min.green(), max.green()),
1543 blue(gamma, min.blue(), max.blue())
1544 {}
1545
operator ()(value_type const & v) const1546 value_type operator()(value_type const & v) const
1547 {
1548 return value_type(red(v.red()), green(v.green()), blue(v.blue()));
1549 }
1550 };
1551
1552
1553 /********************************************************/
1554 /* */
1555 /* VectorNormFunctor */
1556 /* */
1557 /********************************************************/
1558
1559 /** \brief A functor for computing the vector norm
1560
1561 Calculate the magnitude or norm from a given vector-valued
1562 entity. The vector type will typically be some sort of
1563 ref vigra::TinyVector. If the vector is represented by a pair of
1564 scalar-valued images, use \ref vigra::MagnitudeFunctor instead.
1565
1566 At least, the vector type is required to have a function
1567 '<em>result</em><TT> = dot(v,v)</TT>'.
1568
1569 <b> Traits defined:</b>
1570
1571 <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
1572
1573 <b> Usage:</b>
1574
1575 <b>\#include</b> \<vigra/transformimage.hxx\><br>
1576 Namespace: vigra
1577
1578 \code
1579 typedef vigra::TinyVector<float, 2> Vector;
1580 vigra::BasicImage<Vector> grad(width, height);
1581 vigra::FImage magn(width,height);
1582 ...
1583 vigra::transformImage(srcImageRange(grad), destImage(magn),
1584 VectorNormFunctor<float>()
1585 );
1586 \endcode
1587
1588 \see vigra::TinyVector, dot(), vigra::MagnitudeFunctor
1589 */
1590 template <class ValueType>
1591 class VectorNormFunctor
1592 {
1593 public:
1594 /** the functor's argument type
1595 */
1596 typedef ValueType argument_type;
1597
1598 /** the functor's result type
1599 */
1600 typedef typename NumericTraits<typename ValueType::value_type>::RealPromote result_type;
1601
1602 /** calculate transform '<TT>sqrt(v1*v1 + v2*v2 + ...)</TT>'.
1603 */
operator ()(const argument_type & a) const1604 result_type operator()( const argument_type &a ) const
1605 {
1606 return VIGRA_CSTD::sqrt( dot(a,a) );
1607 }
1608 }; //-- class VectorNormFunctor
1609
1610 template <class ValueType>
1611 class FunctorTraits<VectorNormFunctor<ValueType> >
1612 : public FunctorTraitsBase<VectorNormFunctor<ValueType> >
1613 {
1614 public:
1615 typedef VigraTrueType isUnaryFunctor;
1616 };
1617
1618 /** \brief A functor for computing the squared vector norm
1619
1620 Calculate the squared magnitude or norm from a given
1621 vector-valued entity. The vector type will typically be some
1622 sort of TinyVector.
1623
1624 At least, the vector type is required to have a function
1625 '<em>result</em><TT> = dot(v,v)</TT>'.
1626
1627 For an example of its usage see VectorNormFunctor
1628
1629 <b> Traits defined:</b>
1630
1631 <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
1632
1633 \see TinyVector, dot()
1634 */
1635 template <class ValueType>
1636 class VectorNormSqFunctor
1637 {
1638 public:
1639 /** the functor's argument type
1640 */
1641 typedef ValueType argument_type;
1642
1643 /** the functor's result type
1644 */
1645 typedef typename NumericTraits<typename ValueType::value_type>::RealPromote result_type;
1646
1647 /** calculate transform '<TT>v1*v1 + v2*v2 + ...</TT>'.
1648 */
operator ()(const argument_type & a) const1649 result_type operator()( const argument_type &a ) const
1650 {
1651 return dot(a,a);
1652 }
1653 }; //-- class VectorNormSqFunctor
1654
1655 template <class ValueType>
1656 class FunctorTraits<VectorNormSqFunctor<ValueType> >
1657 : public FunctorTraitsBase<VectorNormSqFunctor<ValueType> >
1658 {
1659 public:
1660 typedef VigraTrueType isUnaryFunctor;
1661 };
1662
1663 //@}
1664
1665 } // namespace vigra
1666
1667 #endif // VIGRA_TRANSFORMIMAGE_HXX
1668