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