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