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

vigra/colorconversions.hxx

00001 /************************************************************************/
00002 /*                                                                      */
00003 /*               Copyright 1998-2002 by Ullrich Koethe                  */
00004 /*       Cognitive Systems Group, University of Hamburg, Germany        */
00005 /*                                                                      */
00006 /*    This file is part of the VIGRA computer vision library.           */
00007 /*    The VIGRA Website is                                              */
00008 /*        http://kogs-www.informatik.uni-hamburg.de/~koethe/vigra/      */
00009 /*    Please direct questions, bug reports, and contributions to        */
00010 /*        ullrich.koethe@iwr.uni-heidelberg.de    or                    */
00011 /*        vigra@informatik.uni-hamburg.de                               */
00012 /*                                                                      */
00013 /*    Permission is hereby granted, free of charge, to any person       */
00014 /*    obtaining a copy of this software and associated documentation    */
00015 /*    files (the "Software"), to deal in the Software without           */
00016 /*    restriction, including without limitation the rights to use,      */
00017 /*    copy, modify, merge, publish, distribute, sublicense, and/or      */
00018 /*    sell copies of the Software, and to permit persons to whom the    */
00019 /*    Software is furnished to do so, subject to the following          */
00020 /*    conditions:                                                       */
00021 /*                                                                      */
00022 /*    The above copyright notice and this permission notice shall be    */
00023 /*    included in all copies or substantial portions of the             */
00024 /*    Software.                                                         */
00025 /*                                                                      */
00026 /*    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND    */
00027 /*    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES   */
00028 /*    OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND          */
00029 /*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
00030 /*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
00031 /*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
00032 /*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
00033 /*    OTHER DEALINGS IN THE SOFTWARE.                                   */                
00034 /*                                                                      */
00035 /************************************************************************/
00036  
00037  
00038 #ifndef VIGRA_COLORCONVERSIONS_HXX
00039 #define VIGRA_COLORCONVERSIONS_HXX
00040 
00041 #include <cmath>
00042 #include "mathutil.hxx"
00043 #include "rgbvalue.hxx"
00044 #include "functortraits.hxx"
00045 
00046 namespace vigra {
00047 
00048 namespace detail
00049 {
00050 
00051 inline double gammaCorrection(double value, double gamma)
00052 {
00053     return (value < 0.0) ? 
00054             -VIGRA_CSTD::pow(-value, gamma) :
00055             VIGRA_CSTD::pow(value, gamma);
00056 }
00057 
00058 inline double gammaCorrection(double value, double gamma, double norm)
00059 {
00060     return (value < 0.0) ? 
00061             -norm*VIGRA_CSTD::pow(-value/norm, gamma) :
00062             norm*VIGRA_CSTD::pow(value/norm, gamma);
00063 }
00064 
00065 inline double sRGBCorrection(double value, double norm)
00066 {
00067     value /= norm;
00068     return (value <= 0.00304) 
00069                ? norm*12.92*value 
00070                : norm*(1.055*VIGRA_CSTD::pow(value, 0.41666666666666667) - 0.055);
00071 }
00072 
00073 inline double inverse_sRGBCorrection(double value, double norm)
00074 {
00075     value /= norm;
00076     return (value <= 0.03928) 
00077                ? norm*value / 12.92
00078                : norm*VIGRA_CSTD::pow((value + 0.055)/1.055, 2.4);
00079 }
00080 
00081 
00082 } // namespace detail
00083 
00084 /** \defgroup ColorConversions  Color Space Conversions
00085 
00086     Convert between RGB, sRGB, R'G'B', XYZ, L*a*b*, L*u*v*, Y'PbPr, Y'CbCr, Y'IQ, and Y'UV color spaces.
00087 
00088     <b>\#include</b> <<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>><br>
00089     Namespace: vigra
00090     
00091     <UL>
00092     <LI> <b>RGB/sRGB/R'G'B'</b><br>
00093         <em>linear and non-linear (gamma corrected) additive color</em>
00094         <p>
00095         <UL style="list-style-image:url(documents/bullet.gif)">
00096         <LI> \ref vigra::RGB2sRGBFunctor
00097         <LI> \ref vigra::sRGB2RGBFunctor
00098         <LI> \ref vigra::RGB2RGBPrimeFunctor
00099         <LI> \ref vigra::RGBPrime2RGBFunctor
00100         </UL><p>
00101     <LI> <b>XYZ</b><br>
00102         <em>device independent color representation 
00103                (according to Publication CIE  No  15.2 "Colorimetry"
00104                 and ITU-R Recommendation BT.709)</em>
00105         <p>
00106         <UL style="list-style-image:url(documents/bullet.gif)">
00107         <LI> \ref vigra::RGB2XYZFunctor
00108         <LI> \ref vigra::RGBPrime2XYZFunctor
00109         <LI> \ref vigra::XYZ2RGBFunctor
00110         <LI> \ref vigra::XYZ2RGBPrimeFunctor
00111         </UL><p>
00112     <LI> <b>L*a*b* </b><br>
00113         <em>perceptually uniform color representation 
00114                (according to Publication CIE No 15.2 "Colorimetry" and
00115                ITU-R Recommendation BT.709)</em>
00116         <p>
00117         <UL style="list-style-image:url(documents/bullet.gif)">
00118         <LI> \ref vigra::RGB2LabFunctor
00119         <LI> \ref vigra::RGBPrime2LabFunctor
00120         <LI> \ref vigra::XYZ2LabFunctor
00121         <LI> \ref vigra::Lab2RGBFunctor
00122         <LI> \ref vigra::Lab2RGBPrimeFunctor
00123         <LI> \ref vigra::Lab2XYZFunctor
00124         <LI> \ref polar2Lab()
00125         <LI> \ref lab2Polar()
00126         </UL><p>
00127     <LI> <b>L*u*v* </b><br>
00128         <em>perceptually uniform color representation 
00129                (according to Publication CIE No 15.2 "Colorimetry" and
00130                ITU-R Recommendation BT.709)</em>
00131         <p>
00132         <UL style="list-style-image:url(documents/bullet.gif)">
00133         <LI> \ref vigra::RGB2LuvFunctor
00134         <LI> \ref vigra::RGBPrime2LuvFunctor
00135         <LI> \ref vigra::XYZ2LuvFunctor
00136         <LI> \ref vigra::Luv2RGBFunctor
00137         <LI> \ref vigra::Luv2RGBPrimeFunctor
00138         <LI> \ref vigra::Luv2XYZFunctor
00139         <LI> \ref polar2Luv()
00140         <LI> \ref luv2Polar()
00141         </UL><p>
00142     <LI> <b>Y'PbPr and Y'CbCr </b><br>
00143         <em>color difference coding
00144                 (according to ITU-R Recommendation BT. 601)</em>
00145         <p>
00146         <UL style="list-style-image:url(documents/bullet.gif)">
00147         <LI> \ref vigra::RGBPrime2YPrimePbPrFunctor
00148         <LI> \ref vigra::YPrimePbPr2RGBPrimeFunctor
00149         <LI> \ref polar2YPrimePbPr()
00150         <LI> \ref yPrimePbPr2Polar()
00151         <LI> \ref vigra::RGBPrime2YPrimeCbCrFunctor
00152         <LI> \ref vigra::YPrimeCbCr2RGBPrimeFunctor
00153         <LI> \ref polar2YPrimeCbCr()
00154         <LI> \ref yPrimeCbCr2Polar()
00155         </UL><p>
00156     <LI> <b>Y'UV and Y'IQ </b><br>
00157         <em>analog video coding according to NTSC and PAL standards</em>
00158         <p>
00159         <UL style="list-style-image:url(documents/bullet.gif)">
00160         <LI> \ref vigra::RGBPrime2YPrimeUVFunctor
00161         <LI> \ref vigra::YPrimeUV2RGBPrimeFunctor
00162         <LI> \ref polar2YPrimeUV()
00163         <LI> \ref yPrimeUV2Polar()
00164         <LI> \ref vigra::RGBPrime2YPrimeIQFunctor
00165         <LI> \ref vigra::YPrimeIQ2RGBPrimeFunctor
00166         <LI> \ref polar2YPrimeIQ()
00167         <LI> \ref yPrimeIQ2Polar()
00168         </UL><p>
00169     </UL>
00170     
00171     \anchor _details
00172     This module provides conversion from RGB/R'G'B' into more perceptually uniform
00173     color spaces. In image analysis, colors are usually converted into another color space 
00174     in order to get good estimates of perceived color differences by just calculating 
00175     Euclidean distances between the transformed colors. The L*a*b* and L*u*v* were 
00176     designed with exactly this application in mind and thus give the best results. But these
00177     conversions are also the most computationally demanding. The Y'PbPr color difference
00178     space (designed for coding digital video) is computationally much cheaper, and 
00179     almost as good. Y'CbCr represents esentially the same transformation, but the color values 
00180     are scaled so that they can be stored with 8 bits per channel with minimal loss of 
00181     information. The other transformations are of lesser interest here: XYZ is a device independent
00182     (but not perceptually uniform) color representation, and Y'IQ and Y'UV are the color 
00183     spaces used by the PAL and NTSC analog video standards. Detailed information about
00184     these color spaces and their transformations can be found in 
00185     <a href="http://www.poynton.com/ColorFAQ.html">Charles Poynton's Color FAQ</a>
00186     
00187     When you want to perform a color conversion, you must first know in which
00188     color space the data are given. Although this sounds trivial, it is
00189     quite often done wrong, because the distinction between RGB and sRGB (still images) or R'G'B' 
00190     (digital video) is frequently overlooked: nowadays, most still images are stored in
00191     sRGB space, and treating them as RGB leads to wrong results (although the color primaries
00192     are named the same). RGB and R'G'B' are related by a so called <em>gamma correction</em>:
00193     
00194     \f[
00195         C' = C_{max} \left(\frac{C_{RGB}}{C_{max}} \right)^{0.45} \qquad
00196     \f]
00197     
00198     where C represents one of the color channels R, G, and B, and \f$ C_{max} \f$ usually equals 255. 
00199     The sRGB color space realizes a slight enhancement of this definition:
00200     
00201     \f[
00202         C_{sRGB} = \left\{\begin{array}{ll}
00203         12.92\,C_{RGB} & \textrm{ if }\frac{C_{RGB}}{C_{max}} \le 0.00304 \\
00204         C_{max}\left( 1.055 \left(\frac{C_{RGB}}{C_{max}}\right)^{1/2.4}-0.055\right) & \textrm{ otherwise}
00205         \end{array} \right.
00206     \f]
00207     
00208     sRGB has now become a widely accepted international standard (IEC 61966-2.1) which is used by most 
00209     consumer products (digital cameras, printers, and screens). In practice, you can 
00210     distinguish between linear and gamma-corrected red, green, and blue by displaying the images: if they look
00211     too dark, they are probably RGB, if they are OK, they are likely sRGB. (However, there are still a few older 
00212     graphics cards and display programs which silently apply an additional gamma correction to every image, 
00213     so that RGB appears correct and sRGB is too bright.) Whether or not the data are represented
00214     in the sRGB color space can also be seen in the color space tag of an image's EXIF data, if available.
00215     
00216     The distinction between RGB and R'G'B' is important because some conversions start at 
00217     RGB (XYZ, L*a*b*, L*u*v*), while others start at R'G'B' (Y'PbPr, Y'CbCr, Y'IQ, and Y'UV). 
00218     The names of VIGRA's color conversion functors always make clear to which color space 
00219     they must be applied.
00220    
00221     In addition VIGRA provides a <em>\ref PolarColors "polar coordinate interface"</em>
00222     to several color spaces (L*a*b*, L*u*v*, Y'PbPr, Y'CbCr, Y'IQ, and Y'UV). This
00223     interface makes use of the fact that these color spaces are conceptually similar:
00224     they represent colors by a "brightness" coordinate (L* or Y') and a pair of 
00225     "chromaticity" coordinates that span a plane of colors with equal brightness.
00226     The polar representation transforms chroma coordinates into a color "angle"
00227     (similar to hue in the HSV system) and a "saturation". The polar coordinates are 
00228     normalized so that a color angle of 0 degrees is always associated with red
00229     (green is at about 120 degrees, blue at about 240 degrees - exact values differ
00230     between color spaces). A saturation of 1 is the highest saturation that any RGB color 
00231     in the unit cube can have after transformation into the respective color space, 
00232     and saturation 0 corresponds to gray. Polar coordinates provide a more intuitive 
00233     interface to color specification by users and make different color spaces somewhat 
00234     comparable.
00235 */
00236 //@{
00237 
00238 
00239 /** \brief Convert linear (raw) RGB into non-linear (gamma corrected) R'G'B'.
00240 
00241     <b>\#include</b> <<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>><br>
00242     Namespace: vigra
00243     
00244     The functor realizes the transformation
00245     
00246     \f[
00247         R' = R_{max} \left(\frac{R}{R_{max}} \right)^{0.45} \qquad
00248         G' = G_{max} \left(\frac{G}{G_{max}} \right)^{0.45} \qquad
00249         B' = B_{max} \left(\frac{B}{B_{max}} \right)^{0.45}
00250     \f]
00251     
00252     By default, \f$ R_{max} = G_{max} = B_{max} = 255 \f$. This default can be overridden
00253     in the constructor. If both source and target colors components are stored 
00254     as <tt>unsigned char</tt>, a look-up-table will be used to speed up the transformation.
00255 
00256     <b> Traits defined:</b>
00257     
00258     <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
00259     */
00260 template <class From, class To = From>
00261 class RGB2RGBPrimeFunctor
00262 {
00263   public:
00264   
00265         /** the functor's argument type
00266         */
00267     typedef TinyVector<From, 3> argument_type;
00268   
00269         /** the functor's result type
00270         */
00271     typedef RGBValue<To> result_type;
00272   
00273         /** \deprecated use argument_type and result_type
00274         */
00275     typedef RGBValue<To> value_type;
00276   
00277         /** the result component's promote type
00278         */
00279     typedef typename NumericTraits<To>::RealPromote component_type;
00280     
00281         /** Default constructor.
00282             The maximum value for each RGB component defaults to 255
00283         */
00284     RGB2RGBPrimeFunctor()
00285     : max_(255.0)
00286     {}
00287     
00288         /** constructor
00289             \arg max - the maximum value for each RGB component
00290         */
00291     RGB2RGBPrimeFunctor(component_type max)
00292     : max_(max)
00293     {}
00294     
00295         /** apply the transformation
00296         */
00297     template <class V>
00298     result_type operator()(V const & rgb) const
00299     {
00300         return RGBValue<To>(
00301             NumericTraits<To>::fromRealPromote(detail::gammaCorrection(rgb[0], 0.45, max_)),
00302             NumericTraits<To>::fromRealPromote(detail::gammaCorrection(rgb[1], 0.45, max_)),
00303             NumericTraits<To>::fromRealPromote(detail::gammaCorrection(rgb[2], 0.45, max_)));
00304     }
00305     
00306   private:
00307     component_type max_;    
00308 };
00309 
00310 template <>
00311 class RGB2RGBPrimeFunctor<unsigned char, unsigned char>
00312 {
00313     unsigned char lut_[256];
00314         
00315   public:
00316   
00317     typedef RGBValue<unsigned char> value_type;
00318     
00319     RGB2RGBPrimeFunctor()
00320     {
00321         for(int i=0; i<256; ++i)
00322         {
00323             lut_[i] = NumericTraits<unsigned char>::fromRealPromote(detail::gammaCorrection(i, 0.45, 255.0));
00324         }
00325     }
00326     
00327     RGB2RGBPrimeFunctor(double max)
00328     {
00329         for(int i=0; i<256; ++i)
00330         {
00331             lut_[i] = NumericTraits<unsigned char>::fromRealPromote(detail::gammaCorrection(i, 0.45, max));
00332         }
00333     }
00334     
00335     template <class V>
00336     RGBValue<unsigned char> operator()(V const & rgb) const
00337     {
00338         return RGBValue<unsigned char>(lut_[rgb[0]], lut_[rgb[1]], lut_[rgb[2]]);
00339     }
00340 };
00341 
00342 template <class From, class To>
00343 class FunctorTraits<RGB2RGBPrimeFunctor<From, To> >
00344 : public FunctorTraitsBase<RGB2RGBPrimeFunctor<From, To> >
00345 {
00346   public:
00347     typedef VigraTrueType isUnaryFunctor;
00348 };
00349 
00350 /** \brief Convert linear (raw) RGB into standardized sRGB.
00351 
00352     <b>\#include</b> <<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>><br>
00353     Namespace: vigra
00354     
00355     The sRGB color space is a slight improvement over the R'G'B' space. It is now a widely accepted 
00356     international standard (IEC 61966-2.1) which is used by most consumer products
00357     (digital cameras, printers, and screens). The functor realizes the transformation
00358     
00359     \f[
00360         C_{sRGB} = \left\{ \begin{array}{ll}
00361         12.92\,C_{RGB} & \textrm{ if }\frac{C_{RGB}}{C_{max}} \le 0.00304 \\
00362         C_{max}\left( 1.055 \left(\frac{C_{RGB}}{C_{max}}\right)^{1/2.4}-0.055\right) & \textrm{ otherwise}
00363         \end{array}  \right.
00364     \f]
00365     
00366     where C is any of the primaries R, G, and B. By default, \f$ C_{max} = 255 \f$ (this default can be
00367     overridden in the constructor). If both source and target color components are stored
00368     as <tt>unsigned char</tt>, a look-up-table will be used to speed up the transformation.
00369 
00370     <b> Traits defined:</b>
00371     
00372     <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
00373     */
00374 template <class From, class To = From>
00375 class RGB2sRGBFunctor
00376 {
00377   public:
00378   
00379         /** the functor's argument type
00380         */
00381     typedef TinyVector<From, 3> argument_type;
00382   
00383         /** the functor's result type
00384         */
00385     typedef RGBValue<To> result_type;
00386   
00387         /** \deprecated use argument_type and result_type
00388         */
00389     typedef RGBValue<To> value_type;
00390   
00391         /** the result component's promote type
00392         */
00393     typedef typename NumericTraits<To>::RealPromote component_type;
00394     
00395         /** Default constructor.
00396             The maximum value for each RGB component defaults to 255
00397         */
00398     RGB2sRGBFunctor()
00399     : max_(255.0)
00400     {}
00401     
00402         /** constructor
00403             \arg max - the maximum value for each RGB component
00404         */
00405     RGB2sRGBFunctor(component_type max)
00406     : max_(max)
00407     {}
00408     
00409         /** apply the transformation
00410         */
00411     template <class V>
00412     result_type operator()(V const & rgb) const
00413     {
00414         return RGBValue<To>(
00415             NumericTraits<To>::fromRealPromote(detail::sRGBCorrection(rgb[0], max_)),
00416             NumericTraits<To>::fromRealPromote(detail::sRGBCorrection(rgb[1], max_)),
00417             NumericTraits<To>::fromRealPromote(detail::sRGBCorrection(rgb[2], max_)));
00418     }
00419     
00420   private:
00421     component_type max_;    
00422 };
00423 
00424 template <>
00425 class RGB2sRGBFunctor<unsigned char, unsigned char>
00426 {
00427     unsigned char lut_[256];
00428         
00429   public:
00430   
00431     typedef RGBValue<unsigned char> value_type;
00432     
00433     RGB2sRGBFunctor()
00434     {
00435         for(int i=0; i<256; ++i)
00436         {
00437             lut_[i] = NumericTraits<unsigned char>::fromRealPromote(detail::sRGBCorrection(i, 255.0));
00438         }
00439     }
00440     
00441     RGB2sRGBFunctor(double max)
00442     {
00443         for(int i=0; i<256; ++i)
00444         {
00445             lut_[i] = NumericTraits<unsigned char>::fromRealPromote(detail::sRGBCorrection(i, max));
00446         }
00447     }
00448     
00449     template <class V>
00450     RGBValue<unsigned char> operator()(V const & rgb) const
00451     {
00452         return RGBValue<unsigned char>(lut_[rgb[0]], lut_[rgb[1]], lut_[rgb[2]]);
00453     }
00454 };
00455 
00456 template <class From, class To>
00457 class FunctorTraits<RGB2sRGBFunctor<From, To> >
00458 : public FunctorTraitsBase<RGB2sRGBFunctor<From, To> >
00459 {
00460   public:
00461     typedef VigraTrueType isUnaryFunctor;
00462 };
00463 
00464 /** \brief Convert non-linear (gamma corrected) R'G'B' into non-linear (raw) RGB.
00465 
00466     <b>\#include</b> <<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>><br>
00467     Namespace: vigra
00468     
00469     The functor realizes the transformation
00470     
00471     \f[
00472         R = R_{max} \left(\frac{R'}{R_{max}} \right)^{1/0.45} \qquad
00473         G = G_{max} \left(\frac{G'}{G_{max}} \right)^{1/0.45} \qquad
00474         B = B_{max} \left(\frac{B'}{B_{max}} \right)^{1/0.45}
00475     \f]
00476     
00477     By default, \f$ R_{max} = G_{max} = B_{max} = 255 \f$. This default can be overridden
00478     in the constructor. If both source and target color components are stored 
00479     as <tt>unsigned char</tt>, a look-up-table will be used to speed up the transformation.
00480 
00481     <b> Traits defined:</b>
00482     
00483     <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
00484 */
00485 template <class From, class To = From>
00486 class RGBPrime2RGBFunctor
00487 {
00488   public:
00489   
00490         /** the functor's argument type
00491         */
00492     typedef TinyVector<From, 3> argument_type;
00493   
00494         /** the functor's result type
00495         */
00496     typedef RGBValue<To> result_type;
00497   
00498         /** \deprecated use argument_type and result_type
00499         */
00500     typedef RGBValue<To> value_type;
00501   
00502         /** the result component's promote type
00503         */
00504     typedef typename NumericTraits<To>::RealPromote component_type;
00505     
00506         /** Default constructor.
00507             The maximum value for each RGB component defaults to 255.
00508         */
00509     RGBPrime2RGBFunctor()
00510     : max_(255.0), gamma_(1.0/0.45)
00511     {}
00512     
00513         /** constructor
00514             \arg max - the maximum value for each RGB component
00515         */
00516     RGBPrime2RGBFunctor(component_type max)
00517     : max_(max), gamma_(1.0/0.45)
00518     {}
00519     
00520         /** apply the transformation
00521         */
00522     result_type operator()(argument_type const & rgb) const
00523     {
00524         return RGBValue<To>(
00525             NumericTraits<To>::fromRealPromote(detail::gammaCorrection(rgb[0], gamma_, max_)),
00526             NumericTraits<To>::fromRealPromote(detail::gammaCorrection(rgb[1], gamma_, max_)),
00527             NumericTraits<To>::fromRealPromote(detail::gammaCorrection(rgb[2], gamma_, max_)));
00528     }
00529 
00530   private:
00531     component_type max_;
00532     double gamma_;
00533 };
00534 
00535 template <>
00536 class RGBPrime2RGBFunctor<unsigned char, unsigned char>
00537 {    
00538     unsigned char lut_[256];
00539         
00540   public:
00541   
00542     typedef RGBValue<unsigned char> value_type;
00543     
00544     RGBPrime2RGBFunctor()
00545     {
00546         for(int i=0; i<256; ++i)
00547         {
00548             lut_[i] = NumericTraits<unsigned char>::fromRealPromote(detail::gammaCorrection(i, 1.0/0.45, 255.0));
00549         }
00550     }
00551     
00552     RGBPrime2RGBFunctor(double max)
00553     {
00554         for(int i=0; i<256; ++i)
00555         {
00556             lut_[i] = NumericTraits<unsigned char>::fromRealPromote(detail::gammaCorrection(i, 1.0/0.45, max));
00557         }
00558     }
00559     
00560     template <class V>
00561     RGBValue<unsigned char> operator()(V const & rgb) const
00562     {
00563         return RGBValue<unsigned char>(lut_[rgb[0]], lut_[rgb[1]], lut_[rgb[2]]);
00564     }
00565 };
00566 
00567 template <class From, class To>
00568 class FunctorTraits<RGBPrime2RGBFunctor<From, To> >
00569 : public FunctorTraitsBase<RGBPrime2RGBFunctor<From, To> >
00570 {
00571   public:
00572     typedef VigraTrueType isUnaryFunctor;
00573 };
00574 
00575 /** \brief Convert standardized sRGB into non-linear (raw) RGB.
00576 
00577     <b>\#include</b> <<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>><br>
00578     Namespace: vigra
00579     
00580     The sRGB color space is a slight improvement over the R'G'B' space. Is is now a widely accepted 
00581     international standard (IEC 61966-2.1) which is used by most consumer products
00582     (digital cameras, printers, and screens). The functor realizes the transformation
00583     
00584     \f[
00585         C_{RGB} = \left\{\begin{array}{ll}
00586         C_{sRGB} / 12.92 & \textrm{if }\frac{C_{sRGB}}{C_{max}} \le 0.03928 \\
00587         C_{max}\left( \frac{C_{sRGB}/C_{max}+0.055}{1.055}\right)^{2.4} & \textrm{otherwise}
00588         \end{array}\right.
00589     \f]
00590     
00591     where C is one of the color channels R, G, or B, and \f$ C_{max}\f$ equals 255 by default (This default 
00592     can be overridden in the constructor). If both source and target color components are stored 
00593     as <tt>unsigned char</tt>, a look-up-table will be used to speed up the transformation.
00594 
00595     <b> Traits defined:</b>
00596     
00597     <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
00598 */
00599 template <class From, class To = From>
00600 class sRGB2RGBFunctor
00601 {
00602   public:
00603   
00604         /** the functor's argument type
00605         */
00606     typedef TinyVector<From, 3> argument_type;
00607   
00608         /** the functor's result type
00609         */
00610     typedef RGBValue<To> result_type;
00611   
00612         /** \deprecated use argument_type and result_type
00613         */
00614     typedef RGBValue<To> value_type;
00615   
00616         /** the result component's promote type
00617         */
00618     typedef typename NumericTraits<To>::RealPromote component_type;
00619     
00620         /** Default constructor.
00621             The maximum value for each RGB component defaults to 255.
00622         */
00623     sRGB2RGBFunctor()
00624     : max_(255.0)
00625     {}
00626     
00627         /** constructor
00628             \arg max - the maximum value for each RGB component
00629         */
00630     sRGB2RGBFunctor(component_type max)
00631     : max_(max)
00632     {}
00633     
00634         /** apply the transformation
00635         */
00636     result_type operator()(argument_type const & rgb) const
00637     {
00638         return RGBValue<To>(
00639             NumericTraits<To>::fromRealPromote(detail::inverse_sRGBCorrection(rgb[0], max_)),
00640             NumericTraits<To>::fromRealPromote(detail::inverse_sRGBCorrection(rgb[1], max_)),
00641             NumericTraits<To>::fromRealPromote(detail::inverse_sRGBCorrection(rgb[2], max_)));
00642     }
00643 
00644   private:
00645     component_type max_;
00646 };
00647 
00648 template <>
00649 class sRGB2RGBFunctor<unsigned char, unsigned char>
00650 {    
00651     unsigned char lut_[256];
00652         
00653   public:
00654   
00655     typedef RGBValue<unsigned char> value_type;
00656     
00657     sRGB2RGBFunctor()
00658     {
00659         for(int i=0; i<256; ++i)
00660         {
00661             lut_[i] = NumericTraits<unsigned char>::fromRealPromote(detail::inverse_sRGBCorrection(i, 255.0));
00662         }
00663     }
00664     
00665     sRGB2RGBFunctor(double max)
00666     {
00667         for(int i=0; i<256; ++i)
00668         {
00669             lut_[i] = NumericTraits<unsigned char>::fromRealPromote(detail::inverse_sRGBCorrection(i, max));
00670         }
00671     }
00672     
00673     template <class V>
00674     RGBValue<unsigned char> operator()(V const & rgb) const
00675     {
00676         return RGBValue<unsigned char>(lut_[rgb[0]], lut_[rgb[1]], lut_[rgb[2]]);
00677     }
00678 };
00679 
00680 template <class From, class To>
00681 class FunctorTraits<sRGB2RGBFunctor<From, To> >
00682 : public FunctorTraitsBase<sRGB2RGBFunctor<From, To> >
00683 {
00684   public:
00685     typedef VigraTrueType isUnaryFunctor;
00686 };
00687 
00688 /** \brief Convert linear (raw) RGB into standardized tri-stimulus XYZ.
00689 
00690     <b>\#include</b> <<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>><br>
00691     Namespace: vigra
00692     
00693     According to ITU-R Recommendation BT.709, the functor realizes the transformation
00694     
00695     \f[
00696         \begin{array}{rcl}
00697         X & = & 0.412453\enspace R / R_{max} + 0.357580\enspace G / G_{max} + 0.180423\enspace B / B_{max}\\
00698         Y & = & 0.212671\enspace R / R_{max} + 0.715160\enspace G / G_{max} + 0.072169\enspace B / B_{max} \\
00699         Z & = & 0.019334\enspace R / R_{max} + 0.119193\enspace G / G_{max} + 0.950227\enspace B / B_{max}
00700         \end{array}
00701     \f]
00702     
00703     By default, \f$ R_{max} = G_{max} = B_{max} = 255 \f$. This default can be overridden
00704     in the constructor. X, Y, and Z are always positive and reach their maximum for white. 
00705     The white point is obtained by transforming RGB(255, 255, 255). It corresponds to the 
00706     D65 illuminant. Y represents the <em>luminance</em> ("brightness") of the color.
00707 
00708     <b> Traits defined:</b>
00709     
00710     <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
00711 */
00712 template <class T>
00713 class RGB2XYZFunctor
00714 {
00715   public:
00716   
00717         /** the result's component type
00718         */
00719     typedef typename NumericTraits<T>::RealPromote component_type;
00720 
00721         /** the functor's argument type
00722         */
00723     typedef TinyVector<T, 3> argument_type;
00724   
00725         /** the functor's result type
00726         */
00727     typedef TinyVector<component_type, 3> result_type;
00728   
00729         /** \deprecated use argument_type and result_type
00730         */
00731     typedef TinyVector<component_type, 3> value_type;
00732     
00733         /** default constructor.
00734             The maximum value for each RGB component defaults to 255.
00735         */
00736     RGB2XYZFunctor()
00737     : max_(255.0)
00738     {}
00739     
00740         /** constructor
00741             \arg max - the maximum value for each RGB component
00742         */
00743     RGB2XYZFunctor(component_type max)
00744     : max_(max)
00745     {}
00746     
00747         /** apply the transformation
00748         */
00749     result_type operator()(argument_type const & rgb) const
00750     {
00751         component_type red = rgb[0] / max_;
00752         component_type green = rgb[1] / max_;
00753         component_type blue = rgb[2] / max_;
00754         result_type result;
00755         result[0] = 0.412453*red + 0.357580*green + 0.180423*blue;
00756         result[1] = 0.212671*red + 0.715160*green + 0.072169*blue;
00757         result[2] = 0.019334*red + 0.119193*green + 0.950227*blue;
00758         return result;
00759     }
00760 
00761   private:
00762     component_type max_;
00763 };
00764 
00765 template <class T>
00766 class FunctorTraits<RGB2XYZFunctor<T> >
00767 : public FunctorTraitsBase<RGB2XYZFunctor<T> >
00768 {
00769   public:
00770     typedef VigraTrueType isUnaryFunctor;
00771 };
00772 
00773 /** \brief Convert non-linear (gamma corrected) R'G'B' into standardized tri-stimulus XYZ.
00774 
00775     <b>\#include</b> <<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>><br>
00776     Namespace: vigra
00777     
00778     The functor realizes the transformation
00779     
00780     \f[
00781         R'G'B' \Rightarrow RGB \Rightarrow XYZ
00782     \f]
00783     
00784     See vigra::RGBPrime2RGBFunctor and vigra::RGB2XYZFunctor for a description of the two 
00785     steps.
00786 
00787     <b> Traits defined:</b>
00788     
00789     <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
00790 */
00791 template <class T>
00792 class RGBPrime2XYZFunctor
00793 {
00794   public:
00795   
00796         /** the result's component type
00797         */
00798     typedef typename NumericTraits<T>::RealPromote component_type;
00799 
00800         /** the functor's argument type
00801         */
00802     typedef TinyVector<T, 3> argument_type;
00803   
00804         /** the functor's result type
00805         */
00806     typedef TinyVector<component_type, 3> result_type;
00807   
00808         /** \deprecated use argument_type and result_type
00809         */
00810     typedef TinyVector<component_type, 3> value_type;
00811     
00812         /** default constructor
00813             The maximum value for each RGB component defaults to 255.
00814         */
00815     RGBPrime2XYZFunctor()
00816     : max_(255.0), gamma_(1.0/ 0.45)
00817     {}
00818     
00819         /** constructor
00820             \arg max - the maximum value for each RGB component
00821         */
00822     RGBPrime2XYZFunctor(component_type max)
00823     : max_(max), gamma_(1.0/ 0.45)
00824     {}
00825     
00826         /** apply the transformation
00827         */
00828     result_type operator()(argument_type const & rgb) const
00829     {
00830         component_type red = detail::gammaCorrection(rgb[0]/max_, gamma_);
00831         component_type green = detail::gammaCorrection(rgb[1]/max_, gamma_);
00832         component_type blue = detail::gammaCorrection(rgb[2]/max_, gamma_);
00833         result_type result;
00834         result[0] = 0.412453*red + 0.357580*green + 0.180423*blue;
00835         result[1] = 0.212671*red + 0.715160*green + 0.072169*blue;
00836         result[2] = 0.019334*red + 0.119193*green + 0.950227*blue;
00837         return result;
00838     }
00839 
00840   private:
00841     component_type max_, gamma_;
00842 };
00843 
00844 template <class T>
00845 class FunctorTraits<RGBPrime2XYZFunctor<T> >
00846 : public FunctorTraitsBase<RGBPrime2XYZFunctor<T> >
00847 {
00848   public:
00849     typedef VigraTrueType isUnaryFunctor;
00850 };
00851 
00852 /** \brief Convert standardized tri-stimulus XYZ into linear (raw) RGB.
00853 
00854     <b>\#include</b> <<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>><br>
00855     Namespace: vigra
00856     
00857     According to ITU-R Recommendation BT.709, the functor realizes the transformation
00858     
00859     \f[
00860         \begin{array}{rcl}
00861         R & = & R_{max} (3.2404813432\enspace X - 1.5371515163\enspace Y - 0.4985363262\enspace Z) \\
00862         G & = & G_{max} (-0.9692549500\enspace X + 1.8759900015\enspace Y + 0.0415559266\enspace Z) \\
00863         B & = & B_{max} (0.0556466391\enspace X - 0.2040413384\enspace Y + 1.0573110696\enspace Z)
00864         \end{array}
00865     \f]
00866     
00867     By default, \f$ R_{max} = G_{max} = B_{max} = 255 \f$. This default can be overridden
00868     in the constructor. This is the inverse transform of vigra::RGB2XYZFunctor.
00869 
00870     <b> Traits defined:</b>
00871     
00872     <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
00873 */
00874 template <class T>
00875 class XYZ2RGBFunctor
00876 {
00877     typedef typename NumericTraits<T>::RealPromote component_type;
00878     
00879     component_type max_;
00880     
00881   public:
00882         /** the functor's argument type. (Actually, the argument type
00883             is more general: <TT>V</TT> with arbitrary
00884             <TT>V</TT>. But this cannot be expressed in a typedef.)
00885         */
00886     typedef TinyVector<T, 3> argument_type;
00887   
00888         /** the functor's result type
00889         */
00890     typedef RGBValue<T> result_type;
00891   
00892         /** \deprecated use argument_type and result_type
00893         */
00894     typedef RGBValue<T> value_type;
00895     
00896         /** default constructor.
00897             The maximum value for each RGB component defaults to 255.
00898         */
00899     XYZ2RGBFunctor()
00900     : max_(255.0)
00901     {}
00902     
00903         /** constructor
00904             \arg max - the maximum value for each RGB component
00905         */
00906     XYZ2RGBFunctor(component_type max)
00907     : max_(max)
00908     {}
00909     
00910         /** apply the transformation
00911         */
00912     template <class V>
00913     result_type operator()(V const & xyz) const
00914     {
00915         component_type red =    3.2404813432*xyz[0] - 1.5371515163*xyz[1] - 0.4985363262*xyz[2];
00916         component_type green = -0.9692549500*xyz[0] + 1.8759900015*xyz[1] + 0.0415559266*xyz[2];
00917         component_type blue =   0.0556466391*xyz[0] - 0.2040413384*xyz[1] + 1.0573110696*xyz[2];
00918         return value_type(NumericTraits<T>::fromRealPromote(red * max_),
00919                           NumericTraits<T>::fromRealPromote(green * max_),
00920                           NumericTraits<T>::fromRealPromote(blue * max_));
00921     }
00922 };
00923 
00924 template <class T>
00925 class FunctorTraits<XYZ2RGBFunctor<T> >
00926 : public FunctorTraitsBase<XYZ2RGBFunctor<T> >
00927 {
00928   public:
00929     typedef VigraTrueType isUnaryFunctor;
00930 };
00931 
00932 /** \brief Convert standardized tri-stimulus XYZ into non-linear (gamma corrected) R'G'B'.
00933 
00934     <b>\#include</b> <<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>><br>
00935     Namespace: vigra
00936     
00937     The functor realizes the transformation
00938     
00939     \f[
00940         XYZ \Rightarrow RGB \Rightarrow R'G'B'
00941     \f]
00942     
00943     See vigra::XYZ2RGBFunctor and vigra::RGB2RGBPrimeFunctor for a description of the two 
00944     steps.
00945 
00946     <b> Traits defined:</b>
00947     
00948     <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
00949 */
00950 template <class T>
00951 class XYZ2RGBPrimeFunctor
00952 {
00953     typedef typename NumericTraits<T>::RealPromote component_type;
00954     
00955     component_type max_, gamma_;
00956     
00957   public:
00958   
00959   public:
00960         /** the functor's argument type. (actually, the argument type
00961             can be any vector type with the same interface. 
00962             But this cannot be expressed in a typedef.)
00963         */
00964     typedef TinyVector<T, 3> argument_type;
00965   
00966         /** the functor's result type
00967         */
00968     typedef RGBValue<T> result_type;
00969   
00970         /** \deprecated use argument_type and result_type
00971         */
00972     typedef RGBValue<T> value_type;
00973     
00974         /** default constructor.
00975             The maximum value for each RGB component defaults to 255.
00976         */
00977     XYZ2RGBPrimeFunctor()
00978     : max_(255.0), gamma_(0.45)
00979     {}
00980     
00981         /** constructor
00982             \arg max - the maximum value for each RGB component
00983         */
00984     XYZ2RGBPrimeFunctor(component_type max)
00985     : max_(max), gamma_(0.45)
00986     {}
00987     
00988         /** apply the transformation
00989         */
00990     template <class V>
00991     result_type operator()(V const & xyz) const
00992     {
00993         component_type red =    3.2404813432*xyz[0] - 1.5371515163*xyz[1] - 0.4985363262*xyz[2];
00994         component_type green = -0.9692549500*xyz[0] + 1.8759900015*xyz[1] + 0.0415559266*xyz[2];
00995         component_type blue =   0.0556466391*xyz[0] - 0.2040413384*xyz[1] + 1.0573110696*xyz[2];
00996         return value_type(NumericTraits<T>::fromRealPromote(detail::gammaCorrection(red, gamma_) * max_),
00997                           NumericTraits<T>::fromRealPromote(detail::gammaCorrection(green, gamma_) * max_),
00998                           NumericTraits<T>::fromRealPromote(detail::gammaCorrection(blue, gamma_) * max_));
00999     }
01000 };
01001 
01002 template <class T>
01003 class FunctorTraits<XYZ2RGBPrimeFunctor<T> >
01004 : public FunctorTraitsBase<XYZ2RGBPrimeFunctor<T> >
01005 {
01006   public:
01007     typedef VigraTrueType isUnaryFunctor;
01008 };
01009 
01010 /** \brief Convert standardized tri-stimulus XYZ into perceptual uniform CIE L*u*v*.
01011 
01012     <b>\#include</b> <<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>><br>
01013     Namespace: vigra
01014     
01015     The functor realizes the transformation
01016     
01017     \f[
01018         \begin{array}{rcl}
01019         L^{*} & = & 116 \left( \frac{Y}{Y_n} \right)^\frac{1}{3}-16 \quad \mbox{if} \quad 0.008856 < \frac{Y}{Y_n}\\
01020         & & \\
01021         L^{*} & = & 903.3\enspace \frac{Y}{Y_n} \quad \mbox{otherwise} \\
01022         & & \\
01023         
01024         u' & = & \frac{4 X}{X+15 Y + 3 Z}, \quad 
01025              v' = \frac{9 Y}{X+15 Y + 3 Z}\\
01026         & & \\
01027         u^{*} & = & 13 L^{*} (u' - u_n'), \quad v^{*} = 13 L^{*} (v' - v_n')
01028         \end{array}
01029     \f]
01030     
01031     where \f$(X_n, Y_n, Z_n)\f$ is the reference white point, and 
01032     \f$u_n' = 0.197839, v_n'=0.468342\f$ are the quantities \f$u', v'\f$ calculated for this
01033     point. \f$L^{*}\f$ represents the
01034     <em>lighness</em> ("brightness") of the color, and \f$u^{*}, v^{*}\f$ code the 
01035     chromaticity.
01036 
01037     <b> Traits defined:</b>
01038     
01039     <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
01040 */
01041 template <class T>
01042 class XYZ2LuvFunctor
01043 {
01044   public:
01045   
01046         /** the result's component type
01047         */
01048     typedef typename NumericTraits<T>::RealPromote component_type;
01049 
01050         /** the functor's argument type
01051         */
01052     typedef TinyVector<T, 3> argument_type;
01053   
01054         /** the functor's result type
01055         */
01056     typedef TinyVector<component_type, 3> result_type;
01057   
01058         /** \deprecated use argument_type and result_type
01059         */
01060     typedef TinyVector<component_type, 3> value_type;
01061     
01062     XYZ2LuvFunctor()
01063     : gamma_(1.0/3.0)
01064     {}
01065     
01066     template <class V>
01067     result_type operator()(V const & xyz) const
01068     {
01069         result_type result;
01070         if(xyz[1] == NumericTraits<T>::zero())
01071         {
01072             result[0] = NumericTraits<component_type>::zero();
01073             result[1] = NumericTraits<component_type>::zero();
01074             result[2] = NumericTraits<component_type>::zero();
01075         }
01076         else
01077         {
01078             component_type L = xyz[1] < 0.008856 ?
01079                                   903.3 * xyz[1] :
01080                                   116.0 * VIGRA_CSTD::pow((double)xyz[1], gamma_) - 16.0;
01081             component_type denom = xyz[0] + 15.0*xyz[1] + 3.0*xyz[2];
01082             component_type uprime = 4.0 * xyz[0] / denom;
01083             component_type vprime = 9.0 * xyz[1] / denom;
01084             result[0] = L;
01085             result[1] = 13.0*L*(uprime - 0.197839);
01086             result[2] = 13.0*L*(vprime - 0.468342);
01087         }
01088         return result;
01089     }
01090 
01091   private:
01092     double gamma_;
01093 };
01094 
01095 template <class T>
01096 class FunctorTraits<XYZ2LuvFunctor<T> >
01097 : public FunctorTraitsBase<XYZ2LuvFunctor<T> >
01098 {
01099   public:
01100     typedef VigraTrueType isUnaryFunctor;
01101 };
01102 
01103 /** \brief Convert perceptual uniform CIE L*u*v* into standardized tri-stimulus XYZ.
01104 
01105     <b>\#include</b> <<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>><br>
01106     Namespace: vigra
01107     
01108     The functor realizes the inverse of the transformation described in vigra::XYZ2LuvFunctor
01109 
01110     <b> Traits defined:</b>
01111     
01112     <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
01113 */
01114 template <class T>
01115 class Luv2XYZFunctor
01116 {
01117   public:
01118   
01119         /** the result's component type
01120         */
01121     typedef typename NumericTraits<T>::RealPromote component_type;
01122 
01123         /** the functor's argument type
01124         */
01125     typedef TinyVector<T, 3> argument_type;
01126   
01127         /** the functor's result type
01128         */
01129     typedef TinyVector<component_type, 3> result_type;
01130   
01131         /** \deprecated use argument_type and result_type
01132         */
01133     typedef TinyVector<component_type, 3> value_type;
01134     
01135     Luv2XYZFunctor()
01136     : gamma_(3.0)
01137     {}
01138     
01139         /** apply the transformation
01140         */
01141     template <class V>
01142     result_type operator()(V const & luv) const
01143     {
01144         result_type result;
01145         if(luv[0] == NumericTraits<T>::zero())
01146         {
01147             result[0] = NumericTraits<component_type>::zero();
01148             result[1] = NumericTraits<component_type>::zero();
01149             result[2] = NumericTraits<component_type>::zero();
01150         }
01151         else
01152         {
01153             component_type uprime = luv[1] / 13.0 / luv[0] + 0.197839;
01154             component_type vprime = luv[2] / 13.0 / luv[0] + 0.468342;
01155 
01156             result[1] = luv[0] < 8.0 ?
01157                                   luv[0] / 903.3 :
01158                                   VIGRA_CSTD::pow((luv[0] + 16.0) / 116.0, gamma_);
01159             result[0] = 9.0*uprime*result[1] / 4.0 / vprime;
01160             result[2] = ((9.0 / vprime - 15.0)*result[1] - result[0])/ 3.0;
01161         }
01162         return result;
01163     }
01164 
01165   private:
01166     double gamma_;
01167 };
01168 
01169 template <class T>
01170 class FunctorTraits<Luv2XYZFunctor<T> >
01171 : public FunctorTraitsBase<Luv2XYZFunctor<T> >
01172 {
01173   public:
01174     typedef VigraTrueType isUnaryFunctor;
01175 };
01176 
01177 /** \brief Convert standardized tri-stimulus XYZ into perceptual uniform CIE L*a*b*.
01178 
01179     <b>\#include</b> <<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>><br>
01180     Namespace: vigra
01181     
01182     The functor realizes the transformation
01183     
01184     \f[
01185         \begin{array}{rcl}
01186         L^{*} & = & 116 \left( \frac{Y}{Y_n} \right)^\frac{1}{3}-16 \quad \mbox{if} \quad 0.008856 < \frac{Y}{Y_n}\\
01187         & & \\
01188         L^{*} & = & 903.3\enspace \frac{Y}{Y_n} \quad \mbox{otherwise} \\
01189         & & \\
01190         a^{*} & = & 500 \left[ \left( \frac{X}{X_n} \right)^\frac{1}{3} - \left( \frac{Y}{Y_n} \right)^\frac{1}{3} \right] \\
01191         & & \\
01192         b^{*} & = & 200 \left[ \left( \frac{Y}{Y_n} \right)^\frac{1}{3} - \left( \frac{Z}{Z_n} \right)^\frac{1}{3} \right] \\
01193         \end{array}
01194     \f]
01195     
01196     where \f$(X_n, Y_n, Z_n)\f$ is the reference white point. \f$L^{*}\f$ represents the
01197     <em>lighness</em> ("brightness") of the color, and \f$a^{*}, b^{*}\f$ code the 
01198     chromaticity.
01199 
01200     <b> Traits defined:</b>
01201     
01202     <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
01203 */
01204 template <class T>
01205 class XYZ2LabFunctor
01206 {
01207   public:
01208   
01209         /** the result's component type
01210         */
01211     typedef typename NumericTraits<T>::RealPromote component_type;
01212 
01213         /** the functor's argument type
01214         */
01215     typedef TinyVector<T, 3> argument_type;
01216   
01217         /** the functor's result type
01218         */
01219     typedef TinyVector<component_type, 3> result_type;
01220   
01221         /** \deprecated use argument_type and result_type
01222         */
01223     typedef TinyVector<component_type, 3> value_type;
01224     
01225     XYZ2LabFunctor()
01226     : gamma_(1.0/3.0)
01227     {}
01228     
01229         /** apply the transformation
01230         */
01231     template <class V>
01232     result_type operator()(V const & xyz) const
01233     {
01234         component_type xgamma = VIGRA_CSTD::pow(xyz[0] / 0.950456, gamma_);
01235         component_type ygamma = VIGRA_CSTD::pow((double)xyz[1], gamma_);
01236         component_type zgamma = VIGRA_CSTD::pow(xyz[2] / 1.088754, gamma_);
01237         component_type L = xyz[1] < 0.008856 ?
01238                               903.3 * xyz[1] :
01239                               116.0 * ygamma - 16.0;
01240         result_type result;
01241         result[0] = L;
01242         result[1] = 500.0*(xgamma - ygamma);
01243         result[2] = 200.0*(ygamma - zgamma);
01244         return result;
01245     }
01246 
01247   private:
01248     double gamma_;
01249 };
01250 
01251 template <class T>
01252 class FunctorTraits<XYZ2LabFunctor<T> >
01253 : public FunctorTraitsBase<XYZ2LabFunctor<T> >
01254 {
01255   public:
01256     typedef VigraTrueType isUnaryFunctor;
01257 };
01258 
01259 /** \brief Convert perceptual uniform CIE L*a*b* into standardized tri-stimulus XYZ.
01260 
01261     <b>\#include</b> <<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>><br>
01262     Namespace: vigra
01263     
01264     The functor realizes the inverse of the transformation described in vigra::XYZ2LabFunctor
01265 
01266     <b> Traits defined:</b>
01267     
01268     <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
01269 */
01270 template <class T>
01271 class Lab2XYZFunctor
01272 {
01273   public:
01274   
01275         /** the result's component type
01276         */
01277     typedef typename NumericTraits<T>::RealPromote component_type;
01278 
01279         /** the functor's argument type
01280         */
01281     typedef TinyVector<T, 3> argument_type;
01282   
01283         /** the functor's result type
01284         */
01285     typedef TinyVector<component_type, 3> result_type;
01286   
01287         /** \deprecated use argument_type and result_type
01288         */
01289     typedef TinyVector<component_type, 3> value_type;
01290     
01291         /** the functor's value type
01292         */
01293     Lab2XYZFunctor()
01294     : gamma_(3.0)
01295     {}
01296     
01297         /** apply the transformation
01298         */
01299     template <class V>
01300     result_type operator()(V const & lab) const
01301     {
01302         component_type Y = lab[0] < 8.0 ?
01303                               lab[0] / 903.3 :
01304                               VIGRA_CSTD::pow((lab[0] + 16.0) / 116.0, gamma_);
01305         component_type ygamma = VIGRA_CSTD::pow((double)Y, 1.0 / gamma_);
01306         component_type X = VIGRA_CSTD::pow(lab[1] / 500.0 + ygamma, gamma_) * 0.950456;
01307         component_type Z = VIGRA_CSTD::pow(-lab[2] / 200.0 + ygamma, gamma_) * 1.088754;
01308         result_type result;
01309         result[0] = X;
01310         result[1] = Y;
01311         result[2] = Z;
01312         return result;
01313     }
01314 
01315   private:
01316     double gamma_;
01317 };
01318 
01319 template <class T>
01320 class FunctorTraits<Lab2XYZFunctor<T> >
01321 : public FunctorTraitsBase<Lab2XYZFunctor<T> >
01322 {
01323   public:
01324     typedef VigraTrueType isUnaryFunctor;
01325 };
01326 
01327 /** \brief Convert linear (raw) RGB into perceptual uniform CIE L*u*v*.
01328 
01329     <b>\#include</b> <<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>><br>
01330     Namespace: vigra
01331     
01332     The functor realizes the transformation
01333     
01334     \f[
01335         RGB \Rightarrow XYZ \Rightarrow L^*u^*v^*
01336     \f]
01337     
01338     See vigra::RGB2XYZFunctor and vigra::XYZ2LuvFunctor for a description of the two 
01339     steps. The resulting color components will have the following bounds:
01340     
01341     \f[
01342         \begin{array}{rcl}
01343         0 \leq & L^* & \leq 100 \\
01344         -83.077 \leq & u^* & \leq 175.015 \\
01345         -134.101 \leq & v^* & \leq 107.393
01346         \end{array}
01347     \f]
01348 
01349     <b> Traits defined:</b>
01350     
01351     <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
01352 */
01353 template <class T>
01354 class RGB2LuvFunctor
01355 {
01356     /*
01357     L in [0, 100]
01358     u in [-83.077, 175.015]
01359     v in [-134.101, 107.393]
01360     maximum saturation: 179.04 
01361     red = [53.2406, 175.015, 37.7522]
01362     */
01363   public:
01364   
01365         /** the result's component type
01366         */
01367     typedef typename NumericTraits<T>::RealPromote component_type;
01368 
01369         /** the functor's argument type
01370         */
01371     typedef TinyVector<T, 3> argument_type;
01372   
01373         /** the functor's result type
01374         */
01375     typedef typename XYZ2LuvFunctor<component_type>::result_type result_type;
01376   
01377         /** \deprecated use argument_type and result_type
01378         */
01379     typedef typename XYZ2LuvFunctor<component_type>::result_type value_type;
01380     
01381         /** default constructor.
01382             The maximum value for each RGB component defaults to 255.
01383         */
01384     RGB2LuvFunctor()
01385     : rgb2xyz(255.0)
01386     {}
01387     
01388         /** constructor
01389             \arg max - the maximum value for each RGB component
01390         */
01391     RGB2LuvFunctor(component_type max)
01392     : rgb2xyz(max)
01393     {}
01394     
01395         /** apply the transformation
01396         */
01397     template <class V>
01398     result_type operator()(V const & rgb) const
01399     {
01400         return xyz2luv(rgb2xyz(rgb));
01401     }
01402 
01403   private:
01404     RGB2XYZFunctor<T> rgb2xyz;
01405     XYZ2LuvFunctor<component_type> xyz2luv;
01406 };
01407 
01408 template <class T>
01409 class FunctorTraits<RGB2LuvFunctor<T> >
01410 : public FunctorTraitsBase<RGB2LuvFunctor<T> >
01411 {
01412   public:
01413     typedef VigraTrueType isUnaryFunctor;
01414 };
01415 
01416 /** \brief Convert linear (raw) RGB into perceptual uniform CIE L*a*b*.
01417 
01418     <b>\#include</b> <<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>><br>
01419     Namespace: vigra
01420     
01421     The functor realizes the transformation
01422     
01423     \f[
01424         RGB \Rightarrow XYZ \Rightarrow L^*a^*b^*
01425     \f]
01426     
01427     See vigra::RGB2XYZFunctor and vigra::XYZ2LabFunctor for a description of the two 
01428     steps. The resulting color components will have the following bounds:
01429     
01430     \f[
01431         \begin{array}{rcl}
01432         0 \leq & L^* & \leq 100 \\
01433         -86.1813 \leq & u^* & \leq 98.2352 \\
01434         -107.862 \leq & v^* & \leq 94.4758
01435         \end{array}
01436     \f]
01437 
01438     <b> Traits defined:</b>
01439     
01440     <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
01441 */
01442 template <class T>
01443 class RGB2LabFunctor
01444 {
01445     /*
01446     L in [0, 100]
01447     a in [-86.1813, 98.2352]
01448     b in [-107.862, 94.4758] 
01449     maximum saturation: 133.809
01450     red = [53.2406, 80.0942, 67.2015]
01451     */
01452   public:
01453   
01454         /** the result's component type
01455         */
01456     typedef typename NumericTraits<T>::RealPromote component_type;
01457 
01458         /** the functor's argument type
01459         */
01460     typedef TinyVector<T, 3> argument_type;
01461   
01462         /** the functor's result type
01463         */
01464     typedef typename XYZ2LabFunctor<component_type>::result_type result_type;
01465   
01466         /** \deprecated use argument_type and result_type
01467         */
01468     typedef typename XYZ2LabFunctor<component_type>::result_type value_type;
01469     
01470         /** default constructor.
01471             The maximum value for each RGB component defaults to 255.
01472         */
01473     RGB2LabFunctor()
01474     : rgb2xyz(255.0)
01475     {}
01476     
01477         /** constructor
01478             \arg max - the maximum value for each RGB component
01479         */
01480     RGB2LabFunctor(component_type max)
01481     : rgb2xyz(max)
01482     {}
01483     
01484         /** apply the transformation
01485         */
01486     template <class V>
01487     result_type operator()(V const & rgb) const
01488     {
01489         return xyz2lab(rgb2xyz(rgb));
01490     }
01491 
01492   private:
01493     RGB2XYZFunctor<T> rgb2xyz;
01494     XYZ2LabFunctor<component_type> xyz2lab;
01495 };
01496 
01497 template <class T>
01498 class FunctorTraits<RGB2LabFunctor<T> >
01499 : public FunctorTraitsBase<RGB2LabFunctor<T> >
01500 {
01501   public:
01502     typedef VigraTrueType isUnaryFunctor;
01503 };
01504 
01505 /** \brief Convert perceptual uniform CIE L*u*v* into linear (raw) RGB.
01506 
01507     <b>\#include</b> <<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>><br>
01508     Namespace: vigra
01509     
01510     The functor realizes the inverse of the transformation described in vigra::RGB2LuvFunctor
01511 
01512     <b> Traits defined:</b>
01513     
01514     <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
01515 */
01516 template <class T>
01517 class Luv2RGBFunctor
01518 {
01519     typedef typename NumericTraits<T>::RealPromote component_type;
01520     
01521     XYZ2RGBFunctor<T> xyz2rgb;
01522     Luv2XYZFunctor<component_type> luv2xyz;
01523     
01524   public:
01525         /** the functor's argument type. (Actually, the argument type
01526             can be any vector type with the same interface. 
01527             But this cannot be expressed in a typedef.)
01528         */
01529     typedef TinyVector<T, 3> argument_type;
01530   
01531         /** the functor's result type
01532         */
01533     typedef typename XYZ2RGBFunctor<T>::result_type result_type;
01534   
01535         /** \deprecated use argument_type and result_type
01536         */
01537     typedef typename XYZ2RGBFunctor<T>::result_type value_type;
01538     
01539     Luv2RGBFunctor()
01540     : xyz2rgb(255.0)
01541     {}
01542     
01543     Luv2RGBFunctor(component_type max)
01544     : xyz2rgb(max)
01545     {}
01546     
01547         /** apply the transformation
01548         */
01549     template <class V>
01550     result_type operator()(V const & luv) const
01551     {
01552         return xyz2rgb(luv2xyz(luv));
01553     }
01554 };
01555 
01556 template <class T>
01557 class FunctorTraits<Luv2RGBFunctor<T> >
01558 : public FunctorTraitsBase<Luv2RGBFunctor<T> >
01559 {
01560   public:
01561     typedef VigraTrueType isUnaryFunctor;
01562 };
01563 
01564 /** \brief Convert perceptual uniform CIE L*a*b* into linear (raw) RGB.
01565 
01566     <b>\#include</b> <<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>><br>
01567     Namespace: vigra
01568     
01569     The functor realizes the inverse of the transformation described in vigra::RGB2LabFunctor
01570 
01571     <b> Traits defined:</b>
01572     
01573     <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
01574 */
01575 template <class T>
01576 class Lab2RGBFunctor
01577 {
01578     typedef typename NumericTraits<T>::RealPromote component_type;
01579     
01580     XYZ2RGBFunctor<T> xyz2rgb;
01581     Lab2XYZFunctor<component_type> lab2xyz;
01582     
01583   public:
01584   
01585         /** the functor's argument type. (Actually, the argument type
01586             can be any vector type with the same interface. 
01587             But this cannot be expressed in a typedef.)
01588         */
01589     typedef TinyVector<T, 3> argument_type;
01590   
01591         /** the functor's result type
01592         */
01593     typedef typename XYZ2RGBFunctor<T>::result_type result_type;
01594   
01595         /** \deprecated use argument_type and result_type
01596         */
01597     typedef typename XYZ2RGBFunctor<T>::result_type value_type;
01598     
01599         /** default constructor.
01600             The maximum value for each RGB component defaults to 255.
01601         */
01602     Lab2RGBFunctor()
01603     : xyz2rgb(255.0)
01604     {}
01605     
01606         /** constructor
01607             \arg max - the maximum value for each RGB component
01608         */
01609     Lab2RGBFunctor(component_type max)
01610     : xyz2rgb(max)
01611     {}
01612     
01613         /** apply the transformation
01614         */
01615     template <class V>
01616     result_type operator()(V const & lab) const
01617     {
01618         return xyz2rgb(lab2xyz(lab));
01619     }
01620 };
01621 
01622 template <class T>
01623 class FunctorTraits<Lab2RGBFunctor<T> >
01624 : public FunctorTraitsBase<Lab2RGBFunctor<T> >
01625 {
01626   public:
01627     typedef VigraTrueType isUnaryFunctor;
01628 };
01629 
01630 /** \brief Convert non-linear (gamma corrected) R'G'B' into perceptual uniform CIE L*u*v*.
01631 
01632     <b>\#include</b> <<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>><br>
01633     Namespace: vigra
01634     
01635     The functor realizes the transformation
01636     
01637     \f[
01638         R'G'B' \Rightarrow RGB \Rightarrow XYZ \Rightarrow L^*u^*v^*
01639     \f]
01640     
01641     See vigra::RGBPrime2RGBFunctor, vigra::RGB2XYZFunctor and vigra::XYZ2LuvFunctor for a description of the three 
01642     steps. The resulting color components will have the following bounds:
01643     
01644     \f[
01645         \begin{array}{rcl}
01646         0 \leq & L^* & \leq 100 \\
01647         -83.077 \leq & u^* & \leq 175.015 \\
01648         -134.101 \leq & v^* & \leq 107.393
01649         \end{array}
01650     \f]
01651 
01652     <b> Traits defined:</b>
01653     
01654     <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
01655 */
01656 template <class T>
01657 class RGBPrime2LuvFunctor
01658 {
01659   public:
01660   
01661         /** the result's component type
01662         */
01663     typedef typename NumericTraits<T>::RealPromote component_type;
01664 
01665         /** the functor's argument type
01666         */
01667     typedef TinyVector<T, 3> argument_type;
01668   
01669         /** the functor's result type
01670         */
01671     typedef typename XYZ2LuvFunctor<component_type>::result_type result_type;
01672   
01673         /** \deprecated use argument_type and result_type
01674         */
01675     typedef typename XYZ2LuvFunctor<component_type>::result_type value_type;
01676     
01677         /** default constructor.
01678             The maximum value for each RGB component defaults to 255.
01679         */
01680     RGBPrime2LuvFunctor()
01681     : rgb2xyz(255.0)
01682     {}
01683     
01684         /** constructor
01685             \arg max - the maximum value for each RGB component
01686         */
01687     RGBPrime2LuvFunctor(component_type max)
01688     : rgb2xyz(max)
01689     {}
01690     
01691         /** apply the transformation
01692         */
01693     template <class V>
01694     result_type operator()(V const & rgb) const
01695     {
01696         return xyz2luv(rgb2xyz(rgb));
01697     }
01698 
01699   private:
01700     RGBPrime2XYZFunctor<T> rgb2xyz;
01701     XYZ2LuvFunctor<component_type> xyz2luv;
01702 };
01703 
01704 template <class T>
01705 class FunctorTraits<RGBPrime2LuvFunctor<T> >
01706 : public FunctorTraitsBase<RGBPrime2LuvFunctor<T> >
01707 {
01708   public:
01709     typedef VigraTrueType isUnaryFunctor;
01710 };
01711 
01712 /** \brief Convert non-linear (gamma corrected) R'G'B' into perceptual uniform CIE L*a*b*.
01713 
01714     <b>\#include</b> <<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>><br>
01715     Namespace: vigra
01716     
01717     The functor realizes the transformation
01718     
01719     \f[
01720         R'G'B' \Rightarrow RGB \Rightarrow XYZ \Rightarrow L^*a^*b^*
01721     \f]
01722     
01723     See vigra::RGBPrime2RGBFunctor, vigra::RGB2XYZFunctor and vigra::XYZ2LabFunctor for a description of the three 
01724     steps. The resulting color components will have the following bounds:
01725     
01726     \f[
01727         \begin{array}{rcl}
01728         0 \leq & L^* & \leq 100 \\
01729         -86.1813 \leq & u^* & \leq 98.2352 \\
01730         -107.862 \leq & v^* & \leq 94.4758
01731         \end{array}
01732     \f]
01733 
01734     <b> Traits defined:</b>
01735     
01736     <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
01737 */
01738 template <class T>
01739 class RGBPrime2LabFunctor
01740 {
01741   public:
01742   
01743         /** the result's component type
01744         */
01745     typedef typename NumericTraits<T>::RealPromote component_type;
01746 
01747         /** the functor's argument type
01748         */
01749     typedef TinyVector<T, 3> argument_type;
01750   
01751         /** the functor's result type
01752         */
01753     typedef typename XYZ2LabFunctor<component_type>::result_type result_type;
01754   
01755         /** \deprecated use argument_type and result_type
01756         */
01757     typedef typename XYZ2LabFunctor<component_type>::result_type value_type;
01758     
01759         /** default constructor.
01760             The maximum value for each RGB component defaults to 255.
01761         */
01762     RGBPrime2LabFunctor()
01763     : rgb2xyz(255.0)
01764     {}
01765     
01766         /** constructor
01767             \arg max - the maximum value for each RGB component
01768         */
01769     RGBPrime2LabFunctor(component_type max)
01770     : rgb2xyz(max)
01771     {}
01772     
01773         /** apply the transformation
01774         */
01775     template <class V>
01776     result_type operator()(V const & rgb) const
01777     {
01778         return xyz2lab(rgb2xyz(rgb));
01779     }
01780 
01781   private:
01782     RGBPrime2XYZFunctor<T> rgb2xyz;
01783     XYZ2LabFunctor<component_type> xyz2lab;
01784 };
01785 
01786 template <class T>
01787 class FunctorTraits<RGBPrime2LabFunctor<T> >
01788 : public FunctorTraitsBase<RGBPrime2LabFunctor<T> >
01789 {
01790   public:
01791     typedef VigraTrueType isUnaryFunctor;
01792 };
01793 
01794 /** \brief Convert perceptual uniform CIE L*u*v* into non-linear (gamma corrected) R'G'B'.
01795 
01796     <b>\#include</b> <<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>><br>
01797     Namespace: vigra
01798     
01799     The functor realizes the inverse of the transformation described in vigra::RGBPrime2LuvFunctor
01800 
01801     <b> Traits defined:</b>
01802     
01803     <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
01804 */
01805 template <class T>
01806 class Luv2RGBPrimeFunctor
01807 {
01808     typedef typename NumericTraits<T>::RealPromote component_type;
01809     
01810     XYZ2RGBPrimeFunctor<T> xyz2rgb;
01811     Luv2XYZFunctor<component_type> luv2xyz;
01812     
01813   public:
01814   
01815         /** the functor's argument type. (Actually, the argument type
01816             can be any vector type with the same interface. 
01817             But this cannot be expressed in a typedef.)
01818         */
01819     typedef TinyVector<T, 3> argument_type;
01820   
01821         /** the functor's result type
01822         */
01823     typedef typename XYZ2RGBFunctor<T>::result_type result_type;
01824   
01825         /** \deprecated use argument_type and result_type
01826         */
01827     typedef typename XYZ2RGBFunctor<T>::result_type value_type;
01828     
01829         /** default constructor.
01830             The maximum value for each RGB component defaults to 255.
01831         */
01832     Luv2RGBPrimeFunctor()
01833     : xyz2rgb(255.0)
01834     {}
01835     
01836         /** constructor
01837             \arg max - the maximum value for each RGB component
01838         */
01839     Luv2RGBPrimeFunctor(component_type max)
01840     : xyz2rgb(max)
01841     {}
01842     
01843         /** apply the transformation
01844         */
01845     template <class V>
01846     result_type operator()(V const & luv) const
01847     {
01848         return xyz2rgb(luv2xyz(luv));
01849     }
01850 };
01851 
01852 template <class T>
01853 class FunctorTraits<Luv2RGBPrimeFunctor<T> >
01854 : public FunctorTraitsBase<Luv2RGBPrimeFunctor<T> >
01855 {
01856   public:
01857     typedef VigraTrueType isUnaryFunctor;
01858 };
01859 
01860 /** \brief Convert perceptual uniform CIE L*a*b* into non-linear (gamma corrected) R'G'B'.
01861 
01862     <b>\#include</b> <<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>><br>
01863     Namespace: vigra
01864     
01865     The functor realizes the inverse of the transformation described in vigra::RGBPrime2LabFunctor
01866 
01867     <b> Traits defined:</b>
01868     
01869     <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
01870 */
01871 template <class T>
01872 class Lab2RGBPrimeFunctor
01873 {
01874     typedef typename NumericTraits<T>::RealPromote component_type;
01875     
01876     XYZ2RGBPrimeFunctor<T> xyz2rgb;
01877     Lab2XYZFunctor<component_type> lab2xyz;
01878     
01879   public:
01880   
01881         /** the functor's argument type. (Actually, the argument type
01882             can be any vector type with the same interface. 
01883             But this cannot be expressed in a typedef.)
01884         */
01885     typedef TinyVector<T, 3> argument_type;
01886   
01887         /** the functor's result type
01888         */
01889     typedef typename XYZ2RGBFunctor<T>::result_type result_type;
01890   
01891         /** \deprecated use argument_type and result_type
01892         */
01893     typedef typename XYZ2RGBFunctor<T>::result_type value_type;
01894     
01895         /** default constructor.
01896             The maximum value for each RGB component defaults to 255.
01897         */
01898     Lab2RGBPrimeFunctor()
01899     : xyz2rgb(255.0)
01900     {}
01901     
01902         /** constructor
01903             \arg max - the maximum value for each RGB component
01904         */
01905     Lab2RGBPrimeFunctor(component_type max)
01906     : xyz2rgb(max)
01907     {}
01908     
01909         /** apply the transformation
01910         */
01911     template <class V>
01912     result_type operator()(V const & lab) const
01913     {
01914         return xyz2rgb(lab2xyz(lab));
01915     }
01916 };
01917 
01918 template <class T>
01919 class FunctorTraits<Lab2RGBPrimeFunctor<T> >
01920 : public FunctorTraitsBase<Lab2RGBPrimeFunctor<T> >
01921 {
01922   public:
01923     typedef VigraTrueType isUnaryFunctor;
01924 };
01925 
01926 /** \brief Convert non-linear (gamma corrected) R'G'B' into Y'PbPr color difference components.
01927 
01928     <b>\#include</b> <<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>><br>
01929     Namespace: vigra
01930     
01931     According to ITU-R Recommendation BT.601, the functor realizes the transformation
01932     
01933     \f[
01934         \begin{array}{rcl}
01935         Y' & = & 0.299\enspace R / R_{max} + 0.587\enspace G / G_{max} + 0.114\enspace B / B_{max}\\
01936         Pb & = & -0.1687358916\enspace R / R_{max} + 0.3312641084\enspace G / G_{max} + 0.5\enspace B / B_{max} \\
01937         Pr & = & 0.5\enspace R / R_{max} + 0.4186875892\enspace G / G_{max} + 0.0813124108\enspace B / B_{max}
01938         \end{array}
01939     \f]
01940     
01941     By default, \f$ R_{max} = G_{max} = B_{max} = 255 \f$. This default can be overridden
01942     in the constructor. Y' represents the <em>luminance</em> ("brightness") of the color, and
01943     Pb and Pr are the blue (B'-Y') and red (R'-Y') color difference components. 
01944     The transformation is scaled so that the following bounds apply:
01945     
01946     \f[
01947         \begin{array}{rcl}
01948         0 \leq & Y' & \leq 1 \\
01949         -0.5 \leq & Pb & \leq 0.5 \\
01950         -0.5 \leq & Pr & \leq 0.5
01951         \end{array}
01952     \f]
01953 
01954     <b> Traits defined:</b>
01955     
01956     <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
01957 */
01958 template <class T>
01959 class RGBPrime2YPrimePbPrFunctor
01960 {
01961     /*
01962     Y in [0, 1]
01963     Pb in [-0.5, 0.5]
01964     Pr in [-0.5, 0.5]
01965     maximum saturation: 0.533887
01966     red = [0.299, -0.168736, 0.5]
01967     */
01968   public:
01969   
01970         /** the result's component type
01971         */
01972     typedef typename NumericTraits<T>::RealPromote component_type;
01973 
01974         /** the functor's argument type
01975         */
01976     typedef TinyVector<T, 3> argument_type;
01977   
01978         /** the functor's result type
01979         */
01980     typedef TinyVector<component_type, 3> result_type;
01981   
01982         /** \deprecated use argument_type and result_type
01983         */
01984     typedef TinyVector<component_type, 3> value_type;
01985     
01986         /** default constructor.
01987             The maximum value for each RGB component defaults to 255.
01988         */
01989     RGBPrime2YPrimePbPrFunctor()
01990     : max_(255.0)
01991     {}
01992     
01993         /** constructor
01994             \arg max - the maximum value for each RGB component
01995         */
01996     RGBPrime2YPrimePbPrFunctor(component_type max)
01997     : max_(max)
01998     {}
01999     
02000         /** apply the transformation
02001         */
02002     template <class V>
02003     result_type operator()(V const & rgb) const
02004     {
02005         component_type red = rgb[0] / max_;
02006         component_type green = rgb[1] / max_;
02007         component_type blue = rgb[2] / max_;
02008         
02009         result_type result;
02010         result[0] = 0.299*red + 0.587*green + 0.114*blue;
02011         result[1] = -0.1687358916*red - 0.3312641084*green + 0.5*blue;
02012         result[2] = 0.5*red - 0.4186875892*green - 0.0813124108*blue;
02013         return result;
02014     }
02015 
02016   private:
02017     component_type max_;
02018 };
02019 
02020 template <class T>
02021 class FunctorTraits<RGBPrime2YPrimePbPrFunctor<T> >
02022 : public FunctorTraitsBase<RGBPrime2YPrimePbPrFunctor<T> >
02023 {
02024   public:
02025     typedef VigraTrueType isUnaryFunctor;
02026 };
02027 
02028 /** \brief Convert Y'PbPr color difference components into non-linear (gamma corrected) R'G'B'.
02029 
02030     <b>\#include</b> <<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>><br>
02031     Namespace: vigra
02032     
02033     The functor realizes the inverse of the transformation described in vigra::RGBPrime2YPrimePbPrFunctor
02034 
02035     <b> Traits defined:</b>
02036     
02037     <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
02038 */
02039 template <class T>
02040 class YPrimePbPr2RGBPrimeFunctor
02041 {
02042     typedef typename NumericTraits<T>::RealPromote component_type;
02043     
02044     component_type max_;
02045     
02046   public:
02047   
02048         /** the functor's argument type. (Actually, the argument type
02049             can be any vector type with the same interface. 
02050             But this cannot be expressed in a typedef.)
02051         */
02052     typedef TinyVector<T, 3> argument_type;
02053   
02054         /** the functor's result type
02055         */
02056     typedef RGBValue<T> result_type;
02057   
02058         /** \deprecated use argument_type and result_type
02059         */
02060     typedef RGBValue<T> value_type;
02061     
02062         /** default constructor.
02063             The maximum value for each RGB component defaults to 255.
02064         */
02065     YPrimePbPr2RGBPrimeFunctor()
02066     : max_(255.0)
02067     {}
02068     
02069         /** constructor
02070             \arg max - the maximum value for each RGB component
02071         */
02072     YPrimePbPr2RGBPrimeFunctor(component_type max)
02073     : max_(max)
02074     {}
02075     
02076         /** apply the transformation
02077         */
02078     template <class V>
02079     result_type operator()(V const & ypbpr) const
02080     {
02081         component_type nred =   ypbpr[0] + 1.402*ypbpr[2];
02082         component_type ngreen = ypbpr[0] - 0.3441362862*ypbpr[1] - 0.7141362862*ypbpr[2];
02083         component_type nblue =  ypbpr[0] + 1.772*ypbpr[1];
02084         return result_type(NumericTraits<T>::fromRealPromote(nred * max_),
02085                            NumericTraits<T>::fromRealPromote(ngreen * max_),
02086                            NumericTraits<T>::fromRealPromote(nblue * max_));
02087     }
02088 };
02089 
02090 template <class T>
02091 class FunctorTraits<YPrimePbPr2RGBPrimeFunctor<T> >
02092 : public FunctorTraitsBase<YPrimePbPr2RGBPrimeFunctor<T> >
02093 {
02094   public:
02095     typedef VigraTrueType isUnaryFunctor;
02096 };
02097 
02098 /** \brief Convert non-linear (gamma corrected) R'G'B' into Y'IQ components.
02099 
02100     <b>\#include</b> <<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>><br>
02101     Namespace: vigra
02102     
02103     According to the PAL analog videa standard, the functor realizes the transformation
02104     
02105     \f[
02106         \begin{array}{rcl}
02107         Y' & = & 0.299\enspace R / R_{max} + 0.587\enspace G / G_{max} + 0.114\enspace B / B_{max}\\
02108         I & = & 0.596\enspace R / R_{max} - 0.274\enspace G / G_{max} - 0.322\enspace B / B_{max} \\
02109         Q & = & 0.212\enspace R / R_{max} - 0.523\enspace G / G_{max} + 0.311\enspace B / B_{max}
02110         \end{array}
02111     \f]
02112     
02113     By default, \f$ R_{max} = G_{max} = B_{max} = 255 \f$. This default can be overridden
02114     in the constructor. Y' represents the <em>luminance</em> ("brightness") of the color. 
02115     The transformation is scaled so that the following bounds apply:
02116     
02117     \f[
02118         \begin{array}{rcl}
02119         0 \leq & Y' & \leq 1 \\
02120         -0.596 \leq & I & \leq 0.596 \\
02121         -0.523 \leq & Q & \leq 0.523
02122         \end{array}
02123     \f]
02124 
02125     <b> Traits defined:</b>
02126     
02127     <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
02128 */
02129 template <class T>
02130 class RGBPrime2YPrimeIQFunctor
02131 {
02132     /*
02133     Y in [0, 1]
02134     I in [-0.596, 0.596]
02135     Q in [-0.523, 0.523]
02136     maximum saturation: 0.632582
02137     red = [0.299, 0.596, 0.212]
02138     */
02139   public:
02140   
02141         /** the result's component type
02142         */
02143     typedef typename NumericTraits<T>::RealPromote component_type;
02144 
02145         /** the functor's argument type
02146         */
02147     typedef TinyVector<T, 3> argument_type;
02148   
02149         /** the functor's result type
02150         */
02151     typedef TinyVector<component_type, 3> result_type;
02152   
02153         /** \deprecated use argument_type and result_type
02154         */
02155     typedef TinyVector<component_type, 3> value_type;
02156     
02157         /** default constructor.
02158             The maximum value for each RGB component defaults to 255.
02159         */
02160     RGBPrime2YPrimeIQFunctor()
02161     : max_(255.0)
02162     {}
02163     
02164         /** constructor
02165             \arg max - the maximum value for each RGB component
02166         */
02167     RGBPrime2YPrimeIQFunctor(component_type max)
02168     : max_(max)
02169     {}
02170     
02171         /** apply the transformation
02172         */
02173     template <class V>
02174     result_type operator()(V const & rgb) const
02175     {
02176         component_type red = rgb[0] / max_;
02177         component_type green = rgb[1] / max_;
02178         component_type blue = rgb[2] / max_;
02179         
02180         result_type result;
02181         result[0] = 0.299*red + 0.587*green + 0.114*blue;
02182         result[1] = 0.596*red - 0.274*green - 0.322*blue;
02183         result[2] = 0.212*red - 0.523*green + 0.311*blue;
02184         return result;
02185     }
02186 
02187   private:
02188     component_type max_;
02189 };
02190 
02191 template <class T>
02192 class FunctorTraits<RGBPrime2YPrimeIQFunctor<T> >
02193 : public FunctorTraitsBase<RGBPrime2YPrimeIQFunctor<T> >
02194 {
02195   public:
02196     typedef VigraTrueType isUnaryFunctor;
02197 };
02198 
02199 /** \brief Convert Y'IQ color components into non-linear (gamma corrected) R'G'B'.
02200 
02201     <b>\#include</b> <<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>><br>
02202     Namespace: vigra
02203     
02204     The functor realizes the inverse of the transformation described in vigra::RGBPrime2YPrimeIQFunctor
02205 
02206     <b> Traits defined:</b>
02207     
02208     <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
02209 */
02210 template <class T>
02211 class YPrimeIQ2RGBPrimeFunctor
02212 {
02213     typedef typename NumericTraits<T>::RealPromote component_type;
02214     
02215     component_type max_;
02216     
02217   public:
02218   
02219         /** the functor's argument type. (Actually, the argument type
02220             can be any vector type with the same interface. 
02221             But this cannot be expressed in a typedef.)
02222         */
02223     typedef TinyVector<T, 3> argument_type;
02224   
02225         /** the functor's result type
02226         */
02227     typedef RGBValue<T> result_type;
02228   
02229         /** \deprecated use argument_type and result_type
02230         */
02231     typedef RGBValue<T> value_type;
02232     
02233         /** default constructor.
02234             The maximum value for each RGB component defaults to 255.
02235         */
02236     YPrimeIQ2RGBPrimeFunctor()
02237     : max_(255.0)
02238     {}
02239     
02240         /** constructor
02241             \arg max - the maximum value for each RGB component
02242         */
02243     YPrimeIQ2RGBPrimeFunctor(component_type max)
02244     : max_(max)
02245     {}
02246     
02247         /** apply the transformation
02248         */
02249     template <class V>
02250     result_type operator()(V const & yiq) const
02251     {
02252         component_type nred =   yiq[0] + 0.9548892043*yiq[1] + 0.6221039350*yiq[2];
02253         component_type ngreen = yiq[0] - 0.2713547827*yiq[1] - 0.6475120259*yiq[2];
02254         component_type nblue =  yiq[0] - 1.1072510054*yiq[1] + 1.7024603738*yiq[2];
02255         return result_type(NumericTraits<T>::fromRealPromote(nred * max_),
02256                            NumericTraits<T>::fromRealPromote(ngreen * max_),
02257                            NumericTraits<T>::fromRealPromote(nblue * max_));
02258     }
02259 };
02260 
02261 template <class T>
02262 class FunctorTraits<YPrimeIQ2RGBPrimeFunctor<T> >
02263 : public FunctorTraitsBase<YPrimeIQ2RGBPrimeFunctor<T> >
02264 {
02265   public:
02266     typedef VigraTrueType isUnaryFunctor;
02267 };
02268 
02269 /** \brief Convert non-linear (gamma corrected) R'G'B' into Y'UV components.
02270 
02271     <b>\#include</b> <<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>><br>
02272     Namespace: vigra
02273     
02274     According to the NTSC analog videa standard, the functor realizes the transformation
02275     
02276     \f[
02277         \begin{array}{rcl}
02278         Y' & = & 0.299\enspace R / R_{max} + 0.587\enspace G / G_{max} + 0.114\enspace B / B_{max}\\
02279         U & = & -0.147\enspace R / R_{max} - 0.289\enspace G / G_{max} + 0.436\enspace B / B_{max} \\
02280         V & = & 0.615\enspace R / R_{max} - 0.515\enspace G / G_{max} - 0.100\enspace B / B_{max}
02281         \end{array}
02282     \f]
02283     
02284     By default, \f$ R_{max} = G_{max} = B_{max} = 255 \f$. This default can be overridden
02285     in the constructor. Y' represents the <em>luminance</em> ("brightness") of the color. 
02286     The transformation is scaled so that the following bounds apply:
02287     
02288     \f[
02289         \begin{array}{rcl}
02290         0 \leq & Y' & \leq 1 \\
02291         -0.436 \leq & U & \leq 0.436 \\
02292         -0.615 \leq & V & \leq 0.615
02293         \end{array}
02294     \f]
02295 
02296     <b> Traits defined:</b>
02297     
02298     <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
02299 */
02300 template <class T>
02301 class RGBPrime2YPrimeUVFunctor
02302 {
02303     /*
02304     Y in [0, 1]
02305     U in [-0.436, 0.436]
02306     V in [-0.615, 0.615]
02307     maximum saturation: 0.632324
02308     red = [0.299, -0.147, 0.615]
02309     */
02310   public:
02311   
02312         /** the result's component type
02313         */
02314     typedef typename NumericTraits<T>::RealPromote component_type;
02315 
02316         /** the functor's argument type
02317         */
02318     typedef TinyVector<T, 3> argument_type;
02319   
02320         /** the functor's result type
02321         */
02322     typedef TinyVector<component_type, 3> result_type;
02323   
02324         /** \deprecated use argument_type and result_type
02325         */
02326     typedef TinyVector<component_type, 3> value_type;
02327     
02328         /** default constructor.
02329             The maximum value for each RGB component defaults to 255.
02330         */
02331     RGBPrime2YPrimeUVFunctor()
02332     : max_(255.0)
02333     {}
02334     
02335         /** constructor
02336             \arg max - the maximum value for each RGB component
02337         */
02338     RGBPrime2YPrimeUVFunctor(component_type max)
02339     : max_(max)
02340     {}
02341     
02342         /** apply the transformation
02343         */
02344     template <class V>
02345     result_type operator()(V const & rgb) const
02346     {
02347         component_type red = rgb[0] / max_;
02348         component_type green = rgb[1] / max_;
02349         component_type blue = rgb[2] / max_;
02350         
02351         result_type result;
02352         result[0] = 0.299*red + 0.587*green + 0.114*blue;
02353         result[1] = -0.1471376975*red - 0.2888623025*green + 0.436*blue;
02354         result[2] = 0.6149122807*red - 0.5149122807*green - 0.100*blue;
02355         return result;
02356     }
02357 
02358   private:
02359     component_type max_;
02360 };
02361 
02362 template <class T>
02363 class FunctorTraits<RGBPrime2YPrimeUVFunctor<T> >
02364 : public FunctorTraitsBase<RGBPrime2YPrimeUVFunctor<T> >
02365 {
02366   public:
02367     typedef VigraTrueType isUnaryFunctor;
02368 };
02369 
02370 /** \brief Convert Y'UV color components into non-linear (gamma corrected) R'G'B'.
02371 
02372     <b>\#include</b> <<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>><br>
02373     Namespace: vigra
02374     
02375     The functor realizes the inverse of the transformation described in vigra::RGBPrime2YPrimeUVFunctor
02376 
02377     <b> Traits defined:</b>
02378     
02379     <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
02380 */
02381 template <class T>
02382 class YPrimeUV2RGBPrimeFunctor
02383 {
02384     typedef typename NumericTraits<T>::RealPromote component_type;
02385     
02386     component_type max_;
02387     
02388   public:
02389   
02390         /** the functor's argument type. (Actually, the argument type
02391             can be any vector type with the same interface. 
02392             But this cannot be expressed in a typedef.)
02393         */
02394     typedef TinyVector<T, 3> argument_type;
02395   
02396         /** the functor's result type
02397         */
02398     typedef RGBValue<T> result_type;
02399   
02400         /** \deprecated use argument_type and result_type
02401         */
02402     typedef RGBValue<T> value_type;
02403     
02404         /** default constructor.
02405             The maximum value for each RGB component defaults to 255.
02406         */
02407     YPrimeUV2RGBPrimeFunctor()
02408     : max_(255.0)
02409     {}
02410     
02411         /** constructor
02412             \arg max - the maximum value for each RGB component
02413         */
02414     YPrimeUV2RGBPrimeFunctor(component_type max)
02415     : max_(max)
02416     {}
02417     
02418         /** apply the transformation
02419         */
02420     template <class V>
02421     result_type operator()(V const & yuv) const
02422     {
02423         component_type nred =   yuv[0] + 1.140*yuv[2];
02424         component_type ngreen = yuv[0] - 0.3946517044*yuv[1] - 0.580681431*yuv[2];
02425         component_type nblue =  yuv[0] + 2.0321100920*yuv[1];
02426         return result_type(NumericTraits<T>::fromRealPromote(nred * max_),
02427                            NumericTraits<T>::fromRealPromote(ngreen * max_),
02428                            NumericTraits<T>::fromRealPromote(nblue * max_));
02429     }
02430 };
02431 
02432 template <class T>
02433 class FunctorTraits<YPrimeUV2RGBPrimeFunctor<T> >
02434 : public FunctorTraitsBase<YPrimeUV2RGBPrimeFunctor<T> >
02435 {
02436   public:
02437     typedef VigraTrueType isUnaryFunctor;
02438 };
02439 
02440 /** \brief Convert non-linear (gamma corrected) R'G'B' into Y'CbCr color difference components.
02441 
02442     <b>\#include</b> <<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>><br>
02443     Namespace: vigra
02444     
02445     This functor basically applies the same transformation as vigra::RGBPrime2YPrimePbPrFunctor
02446     but the color components are scaled so that they can be coded as 8 bit intergers with
02447     minimal loss of information:
02448     
02449     \f[
02450         \begin{array}{rcl}
02451         16\leq & Y' & \leq 235 \\
02452         16 \leq & Cb & \leq 240 \\
02453         16 \leq & Cr & \leq 240
02454         \end{array}
02455     \f]
02456 
02457     <b> Traits defined:</b>
02458     
02459     <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
02460 */
02461 template <class T>
02462 class RGBPrime2YPrimeCbCrFunctor
02463 {
02464     /*
02465     Y in [16, 235]
02466     Cb in [16, 240]
02467     Cr in [16, 240]
02468     maximum saturation: 119.591
02469     red = [81.481, 90.203, 240]
02470     */
02471   public:
02472   
02473         /** the result's component type
02474         */
02475     typedef typename NumericTraits<T>::RealPromote component_type;
02476 
02477         /** the functor's argument type
02478         */
02479     typedef TinyVector<T, 3> argument_type;
02480   
02481         /** the functor's result type
02482         */
02483     typedef TinyVector<component_type, 3> result_type;
02484   
02485         /** \deprecated use argument_type and result_type
02486         */
02487     typedef TinyVector<component_type, 3> value_type;
02488     
02489         /** default constructor.
02490             The maximum value for each RGB component defaults to 255.
02491         */
02492     RGBPrime2YPrimeCbCrFunctor()
02493     : max_(255.0)
02494     {}
02495     
02496         /** constructor
02497             \arg max - the maximum value for each RGB component
02498         */
02499     RGBPrime2YPrimeCbCrFunctor(component_type max)
02500     : max_(max)
02501     {}
02502     
02503         /** apply the transformation
02504         */
02505     template <class V>
02506     result_type operator()(V const & rgb) const
02507     {
02508         component_type red = rgb[0] / max_;
02509         component_type green = rgb[1] / max_;
02510         component_type blue = rgb[2] / max_;
02511         
02512         result_type result;
02513         result[0] = 16.0 + 65.481*red + 128.553*green + 24.966*blue;
02514         result[1] = 128.0 - 37.79683972*red - 74.20316028*green + 112.0*blue;
02515         result[2] = 128.0 + 112.0*red - 93.78601998*green - 18.21398002*blue;
02516         return result;
02517     }
02518 
02519   private:
02520     component_type max_;
02521 };
02522 
02523 template <class T>
02524 class FunctorTraits<RGBPrime2YPrimeCbCrFunctor<T> >
02525 : public FunctorTraitsBase<RGBPrime2YPrimeCbCrFunctor<T> >
02526 {
02527   public:
02528     typedef VigraTrueType isUnaryFunctor;
02529 };
02530 
02531 /** \brief Convert Y'CbCr color difference components into non-linear (gamma corrected) R'G'B'.
02532 
02533     <b>\#include</b> <<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>><br>
02534     Namespace: vigra
02535     
02536     The functor realizes the inverse of the transformation described in vigra::RGBPrime2YPrimeCbCrFunctor
02537 
02538     <b> Traits defined:</b>
02539     
02540     <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
02541 */
02542 template <class T>
02543 class YPrimeCbCr2RGBPrimeFunctor
02544 {
02545     typedef typename NumericTraits<T>::RealPromote component_type;
02546     
02547     component_type max_;
02548     
02549   public:
02550   
02551         /** the functor's argument type. (Actually, the argument type
02552             can be any vector type with the same interface. 
02553             But this cannot be expressed in a typedef.)
02554         */
02555     typedef TinyVector<T, 3> argument_type;
02556   
02557         /** the functor's result type
02558         */
02559     typedef RGBValue<T> result_type;
02560   
02561         /** \deprecated use argument_type and result_type
02562         */
02563     typedef RGBValue<T> value_type;
02564     
02565         /** default constructor.
02566             The maximum value for each RGB component defaults to 255.
02567         */
02568     YPrimeCbCr2RGBPrimeFunctor()
02569     : max_(255.0)
02570     {}
02571     
02572         /** constructor
02573             \arg max - the maximum value for each RGB component
02574         */
02575     YPrimeCbCr2RGBPrimeFunctor(component_type max)
02576     : max_(max)
02577     {}
02578     
02579         /** apply the transformation
02580         */
02581     template <class V>
02582     result_type operator()(V const & ycbcr) const
02583     {
02584         component_type y = ycbcr[0] - 16.0;
02585         component_type cb = ycbcr[1] - 128.0;
02586         component_type cr = ycbcr[2] - 128.0;
02587         
02588         component_type nred =   0.00456621*y + 0.006258928571*cr;
02589         component_type ngreen = 0.00456621*y - 0.001536322706*cb - 0.003188108420*cr;
02590         component_type nblue =  0.00456621*y + 0.007910714286*cb;
02591         return result_type(NumericTraits<T>::fromRealPromote(nred * max_),
02592                            NumericTraits<T>::fromRealPromote(ngreen * max_),
02593                            NumericTraits<T>::fromRealPromote(nblue * max_));
02594     }
02595 };
02596 
02597 template <class T>
02598 class FunctorTraits<YPrimeCbCr2RGBPrimeFunctor<T> >
02599 : public FunctorTraitsBase<YPrimeCbCr2RGBPrimeFunctor<T> >
02600 {
02601   public:
02602     typedef VigraTrueType isUnaryFunctor;
02603 };
02604 
02605 //@}
02606 
02607 /*
02608 Polar coordinates of standard colors:
02609 =====================================
02610 
02611 Lab: black = [320.002, 0, 0]
02612 Luv: black = [347.827, 0, 0]
02613 YPbPr: black = [341.352, 0, 0]
02614 YCbCr: black = [341.352, 0, 0]
02615 YIQ: black = [19.5807, 0, 0]
02616 YUV: black = [346.557, 0, 0]
02617 Lab: red = [1.20391e-05, 0.532406, 0.781353]
02618 Luv: red = [360, 0.532406, 1]
02619 YPbPr: red = [360, 0.299, 0.988419]
02620 YCbCr: red = [360, 0.299, 0.988417]
02621 YIQ: red = [360, 0.299, 1]
02622 YUV: red = [360, 0.299, 1]
02623 Lab: green = [96.0184, 0.877351, 0.895108]
02624 Luv: green = [115.552, 0.877351, 0.758352]
02625 YPbPr: green = [123.001, 0.587, 1]
02626 YCbCr: green = [123.001, 0.587, 0.999996]
02627 YIQ: green = [137.231, 0.587, 0.933362]
02628 YUV: green = [137.257, 0.587, 0.933931]
02629 Lab: blue = [266.287, 0.322957, 0.999997]
02630 Luv: blue = [253.7, 0.322957, 0.729883]
02631 YPbPr: blue = [242.115, 0.114, 0.948831]
02632 YCbCr: blue = [242.115, 0.114, 0.948829]
02633 YIQ: blue = [243.585, 0.114, 0.707681]
02634 YUV: blue = [243.639, 0.114, 0.707424]
02635 Lab: yellow = [62.8531, 0.971395, 0.724189]
02636 Luv: yellow = [73.7, 0.971395, 0.597953]
02637 YPbPr: yellow = [62.1151, 0.886, 0.948831]
02638 YCbCr: yellow = [62.1149, 0.886, 0.948829]
02639 YIQ: yellow = [63.5851, 0.886, 0.707681]
02640 YUV: yellow = [63.6393, 0.886, 0.707424]
02641 Lab: magenta = [288.237, 0.603235, 0.863482]
02642 Luv: magenta = [295.553, 0.603235, 0.767457]
02643 YPbPr: magenta = [303.001, 0.413, 1]
02644 YCbCr: magenta = [303.001, 0.413, 0.999996]
02645 YIQ: magenta = [317.231, 0.413, 0.933362]
02646 YUV: magenta = [317.257, 0.413, 0.933931]
02647 Lab: cyan = [156.378, 0.911133, 0.374577]
02648 Luv: cyan = [180, 0.911133, 0.402694]
02649 YPbPr: cyan = [180, 0.701, 0.988419]
02650 YCbCr: cyan = [180, 0.701, 0.988417]
02651 YIQ: cyan = [180, 0.701, 1]
02652 YUV: cyan = [180, 0.701, 1]
02653 Lab: white = [320.002, 1, 0]
02654 Luv: white = [14.3606, 1, 3.26357e-06]
02655 YPbPr: white = [341.352, 1, 0]
02656 YCbCr: white = [341.352, 1, 0]
02657 YIQ: white = [154.581, 1, 1.24102e-16]
02658 YUV: white = [229.992, 1, 9.81512e-17]
02659 
02660 */
02661 
02662 /** \ingroup ColorConversions
02663     \defgroup PolarColors Polar Color Coordinates
02664     
02665     Transform colors from/to a polar representation (hue, brighness, saturation).
02666     In many situations, this is more inituitive than direct initialization in a 
02667     particular color space. The polar coordinates are 
02668     normalized so that a color angle of 0 degrees is always associated with red
02669     (green is at about 120 degrees, blue at about 240 degrees - exact values differ
02670     between color spaces). A saturation of 1 is the highest saturation that any RGB color 
02671     gets after transformation into the respective color space, and saturation 0 corresponds to
02672     gray. Thus, different color spaces become somewhat comparable.
02673 */
02674 //@{
02675 /** \brief Init L*a*b* color triple from polar representation.
02676 
02677     <b>\#include</b> <<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>><br>
02678     Namespace: vigra
02679     
02680     <b> Declarations:</b>
02681     
02682     \code
02683     TinyVector<float, 3>
02684     polar2Lab(double color, double brightness, double saturation);
02685     
02686     TinyVector<float, 3>
02687     polar2Lab(TinyVector<float, 3> const & polar);
02688     \endcode
02689     
02690     \arg color - the color angle in degrees
02691     \arg brightness - between 0 and 1
02692     \arg saturation - between 0 and 1
02693     
02694     L*a*b* polar coordinates of some important colors:
02695     
02696     \code
02697     black   = [*, 0, 0]    * - arbitrary
02698     white   = [*, 1, 0]    * - arbitrary
02699     
02700     red     = [      0, 0.532406, 0.781353]
02701     yellow  = [62.8531, 0.971395, 0.724189]
02702     green   = [96.0184, 0.877351, 0.895108]
02703     cyan    = [156.378, 0.911133, 0.374577]
02704     blue    = [266.287, 0.322957, 0.999997]
02705     magenta = [288.237, 0.603235, 0.863482]
02706     \endcode
02707 */
02708 inline TinyVector<float, 3>
02709 polar2Lab(double color, double brightness, double saturation)
02710 {
02711     double angle = (color+39.9977)/180.0*M_PI;
02712     double normsat = saturation*133.809;
02713     
02714     TinyVector<float, 3> result;
02715     result[0] = 100.0*brightness;
02716     result[1] = normsat*VIGRA_CSTD::cos(angle);
02717     result[2] = normsat*VIGRA_CSTD::sin(angle);
02718     return result;
02719 }
02720 
02721 
02722 template <class V>
02723 TinyVector<float, 3>
02724 polar2Lab(V const & polar)
02725 {
02726     return polar2Lab(polar[0], polar[1], polar[2]);
02727 }
02728 
02729 /** \brief Create polar representation form L*a*b*
02730 
02731     <b> Declaration:</b>
02732     
02733     \code
02734     namespace vigra {
02735         TinyVector<float, 3> lab2Polar(TinyVector<float, 3> const & lab);
02736     }
02737     \endcode
02738     
02739     <b>\#include</b> <<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>><br>
02740     Namespace: vigra
02741     
02742     This realizes the inverse of the transformation described in 
02743     \ref polar2Lab().
02744 */
02745 template <class V>
02746 TinyVector<float, 3>
02747 lab2Polar(V const & lab)
02748 {
02749     TinyVector<float, 3> result;
02750     result[1] = lab[0]/100.0;
02751     double angle = (lab[1] == 0.0 && lab[2] == 0.0)
02752         ? 0.0
02753         : VIGRA_CSTD::atan2(lab[2], lab[1])/M_PI*180.0-39.9977;
02754     result[0] = angle < 0.0 ?
02755                     angle + 360.0 :
02756                     angle;
02757     result[2] = VIGRA_CSTD::sqrt(lab[1]*lab[1] + lab[2]*lab[2])/133.809;
02758     return result;
02759 }
02760 
02761 /** \brief Init L*u*v* color triple from polar representation.
02762 
02763     <b>\#include</b> <<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>><br>
02764     Namespace: vigra
02765     
02766     <b> Declarations:</b>
02767     
02768     \code
02769     TinyVector<float, 3>
02770     polar2Luv(double color, double brightness, double saturation);
02771     
02772     TinyVector<float, 3>
02773     polar2Luv(TinyVector<float, 3> const & polar);
02774     \endcode
02775     
02776     \arg color - the color angle in degrees
02777     \arg brightness - between 0 and 1
02778     \arg saturation - between 0 and 1
02779     
02780     L*u*v* polar coordinates of some important colors:
02781     
02782     \code
02783     black   = [*, 0, 0]    * - arbitrary
02784     white   = [*, 1, 0]    * - arbitrary
02785     
02786     red     = [      0, 0.532406,        1]
02787     yellow  = [   73.7, 0.971395, 0.597953]
02788     green   = [115.552, 0.877351, 0.758352]
02789     cyan    = [  180.0, 0.911133, 0.402694]
02790     blue    = [  253.7, 0.322957, 0.729883]
02791     magenta = [295.553, 0.603235, 0.767457]
02792     \endcode
02793 */
02794 inline TinyVector<float, 3>
02795 polar2Luv(double color, double brightness, double saturation)
02796 {
02797     double angle = (color+12.1727)/180.0*M_PI;
02798     double normsat = saturation*179.04;
02799     
02800     TinyVector<float, 3> result;
02801     result[0] = 100.0*brightness;
02802     result[1] = normsat*VIGRA_CSTD::cos(angle);
02803     result[2] = normsat*VIGRA_CSTD::sin(angle);
02804     return result;
02805 }
02806 
02807 template <class V>
02808 TinyVector<float, 3>
02809 polar2Luv(V const & polar)
02810 {
02811     return polar2Luv(polar[0], polar[1], polar[2]);
02812 }
02813 
02814 /** \brief Create polar representation form L*u*v*
02815 
02816     <b> Declaration:</b>
02817     
02818     \code
02819     namespace vigra {
02820         TinyVector<float, 3> luv2Polar(TinyVector<float, 3> const & luv);
02821     }
02822     \endcode
02823     
02824     <b>\#include</b> <<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>><br>
02825     Namespace: vigra
02826     
02827     This realizes the inverse of the transformation described in 
02828     \ref polar2Luv().
02829 */
02830 template <class V>
02831 TinyVector<float, 3>
02832 luv2Polar(V const & luv)
02833 {
02834     TinyVector<float, 3> result;
02835     result[1] = luv[0]/100.0;
02836     double angle = (luv[1] == 0.0 && luv[2] == 0.0)
02837         ? 0.0
02838         : VIGRA_CSTD::atan2(luv[2], luv[1])/M_PI*180.0-12.1727;
02839     result[0] = angle < 0.0 ?
02840                     angle + 360.0 :
02841                     angle;
02842     result[2] = VIGRA_CSTD::sqrt(luv[1]*luv[1] + luv[2]*luv[2])/179.04;
02843     return result;
02844 }
02845 
02846 /** \brief Init Y'PbPr color triple from polar representation.
02847 
02848     <b>\#include</b> <<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>><br>
02849     Namespace: vigra
02850     
02851     <b> Declarations:</b>
02852     
02853     \code
02854     TinyVector<float, 3>
02855     polar2YPrimePbPr(double color, double brightness, double saturation);
02856     
02857     TinyVector<float, 3>
02858     polar2YPrimePbPr(TinyVector<float, 3> const & polar);
02859     \endcode
02860     
02861     \arg color - the color angle in degrees
02862     \arg brightness - between 0 and 1
02863     \arg saturation - between 0 and 1
02864     
02865     Y'PbPr polar coordinates of some important colors:
02866     
02867     \code
02868     black   = [*, 0, 0]    * - arbitrary
02869     white   = [*, 1, 0]    * - arbitrary
02870     
02871     red     = [      0,  0.299, 0.988419]
02872     yellow  = [62.1151,  0.886, 0.948831]
02873     green   = [123.001,  0.587,        1]
02874     cyan    = [  180.0,  0.701, 0.988419]
02875     blue    = [242.115,  0.114, 0.948831]
02876     magenta = [303.001,  0.413,        1]
02877     \endcode
02878 */
02879 inline TinyVector<float, 3>
02880 polar2YPrimePbPr(double color, double brightness, double saturation)
02881 {
02882     double angle = (color+18.6481)/180.0*M_PI;
02883     double normsat = saturation*0.533887;
02884     
02885     TinyVector<float, 3> result;
02886     result[0] = brightness;
02887     result[1] = -normsat*VIGRA_CSTD::sin(angle);
02888     result[2] = normsat*VIGRA_CSTD::cos(angle);
02889     return result;
02890 }
02891 
02892 template <class V>
02893 TinyVector<float, 3>
02894 polar2YPrimePbPr(V const & polar)
02895 {
02896     return polar2YPrimePbPr(polar[0], polar[1], polar[2]);
02897 }
02898 
02899 /** \brief Create polar representation form Y'PbPr
02900 
02901     <b> Declaration:</b>
02902     
02903     \code
02904     namespace vigra {
02905         TinyVector<float, 3> yPrimePbPr2Polar(TinyVector<float, 3> const & ypbpr);
02906     }
02907     \endcode
02908     
02909     <b>\#include</b> <<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>><br>
02910     Namespace: vigra
02911     
02912     This realizes the inverse of the transformation described in 
02913     \ref polar2YPrimePbPr().
02914 */
02915 template <class V>
02916 TinyVector<float, 3>
02917 yPrimePbPr2Polar(V const & ypbpr)
02918 {
02919     TinyVector<float, 3> result;
02920     result[1] = ypbpr[0];
02921     double angle = (ypbpr[1] == 0.0 && ypbpr[2] == 0.0)
02922         ? 0.0
02923         : VIGRA_CSTD::atan2(-ypbpr[1], ypbpr[2])/M_PI*180.0-18.6481;
02924     result[0] = angle < 0.0 ?
02925                     angle + 360.0 :
02926                     angle;
02927     result[2] = VIGRA_CSTD::sqrt(ypbpr[1]*ypbpr[1] + ypbpr[2]*ypbpr[2])/0.533887;
02928     return result;
02929 }
02930 
02931 /** \brief Init Y'CbCr color triple from polar representation.
02932 
02933     <b>\#include</b> <<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>><br>
02934     Namespace: vigra
02935     
02936     <b> Declarations:</b>
02937     
02938     \code
02939     TinyVector<float, 3>
02940     polar2YPrimeCbCr(double color, double brightness, double saturation);
02941     
02942     TinyVector<float, 3>
02943     polar2YPrimeCbCr(TinyVector<float, 3> const & polar);
02944     \endcode
02945     
02946     \arg color - the color angle in degrees
02947     \arg brightness - between 0 and 1
02948     \arg saturation - between 0 and 1
02949     
02950     Y'CbCr polar coordinates of some important colors:
02951     
02952     \code
02953     black   = [*, 0, 0]    * - arbitrary
02954     white   = [*, 1, 0]    * - arbitrary
02955     
02956     red     = [      0,  0.299, 0.988419]
02957     yellow  = [62.1151,  0.886, 0.948831]
02958     green   = [123.001,  0.587,        1]
02959     cyan    = [  180.0,  0.701, 0.988419]
02960     blue    = [242.115,  0.114, 0.948831]
02961     magenta = [303.001,  0.413,        1]
02962     \endcode
02963 */
02964 inline TinyVector<float, 3>
02965 polar2YPrimeCbCr(double color, double brightness, double saturation)
02966 {
02967     double angle = (color+18.6482)/180.0*M_PI;
02968     double normsat = saturation*119.591;
02969     
02970     TinyVector<float, 3> result;
02971     result[0] = brightness*219.0 + 16.0;
02972     result[1] = -normsat*VIGRA_CSTD::sin(angle)+128.0;
02973     result[2] = normsat*VIGRA_CSTD::cos(angle)+128.0;
02974     return result;
02975 }
02976 
02977 template <class V>
02978 TinyVector<float, 3>
02979 polar2YPrimeCbCr(V const & polar)
02980 {
02981     return polar2YPrimeCbCr(polar[0], polar[1], polar[2]);
02982 }
02983 
02984 /** \brief Create polar representation form Y'CbCr
02985 
02986     <b> Declaration:</b>
02987     
02988     \code
02989     namespace vigra {
02990         TinyVector<float, 3> yPrimeCbCr2Polar(TinyVector<float, 3> const & ycbcr);
02991     }
02992     \endcode
02993     
02994     <b>\#include</b> <<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>><br>
02995     Namespace: vigra
02996     
02997     This realizes the inverse of the transformation described in 
02998     \ref polar2YPrimeCbCr().
02999 */
03000 template <class V>
03001 TinyVector<float, 3>
03002 yPrimeCbCr2Polar(V const & ycbcr)
03003 {
03004     TinyVector<float, 3> result;
03005     result[1] = (ycbcr[0]-16.0)/219.0;
03006     double cb = ycbcr[1]-128.0;
03007     double cr = ycbcr[2]-128.0;
03008     double angle = (cb == 0.0 && cr == 0.0)
03009         ? 0.0
03010         : VIGRA_CSTD::atan2(-cb, cr)/M_PI*180.0-18.6482;
03011     result[0] = angle < 0.0 ?
03012                     angle + 360.0 :
03013                     angle;
03014     result[2] = VIGRA_CSTD::sqrt(cb*cb + cr*cr)/119.591;
03015     return result;
03016 }
03017 
03018 /** \brief Init Y'IQ color triple from polar representation.
03019 
03020     <b>\#include</b> <<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>><br>
03021     Namespace: vigra
03022     
03023     <b> Declarations:</b>
03024     
03025     \code
03026     TinyVector<float, 3>
03027     polar2YPrimeIQ(double color, double brightness, double saturation);
03028     
03029     TinyVector<float, 3>
03030     polar2YPrimeIQ(TinyVector<float, 3> const & polar);
03031     \endcode
03032     
03033     \arg color - the color angle in degrees
03034     \arg brightness - between 0 and 1
03035     \arg saturation - between 0 and 1
03036     
03037     Y'IQ polar coordinates of some important colors:
03038     
03039     \code
03040     black   = [*, 0, 0]    * - arbitrary
03041     white   = [*, 1, 0]    * - arbitrary
03042     
03043     red     = [      0, 0.299,        1]
03044     yellow  = [63.5851, 0.886, 0.707681]
03045     green   = [137.231, 0.587, 0.933362]
03046     cyan    = [  180.0, 0.701,        1]
03047     blue    = [243.585, 0.114, 0.707681]
03048     magenta = [317.231, 0.413, 0.933362]
03049     \endcode
03050 */
03051 inline TinyVector<float, 3>
03052 polar2YPrimeIQ(double color, double brightness, double saturation)
03053 {
03054     double angle = (color-19.5807)/180.0*M_PI;
03055     double normsat = saturation*0.632582;
03056     
03057     TinyVector<float, 3> result;
03058     result[0] = brightness;
03059     result[1] = normsat*VIGRA_CSTD::cos(angle);
03060     result[2] = -normsat*VIGRA_CSTD::sin(angle);
03061     return result;
03062 }
03063 
03064 template <class V>
03065 TinyVector<float, 3>
03066 polar2YPrimeIQ(V const & polar)
03067 {
03068     return polar2YPrimeIQ(polar[0], polar[1], polar[2]);
03069 }
03070 
03071 /** \brief Create polar representation form Y'IQ
03072 
03073     <b> Declaration:</b>
03074     
03075     \code
03076     namespace vigra {
03077         TinyVector<float, 3> yPrimeIQ2Polar(TinyVector<float, 3> const & yiq);
03078     }
03079     \endcode
03080     
03081     <b>\#include</b> <<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>><br>
03082     Namespace: vigra
03083     
03084     This realizes the inverse of the transformation described in 
03085     \ref polar2YPrimeIQ().
03086 */
03087 template <class V>
03088 TinyVector<float, 3>
03089 yPrimeIQ2Polar(V const & yiq)
03090 {
03091     TinyVector<float, 3> result;
03092     result[1] = yiq[0];
03093     double angle = (yiq[1] == 0.0 && yiq[2] == 0.0)
03094         ? 0.0
03095         : VIGRA_CSTD::atan2(-yiq[2], yiq[1])/M_PI*180.0+19.5807;
03096     result[0] = angle < 0.0 ?
03097                     angle + 360.0 :
03098                     angle;
03099     result[2] = VIGRA_CSTD::sqrt(yiq[1]*yiq[1] + yiq[2]*yiq[2])/0.632582;
03100     return result;
03101 }
03102 
03103 /** \brief Init Y'UV color triple from polar representation.
03104 
03105     <b>\#include</b> <<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>><br>
03106     Namespace: vigra
03107     
03108     <b> Declarations:</b>
03109     
03110     \code
03111     TinyVector<float, 3>
03112     polar2YPrimeUV(double color, double brightness, double saturation);
03113     
03114     TinyVector<float, 3>
03115     polar2YPrimeUV(TinyVector<float, 3> const & polar);
03116     \endcode
03117     
03118     \arg color - the color angle in degrees
03119     \arg brightness - between 0 and 1
03120     \arg saturation - between 0 and 1
03121     
03122     Y'UV polar coordinates of some important colors:
03123     
03124     \code
03125     black   = [*, 0, 0]    * - arbitrary
03126     white   = [*, 1, 0]    * - arbitrary
03127     
03128     red     = [      0, 0.299,        1]
03129     yellow  = [63.5851, 0.886, 0.707681]
03130     green   = [137.231, 0.587, 0.933362]
03131     cyan    = [  180.0, 0.701,        1]
03132     blue    = [243.585, 0.114, 0.707681]
03133     magenta = [317.231, 0.413, 0.933362]
03134     \endcode
03135 */
03136 inline TinyVector<float, 3>
03137 polar2YPrimeUV(double color, double brightness, double saturation)
03138 {
03139     double angle = (color+13.4569)/180.0*M_PI;
03140     double normsat = saturation*0.632324;
03141     
03142     TinyVector<float, 3> result;
03143     result[0] = brightness;
03144     result[1] = -normsat*VIGRA_CSTD::sin(angle);
03145     result[2] = normsat*VIGRA_CSTD::cos(angle);
03146     return result;
03147 }
03148 
03149 template <class V>
03150 TinyVector<float, 3>
03151 polar2YPrimeUV(V const & polar)
03152 {
03153     return polar2YPrimeUV(polar[0], polar[1], polar[2]);
03154 }
03155 
03156 /** \brief Create polar representation form Y'UV
03157 
03158     <b> Declaration:</b>
03159     
03160     \code
03161     namespace vigra {
03162         TinyVector<float, 3> yPrimeUV2Polar(TinyVector<float, 3> const & yuv);
03163     }
03164     \endcode
03165     
03166     <b>\#include</b> <<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>><br>
03167     Namespace: vigra
03168     
03169     This realizes the inverse of the transformation described in 
03170     \ref polar2YPrimeUV().
03171 */
03172 template <class V>
03173 TinyVector<float, 3>
03174 yPrimeUV2Polar(V const & yuv)
03175 {
03176     TinyVector<float, 3> result;
03177     result[1] = yuv[0];
03178     double angle = (yuv[1] == 0.0 && yuv[2] == 0.0)
03179         ? 0.0
03180         : VIGRA_CSTD::atan2(-yuv[1], yuv[2])/M_PI*180.0-13.4569;
03181     result[0] = angle < 0.0 ?
03182                     angle + 360.0 :
03183                     angle;
03184     result[2] = VIGRA_CSTD::sqrt(yuv[1]*yuv[1] + yuv[2]*yuv[2])/0.632324;
03185     return result;
03186 }
03187 
03188 //@}
03189 
03190 } // namespace vigra 
03191 
03192 #endif /* VIGRA_COLORCONVERSIONS_HXX */

© Ullrich Köthe (ullrich.koethe@iwr.uni-heidelberg.de)
Heidelberg Collaboratory for Image Processing, University of Heidelberg, Germany

html generated using doxygen and Python
VIGRA 1.6.0 (5 Nov 2009)