include/vigra/colorconversions.hxx
author Ullrich Koethe <ullrich.koethe@iwr.uni-heidelberg.de>
Tue May 04 22:26:04 2010 +0200 (2010-05-04)
changeset 2537 6c8eb0e5517a
parent 2512 b34bedd8a498
child 2704 ce4c04da67c9
permissions -rw-r--r--
added argument_type and result_type to functors (patch by Volker Grabsch)
     1 /************************************************************************/
     2 /*                                                                      */
     3 /*               Copyright 1998-2002 by Ullrich Koethe                  */
     4 /*                                                                      */
     5 /*    This file is part of the VIGRA computer vision library.           */
     6 /*    The VIGRA Website is                                              */
     7 /*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
     8 /*    Please direct questions, bug reports, and contributions to        */
     9 /*        ullrich.koethe@iwr.uni-heidelberg.de    or                    */
    10 /*        vigra@informatik.uni-hamburg.de                               */
    11 /*                                                                      */
    12 /*    Permission is hereby granted, free of charge, to any person       */
    13 /*    obtaining a copy of this software and associated documentation    */
    14 /*    files (the "Software"), to deal in the Software without           */
    15 /*    restriction, including without limitation the rights to use,      */
    16 /*    copy, modify, merge, publish, distribute, sublicense, and/or      */
    17 /*    sell copies of the Software, and to permit persons to whom the    */
    18 /*    Software is furnished to do so, subject to the following          */
    19 /*    conditions:                                                       */
    20 /*                                                                      */
    21 /*    The above copyright notice and this permission notice shall be    */
    22 /*    included in all copies or substantial portions of the             */
    23 /*    Software.                                                         */
    24 /*                                                                      */
    25 /*    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND    */
    26 /*    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES   */
    27 /*    OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND          */
    28 /*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
    29 /*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
    30 /*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
    31 /*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
    32 /*    OTHER DEALINGS IN THE SOFTWARE.                                   */                
    33 /*                                                                      */
    34 /************************************************************************/
    35  
    36  
    37 #ifndef VIGRA_COLORCONVERSIONS_HXX
    38 #define VIGRA_COLORCONVERSIONS_HXX
    39 
    40 #include <cmath>
    41 #include "mathutil.hxx"
    42 #include "rgbvalue.hxx"
    43 #include "functortraits.hxx"
    44 
    45 namespace vigra {
    46 
    47 namespace detail
    48 {
    49 
    50 template<class ValueType>
    51 inline ValueType gammaCorrection(double value, double gamma)
    52 {
    53     typedef typename NumericTraits<ValueType>::RealPromote Promote;
    54     return NumericTraits<ValueType>::fromRealPromote(
    55               RequiresExplicitCast<Promote>::cast(
    56                 (value < 0.0) 
    57                     ? -std::pow(-value, gamma) 
    58                     : std::pow(value, gamma)));
    59 }
    60 
    61 template<class ValueType>
    62 inline ValueType gammaCorrection(double value, double gamma, double norm)
    63 {
    64     typedef typename NumericTraits<ValueType>::RealPromote Promote;
    65     return NumericTraits<ValueType>::fromRealPromote(
    66               RequiresExplicitCast<Promote>::cast(
    67                 (value < 0.0) 
    68                     ? -norm*std::pow(-value/norm, gamma)
    69                     : norm*std::pow(value/norm, gamma)));
    70 }
    71 
    72 template<class ValueType>
    73 inline ValueType sRGBCorrection(double value, double norm)
    74 {
    75     value /= norm;
    76     typedef typename NumericTraits<ValueType>::RealPromote Promote;
    77     return NumericTraits<ValueType>::fromRealPromote(
    78               RequiresExplicitCast<ValueType>::cast(
    79                 (value <= 0.0031308) 
    80                     ? norm*12.92*value 
    81                     : norm*(1.055*std::pow(value, 0.41666666666666667) - 0.055)));
    82 }
    83 
    84 template<class ValueType>
    85 inline ValueType inverse_sRGBCorrection(double value, double norm)
    86 {
    87     value /= norm;
    88     typedef typename NumericTraits<ValueType>::RealPromote Promote;
    89     return NumericTraits<ValueType>::fromRealPromote(
    90              RequiresExplicitCast<ValueType>::cast(
    91                 (value <= 0.04045) 
    92                     ? norm*value / 12.92
    93                     : norm*VIGRA_CSTD::pow((value + 0.055)/1.055, 2.4)));
    94 }
    95 
    96 
    97 } // namespace detail
    98 
    99 /** \defgroup ColorConversions  Color Space Conversions
   100 
   101     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.
   102 
   103     <b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>\><br>
   104     Namespace: vigra
   105     
   106     <UL>
   107     <LI> <b>RGB/sRGB/R'G'B'</b><br>
   108         <em>linear and non-linear (gamma corrected) additive color</em>
   109         <p>
   110         <UL style="list-style-image:url(documents/bullet.gif)">
   111         <LI> \ref vigra::RGB2sRGBFunctor
   112         <LI> \ref vigra::sRGB2RGBFunctor
   113         <LI> \ref vigra::RGB2RGBPrimeFunctor
   114         <LI> \ref vigra::RGBPrime2RGBFunctor
   115         </UL><p>
   116     <LI> <b>XYZ</b><br>
   117         <em>device independent color representation 
   118                (according to Publication CIE  No  15.2 "Colorimetry"
   119                 and ITU-R Recommendation BT.709)</em>
   120         <p>
   121         <UL style="list-style-image:url(documents/bullet.gif)">
   122         <LI> \ref vigra::RGB2XYZFunctor
   123         <LI> \ref vigra::RGBPrime2XYZFunctor
   124         <LI> \ref vigra::XYZ2RGBFunctor
   125         <LI> \ref vigra::XYZ2RGBPrimeFunctor
   126         </UL><p>
   127     <LI> <b>L*a*b* </b><br>
   128         <em>perceptually uniform color representation 
   129                (according to Publication CIE No 15.2 "Colorimetry" and
   130                ITU-R Recommendation BT.709)</em>
   131         <p>
   132         <UL style="list-style-image:url(documents/bullet.gif)">
   133         <LI> \ref vigra::RGB2LabFunctor
   134         <LI> \ref vigra::RGBPrime2LabFunctor
   135         <LI> \ref vigra::XYZ2LabFunctor
   136         <LI> \ref vigra::Lab2RGBFunctor
   137         <LI> \ref vigra::Lab2RGBPrimeFunctor
   138         <LI> \ref vigra::Lab2XYZFunctor
   139         <LI> \ref polar2Lab()
   140         <LI> \ref lab2Polar()
   141         </UL><p>
   142     <LI> <b>L*u*v* </b><br>
   143         <em>perceptually uniform color representation 
   144                (according to Publication CIE No 15.2 "Colorimetry" and
   145                ITU-R Recommendation BT.709)</em>
   146         <p>
   147         <UL style="list-style-image:url(documents/bullet.gif)">
   148         <LI> \ref vigra::RGB2LuvFunctor
   149         <LI> \ref vigra::RGBPrime2LuvFunctor
   150         <LI> \ref vigra::XYZ2LuvFunctor
   151         <LI> \ref vigra::Luv2RGBFunctor
   152         <LI> \ref vigra::Luv2RGBPrimeFunctor
   153         <LI> \ref vigra::Luv2XYZFunctor
   154         <LI> \ref polar2Luv()
   155         <LI> \ref luv2Polar()
   156         </UL><p>
   157     <LI> <b>Y'PbPr and Y'CbCr </b><br>
   158         <em>color difference coding
   159                 (according to ITU-R Recommendation BT. 601)</em>
   160         <p>
   161         <UL style="list-style-image:url(documents/bullet.gif)">
   162         <LI> \ref vigra::RGBPrime2YPrimePbPrFunctor
   163         <LI> \ref vigra::YPrimePbPr2RGBPrimeFunctor
   164         <LI> \ref polar2YPrimePbPr()
   165         <LI> \ref yPrimePbPr2Polar()
   166         <LI> \ref vigra::RGBPrime2YPrimeCbCrFunctor
   167         <LI> \ref vigra::YPrimeCbCr2RGBPrimeFunctor
   168         <LI> \ref polar2YPrimeCbCr()
   169         <LI> \ref yPrimeCbCr2Polar()
   170         </UL><p>
   171     <LI> <b>Y'UV and Y'IQ </b><br>
   172         <em>analog video coding according to NTSC and PAL standards</em>
   173         <p>
   174         <UL style="list-style-image:url(documents/bullet.gif)">
   175         <LI> \ref vigra::RGBPrime2YPrimeUVFunctor
   176         <LI> \ref vigra::YPrimeUV2RGBPrimeFunctor
   177         <LI> \ref polar2YPrimeUV()
   178         <LI> \ref yPrimeUV2Polar()
   179         <LI> \ref vigra::RGBPrime2YPrimeIQFunctor
   180         <LI> \ref vigra::YPrimeIQ2RGBPrimeFunctor
   181         <LI> \ref polar2YPrimeIQ()
   182         <LI> \ref yPrimeIQ2Polar()
   183         </UL><p>
   184     </UL>
   185     
   186     \anchor _details
   187     This module provides conversion from RGB/R'G'B' into more perceptually uniform
   188     color spaces. In image analysis, colors are usually converted into another color space 
   189     in order to get good estimates of perceived color differences by just calculating 
   190     Euclidean distances between the transformed colors. The L*a*b* and L*u*v* were 
   191     designed with exactly this application in mind and thus give the best results. But these
   192     conversions are also the most computationally demanding. The Y'PbPr color difference
   193     space (designed for coding digital video) is computationally much cheaper, and 
   194     almost as good. Y'CbCr represents esentially the same transformation, but the color values 
   195     are scaled so that they can be stored with 8 bits per channel with minimal loss of 
   196     information. The other transformations are of lesser interest here: XYZ is a device independent
   197     (but not perceptually uniform) color representation, and Y'IQ and Y'UV are the color 
   198     spaces used by the PAL and NTSC analog video standards. Detailed information about
   199     these color spaces and their transformations can be found in 
   200     <a href="http://www.poynton.com/ColorFAQ.html">Charles Poynton's Color FAQ</a>
   201     
   202     When you want to perform a color conversion, you must first know in which
   203     color space the data are given. Although this sounds trivial, it is
   204     quite often done wrong, because the distinction between RGB and sRGB (still images) or R'G'B' 
   205     (digital video) is frequently overlooked: nowadays, most still images are stored in
   206     sRGB space, and treating them as RGB leads to wrong results (although the color primaries
   207     are named the same). RGB and R'G'B' are related by a so called <em>gamma correction</em>:
   208     
   209     \f[
   210         C' = C_{max} \left(\frac{C_{RGB}}{C_{max}} \right)^{0.45} \qquad
   211     \f]
   212     
   213     where C represents one of the color channels R, G, and B, and \f$ C_{max} \f$ usually equals 255. 
   214     The sRGB color space realizes a slight enhancement of this definition:
   215     
   216     \f[
   217         C_{sRGB} = \left\{\begin{array}{ll}
   218         12.92\,C_{RGB} & \textrm{ if }\frac{C_{RGB}}{C_{max}} \le 0.00304 \\
   219         C_{max}\left( 1.055 \left(\frac{C_{RGB}}{C_{max}}\right)^{1/2.4}-0.055\right) & \textrm{ otherwise}
   220         \end{array} \right.
   221     \f]
   222     
   223     sRGB has now become a widely accepted international standard (IEC 61966-2.1) which is used by most 
   224     consumer products (digital cameras, printers, and screens). In practice, you can 
   225     distinguish between linear and gamma-corrected red, green, and blue by displaying the images: if they look
   226     too dark, they are probably RGB, if they are OK, they are likely sRGB. (However, there are still a few older 
   227     graphics cards and display programs which silently apply an additional gamma correction to every image, 
   228     so that RGB appears correct and sRGB is too bright.) Whether or not the data are represented
   229     in the sRGB color space can also be seen in the color space tag of an image's EXIF data, if available.
   230     
   231     The distinction between RGB and R'G'B' is important because some conversions start at 
   232     RGB (XYZ, L*a*b*, L*u*v*), while others start at R'G'B' (Y'PbPr, Y'CbCr, Y'IQ, and Y'UV). 
   233     The names of VIGRA's color conversion functors always make clear to which color space 
   234     they must be applied.
   235    
   236     In addition VIGRA provides a <em>\ref PolarColors "polar coordinate interface"</em>
   237     to several color spaces (L*a*b*, L*u*v*, Y'PbPr, Y'CbCr, Y'IQ, and Y'UV). This
   238     interface makes use of the fact that these color spaces are conceptually similar:
   239     they represent colors by a "brightness" coordinate (L* or Y') and a pair of 
   240     "chromaticity" coordinates that span a plane of colors with equal brightness.
   241     The polar representation transforms chroma coordinates into a color "angle"
   242     (similar to hue in the HSV system) and a "saturation". The polar coordinates are 
   243     normalized so that a color angle of 0 degrees is always associated with red
   244     (green is at about 120 degrees, blue at about 240 degrees - exact values differ
   245     between color spaces). A saturation of 1 is the highest saturation that any RGB color 
   246     in the unit cube can have after transformation into the respective color space, 
   247     and saturation 0 corresponds to gray. Polar coordinates provide a more intuitive 
   248     interface to color specification by users and make different color spaces somewhat 
   249     comparable.
   250 */
   251 //@{
   252 
   253 
   254 /** \brief Convert linear (raw) RGB into non-linear (gamma corrected) R'G'B'.
   255 
   256     <b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>\><br>
   257     Namespace: vigra
   258     
   259     The functor realizes the transformation
   260     
   261     \f[
   262         R' = R_{max} \left(\frac{R}{R_{max}} \right)^{0.45} \qquad
   263         G' = G_{max} \left(\frac{G}{G_{max}} \right)^{0.45} \qquad
   264         B' = B_{max} \left(\frac{B}{B_{max}} \right)^{0.45}
   265     \f]
   266     
   267     By default, \f$ R_{max} = G_{max} = B_{max} = 255 \f$. This default can be overridden
   268     in the constructor. If both source and target colors components are stored 
   269     as <tt>unsigned char</tt>, a look-up-table will be used to speed up the transformation.
   270 
   271     <b> Traits defined:</b>
   272     
   273     <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
   274     */
   275 template <class From, class To = From>
   276 class RGB2RGBPrimeFunctor
   277 {
   278   public:
   279   
   280         /** the functor's argument type
   281         */
   282     typedef TinyVector<From, 3> argument_type;
   283   
   284         /** the functor's result type
   285         */
   286     typedef TinyVector<To, 3> result_type;
   287   
   288         /** \deprecated use argument_type and result_type
   289         */
   290     typedef TinyVector<To, 3> value_type;
   291   
   292         /** the result component's promote type
   293         */
   294     typedef typename NumericTraits<To>::RealPromote component_type;
   295     
   296         /** Default constructor.
   297             The maximum value for each RGB component defaults to 255
   298         */
   299     RGB2RGBPrimeFunctor()
   300     : max_(255.0)
   301     {}
   302     
   303         /** constructor
   304             \arg max - the maximum value for each RGB component
   305         */
   306     RGB2RGBPrimeFunctor(component_type max)
   307     : max_(max)
   308     {}
   309     
   310         /** apply the transformation
   311         */
   312     template <class V>
   313     result_type operator()(V const & rgb) const
   314     {
   315         return TinyVector<To, 3>(
   316             detail::gammaCorrection<To>(rgb[0], 0.45, max_),
   317             detail::gammaCorrection<To>(rgb[1], 0.45, max_),
   318             detail::gammaCorrection<To>(rgb[2], 0.45, max_));
   319     }
   320     
   321   private:
   322     component_type max_;    
   323 };
   324 
   325 template <>
   326 class RGB2RGBPrimeFunctor<unsigned char, unsigned char>
   327 {
   328     unsigned char lut_[256];
   329         
   330   public:
   331   
   332     typedef TinyVector<unsigned char, 3> argument_type;
   333     
   334     typedef TinyVector<unsigned char, 3> result_type;
   335     
   336     typedef TinyVector<unsigned char, 3> value_type;
   337     
   338     RGB2RGBPrimeFunctor()
   339     {
   340         for(int i=0; i<256; ++i)
   341         {
   342             lut_[i] = detail::gammaCorrection<unsigned char>(i, 0.45, 255.0);
   343         }
   344     }
   345     
   346     RGB2RGBPrimeFunctor(double max)
   347     {
   348         for(int i=0; i<256; ++i)
   349         {
   350             lut_[i] = detail::gammaCorrection<unsigned char>(i, 0.45, max);
   351         }
   352     }
   353     
   354     template <class V>
   355     TinyVector<unsigned char, 3> operator()(V const & rgb) const
   356     {
   357         return TinyVector<unsigned char, 3>(lut_[rgb[0]], lut_[rgb[1]], lut_[rgb[2]]);
   358     }
   359 };
   360 
   361 template <class From, class To>
   362 class FunctorTraits<RGB2RGBPrimeFunctor<From, To> >
   363 : public FunctorTraitsBase<RGB2RGBPrimeFunctor<From, To> >
   364 {
   365   public:
   366     typedef VigraTrueType isUnaryFunctor;
   367 };
   368 
   369 /** \brief Convert linear (raw) RGB into standardized sRGB.
   370 
   371     <b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>\><br>
   372     Namespace: vigra
   373     
   374     The sRGB color space is a slight improvement over the R'G'B' space. It is now a widely accepted 
   375     international standard (IEC 61966-2.1) which is used by most consumer products
   376     (digital cameras, printers, and screens). The functor realizes the transformation
   377     
   378     \f[
   379         C_{sRGB} = \left\{ \begin{array}{ll}
   380         12.92\,C_{RGB} & \textrm{ if }\frac{C_{RGB}}{C_{max}} \le 0.0031308 \\
   381         C_{max}\left( 1.055 \left(\frac{C_{RGB}}{C_{max}}\right)^{1/2.4}-0.055\right) & \textrm{ otherwise}
   382         \end{array}  \right.
   383     \f]
   384     
   385     where C is any of the primaries R, G, and B. By default, \f$ C_{max} = 255 \f$ (this default can be
   386     overridden in the constructor). If both source and target color components are stored
   387     as <tt>unsigned char</tt>, a look-up-table will be used to speed up the transformation.
   388 
   389     <b> Traits defined:</b>
   390     
   391     <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
   392     */
   393 template <class From, class To = From>
   394 class RGB2sRGBFunctor
   395 {
   396   public:
   397   
   398         /** the functor's argument type
   399         */
   400     typedef TinyVector<From, 3> argument_type;
   401   
   402         /** the functor's result type
   403         */
   404     typedef TinyVector<To, 3> result_type;
   405   
   406         /** \deprecated use argument_type and result_type
   407         */
   408     typedef TinyVector<To, 3> value_type;
   409   
   410         /** the result component's promote type
   411         */
   412     typedef typename NumericTraits<To>::RealPromote component_type;
   413     
   414         /** Default constructor.
   415             The maximum value for each RGB component defaults to 255
   416         */
   417     RGB2sRGBFunctor()
   418     : max_(255.0)
   419     {}
   420     
   421         /** constructor
   422             \arg max - the maximum value for each RGB component
   423         */
   424     RGB2sRGBFunctor(component_type max)
   425     : max_(max)
   426     {}
   427     
   428         /** apply the transformation
   429         */
   430     template <class V>
   431     result_type operator()(V const & rgb) const
   432     {
   433         return TinyVector<To, 3>(
   434             detail::sRGBCorrection<To>(rgb[0], max_),
   435             detail::sRGBCorrection<To>(rgb[1], max_),
   436             detail::sRGBCorrection<To>(rgb[2], max_));
   437     }
   438     
   439   private:
   440     component_type max_;    
   441 };
   442 
   443 template <>
   444 class RGB2sRGBFunctor<unsigned char, unsigned char>
   445 {
   446     unsigned char lut_[256];
   447         
   448   public:
   449   
   450     typedef TinyVector<unsigned char, 3> argument_type;
   451     
   452     typedef TinyVector<unsigned char, 3> result_type;
   453     
   454     typedef TinyVector<unsigned char, 3> value_type;
   455     
   456     RGB2sRGBFunctor()
   457     {
   458         for(int i=0; i<256; ++i)
   459         {
   460             lut_[i] = detail::sRGBCorrection<unsigned char>(i, 255.0);
   461         }
   462     }
   463     
   464     RGB2sRGBFunctor(double max)
   465     {
   466         for(int i=0; i<256; ++i)
   467         {
   468             lut_[i] = detail::sRGBCorrection<unsigned char>(i, max);
   469         }
   470     }
   471     
   472     template <class V>
   473     TinyVector<unsigned char, 3> operator()(V const & rgb) const
   474     {
   475         return TinyVector<unsigned char, 3>(lut_[rgb[0]], lut_[rgb[1]], lut_[rgb[2]]);
   476     }
   477 };
   478 
   479 template <class From, class To>
   480 class FunctorTraits<RGB2sRGBFunctor<From, To> >
   481 : public FunctorTraitsBase<RGB2sRGBFunctor<From, To> >
   482 {
   483   public:
   484     typedef VigraTrueType isUnaryFunctor;
   485 };
   486 
   487 /** \brief Convert non-linear (gamma corrected) R'G'B' into non-linear (raw) RGB.
   488 
   489     <b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>\><br>
   490     Namespace: vigra
   491     
   492     The functor realizes the transformation
   493     
   494     \f[
   495         R = R_{max} \left(\frac{R'}{R_{max}} \right)^{1/0.45} \qquad
   496         G = G_{max} \left(\frac{G'}{G_{max}} \right)^{1/0.45} \qquad
   497         B = B_{max} \left(\frac{B'}{B_{max}} \right)^{1/0.45}
   498     \f]
   499     
   500     By default, \f$ R_{max} = G_{max} = B_{max} = 255 \f$. This default can be overridden
   501     in the constructor. If both source and target color components are stored 
   502     as <tt>unsigned char</tt>, a look-up-table will be used to speed up the transformation.
   503 
   504     <b> Traits defined:</b>
   505     
   506     <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
   507 */
   508 template <class From, class To = From>
   509 class RGBPrime2RGBFunctor
   510 {
   511   public:
   512   
   513         /** the functor's argument type
   514         */
   515     typedef TinyVector<From, 3> argument_type;
   516   
   517         /** the functor's result type
   518         */
   519     typedef TinyVector<To, 3> result_type;
   520   
   521         /** \deprecated use argument_type and result_type
   522         */
   523     typedef TinyVector<To, 3> value_type;
   524   
   525         /** the result component's promote type
   526         */
   527     typedef typename NumericTraits<To>::RealPromote component_type;
   528     
   529         /** Default constructor.
   530             The maximum value for each RGB component defaults to 255.
   531         */
   532     RGBPrime2RGBFunctor()
   533     : max_(255.0), gamma_(1.0/0.45)
   534     {}
   535     
   536         /** constructor
   537             \arg max - the maximum value for each RGB component
   538         */
   539     RGBPrime2RGBFunctor(component_type max)
   540     : max_(max), gamma_(1.0/0.45)
   541     {}
   542     
   543         /** apply the transformation
   544         */
   545     result_type operator()(argument_type const & rgb) const
   546     {
   547         return TinyVector<To, 3>(
   548             detail::gammaCorrection<To>(rgb[0], gamma_, max_),
   549             detail::gammaCorrection<To>(rgb[1], gamma_, max_),
   550             detail::gammaCorrection<To>(rgb[2], gamma_, max_));
   551     }
   552 
   553   private:
   554     component_type max_;
   555     double gamma_;
   556 };
   557 
   558 template <>
   559 class RGBPrime2RGBFunctor<unsigned char, unsigned char>
   560 {    
   561     unsigned char lut_[256];
   562         
   563   public:
   564   
   565     typedef TinyVector<unsigned char, 3> argument_type;
   566     
   567     typedef TinyVector<unsigned char, 3> result_type;
   568     
   569     typedef TinyVector<unsigned char, 3> value_type;
   570     
   571     RGBPrime2RGBFunctor()
   572     {
   573         for(int i=0; i<256; ++i)
   574         {
   575             lut_[i] = detail::gammaCorrection<unsigned char>(i, 1.0/0.45, 255.0);
   576         }
   577     }
   578     
   579     RGBPrime2RGBFunctor(double max)
   580     {
   581         for(int i=0; i<256; ++i)
   582         {
   583             lut_[i] = detail::gammaCorrection<unsigned char>(i, 1.0/0.45, max);
   584         }
   585     }
   586     
   587     template <class V>
   588     TinyVector<unsigned char, 3> operator()(V const & rgb) const
   589     {
   590         return TinyVector<unsigned char, 3>(lut_[rgb[0]], lut_[rgb[1]], lut_[rgb[2]]);
   591     }
   592 };
   593 
   594 template <class From, class To>
   595 class FunctorTraits<RGBPrime2RGBFunctor<From, To> >
   596 : public FunctorTraitsBase<RGBPrime2RGBFunctor<From, To> >
   597 {
   598   public:
   599     typedef VigraTrueType isUnaryFunctor;
   600 };
   601 
   602 /** \brief Convert standardized sRGB into non-linear (raw) RGB.
   603 
   604     <b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>\><br>
   605     Namespace: vigra
   606     
   607     The sRGB color space is a slight improvement over the R'G'B' space. Is is now a widely accepted 
   608     international standard (IEC 61966-2.1) which is used by most consumer products
   609     (digital cameras, printers, and screens). The functor realizes the transformation
   610     
   611     \f[
   612         C_{RGB} = \left\{\begin{array}{ll}
   613         C_{sRGB} / 12.92 & \textrm{if }\frac{C_{sRGB}}{C_{max}} \le 0.04045 \\
   614         C_{max}\left( \frac{C_{sRGB}/C_{max}+0.055}{1.055}\right)^{2.4} & \textrm{otherwise}
   615         \end{array}\right.
   616     \f]
   617     
   618     where C is one of the color channels R, G, or B, and \f$ C_{max}\f$ equals 255 by default (This default 
   619     can be overridden in the constructor). If both source and target color components are stored 
   620     as <tt>unsigned char</tt>, a look-up-table will be used to speed up the transformation.
   621 
   622     <b> Traits defined:</b>
   623     
   624     <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
   625 */
   626 template <class From, class To = From>
   627 class sRGB2RGBFunctor
   628 {
   629   public:
   630   
   631         /** the functor's argument type
   632         */
   633     typedef TinyVector<From, 3> argument_type;
   634   
   635         /** the functor's result type
   636         */
   637     typedef TinyVector<To, 3> result_type;
   638   
   639         /** \deprecated use argument_type and result_type
   640         */
   641     typedef TinyVector<To, 3> value_type;
   642   
   643         /** the result component's promote type
   644         */
   645     typedef typename NumericTraits<To>::RealPromote component_type;
   646     
   647         /** Default constructor.
   648             The maximum value for each RGB component defaults to 255.
   649         */
   650     sRGB2RGBFunctor()
   651     : max_(255.0)
   652     {}
   653     
   654         /** constructor
   655             \arg max - the maximum value for each RGB component
   656         */
   657     sRGB2RGBFunctor(component_type max)
   658     : max_(max)
   659     {}
   660     
   661         /** apply the transformation
   662         */
   663     result_type operator()(argument_type const & rgb) const
   664     {
   665         return TinyVector<To, 3>(
   666             detail::inverse_sRGBCorrection<To>(rgb[0], max_),
   667             detail::inverse_sRGBCorrection<To>(rgb[1], max_),
   668             detail::inverse_sRGBCorrection<To>(rgb[2], max_));
   669     }
   670 
   671   private:
   672     component_type max_;
   673 };
   674 
   675 template <>
   676 class sRGB2RGBFunctor<unsigned char, unsigned char>
   677 {    
   678     unsigned char lut_[256];
   679         
   680   public:
   681   
   682     typedef TinyVector<unsigned char, 3> argument_type;
   683     
   684     typedef TinyVector<unsigned char, 3> result_type;
   685     
   686     typedef TinyVector<unsigned char, 3> value_type;
   687     
   688     sRGB2RGBFunctor()
   689     {
   690         for(int i=0; i<256; ++i)
   691         {
   692             lut_[i] = detail::inverse_sRGBCorrection<unsigned char>(i, 255.0);
   693         }
   694     }
   695     
   696     sRGB2RGBFunctor(double max)
   697     {
   698         for(int i=0; i<256; ++i)
   699         {
   700             lut_[i] = detail::inverse_sRGBCorrection<unsigned char>(i, max);
   701         }
   702     }
   703     
   704     template <class V>
   705     TinyVector<unsigned char, 3> operator()(V const & rgb) const
   706     {
   707         return TinyVector<unsigned char, 3>(lut_[rgb[0]], lut_[rgb[1]], lut_[rgb[2]]);
   708     }
   709 };
   710 
   711 template <class From, class To>
   712 class FunctorTraits<sRGB2RGBFunctor<From, To> >
   713 : public FunctorTraitsBase<sRGB2RGBFunctor<From, To> >
   714 {
   715   public:
   716     typedef VigraTrueType isUnaryFunctor;
   717 };
   718 
   719 /** \brief Convert linear (raw) RGB into standardized tri-stimulus XYZ.
   720 
   721     <b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>\><br>
   722     Namespace: vigra
   723     
   724     According to ITU-R Recommendation BT.709, the functor realizes the transformation
   725     
   726     \f[
   727         \begin{array}{rcl}
   728         X & = & 0.412453\enspace R / R_{max} + 0.357580\enspace G / G_{max} + 0.180423\enspace B / B_{max}\\
   729         Y & = & 0.212671\enspace R / R_{max} + 0.715160\enspace G / G_{max} + 0.072169\enspace B / B_{max} \\
   730         Z & = & 0.019334\enspace R / R_{max} + 0.119193\enspace G / G_{max} + 0.950227\enspace B / B_{max}
   731         \end{array}
   732     \f]
   733     
   734     By default, \f$ R_{max} = G_{max} = B_{max} = 255 \f$. This default can be overridden
   735     in the constructor. X, Y, and Z are always positive and reach their maximum for white. 
   736     The white point is obtained by transforming RGB(255, 255, 255). It corresponds to the 
   737     D65 illuminant. Y represents the <em>luminance</em> ("brightness") of the color. The above
   738     transformation is officially defined in connection with the sRGB color space (i.e. when the RGB values
   739     are obtained by inverse gamma correction of sRGB), other color spaces use slightly different numbers
   740     or another standard illuminant (which gives raise to significantly different numbers).
   741 
   742     <b> Traits defined:</b>
   743     
   744     <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
   745 */
   746 template <class T>
   747 class RGB2XYZFunctor
   748 {
   749   public:
   750   
   751         /** the result's component type
   752         */
   753     typedef typename NumericTraits<T>::RealPromote component_type;
   754 
   755         /** the functor's argument type
   756         */
   757     typedef TinyVector<T, 3> argument_type;
   758   
   759         /** the functor's result type
   760         */
   761     typedef TinyVector<component_type, 3> result_type;
   762   
   763         /** \deprecated use argument_type and result_type
   764         */
   765     typedef TinyVector<component_type, 3> value_type;
   766     
   767         /** default constructor.
   768             The maximum value for each RGB component defaults to 255.
   769         */
   770     RGB2XYZFunctor()
   771     : max_(255.0)
   772     {}
   773     
   774         /** constructor
   775             \arg max - the maximum value for each RGB component
   776         */
   777     RGB2XYZFunctor(component_type max)
   778     : max_(max)
   779     {}
   780     
   781         /** apply the transformation
   782         */
   783     result_type operator()(argument_type const & rgb) const
   784     {
   785         typedef detail::RequiresExplicitCast<component_type> Convert;
   786         component_type red = rgb[0] / max_;
   787         component_type green = rgb[1] / max_;
   788         component_type blue = rgb[2] / max_;
   789         result_type result;
   790         result[0] = Convert::cast(0.412453*red + 0.357580*green + 0.180423*blue);
   791         result[1] = Convert::cast(0.212671*red + 0.715160*green + 0.072169*blue);
   792         result[2] = Convert::cast(0.019334*red + 0.119193*green + 0.950227*blue);
   793         return result;
   794     }
   795 
   796   private:
   797     component_type max_;
   798 };
   799 
   800 template <class T>
   801 class FunctorTraits<RGB2XYZFunctor<T> >
   802 : public FunctorTraitsBase<RGB2XYZFunctor<T> >
   803 {
   804   public:
   805     typedef VigraTrueType isUnaryFunctor;
   806 };
   807 
   808 /** \brief Convert non-linear (gamma corrected) R'G'B' into standardized tri-stimulus XYZ.
   809 
   810     <b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>\><br>
   811     Namespace: vigra
   812     
   813     The functor realizes the transformation
   814     
   815     \f[
   816         R'G'B' \Rightarrow RGB \Rightarrow XYZ
   817     \f]
   818     
   819     See vigra::RGBPrime2RGBFunctor and vigra::RGB2XYZFunctor for a description of the two 
   820     steps.
   821 
   822     <b> Traits defined:</b>
   823     
   824     <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
   825 */
   826 template <class T>
   827 class RGBPrime2XYZFunctor
   828 {
   829   public:
   830   
   831         /** the result's component type
   832         */
   833     typedef typename NumericTraits<T>::RealPromote component_type;
   834 
   835         /** the functor's argument type
   836         */
   837     typedef TinyVector<T, 3> argument_type;
   838   
   839         /** the functor's result type
   840         */
   841     typedef TinyVector<component_type, 3> result_type;
   842   
   843         /** \deprecated use argument_type and result_type
   844         */
   845     typedef TinyVector<component_type, 3> value_type;
   846     
   847         /** default constructor
   848             The maximum value for each RGB component defaults to 255.
   849         */
   850     RGBPrime2XYZFunctor()
   851 	: gamma_(1.0/ 0.45), max_(component_type(255.0))
   852     {}
   853     
   854         /** constructor
   855             \arg max - the maximum value for each RGB component
   856         */
   857     RGBPrime2XYZFunctor(component_type max)
   858 	: gamma_(1.0/ 0.45), max_(max)
   859     {}
   860     
   861         /** apply the transformation
   862         */
   863     result_type operator()(argument_type const & rgb) const
   864     {
   865         typedef detail::RequiresExplicitCast<component_type> Convert;
   866         component_type red = detail::gammaCorrection<component_type>(rgb[0]/max_, gamma_);
   867         component_type green = detail::gammaCorrection<component_type>(rgb[1]/max_, gamma_);
   868         component_type blue = detail::gammaCorrection<component_type>(rgb[2]/max_, gamma_);
   869         result_type result;
   870         result[0] = Convert::cast(0.412453*red + 0.357580*green + 0.180423*blue);
   871         result[1] = Convert::cast(0.212671*red + 0.715160*green + 0.072169*blue);
   872         result[2] = Convert::cast(0.019334*red + 0.119193*green + 0.950227*blue);
   873         return result;
   874     }
   875 
   876   private:
   877     double gamma_;
   878     component_type max_;
   879 };
   880 
   881 template <class T>
   882 class FunctorTraits<RGBPrime2XYZFunctor<T> >
   883 : public FunctorTraitsBase<RGBPrime2XYZFunctor<T> >
   884 {
   885   public:
   886     typedef VigraTrueType isUnaryFunctor;
   887 };
   888 
   889 /** \brief Convert standardized tri-stimulus XYZ into linear (raw) RGB.
   890 
   891     <b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>\><br>
   892     Namespace: vigra
   893     
   894     According to ITU-R Recommendation BT.709, the functor realizes the transformation
   895     
   896     \f[
   897         \begin{array}{rcl}
   898         R & = & R_{max} (3.2404813432\enspace X - 1.5371515163\enspace Y - 0.4985363262\enspace Z) \\
   899         G & = & G_{max} (-0.9692549500\enspace X + 1.8759900015\enspace Y + 0.0415559266\enspace Z) \\
   900         B & = & B_{max} (0.0556466391\enspace X - 0.2040413384\enspace Y + 1.0573110696\enspace Z)
   901         \end{array}
   902     \f]
   903     
   904     By default, \f$ R_{max} = G_{max} = B_{max} = 255 \f$. This default can be overridden
   905     in the constructor. This is the inverse transform of vigra::RGB2XYZFunctor.
   906 
   907     <b> Traits defined:</b>
   908     
   909     <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
   910 */
   911 template <class T>
   912 class XYZ2RGBFunctor
   913 {
   914     typedef typename NumericTraits<T>::RealPromote component_type;
   915     
   916     component_type max_;
   917     
   918   public:
   919         /** the functor's argument type. (Actually, the argument type
   920             is more general: <TT>V</TT> with arbitrary
   921             <TT>V</TT>. But this cannot be expressed in a typedef.)
   922         */
   923     typedef TinyVector<T, 3> argument_type;
   924   
   925         /** the functor's result type
   926         */
   927     typedef TinyVector<T, 3> result_type;
   928   
   929         /** \deprecated use argument_type and result_type
   930         */
   931     typedef TinyVector<T, 3> value_type;
   932     
   933         /** default constructor.
   934             The maximum value for each RGB component defaults to 255.
   935         */
   936     XYZ2RGBFunctor()
   937     : max_(255.0)
   938     {}
   939     
   940         /** constructor
   941             \arg max - the maximum value for each RGB component
   942         */
   943     XYZ2RGBFunctor(component_type max)
   944     : max_(max)
   945     {}
   946     
   947         /** apply the transformation
   948         */
   949     template <class V>
   950     result_type operator()(V const & xyz) const
   951     {
   952         typedef detail::RequiresExplicitCast<component_type> Convert;
   953         component_type red   = Convert::cast( 3.2404813432*xyz[0] - 1.5371515163*xyz[1] - 0.4985363262*xyz[2]);
   954         component_type green = Convert::cast(-0.9692549500*xyz[0] + 1.8759900015*xyz[1] + 0.0415559266*xyz[2]);
   955         component_type blue  = Convert::cast( 0.0556466391*xyz[0] - 0.2040413384*xyz[1] + 1.0573110696*xyz[2]);
   956         return value_type(NumericTraits<T>::fromRealPromote(red * max_),
   957                           NumericTraits<T>::fromRealPromote(green * max_),
   958                           NumericTraits<T>::fromRealPromote(blue * max_));
   959     }
   960 };
   961 
   962 template <class T>
   963 class FunctorTraits<XYZ2RGBFunctor<T> >
   964 : public FunctorTraitsBase<XYZ2RGBFunctor<T> >
   965 {
   966   public:
   967     typedef VigraTrueType isUnaryFunctor;
   968 };
   969 
   970 /** \brief Convert standardized tri-stimulus XYZ into non-linear (gamma corrected) R'G'B'.
   971 
   972     <b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>\><br>
   973     Namespace: vigra
   974     
   975     The functor realizes the transformation
   976     
   977     \f[
   978         XYZ \Rightarrow RGB \Rightarrow R'G'B'
   979     \f]
   980     
   981     See vigra::XYZ2RGBFunctor and vigra::RGB2RGBPrimeFunctor for a description of the two 
   982     steps.
   983 
   984     <b> Traits defined:</b>
   985     
   986     <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
   987 */
   988 template <class T>
   989 class XYZ2RGBPrimeFunctor
   990 {
   991     typedef typename NumericTraits<T>::RealPromote component_type;
   992     
   993     double gamma_;
   994     component_type max_;
   995     
   996   public:
   997   
   998   public:
   999         /** the functor's argument type. (actually, the argument type
  1000             can be any vector type with the same interface. 
  1001             But this cannot be expressed in a typedef.)
  1002         */
  1003     typedef TinyVector<T, 3> argument_type;
  1004   
  1005         /** the functor's result type
  1006         */
  1007     typedef TinyVector<T, 3> result_type;
  1008   
  1009         /** \deprecated use argument_type and result_type
  1010         */
  1011     typedef TinyVector<T, 3> value_type;
  1012     
  1013         /** default constructor.
  1014             The maximum value for each RGB component defaults to 255.
  1015         */
  1016     XYZ2RGBPrimeFunctor()
  1017 	: gamma_(0.45), max_(component_type(255.0))
  1018     {}
  1019     
  1020         /** constructor
  1021             \arg max - the maximum value for each RGB component
  1022         */
  1023     XYZ2RGBPrimeFunctor(component_type max)
  1024 	: gamma_(0.45), max_(max)
  1025     {}
  1026     
  1027         /** apply the transformation
  1028         */
  1029     template <class V>
  1030     result_type operator()(V const & xyz) const
  1031     {
  1032         typedef detail::RequiresExplicitCast<component_type> Convert;
  1033         component_type red   = Convert::cast( 3.2404813432*xyz[0] - 1.5371515163*xyz[1] - 0.4985363262*xyz[2]);
  1034         component_type green = Convert::cast(-0.9692549500*xyz[0] + 1.8759900015*xyz[1] + 0.0415559266*xyz[2]);
  1035         component_type blue  = Convert::cast( 0.0556466391*xyz[0] - 0.2040413384*xyz[1] + 1.0573110696*xyz[2]);
  1036         return value_type(NumericTraits<T>::fromRealPromote(detail::gammaCorrection<component_type>(red, gamma_) * max_),
  1037                           NumericTraits<T>::fromRealPromote(detail::gammaCorrection<component_type>(green, gamma_) * max_),
  1038                           NumericTraits<T>::fromRealPromote(detail::gammaCorrection<component_type>(blue, gamma_) * max_));
  1039     }
  1040 };
  1041 
  1042 template <class T>
  1043 class FunctorTraits<XYZ2RGBPrimeFunctor<T> >
  1044 : public FunctorTraitsBase<XYZ2RGBPrimeFunctor<T> >
  1045 {
  1046   public:
  1047     typedef VigraTrueType isUnaryFunctor;
  1048 };
  1049 
  1050 /** \brief Convert standardized tri-stimulus XYZ into perceptual uniform CIE L*u*v*.
  1051 
  1052     <b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>\><br>
  1053     Namespace: vigra
  1054     
  1055     The functor realizes the transformation
  1056     
  1057     \f[
  1058         \begin{array}{rcl}
  1059         L^{*} & = & 116 \left( \frac{Y}{Y_n} \right)^\frac{1}{3}-16 \quad \mbox{if} \quad 0.008856 < \frac{Y}{Y_n}\\
  1060         & & \\
  1061         L^{*} & = & 903.3\enspace \frac{Y}{Y_n} \quad \mbox{otherwise} \\
  1062         & & \\
  1063         
  1064         u' & = & \frac{4 X}{X+15 Y + 3 Z}, \quad 
  1065              v' = \frac{9 Y}{X+15 Y + 3 Z}\\
  1066         & & \\
  1067         u^{*} & = & 13 L^{*} (u' - u_n'), \quad v^{*} = 13 L^{*} (v' - v_n')
  1068         \end{array}
  1069     \f]
  1070     
  1071     where \f$(X_n, Y_n, Z_n) = (0.950456, 1.0, 1.088754)\f$ is the reference white point of standard illuminant D65, 
  1072     and \f$u_n' = 0.197839, v_n'=0.468342\f$ are the quantities \f$u', v'\f$ calculated for this point. 
  1073     \f$L^{*}\f$ represents the <em>lightness</em> ("brightness") of the color, and \f$u^{*}, v^{*}\f$ code the 
  1074     chromaticity. (Instead of the rationals \f$\frac{216}{24389}\f$ and \f$\frac{24389}{27}\f$, the original standard gives the
  1075     rounded values 0.008856 and 903.3. As <a href="http://www.brucelindbloom.com/index.html?LContinuity.html">Bruce Lindbloom</a> 
  1076     points out, the rounded values give raise to a discontinuity which is removed by the accurate rationals. This bug will be fixed 
  1077     in future versions of the CIE Luv standard.)
  1078 
  1079     <b> Traits defined:</b>
  1080     
  1081     <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
  1082 */
  1083 template <class T>
  1084 class XYZ2LuvFunctor
  1085 {
  1086   public:
  1087   
  1088         /** the result's component type
  1089         */
  1090     typedef typename NumericTraits<T>::RealPromote component_type;
  1091 
  1092         /** the functor's argument type
  1093         */
  1094     typedef TinyVector<T, 3> argument_type;
  1095   
  1096         /** the functor's result type
  1097         */
  1098     typedef TinyVector<component_type, 3> result_type;
  1099   
  1100         /** \deprecated use argument_type and result_type
  1101         */
  1102     typedef TinyVector<component_type, 3> value_type;
  1103     
  1104     XYZ2LuvFunctor()
  1105     : gamma_(1.0/3.0),
  1106       kappa_(24389.0/27.0),
  1107       epsilon_(216.0/24389.0)
  1108     {}
  1109     
  1110     template <class V>
  1111     result_type operator()(V const & xyz) const
  1112     {
  1113         result_type result;
  1114         if(xyz[1] == NumericTraits<T>::zero())
  1115         {
  1116             result[0] = NumericTraits<component_type>::zero();
  1117             result[1] = NumericTraits<component_type>::zero();
  1118             result[2] = NumericTraits<component_type>::zero();
  1119         }
  1120         else
  1121         {
  1122             typedef detail::RequiresExplicitCast<component_type> Convert;
  1123             component_type L = Convert::cast(
  1124                                   xyz[1] < epsilon_
  1125                                       ? kappa_ * xyz[1]
  1126                                       : 116.0 * VIGRA_CSTD::pow((double)xyz[1], gamma_) - 16.0);
  1127             component_type denom = Convert::cast(xyz[0] + 15.0*xyz[1] + 3.0*xyz[2]);
  1128             component_type uprime = Convert::cast(4.0 * xyz[0] / denom);
  1129             component_type vprime = Convert::cast(9.0 * xyz[1] / denom);
  1130             result[0] = L;
  1131             result[1] = Convert::cast(13.0*L*(uprime - 0.197839));
  1132             result[2] = Convert::cast(13.0*L*(vprime - 0.468342));
  1133         }
  1134         return result;
  1135     }
  1136 
  1137   private:
  1138     double gamma_, kappa_, epsilon_;
  1139 };
  1140 
  1141 template <class T>
  1142 class FunctorTraits<XYZ2LuvFunctor<T> >
  1143 : public FunctorTraitsBase<XYZ2LuvFunctor<T> >
  1144 {
  1145   public:
  1146     typedef VigraTrueType isUnaryFunctor;
  1147 };
  1148 
  1149 /** \brief Convert perceptual uniform CIE L*u*v* into standardized tri-stimulus XYZ.
  1150 
  1151     <b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>\><br>
  1152     Namespace: vigra
  1153     
  1154     The functor realizes the inverse of the transformation described in vigra::XYZ2LuvFunctor
  1155 
  1156     <b> Traits defined:</b>
  1157     
  1158     <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
  1159 */
  1160 template <class T>
  1161 class Luv2XYZFunctor
  1162 {
  1163   public:
  1164   
  1165         /** the result's component type
  1166         */
  1167     typedef typename NumericTraits<T>::RealPromote component_type;
  1168 
  1169         /** the functor's argument type
  1170         */
  1171     typedef TinyVector<T, 3> argument_type;
  1172   
  1173         /** the functor's result type
  1174         */
  1175     typedef TinyVector<component_type, 3> result_type;
  1176   
  1177         /** \deprecated use argument_type and result_type
  1178         */
  1179     typedef TinyVector<component_type, 3> value_type;
  1180     
  1181     Luv2XYZFunctor()
  1182     : gamma_(3.0),
  1183       ikappa_(27.0/24389.0)
  1184     {}
  1185     
  1186         /** apply the transformation
  1187         */
  1188     template <class V>
  1189     result_type operator()(V const & luv) const
  1190     {
  1191         result_type result;
  1192         if(luv[0] == NumericTraits<T>::zero())
  1193         {
  1194             result[0] = NumericTraits<component_type>::zero();
  1195             result[1] = NumericTraits<component_type>::zero();
  1196             result[2] = NumericTraits<component_type>::zero();
  1197         }
  1198         else
  1199         {
  1200             typedef detail::RequiresExplicitCast<component_type> Convert;
  1201             component_type uprime = Convert::cast(luv[1] / 13.0 / luv[0] + 0.197839);
  1202             component_type vprime = Convert::cast(luv[2] / 13.0 / luv[0] + 0.468342);
  1203 
  1204             result[1] = Convert::cast(
  1205                             luv[0] < 8.0 
  1206                                 ? luv[0] * ikappa_ 
  1207                                 : VIGRA_CSTD::pow((luv[0] + 16.0) / 116.0, gamma_));
  1208             result[0] = Convert::cast(9.0*uprime*result[1] / 4.0 / vprime);
  1209             result[2] = Convert::cast(((9.0 / vprime - 15.0)*result[1] - result[0])/ 3.0);
  1210         }
  1211         return result;
  1212     }
  1213 
  1214   private:
  1215     double gamma_, ikappa_;
  1216 };
  1217 
  1218 template <class T>
  1219 class FunctorTraits<Luv2XYZFunctor<T> >
  1220 : public FunctorTraitsBase<Luv2XYZFunctor<T> >
  1221 {
  1222   public:
  1223     typedef VigraTrueType isUnaryFunctor;
  1224 };
  1225 
  1226 /** \brief Convert standardized tri-stimulus XYZ into perceptual uniform CIE L*a*b*.
  1227 
  1228     <b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>\><br>
  1229     Namespace: vigra
  1230     
  1231     The functor realizes the transformation
  1232     
  1233     \f[
  1234         \begin{array}{rcl}
  1235         L^{*} & = & 116 \left( \frac{Y}{Y_n} \right)^\frac{1}{3}-16 \quad \mbox{if} \quad \frac{216}{24389} < \frac{Y}{Y_n}\\
  1236         & & \\
  1237         L^{*} & = & \frac{24389}{27} \enspace \frac{Y}{Y_n} \quad \mbox{otherwise} \\
  1238         & & \\
  1239         a^{*} & = & 500 \left[ \left( \frac{X}{X_n} \right)^\frac{1}{3} - \left( \frac{Y}{Y_n} \right)^\frac{1}{3} \right] \\
  1240         & & \\
  1241         b^{*} & = & 200 \left[ \left( \frac{Y}{Y_n} \right)^\frac{1}{3} - \left( \frac{Z}{Z_n} \right)^\frac{1}{3} \right] \\
  1242         \end{array}
  1243     \f]
  1244     
  1245     where \f$(X_n, Y_n, Z_n) = (0.950456, 1.0, 1.088754)\f$ is the reference white point of standard illuminant D65. 
  1246     \f$L^{*}\f$ represents the <em>lightness</em> ("brightness") of the color, and \f$a^{*}, b^{*}\f$ code the 
  1247     chromaticity. (Instead of the rationals \f$\frac{216}{24389}\f$ and \f$\frac{24389}{27}\f$, the original standard gives the
  1248     rounded values 0.008856 and 903.3. As <a href="http://www.brucelindbloom.com/index.html?LContinuity.html">Bruce Lindbloom</a> 
  1249     points out, the rounded values give raise to a discontinuity which is removed by the accurate rationals. This bug will be fixed 
  1250     in future versions of the CIE Lab standard.)
  1251 
  1252     <b> Traits defined:</b>
  1253     
  1254     <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
  1255 */
  1256 template <class T>
  1257 class XYZ2LabFunctor
  1258 {
  1259   public:
  1260   
  1261         /** the result's component type
  1262         */
  1263     typedef typename NumericTraits<T>::RealPromote component_type;
  1264 
  1265         /** the functor's argument type
  1266         */
  1267     typedef TinyVector<T, 3> argument_type;
  1268   
  1269         /** the functor's result type
  1270         */
  1271     typedef TinyVector<component_type, 3> result_type;
  1272   
  1273         /** \deprecated use argument_type and result_type
  1274         */
  1275     typedef TinyVector<component_type, 3> value_type;
  1276     
  1277     XYZ2LabFunctor()
  1278     : gamma_(1.0/3.0),
  1279       kappa_(24389.0/27.0),
  1280       epsilon_(216.0/24389.0)
  1281     {}
  1282     
  1283         /** apply the transformation
  1284         */
  1285     template <class V>
  1286     result_type operator()(V const & xyz) const
  1287     {
  1288         typedef detail::RequiresExplicitCast<component_type> Convert;
  1289         component_type xgamma = Convert::cast(std::pow(xyz[0] / 0.950456, gamma_));
  1290         component_type ygamma = Convert::cast(std::pow((double)xyz[1], gamma_));
  1291         component_type zgamma = Convert::cast(std::pow(xyz[2] / 1.088754, gamma_));
  1292         component_type L = Convert::cast(
  1293                               xyz[1] < epsilon_ 
  1294                                   ? kappa_ * xyz[1] 
  1295                                   : 116.0 * ygamma - 16.0);
  1296         result_type result;
  1297         result[0] = L;
  1298         result[1] = Convert::cast(500.0*(xgamma - ygamma));
  1299         result[2] = Convert::cast(200.0*(ygamma - zgamma));
  1300         return result;
  1301     }
  1302 
  1303   private:
  1304     double gamma_, kappa_, epsilon_;
  1305 };
  1306 
  1307 template <class T>
  1308 class FunctorTraits<XYZ2LabFunctor<T> >
  1309 : public FunctorTraitsBase<XYZ2LabFunctor<T> >
  1310 {
  1311   public:
  1312     typedef VigraTrueType isUnaryFunctor;
  1313 };
  1314 
  1315 /** \brief Convert perceptual uniform CIE L*a*b* into standardized tri-stimulus XYZ.
  1316 
  1317     <b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>\><br>
  1318     Namespace: vigra
  1319     
  1320     The functor realizes the inverse of the transformation described in vigra::XYZ2LabFunctor
  1321 
  1322     <b> Traits defined:</b>
  1323     
  1324     <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
  1325 */
  1326 template <class T>
  1327 class Lab2XYZFunctor
  1328 {
  1329   public:
  1330   
  1331         /** the result's component type
  1332         */
  1333     typedef typename NumericTraits<T>::RealPromote component_type;
  1334 
  1335         /** the functor's argument type
  1336         */
  1337     typedef TinyVector<T, 3> argument_type;
  1338   
  1339         /** the functor's result type
  1340         */
  1341     typedef TinyVector<component_type, 3> result_type;
  1342   
  1343         /** \deprecated use argument_type and result_type
  1344         */
  1345     typedef TinyVector<component_type, 3> value_type;
  1346     
  1347         /** the functor's value type
  1348         */
  1349     Lab2XYZFunctor()
  1350     : gamma_(3.0),
  1351       ikappa_(27.0/24389.0)
  1352     {}
  1353     
  1354         /** apply the transformation
  1355         */
  1356     template <class V>
  1357     result_type operator()(V const & lab) const
  1358     {
  1359         typedef detail::RequiresExplicitCast<component_type> Convert;
  1360         component_type Y = Convert::cast(
  1361                               lab[0] < 8.0
  1362                                   ? lab[0] * ikappa_
  1363                                   : std::pow((lab[0] + 16.0) / 116.0, gamma_));
  1364         component_type ygamma = Convert::cast(std::pow((double)Y, 1.0 / gamma_));
  1365         component_type X = Convert::cast(std::pow(lab[1] / 500.0 + ygamma, gamma_) * 0.950456);
  1366         component_type Z = Convert::cast(std::pow(-lab[2] / 200.0 + ygamma, gamma_) * 1.088754);
  1367         result_type result;
  1368         result[0] = X;
  1369         result[1] = Y;
  1370         result[2] = Z;
  1371         return result;
  1372     }
  1373 
  1374   private:
  1375     double gamma_, ikappa_;
  1376 };
  1377 
  1378 template <class T>
  1379 class FunctorTraits<Lab2XYZFunctor<T> >
  1380 : public FunctorTraitsBase<Lab2XYZFunctor<T> >
  1381 {
  1382   public:
  1383     typedef VigraTrueType isUnaryFunctor;
  1384 };
  1385 
  1386 /** \brief Convert linear (raw) RGB into perceptual uniform CIE L*u*v*.
  1387 
  1388     <b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>\><br>
  1389     Namespace: vigra
  1390     
  1391     The functor realizes the transformation
  1392     
  1393     \f[
  1394         RGB \Rightarrow XYZ \Rightarrow L^*u^*v^*
  1395     \f]
  1396     
  1397     See vigra::RGB2XYZFunctor and vigra::XYZ2LuvFunctor for a description of the two 
  1398     steps. The resulting color components will have the following bounds:
  1399     
  1400     \f[
  1401         \begin{array}{rcl}
  1402         0 \leq & L^* & \leq 100 \\
  1403         -83.077 \leq & u^* & \leq 175.015 \\
  1404         -134.101 \leq & v^* & \leq 107.393
  1405         \end{array}
  1406     \f]
  1407 
  1408     <b> Traits defined:</b>
  1409     
  1410     <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
  1411 */
  1412 template <class T>
  1413 class RGB2LuvFunctor
  1414 {
  1415     /*
  1416     L in [0, 100]
  1417     u in [-83.077, 175.015]
  1418     v in [-134.101, 107.393]
  1419     maximum saturation: 179.04 
  1420     red = [53.2406, 175.015, 37.7522]
  1421     */
  1422   public:
  1423   
  1424         /** the result's component type
  1425         */
  1426     typedef typename NumericTraits<T>::RealPromote component_type;
  1427 
  1428         /** the functor's argument type
  1429         */
  1430     typedef TinyVector<T, 3> argument_type;
  1431   
  1432         /** the functor's result type
  1433         */
  1434     typedef typename XYZ2LuvFunctor<component_type>::result_type result_type;
  1435   
  1436         /** \deprecated use argument_type and result_type
  1437         */
  1438     typedef typename XYZ2LuvFunctor<component_type>::result_type value_type;
  1439     
  1440         /** default constructor.
  1441             The maximum value for each RGB component defaults to 255.
  1442         */
  1443     RGB2LuvFunctor()
  1444     : rgb2xyz(255.0)
  1445     {}
  1446     
  1447         /** constructor
  1448             \arg max - the maximum value for each RGB component
  1449         */
  1450     RGB2LuvFunctor(component_type max)
  1451     : rgb2xyz(max)
  1452     {}
  1453     
  1454         /** apply the transformation
  1455         */
  1456     template <class V>
  1457     result_type operator()(V const & rgb) const
  1458     {
  1459         return xyz2luv(rgb2xyz(rgb));
  1460     }
  1461 
  1462   private:
  1463     RGB2XYZFunctor<T> rgb2xyz;
  1464     XYZ2LuvFunctor<component_type> xyz2luv;
  1465 };
  1466 
  1467 template <class T>
  1468 class FunctorTraits<RGB2LuvFunctor<T> >
  1469 : public FunctorTraitsBase<RGB2LuvFunctor<T> >
  1470 {
  1471   public:
  1472     typedef VigraTrueType isUnaryFunctor;
  1473 };
  1474 
  1475 /** \brief Convert linear (raw) RGB into perceptual uniform CIE L*a*b*.
  1476 
  1477     <b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>\><br>
  1478     Namespace: vigra
  1479     
  1480     The functor realizes the transformation
  1481     
  1482     \f[
  1483         RGB \Rightarrow XYZ \Rightarrow L^*a^*b^*
  1484     \f]
  1485     
  1486     See vigra::RGB2XYZFunctor and vigra::XYZ2LabFunctor for a description of the two 
  1487     steps. The resulting color components will have the following bounds:
  1488     
  1489     \f[
  1490         \begin{array}{rcl}
  1491         0 \leq & L^* & \leq 100 \\
  1492         -86.1813 \leq & u^* & \leq 98.2352 \\
  1493         -107.862 \leq & v^* & \leq 94.4758
  1494         \end{array}
  1495     \f]
  1496 
  1497     <b> Traits defined:</b>
  1498     
  1499     <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
  1500 */
  1501 template <class T>
  1502 class RGB2LabFunctor
  1503 {
  1504     /*
  1505     L in [0, 100]
  1506     a in [-86.1813, 98.2352]
  1507     b in [-107.862, 94.4758] 
  1508     maximum saturation: 133.809
  1509     red = [53.2406, 80.0942, 67.2015]
  1510     */
  1511   public:
  1512   
  1513         /** the result's component type
  1514         */
  1515     typedef typename NumericTraits<T>::RealPromote component_type;
  1516 
  1517         /** the functor's argument type
  1518         */
  1519     typedef TinyVector<T, 3> argument_type;
  1520   
  1521         /** the functor's result type
  1522         */
  1523     typedef typename XYZ2LabFunctor<component_type>::result_type result_type;
  1524   
  1525         /** \deprecated use argument_type and result_type
  1526         */
  1527     typedef typename XYZ2LabFunctor<component_type>::result_type value_type;
  1528     
  1529         /** default constructor.
  1530             The maximum value for each RGB component defaults to 255.
  1531         */
  1532     RGB2LabFunctor()
  1533     : rgb2xyz(255.0)
  1534     {}
  1535     
  1536         /** constructor
  1537             \arg max - the maximum value for each RGB component
  1538         */
  1539     RGB2LabFunctor(component_type max)
  1540     : rgb2xyz(max)
  1541     {}
  1542     
  1543         /** apply the transformation
  1544         */
  1545     template <class V>
  1546     result_type operator()(V const & rgb) const
  1547     {
  1548         return xyz2lab(rgb2xyz(rgb));
  1549     }
  1550 
  1551   private:
  1552     RGB2XYZFunctor<T> rgb2xyz;
  1553     XYZ2LabFunctor<component_type> xyz2lab;
  1554 };
  1555 
  1556 template <class T>
  1557 class FunctorTraits<RGB2LabFunctor<T> >
  1558 : public FunctorTraitsBase<RGB2LabFunctor<T> >
  1559 {
  1560   public:
  1561     typedef VigraTrueType isUnaryFunctor;
  1562 };
  1563 
  1564 /** \brief Convert perceptual uniform CIE L*u*v* into linear (raw) RGB.
  1565 
  1566     <b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>\><br>
  1567     Namespace: vigra
  1568     
  1569     The functor realizes the inverse of the transformation described in vigra::RGB2LuvFunctor
  1570 
  1571     <b> Traits defined:</b>
  1572     
  1573     <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
  1574 */
  1575 template <class T>
  1576 class Luv2RGBFunctor
  1577 {
  1578     typedef typename NumericTraits<T>::RealPromote component_type;
  1579     
  1580     XYZ2RGBFunctor<T> xyz2rgb;
  1581     Luv2XYZFunctor<component_type> luv2xyz;
  1582     
  1583   public:
  1584         /** the functor's argument type. (Actually, the argument type
  1585             can be any vector type with the same interface. 
  1586             But this cannot be expressed in a typedef.)
  1587         */
  1588     typedef TinyVector<T, 3> argument_type;
  1589   
  1590         /** the functor's result type
  1591         */
  1592     typedef typename XYZ2RGBFunctor<T>::result_type result_type;
  1593   
  1594         /** \deprecated use argument_type and result_type
  1595         */
  1596     typedef typename XYZ2RGBFunctor<T>::result_type value_type;
  1597     
  1598     Luv2RGBFunctor()
  1599     : xyz2rgb(255.0)
  1600     {}
  1601     
  1602     Luv2RGBFunctor(component_type max)
  1603     : xyz2rgb(max)
  1604     {}
  1605     
  1606         /** apply the transformation
  1607         */
  1608     template <class V>
  1609     result_type operator()(V const & luv) const
  1610     {
  1611         return xyz2rgb(luv2xyz(luv));
  1612     }
  1613 };
  1614 
  1615 template <class T>
  1616 class FunctorTraits<Luv2RGBFunctor<T> >
  1617 : public FunctorTraitsBase<Luv2RGBFunctor<T> >
  1618 {
  1619   public:
  1620     typedef VigraTrueType isUnaryFunctor;
  1621 };
  1622 
  1623 /** \brief Convert perceptual uniform CIE L*a*b* into linear (raw) RGB.
  1624 
  1625     <b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>\><br>
  1626     Namespace: vigra
  1627     
  1628     The functor realizes the inverse of the transformation described in vigra::RGB2LabFunctor
  1629 
  1630     <b> Traits defined:</b>
  1631     
  1632     <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
  1633 */
  1634 template <class T>
  1635 class Lab2RGBFunctor
  1636 {
  1637     typedef typename NumericTraits<T>::RealPromote component_type;
  1638     
  1639     XYZ2RGBFunctor<T> xyz2rgb;
  1640     Lab2XYZFunctor<component_type> lab2xyz;
  1641     
  1642   public:
  1643   
  1644         /** the functor's argument type. (Actually, the argument type
  1645             can be any vector type with the same interface. 
  1646             But this cannot be expressed in a typedef.)
  1647         */
  1648     typedef TinyVector<T, 3> argument_type;
  1649   
  1650         /** the functor's result type
  1651         */
  1652     typedef typename XYZ2RGBFunctor<T>::result_type result_type;
  1653   
  1654         /** \deprecated use argument_type and result_type
  1655         */
  1656     typedef typename XYZ2RGBFunctor<T>::result_type value_type;
  1657     
  1658         /** default constructor.
  1659             The maximum value for each RGB component defaults to 255.
  1660         */
  1661     Lab2RGBFunctor()
  1662     : xyz2rgb(255.0)
  1663     {}
  1664     
  1665         /** constructor
  1666             \arg max - the maximum value for each RGB component
  1667         */
  1668     Lab2RGBFunctor(component_type max)
  1669     : xyz2rgb(max)
  1670     {}
  1671     
  1672         /** apply the transformation
  1673         */
  1674     template <class V>
  1675     result_type operator()(V const & lab) const
  1676     {
  1677         return xyz2rgb(lab2xyz(lab));
  1678     }
  1679 };
  1680 
  1681 template <class T>
  1682 class FunctorTraits<Lab2RGBFunctor<T> >
  1683 : public FunctorTraitsBase<Lab2RGBFunctor<T> >
  1684 {
  1685   public:
  1686     typedef VigraTrueType isUnaryFunctor;
  1687 };
  1688 
  1689 /** \brief Convert non-linear (gamma corrected) R'G'B' into perceptual uniform CIE L*u*v*.
  1690 
  1691     <b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>\><br>
  1692     Namespace: vigra
  1693     
  1694     The functor realizes the transformation
  1695     
  1696     \f[
  1697         R'G'B' \Rightarrow RGB \Rightarrow XYZ \Rightarrow L^*u^*v^*
  1698     \f]
  1699     
  1700     See vigra::RGBPrime2RGBFunctor, vigra::RGB2XYZFunctor and vigra::XYZ2LuvFunctor for a description of the three 
  1701     steps. The resulting color components will have the following bounds:
  1702     
  1703     \f[
  1704         \begin{array}{rcl}
  1705         0 \leq & L^* & \leq 100 \\
  1706         -83.077 \leq & u^* & \leq 175.015 \\
  1707         -134.101 \leq & v^* & \leq 107.393
  1708         \end{array}
  1709     \f]
  1710 
  1711     <b> Traits defined:</b>
  1712     
  1713     <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
  1714 */
  1715 template <class T>
  1716 class RGBPrime2LuvFunctor
  1717 {
  1718   public:
  1719   
  1720         /** the result's component type
  1721         */
  1722     typedef typename NumericTraits<T>::RealPromote component_type;
  1723 
  1724         /** the functor's argument type
  1725         */
  1726     typedef TinyVector<T, 3> argument_type;
  1727   
  1728         /** the functor's result type
  1729         */
  1730     typedef typename XYZ2LuvFunctor<component_type>::result_type result_type;
  1731   
  1732         /** \deprecated use argument_type and result_type
  1733         */
  1734     typedef typename XYZ2LuvFunctor<component_type>::result_type value_type;
  1735     
  1736         /** default constructor.
  1737             The maximum value for each RGB component defaults to 255.
  1738         */
  1739     RGBPrime2LuvFunctor()
  1740     : rgb2xyz(255.0)
  1741     {}
  1742     
  1743         /** constructor
  1744             \arg max - the maximum value for each RGB component
  1745         */
  1746     RGBPrime2LuvFunctor(component_type max)
  1747     : rgb2xyz(max)
  1748     {}
  1749     
  1750         /** apply the transformation
  1751         */
  1752     template <class V>
  1753     result_type operator()(V const & rgb) const
  1754     {
  1755         return xyz2luv(rgb2xyz(rgb));
  1756     }
  1757 
  1758   private:
  1759     RGBPrime2XYZFunctor<T> rgb2xyz;
  1760     XYZ2LuvFunctor<component_type> xyz2luv;
  1761 };
  1762 
  1763 template <class T>
  1764 class FunctorTraits<RGBPrime2LuvFunctor<T> >
  1765 : public FunctorTraitsBase<RGBPrime2LuvFunctor<T> >
  1766 {
  1767   public:
  1768     typedef VigraTrueType isUnaryFunctor;
  1769 };
  1770 
  1771 /** \brief Convert non-linear (gamma corrected) R'G'B' into perceptual uniform CIE L*a*b*.
  1772 
  1773     <b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>\><br>
  1774     Namespace: vigra
  1775     
  1776     The functor realizes the transformation
  1777     
  1778     \f[
  1779         R'G'B' \Rightarrow RGB \Rightarrow XYZ \Rightarrow L^*a^*b^*
  1780     \f]
  1781     
  1782     See vigra::RGBPrime2RGBFunctor, vigra::RGB2XYZFunctor and vigra::XYZ2LabFunctor for a description of the three 
  1783     steps. The resulting color components will have the following bounds:
  1784     
  1785     \f[
  1786         \begin{array}{rcl}
  1787         0 \leq & L^* & \leq 100 \\
  1788         -86.1813 \leq & u^* & \leq 98.2352 \\
  1789         -107.862 \leq & v^* & \leq 94.4758
  1790         \end{array}
  1791     \f]
  1792 
  1793     <b> Traits defined:</b>
  1794     
  1795     <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
  1796 */
  1797 template <class T>
  1798 class RGBPrime2LabFunctor
  1799 {
  1800   public:
  1801   
  1802         /** the result's component type
  1803         */
  1804     typedef typename NumericTraits<T>::RealPromote component_type;
  1805 
  1806         /** the functor's argument type
  1807         */
  1808     typedef TinyVector<T, 3> argument_type;
  1809   
  1810         /** the functor's result type
  1811         */
  1812     typedef typename XYZ2LabFunctor<component_type>::result_type result_type;
  1813   
  1814         /** \deprecated use argument_type and result_type
  1815         */
  1816     typedef typename XYZ2LabFunctor<component_type>::result_type value_type;
  1817     
  1818         /** default constructor.
  1819             The maximum value for each RGB component defaults to 255.
  1820         */
  1821     RGBPrime2LabFunctor()
  1822     : rgb2xyz(255.0)
  1823     {}
  1824     
  1825         /** constructor
  1826             \arg max - the maximum value for each RGB component
  1827         */
  1828     RGBPrime2LabFunctor(component_type max)
  1829     : rgb2xyz(max)
  1830     {}
  1831     
  1832         /** apply the transformation
  1833         */
  1834     template <class V>
  1835     result_type operator()(V const & rgb) const
  1836     {
  1837         return xyz2lab(rgb2xyz(rgb));
  1838     }
  1839 
  1840   private:
  1841     RGBPrime2XYZFunctor<T> rgb2xyz;
  1842     XYZ2LabFunctor<component_type> xyz2lab;
  1843 };
  1844 
  1845 template <class T>
  1846 class FunctorTraits<RGBPrime2LabFunctor<T> >
  1847 : public FunctorTraitsBase<RGBPrime2LabFunctor<T> >
  1848 {
  1849   public:
  1850     typedef VigraTrueType isUnaryFunctor;
  1851 };
  1852 
  1853 /** \brief Convert perceptual uniform CIE L*u*v* into non-linear (gamma corrected) R'G'B'.
  1854 
  1855     <b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>\><br>
  1856     Namespace: vigra
  1857     
  1858     The functor realizes the inverse of the transformation described in vigra::RGBPrime2LuvFunctor
  1859 
  1860     <b> Traits defined:</b>
  1861     
  1862     <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
  1863 */
  1864 template <class T>
  1865 class Luv2RGBPrimeFunctor
  1866 {
  1867     typedef typename NumericTraits<T>::RealPromote component_type;
  1868     
  1869     XYZ2RGBPrimeFunctor<T> xyz2rgb;
  1870     Luv2XYZFunctor<component_type> luv2xyz;
  1871     
  1872   public:
  1873   
  1874         /** the functor's argument type. (Actually, the argument type
  1875             can be any vector type with the same interface. 
  1876             But this cannot be expressed in a typedef.)
  1877         */
  1878     typedef TinyVector<T, 3> argument_type;
  1879   
  1880         /** the functor's result type
  1881         */
  1882     typedef typename XYZ2RGBFunctor<T>::result_type result_type;
  1883   
  1884         /** \deprecated use argument_type and result_type
  1885         */
  1886     typedef typename XYZ2RGBFunctor<T>::result_type value_type;
  1887     
  1888         /** default constructor.
  1889             The maximum value for each RGB component defaults to 255.
  1890         */
  1891     Luv2RGBPrimeFunctor()
  1892     : xyz2rgb(255.0)
  1893     {}
  1894     
  1895         /** constructor
  1896             \arg max - the maximum value for each RGB component
  1897         */
  1898     Luv2RGBPrimeFunctor(component_type max)
  1899     : xyz2rgb(max)
  1900     {}
  1901     
  1902         /** apply the transformation
  1903         */
  1904     template <class V>
  1905     result_type operator()(V const & luv) const
  1906     {
  1907         return xyz2rgb(luv2xyz(luv));
  1908     }
  1909 };
  1910 
  1911 template <class T>
  1912 class FunctorTraits<Luv2RGBPrimeFunctor<T> >
  1913 : public FunctorTraitsBase<Luv2RGBPrimeFunctor<T> >
  1914 {
  1915   public:
  1916     typedef VigraTrueType isUnaryFunctor;
  1917 };
  1918 
  1919 /** \brief Convert perceptual uniform CIE L*a*b* into non-linear (gamma corrected) R'G'B'.
  1920 
  1921     <b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>\><br>
  1922     Namespace: vigra
  1923     
  1924     The functor realizes the inverse of the transformation described in vigra::RGBPrime2LabFunctor
  1925 
  1926     <b> Traits defined:</b>
  1927     
  1928     <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
  1929 */
  1930 template <class T>
  1931 class Lab2RGBPrimeFunctor
  1932 {
  1933     typedef typename NumericTraits<T>::RealPromote component_type;
  1934     
  1935     XYZ2RGBPrimeFunctor<T> xyz2rgb;
  1936     Lab2XYZFunctor<component_type> lab2xyz;
  1937     
  1938   public:
  1939   
  1940         /** the functor's argument type. (Actually, the argument type
  1941             can be any vector type with the same interface. 
  1942             But this cannot be expressed in a typedef.)
  1943         */
  1944     typedef TinyVector<T, 3> argument_type;
  1945   
  1946         /** the functor's result type
  1947         */
  1948     typedef typename XYZ2RGBFunctor<T>::result_type result_type;
  1949   
  1950         /** \deprecated use argument_type and result_type
  1951         */
  1952     typedef typename XYZ2RGBFunctor<T>::result_type value_type;
  1953     
  1954         /** default constructor.
  1955             The maximum value for each RGB component defaults to 255.
  1956         */
  1957     Lab2RGBPrimeFunctor()
  1958     : xyz2rgb(255.0)
  1959     {}
  1960     
  1961         /** constructor
  1962             \arg max - the maximum value for each RGB component
  1963         */
  1964     Lab2RGBPrimeFunctor(component_type max)
  1965     : xyz2rgb(max)
  1966     {}
  1967     
  1968         /** apply the transformation
  1969         */
  1970     template <class V>
  1971     result_type operator()(V const & lab) const
  1972     {
  1973         return xyz2rgb(lab2xyz(lab));
  1974     }
  1975 };
  1976 
  1977 template <class T>
  1978 class FunctorTraits<Lab2RGBPrimeFunctor<T> >
  1979 : public FunctorTraitsBase<Lab2RGBPrimeFunctor<T> >
  1980 {
  1981   public:
  1982     typedef VigraTrueType isUnaryFunctor;
  1983 };
  1984 
  1985 /** \brief Convert non-linear (gamma corrected) R'G'B' into Y'PbPr color difference components.
  1986 
  1987     <b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>\><br>
  1988     Namespace: vigra
  1989     
  1990     According to ITU-R Recommendation BT.601, the functor realizes the transformation
  1991     
  1992     \f[
  1993         \begin{array}{rcl}
  1994         Y' & = & 0.299\enspace R / R_{max} + 0.587\enspace G / G_{max} + 0.114\enspace B / B_{max}\\
  1995         Pb & = & -0.1687358916\enspace R / R_{max} + 0.3312641084\enspace G / G_{max} + 0.5\enspace B / B_{max} \\
  1996         Pr & = & 0.5\enspace R / R_{max} + 0.4186875892\enspace G / G_{max} + 0.0813124108\enspace B / B_{max}
  1997         \end{array}
  1998     \f]
  1999     
  2000     By default, \f$ R_{max} = G_{max} = B_{max} = 255 \f$. This default can be overridden
  2001     in the constructor. Y' represents the <em>luminance</em> ("brightness") of the color, and
  2002     Pb and Pr are the blue (B'-Y') and red (R'-Y') color difference components. 
  2003     The transformation is scaled so that the following bounds apply:
  2004     
  2005     \f[
  2006         \begin{array}{rcl}
  2007         0 \leq & Y' & \leq 1 \\
  2008         -0.5 \leq & Pb & \leq 0.5 \\
  2009         -0.5 \leq & Pr & \leq 0.5
  2010         \end{array}
  2011     \f]
  2012 
  2013     <b> Traits defined:</b>
  2014     
  2015     <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
  2016 */
  2017 template <class T>
  2018 class RGBPrime2YPrimePbPrFunctor
  2019 {
  2020     /*
  2021     Y in [0, 1]
  2022     Pb in [-0.5, 0.5]
  2023     Pr in [-0.5, 0.5]
  2024     maximum saturation: 0.533887
  2025     red = [0.299, -0.168736, 0.5]
  2026     */
  2027   public:
  2028   
  2029         /** the result's component type
  2030         */
  2031     typedef typename NumericTraits<T>::RealPromote component_type;
  2032 
  2033         /** the functor's argument type
  2034         */
  2035     typedef TinyVector<T, 3> argument_type;
  2036   
  2037         /** the functor's result type
  2038         */
  2039     typedef TinyVector<component_type, 3> result_type;
  2040   
  2041         /** \deprecated use argument_type and result_type
  2042         */
  2043     typedef TinyVector<component_type, 3> value_type;
  2044     
  2045         /** default constructor.
  2046             The maximum value for each RGB component defaults to 255.
  2047         */
  2048     RGBPrime2YPrimePbPrFunctor()
  2049     : max_(255.0)
  2050     {}
  2051     
  2052         /** constructor
  2053             \arg max - the maximum value for each RGB component
  2054         */
  2055     RGBPrime2YPrimePbPrFunctor(component_type max)
  2056     : max_(max)
  2057     {}
  2058     
  2059         /** apply the transformation
  2060         */
  2061     template <class V>
  2062     result_type operator()(V const & rgb) const
  2063     {
  2064         typedef detail::RequiresExplicitCast<component_type> Convert;
  2065         component_type red = rgb[0] / max_;
  2066         component_type green = rgb[1] / max_;
  2067         component_type blue = rgb[2] / max_;
  2068         
  2069         result_type result;
  2070         result[0] = Convert::cast(0.299*red + 0.587*green + 0.114*blue);
  2071         result[1] = Convert::cast(-0.1687358916*red - 0.3312641084*green + 0.5*blue);
  2072         result[2] = Convert::cast(0.5*red - 0.4186875892*green - 0.0813124108*blue);
  2073         return result;
  2074     }
  2075 
  2076   private:
  2077     component_type max_;
  2078 };
  2079 
  2080 template <class T>
  2081 class FunctorTraits<RGBPrime2YPrimePbPrFunctor<T> >
  2082 : public FunctorTraitsBase<RGBPrime2YPrimePbPrFunctor<T> >
  2083 {
  2084   public:
  2085     typedef VigraTrueType isUnaryFunctor;
  2086 };
  2087 
  2088 /** \brief Convert Y'PbPr color difference components into non-linear (gamma corrected) R'G'B'.
  2089 
  2090     <b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>\><br>
  2091     Namespace: vigra
  2092     
  2093     The functor realizes the inverse of the transformation described in vigra::RGBPrime2YPrimePbPrFunctor
  2094 
  2095     <b> Traits defined:</b>
  2096     
  2097     <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
  2098 */
  2099 template <class T>
  2100 class YPrimePbPr2RGBPrimeFunctor
  2101 {
  2102     typedef typename NumericTraits<T>::RealPromote component_type;
  2103     
  2104     component_type max_;
  2105     
  2106   public:
  2107   
  2108         /** the functor's argument type. (Actually, the argument type
  2109             can be any vector type with the same interface. 
  2110             But this cannot be expressed in a typedef.)
  2111         */
  2112     typedef TinyVector<T, 3> argument_type;
  2113   
  2114         /** the functor's result type
  2115         */
  2116     typedef TinyVector<T, 3> result_type;
  2117   
  2118         /** \deprecated use argument_type and result_type
  2119         */
  2120     typedef TinyVector<T, 3> value_type;
  2121     
  2122         /** default constructor.
  2123             The maximum value for each RGB component defaults to 255.
  2124         */
  2125     YPrimePbPr2RGBPrimeFunctor()
  2126     : max_(255.0)
  2127     {}
  2128     
  2129         /** constructor
  2130             \arg max - the maximum value for each RGB component
  2131         */
  2132     YPrimePbPr2RGBPrimeFunctor(component_type max)
  2133     : max_(max)
  2134     {}
  2135     
  2136         /** apply the transformation
  2137         */
  2138     template <class V>
  2139     result_type operator()(V const & ypbpr) const
  2140     {
  2141         typedef detail::RequiresExplicitCast<component_type> Convert;
  2142         component_type nred   = Convert::cast(ypbpr[0] + 1.402*ypbpr[2]);
  2143         component_type ngreen = Convert::cast(ypbpr[0] - 0.3441362862*ypbpr[1] - 0.7141362862*ypbpr[2]);
  2144         component_type nblue  = Convert::cast(ypbpr[0] + 1.772*ypbpr[1]);
  2145         return result_type(NumericTraits<T>::fromRealPromote(nred * max_),
  2146                            NumericTraits<T>::fromRealPromote(ngreen * max_),
  2147                            NumericTraits<T>::fromRealPromote(nblue * max_));
  2148     }
  2149 };
  2150 
  2151 template <class T>
  2152 class FunctorTraits<YPrimePbPr2RGBPrimeFunctor<T> >
  2153 : public FunctorTraitsBase<YPrimePbPr2RGBPrimeFunctor<T> >
  2154 {
  2155   public:
  2156     typedef VigraTrueType isUnaryFunctor;
  2157 };
  2158 
  2159 /** \brief Convert non-linear (gamma corrected) R'G'B' into Y'IQ components.
  2160 
  2161     <b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>\><br>
  2162     Namespace: vigra
  2163     
  2164     According to the PAL analog videa standard, the functor realizes the transformation
  2165     
  2166     \f[
  2167         \begin{array}{rcl}
  2168         Y' & = & 0.299\enspace R / R_{max} + 0.587\enspace G / G_{max} + 0.114\enspace B / B_{max}\\
  2169         I & = & 0.596\enspace R / R_{max} - 0.274\enspace G / G_{max} - 0.322\enspace B / B_{max} \\
  2170         Q & = & 0.212\enspace R / R_{max} - 0.523\enspace G / G_{max} + 0.311\enspace B / B_{max}
  2171         \end{array}
  2172     \f]
  2173     
  2174     By default, \f$ R_{max} = G_{max} = B_{max} = 255 \f$. This default can be overridden
  2175     in the constructor. Y' represents the <em>luminance</em> ("brightness") of the color. 
  2176     The transformation is scaled so that the following bounds apply:
  2177     
  2178     \f[
  2179         \begin{array}{rcl}
  2180         0 \leq & Y' & \leq 1 \\
  2181         -0.596 \leq & I & \leq 0.596 \\
  2182         -0.523 \leq & Q & \leq 0.523
  2183         \end{array}
  2184     \f]
  2185 
  2186     <b> Traits defined:</b>
  2187     
  2188     <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
  2189 */
  2190 template <class T>
  2191 class RGBPrime2YPrimeIQFunctor
  2192 {
  2193     /*
  2194     Y in [0, 1]
  2195     I in [-0.596, 0.596]
  2196     Q in [-0.523, 0.523]
  2197     maximum saturation: 0.632582
  2198     red = [0.299, 0.596, 0.212]
  2199     */
  2200   public:
  2201   
  2202         /** the result's component type
  2203         */
  2204     typedef typename NumericTraits<T>::RealPromote component_type;
  2205 
  2206         /** the functor's argument type
  2207         */
  2208     typedef TinyVector<T, 3> argument_type;
  2209   
  2210         /** the functor's result type
  2211         */
  2212     typedef TinyVector<component_type, 3> result_type;
  2213   
  2214         /** \deprecated use argument_type and result_type
  2215         */
  2216     typedef TinyVector<component_type, 3> value_type;
  2217     
  2218         /** default constructor.
  2219             The maximum value for each RGB component defaults to 255.
  2220         */
  2221     RGBPrime2YPrimeIQFunctor()
  2222     : max_(255.0)
  2223     {}
  2224     
  2225         /** constructor
  2226             \arg max - the maximum value for each RGB component
  2227         */
  2228     RGBPrime2YPrimeIQFunctor(component_type max)
  2229     : max_(max)
  2230     {}
  2231     
  2232         /** apply the transformation
  2233         */
  2234     template <class V>
  2235     result_type operator()(V const & rgb) const
  2236     {
  2237         typedef detail::RequiresExplicitCast<component_type> Convert;
  2238         component_type red = rgb[0] / max_;
  2239         component_type green = rgb[1] / max_;
  2240         component_type blue = rgb[2] / max_;
  2241         
  2242         result_type result;
  2243         result[0] = Convert::cast(0.299*red + 0.587*green + 0.114*blue);
  2244         result[1] = Convert::cast(0.596*red - 0.274*green - 0.322*blue);
  2245         result[2] = Convert::cast(0.212*red - 0.523*green + 0.311*blue);
  2246         return result;
  2247     }
  2248 
  2249   private:
  2250     component_type max_;
  2251 };
  2252 
  2253 template <class T>
  2254 class FunctorTraits<RGBPrime2YPrimeIQFunctor<T> >
  2255 : public FunctorTraitsBase<RGBPrime2YPrimeIQFunctor<T> >
  2256 {
  2257   public:
  2258     typedef VigraTrueType isUnaryFunctor;
  2259 };
  2260 
  2261 /** \brief Convert Y'IQ color components into non-linear (gamma corrected) R'G'B'.
  2262 
  2263     <b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>\><br>
  2264     Namespace: vigra
  2265     
  2266     The functor realizes the inverse of the transformation described in vigra::RGBPrime2YPrimeIQFunctor
  2267 
  2268     <b> Traits defined:</b>
  2269     
  2270     <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
  2271 */
  2272 template <class T>
  2273 class YPrimeIQ2RGBPrimeFunctor
  2274 {
  2275     typedef typename NumericTraits<T>::RealPromote component_type;
  2276     
  2277     component_type max_;
  2278     
  2279   public:
  2280   
  2281         /** the functor's argument type. (Actually, the argument type
  2282             can be any vector type with the same interface. 
  2283             But this cannot be expressed in a typedef.)
  2284         */
  2285     typedef TinyVector<T, 3> argument_type;
  2286   
  2287         /** the functor's result type
  2288         */
  2289     typedef TinyVector<T, 3> result_type;
  2290   
  2291         /** \deprecated use argument_type and result_type
  2292         */
  2293     typedef TinyVector<T, 3> value_type;
  2294     
  2295         /** default constructor.
  2296             The maximum value for each RGB component defaults to 255.
  2297         */
  2298     YPrimeIQ2RGBPrimeFunctor()
  2299     : max_(255.0)
  2300     {}
  2301     
  2302         /** constructor
  2303             \arg max - the maximum value for each RGB component
  2304         */
  2305     YPrimeIQ2RGBPrimeFunctor(component_type max)
  2306     : max_(max)
  2307     {}
  2308     
  2309         /** apply the transformation
  2310         */
  2311     template <class V>
  2312     result_type operator()(V const & yiq) const
  2313     {
  2314         typedef detail::RequiresExplicitCast<component_type> Convert;
  2315         component_type nred   = Convert::cast(yiq[0] + 0.9548892043*yiq[1] + 0.6221039350*yiq[2]);
  2316         component_type ngreen = Convert::cast(yiq[0] - 0.2713547827*yiq[1] - 0.6475120259*yiq[2]);
  2317         component_type nblue  = Convert::cast(yiq[0] - 1.1072510054*yiq[1] + 1.7024603738*yiq[2]);
  2318         return result_type(NumericTraits<T>::fromRealPromote(nred * max_),
  2319                            NumericTraits<T>::fromRealPromote(ngreen * max_),
  2320                            NumericTraits<T>::fromRealPromote(nblue * max_));
  2321     }
  2322 };
  2323 
  2324 template <class T>
  2325 class FunctorTraits<YPrimeIQ2RGBPrimeFunctor<T> >
  2326 : public FunctorTraitsBase<YPrimeIQ2RGBPrimeFunctor<T> >
  2327 {
  2328   public:
  2329     typedef VigraTrueType isUnaryFunctor;
  2330 };
  2331 
  2332 /** \brief Convert non-linear (gamma corrected) R'G'B' into Y'UV components.
  2333 
  2334     <b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>\><br>
  2335     Namespace: vigra
  2336     
  2337     According to the NTSC analog videa standard, the functor realizes the transformation
  2338     
  2339     \f[
  2340         \begin{array}{rcl}
  2341         Y' & = & 0.299\enspace R / R_{max} + 0.587\enspace G / G_{max} + 0.114\enspace B / B_{max}\\
  2342         U & = & -0.147\enspace R / R_{max} - 0.289\enspace G / G_{max} + 0.436\enspace B / B_{max} \\
  2343         V & = & 0.615\enspace R / R_{max} - 0.515\enspace G / G_{max} - 0.100\enspace B / B_{max}
  2344         \end{array}
  2345     \f]
  2346     
  2347     By default, \f$ R_{max} = G_{max} = B_{max} = 255 \f$. This default can be overridden
  2348     in the constructor. Y' represents the <em>luminance</em> ("brightness") of the color. 
  2349     The transformation is scaled so that the following bounds apply:
  2350     
  2351     \f[
  2352         \begin{array}{rcl}
  2353         0 \leq & Y' & \leq 1 \\
  2354         -0.436 \leq & U & \leq 0.436 \\
  2355         -0.615 \leq & V & \leq 0.615
  2356         \end{array}
  2357     \f]
  2358 
  2359     <b> Traits defined:</b>
  2360     
  2361     <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
  2362 */
  2363 template <class T>
  2364 class RGBPrime2YPrimeUVFunctor
  2365 {
  2366     /*
  2367     Y in [0, 1]
  2368     U in [-0.436, 0.436]
  2369     V in [-0.615, 0.615]
  2370     maximum saturation: 0.632324
  2371     red = [0.299, -0.147, 0.615]
  2372     */
  2373   public:
  2374   
  2375         /** the result's component type
  2376         */
  2377     typedef typename NumericTraits<T>::RealPromote component_type;
  2378 
  2379         /** the functor's argument type
  2380         */
  2381     typedef TinyVector<T, 3> argument_type;
  2382   
  2383         /** the functor's result type
  2384         */
  2385     typedef TinyVector<component_type, 3> result_type;
  2386   
  2387         /** \deprecated use argument_type and result_type
  2388         */
  2389     typedef TinyVector<component_type, 3> value_type;
  2390     
  2391         /** default constructor.
  2392             The maximum value for each RGB component defaults to 255.
  2393         */
  2394     RGBPrime2YPrimeUVFunctor()
  2395     : max_(255.0)
  2396     {}
  2397     
  2398         /** constructor
  2399             \arg max - the maximum value for each RGB component
  2400         */
  2401     RGBPrime2YPrimeUVFunctor(component_type max)
  2402     : max_(max)
  2403     {}
  2404     
  2405         /** apply the transformation
  2406         */
  2407     template <class V>
  2408     result_type operator()(V const & rgb) const
  2409     {
  2410         typedef detail::RequiresExplicitCast<component_type> Convert;
  2411         component_type red = rgb[0] / max_;
  2412         component_type green = rgb[1] / max_;
  2413         component_type blue = rgb[2] / max_;
  2414         
  2415         result_type result;
  2416         result[0] = Convert::cast(0.299*red + 0.587*green + 0.114*blue);
  2417         result[1] = Convert::cast(-0.1471376975*red - 0.2888623025*green + 0.436*blue);
  2418         result[2] = Convert::cast(0.6149122807*red - 0.5149122807*green - 0.100*blue);
  2419         return result;
  2420     }
  2421 
  2422   private:
  2423     component_type max_;
  2424 };
  2425 
  2426 template <class T>
  2427 class FunctorTraits<RGBPrime2YPrimeUVFunctor<T> >
  2428 : public FunctorTraitsBase<RGBPrime2YPrimeUVFunctor<T> >
  2429 {
  2430   public:
  2431     typedef VigraTrueType isUnaryFunctor;
  2432 };
  2433 
  2434 /** \brief Convert Y'UV color components into non-linear (gamma corrected) R'G'B'.
  2435 
  2436     <b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>\><br>
  2437     Namespace: vigra
  2438     
  2439     The functor realizes the inverse of the transformation described in vigra::RGBPrime2YPrimeUVFunctor
  2440 
  2441     <b> Traits defined:</b>
  2442     
  2443     <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
  2444 */
  2445 template <class T>
  2446 class YPrimeUV2RGBPrimeFunctor
  2447 {
  2448     typedef typename NumericTraits<T>::RealPromote component_type;
  2449     
  2450     component_type max_;
  2451     
  2452   public:
  2453   
  2454         /** the functor's argument type. (Actually, the argument type
  2455             can be any vector type with the same interface. 
  2456             But this cannot be expressed in a typedef.)
  2457         */
  2458     typedef TinyVector<T, 3> argument_type;
  2459   
  2460         /** the functor's result type
  2461         */
  2462     typedef TinyVector<T, 3> result_type;
  2463   
  2464         /** \deprecated use argument_type and result_type
  2465         */
  2466     typedef TinyVector<T, 3> value_type;
  2467     
  2468         /** default constructor.
  2469             The maximum value for each RGB component defaults to 255.
  2470         */
  2471     YPrimeUV2RGBPrimeFunctor()
  2472     : max_(255.0)
  2473     {}
  2474     
  2475         /** constructor
  2476             \arg max - the maximum value for each RGB component
  2477         */
  2478     YPrimeUV2RGBPrimeFunctor(component_type max)
  2479     : max_(max)
  2480     {}
  2481     
  2482         /** apply the transformation
  2483         */
  2484     template <class V>
  2485     result_type operator()(V const & yuv) const
  2486     {
  2487         typedef detail::RequiresExplicitCast<component_type> Convert;
  2488         component_type nred   = Convert::cast(yuv[0] + 1.140*yuv[2]);
  2489         component_type ngreen = Convert::cast(yuv[0] - 0.3946517044*yuv[1] - 0.580681431*yuv[2]);
  2490         component_type nblue  = Convert::cast(yuv[0] + 2.0321100920*yuv[1]);
  2491         return result_type(NumericTraits<T>::fromRealPromote(nred * max_),
  2492                            NumericTraits<T>::fromRealPromote(ngreen * max_),
  2493                            NumericTraits<T>::fromRealPromote(nblue * max_));
  2494     }
  2495 };
  2496 
  2497 template <class T>
  2498 class FunctorTraits<YPrimeUV2RGBPrimeFunctor<T> >
  2499 : public FunctorTraitsBase<YPrimeUV2RGBPrimeFunctor<T> >
  2500 {
  2501   public:
  2502     typedef VigraTrueType isUnaryFunctor;
  2503 };
  2504 
  2505 /** \brief Convert non-linear (gamma corrected) R'G'B' into Y'CbCr color difference components.
  2506 
  2507     <b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>\><br>
  2508     Namespace: vigra
  2509     
  2510     This functor basically applies the same transformation as vigra::RGBPrime2YPrimePbPrFunctor
  2511     but the color components are scaled so that they can be coded as 8 bit intergers with
  2512     minimal loss of information:
  2513     
  2514     \f[
  2515         \begin{array}{rcl}
  2516         16\leq & Y' & \leq 235 \\
  2517         16 \leq & Cb & \leq 240 \\
  2518         16 \leq & Cr & \leq 240
  2519         \end{array}
  2520     \f]
  2521 
  2522     <b> Traits defined:</b>
  2523     
  2524     <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
  2525 */
  2526 template <class T>
  2527 class RGBPrime2YPrimeCbCrFunctor
  2528 {
  2529     /*
  2530     Y in [16, 235]
  2531     Cb in [16, 240]
  2532     Cr in [16, 240]
  2533     maximum saturation: 119.591
  2534     red = [81.481, 90.203, 240]
  2535     */
  2536   public:
  2537   
  2538         /** the result's component type
  2539         */
  2540     typedef typename NumericTraits<T>::RealPromote component_type;
  2541 
  2542         /** the functor's argument type
  2543         */
  2544     typedef TinyVector<T, 3> argument_type;
  2545   
  2546         /** the functor's result type
  2547         */
  2548     typedef TinyVector<component_type, 3> result_type;
  2549   
  2550         /** \deprecated use argument_type and result_type
  2551         */
  2552     typedef TinyVector<component_type, 3> value_type;
  2553     
  2554         /** default constructor.
  2555             The maximum value for each RGB component defaults to 255.
  2556         */
  2557     RGBPrime2YPrimeCbCrFunctor()
  2558     : max_(255.0)
  2559     {}
  2560     
  2561         /** constructor
  2562             \arg max - the maximum value for each RGB component
  2563         */
  2564     RGBPrime2YPrimeCbCrFunctor(component_type max)
  2565     : max_(max)
  2566     {}
  2567     
  2568         /** apply the transformation
  2569         */
  2570     template <class V>
  2571     result_type operator()(V const & rgb) const
  2572     {
  2573         typedef detail::RequiresExplicitCast<component_type> Convert;
  2574         component_type red = rgb[0] / max_;
  2575         component_type green = rgb[1] / max_;
  2576         component_type blue = rgb[2] / max_;
  2577         
  2578         result_type result;
  2579         result[0] = Convert::cast(16.0 + 65.481*red + 128.553*green + 24.966*blue);
  2580         result[1] = Convert::cast(128.0 - 37.79683972*red - 74.20316028*green + 112.0*blue);
  2581         result[2] = Convert::cast(128.0 + 112.0*red - 93.78601998*green - 18.21398002*blue);
  2582         return result;
  2583     }
  2584 
  2585   private:
  2586     component_type max_;
  2587 };
  2588 
  2589 template <class T>
  2590 class FunctorTraits<RGBPrime2YPrimeCbCrFunctor<T> >
  2591 : public FunctorTraitsBase<RGBPrime2YPrimeCbCrFunctor<T> >
  2592 {
  2593   public:
  2594     typedef VigraTrueType isUnaryFunctor;
  2595 };
  2596 
  2597 /** \brief Convert Y'CbCr color difference components into non-linear (gamma corrected) R'G'B'.
  2598 
  2599     <b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>\><br>
  2600     Namespace: vigra
  2601     
  2602     The functor realizes the inverse of the transformation described in vigra::RGBPrime2YPrimeCbCrFunctor
  2603 
  2604     <b> Traits defined:</b>
  2605     
  2606     <tt>FunctorTraits::isUnaryFunctor</tt> is true (<tt>VigraTrueType</tt>)
  2607 */
  2608 template <class T>
  2609 class YPrimeCbCr2RGBPrimeFunctor
  2610 {
  2611     typedef typename NumericTraits<T>::RealPromote component_type;
  2612     
  2613     component_type max_;
  2614     
  2615   public:
  2616   
  2617         /** the functor's argument type. (Actually, the argument type
  2618             can be any vector type with the same interface. 
  2619             But this cannot be expressed in a typedef.)
  2620         */
  2621     typedef TinyVector<T, 3> argument_type;
  2622   
  2623         /** the functor's result type
  2624         */
  2625     typedef TinyVector<T, 3> result_type;
  2626   
  2627         /** \deprecated use argument_type and result_type
  2628         */
  2629     typedef TinyVector<T, 3> value_type;
  2630     
  2631         /** default constructor.
  2632             The maximum value for each RGB component defaults to 255.
  2633         */
  2634     YPrimeCbCr2RGBPrimeFunctor()
  2635     : max_(255.0)
  2636     {}
  2637     
  2638         /** constructor
  2639             \arg max - the maximum value for each RGB component
  2640         */
  2641     YPrimeCbCr2RGBPrimeFunctor(component_type max)
  2642     : max_(max)
  2643     {}
  2644     
  2645         /** apply the transformation
  2646         */
  2647     template <class V>
  2648     result_type operator()(V const & ycbcr) const
  2649     {
  2650         typedef detail::RequiresExplicitCast<component_type> Convert;
  2651         component_type y  = Convert::cast(ycbcr[0] - 16.0);
  2652         component_type cb = Convert::cast(ycbcr[1] - 128.0);
  2653         component_type cr = Convert::cast(ycbcr[2] - 128.0);
  2654         
  2655         component_type nred   = Convert::cast(0.00456621*y + 0.006258928571*cr);
  2656         component_type ngreen = Convert::cast(0.00456621*y - 0.001536322706*cb - 0.003188108420*cr);
  2657         component_type nblue  = Convert::cast(0.00456621*y + 0.007910714286*cb);
  2658         return result_type(NumericTraits<T>::fromRealPromote(nred * max_),
  2659                            NumericTraits<T>::fromRealPromote(ngreen * max_),
  2660                            NumericTraits<T>::fromRealPromote(nblue * max_));
  2661     }
  2662 };
  2663 
  2664 template <class T>
  2665 class FunctorTraits<YPrimeCbCr2RGBPrimeFunctor<T> >
  2666 : public FunctorTraitsBase<YPrimeCbCr2RGBPrimeFunctor<T> >
  2667 {
  2668   public:
  2669     typedef VigraTrueType isUnaryFunctor;
  2670 };
  2671 
  2672 //@}
  2673 
  2674 /*
  2675 Polar coordinates of standard colors:
  2676 =====================================
  2677 
  2678 Lab: black = [320.002, 0, 0]
  2679 Luv: black = [347.827, 0, 0]
  2680 YPbPr: black = [341.352, 0, 0]
  2681 YCbCr: black = [341.352, 0, 0]
  2682 YIQ: black = [19.5807, 0, 0]
  2683 YUV: black = [346.557, 0, 0]
  2684 Lab: red = [1.20391e-05, 0.532406, 0.781353]
  2685 Luv: red = [360, 0.532406, 1]
  2686 YPbPr: red = [360, 0.299, 0.988419]
  2687 YCbCr: red = [360, 0.299, 0.988417]
  2688 YIQ: red = [360, 0.299, 1]
  2689 YUV: red = [360, 0.299, 1]
  2690 Lab: green = [96.0184, 0.877351, 0.895108]
  2691 Luv: green = [115.552, 0.877351, 0.758352]
  2692 YPbPr: green = [123.001, 0.587, 1]
  2693 YCbCr: green = [123.001, 0.587, 0.999996]
  2694 YIQ: green = [137.231, 0.587, 0.933362]
  2695 YUV: green = [137.257, 0.587, 0.933931]
  2696 Lab: blue = [266.287, 0.322957, 0.999997]
  2697 Luv: blue = [253.7, 0.322957, 0.729883]
  2698 YPbPr: blue = [242.115, 0.114, 0.948831]
  2699 YCbCr: blue = [242.115, 0.114, 0.948829]
  2700 YIQ: blue = [243.585, 0.114, 0.707681]
  2701 YUV: blue = [243.639, 0.114, 0.707424]
  2702 Lab: yellow = [62.8531, 0.971395, 0.724189]
  2703 Luv: yellow = [73.7, 0.971395, 0.597953]
  2704 YPbPr: yellow = [62.1151, 0.886, 0.948831]
  2705 YCbCr: yellow = [62.1149, 0.886, 0.948829]
  2706 YIQ: yellow = [63.5851, 0.886, 0.707681]
  2707 YUV: yellow = [63.6393, 0.886, 0.707424]
  2708 Lab: magenta = [288.237, 0.603235, 0.863482]
  2709 Luv: magenta = [295.553, 0.603235, 0.767457]
  2710 YPbPr: magenta = [303.001, 0.413, 1]
  2711 YCbCr: magenta = [303.001, 0.413, 0.999996]
  2712 YIQ: magenta = [317.231, 0.413, 0.933362]
  2713 YUV: magenta = [317.257, 0.413, 0.933931]
  2714 Lab: cyan = [156.378, 0.911133, 0.374577]
  2715 Luv: cyan = [180, 0.911133, 0.402694]
  2716 YPbPr: cyan = [180, 0.701, 0.988419]
  2717 YCbCr: cyan = [180, 0.701, 0.988417]
  2718 YIQ: cyan = [180, 0.701, 1]
  2719 YUV: cyan = [180, 0.701, 1]
  2720 Lab: white = [320.002, 1, 0]
  2721 Luv: white = [14.3606, 1, 3.26357e-06]
  2722 YPbPr: white = [341.352, 1, 0]
  2723 YCbCr: white = [341.352, 1, 0]
  2724 YIQ: white = [154.581, 1, 1.24102e-16]
  2725 YUV: white = [229.992, 1, 9.81512e-17]
  2726 
  2727 */
  2728 
  2729 /** \ingroup ColorConversions
  2730     \defgroup PolarColors Polar Color Coordinates
  2731     
  2732     Transform colors from/to a polar representation (hue, brighness, saturation).
  2733     In many situations, this is more inituitive than direct initialization in a 
  2734     particular color space. The polar coordinates are 
  2735     normalized so that a color angle of 0 degrees is always associated with red
  2736     (green is at about 120 degrees, blue at about 240 degrees - exact values differ
  2737     between color spaces). A saturation of 1 is the highest saturation that any RGB color 
  2738     gets after transformation into the respective color space, and saturation 0 corresponds to
  2739     gray. Thus, different color spaces become somewhat comparable.
  2740 */
  2741 //@{
  2742 /** \brief Init L*a*b* color triple from polar representation.
  2743 
  2744     <b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>\><br>
  2745     Namespace: vigra
  2746     
  2747     <b> Declarations:</b>
  2748     
  2749     \code
  2750     TinyVector<float, 3>
  2751     polar2Lab(double color, double brightness, double saturation);
  2752     
  2753     TinyVector<float, 3>
  2754     polar2Lab(TinyVector<float, 3> const & polar);
  2755     \endcode
  2756     
  2757     \arg color - the color angle in degrees
  2758     \arg brightness - between 0 and 1
  2759     \arg saturation - between 0 and 1
  2760     
  2761     L*a*b* polar coordinates of some important colors:
  2762     
  2763     \code
  2764     black   = [*, 0, 0]    * - arbitrary
  2765     white   = [*, 1, 0]    * - arbitrary
  2766     
  2767     red     = [      0, 0.532406, 0.781353]
  2768     yellow  = [62.8531, 0.971395, 0.724189]
  2769     green   = [96.0184, 0.877351, 0.895108]
  2770     cyan    = [156.378, 0.911133, 0.374577]
  2771     blue    = [266.287, 0.322957, 0.999997]
  2772     magenta = [288.237, 0.603235, 0.863482]
  2773     \endcode
  2774 */
  2775 inline TinyVector<float, 3>
  2776 polar2Lab(double color, double brightness, double saturation)
  2777 {
  2778     double angle = (color+39.9977)/180.0*M_PI;
  2779     double normsat = saturation*133.809;
  2780     
  2781     TinyVector<float, 3> result;
  2782     result[0] = float(100.0*brightness);
  2783     result[1] = float(normsat*VIGRA_CSTD::cos(angle));
  2784     result[2] = float(normsat*VIGRA_CSTD::sin(angle));
  2785     return result;
  2786 }
  2787 
  2788 
  2789 template <class V>
  2790 TinyVector<float, 3>
  2791 polar2Lab(V const & polar)
  2792 {
  2793     return polar2Lab(polar[0], polar[1], polar[2]);
  2794 }
  2795 
  2796 /** \brief Create polar representation form L*a*b*
  2797 
  2798     <b> Declaration:</b>
  2799     
  2800     \code
  2801     namespace vigra {
  2802         TinyVector<float, 3> lab2Polar(TinyVector<float, 3> const & lab);
  2803     }
  2804     \endcode
  2805     
  2806     <b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>\><br>
  2807     Namespace: vigra
  2808     
  2809     This realizes the inverse of the transformation described in 
  2810     \ref polar2Lab().
  2811 */
  2812 template <class V>
  2813 TinyVector<float, 3>
  2814 lab2Polar(V const & lab)
  2815 {
  2816     TinyVector<float, 3> result;
  2817     result[1] = float(lab[0]/100.0);
  2818     double angle = (lab[1] == 0.0 && lab[2] == 0.0)
  2819         ? 0.0
  2820         : VIGRA_CSTD::atan2(lab[2], lab[1])/M_PI*180.0-39.9977;
  2821     result[0] = angle < 0.0 ?
  2822                     float(angle + 360.0) :
  2823                     float(angle);
  2824     result[2] = float(VIGRA_CSTD::sqrt(lab[1]*lab[1] + lab[2]*lab[2])/133.809);
  2825     return result;
  2826 }
  2827 
  2828 /** \brief Init L*u*v* color triple from polar representation.
  2829 
  2830     <b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>\><br>
  2831     Namespace: vigra
  2832     
  2833     <b> Declarations:</b>
  2834     
  2835     \code
  2836     TinyVector<float, 3>
  2837     polar2Luv(double color, double brightness, double saturation);
  2838     
  2839     TinyVector<float, 3>
  2840     polar2Luv(TinyVector<float, 3> const & polar);
  2841     \endcode
  2842     
  2843     \arg color - the color angle in degrees
  2844     \arg brightness - between 0 and 1
  2845     \arg saturation - between 0 and 1
  2846     
  2847     L*u*v* polar coordinates of some important colors:
  2848     
  2849     \code
  2850     black   = [*, 0, 0]    * - arbitrary
  2851     white   = [*, 1, 0]    * - arbitrary
  2852     
  2853     red     = [      0, 0.532406,        1]
  2854     yellow  = [   73.7, 0.971395, 0.597953]
  2855     green   = [115.552, 0.877351, 0.758352]
  2856     cyan    = [  180.0, 0.911133, 0.402694]
  2857     blue    = [  253.7, 0.322957, 0.729883]
  2858     magenta = [295.553, 0.603235, 0.767457]
  2859     \endcode
  2860 */
  2861 inline TinyVector<float, 3>
  2862 polar2Luv(double color, double brightness, double saturation)
  2863 {
  2864     double angle = (color+12.1727)/180.0*M_PI;
  2865     double normsat = saturation*179.04;
  2866     
  2867     TinyVector<float, 3> result;
  2868     result[0] = float(100.0*brightness);
  2869     result[1] = float(normsat*VIGRA_CSTD::cos(angle));
  2870     result[2] = float(normsat*VIGRA_CSTD::sin(angle));
  2871     return result;
  2872 }
  2873 
  2874 template <class V>
  2875 TinyVector<float, 3>
  2876 polar2Luv(V const & polar)
  2877 {
  2878     return polar2Luv(polar[0], polar[1], polar[2]);
  2879 }
  2880 
  2881 /** \brief Create polar representation form L*u*v*
  2882 
  2883     <b> Declaration:</b>
  2884     
  2885     \code
  2886     namespace vigra {
  2887         TinyVector<float, 3> luv2Polar(TinyVector<float, 3> const & luv);
  2888     }
  2889     \endcode
  2890     
  2891     <b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>\><br>
  2892     Namespace: vigra
  2893     
  2894     This realizes the inverse of the transformation described in 
  2895     \ref polar2Luv().
  2896 */
  2897 template <class V>
  2898 TinyVector<float, 3>
  2899 luv2Polar(V const & luv)
  2900 {
  2901     TinyVector<float, 3> result;
  2902     result[1] = float(luv[0]/100.0);
  2903     double angle = (luv[1] == 0.0 && luv[2] == 0.0)
  2904         ? 0.0
  2905         : VIGRA_CSTD::atan2(luv[2], luv[1])/M_PI*180.0-12.1727;
  2906     result[0] = angle < 0.0 ?
  2907                     float(angle + 360.0) :
  2908                     float(angle);
  2909     result[2] = float(VIGRA_CSTD::sqrt(luv[1]*luv[1] + luv[2]*luv[2])/179.04);
  2910     return result;
  2911 }
  2912 
  2913 /** \brief Init Y'PbPr color triple from polar representation.
  2914 
  2915     <b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>\><br>
  2916     Namespace: vigra
  2917     
  2918     <b> Declarations:</b>
  2919     
  2920     \code
  2921     TinyVector<float, 3>
  2922     polar2YPrimePbPr(double color, double brightness, double saturation);
  2923     
  2924     TinyVector<float, 3>
  2925     polar2YPrimePbPr(TinyVector<float, 3> const & polar);
  2926     \endcode
  2927     
  2928     \arg color - the color angle in degrees
  2929     \arg brightness - between 0 and 1
  2930     \arg saturation - between 0 and 1
  2931     
  2932     Y'PbPr polar coordinates of some important colors:
  2933     
  2934     \code
  2935     black   = [*, 0, 0]    * - arbitrary
  2936     white   = [*, 1, 0]    * - arbitrary
  2937     
  2938     red     = [      0,  0.299, 0.988419]
  2939     yellow  = [62.1151,  0.886, 0.948831]
  2940     green   = [123.001,  0.587,        1]
  2941     cyan    = [  180.0,  0.701, 0.988419]
  2942     blue    = [242.115,  0.114, 0.948831]
  2943     magenta = [303.001,  0.413,        1]
  2944     \endcode
  2945 */
  2946 inline TinyVector<float, 3>
  2947 polar2YPrimePbPr(double color, double brightness, double saturation)
  2948 {
  2949     double angle = (color+18.6481)/180.0*M_PI;
  2950     double normsat = saturation*0.533887;
  2951     
  2952     TinyVector<float, 3> result;
  2953     result[0] = float(brightness);
  2954     result[1] = float(-normsat*VIGRA_CSTD::sin(angle));
  2955     result[2] = float(normsat*VIGRA_CSTD::cos(angle));
  2956     return result;
  2957 }
  2958 
  2959 template <class V>
  2960 TinyVector<float, 3>
  2961 polar2YPrimePbPr(V const & polar)
  2962 {
  2963     return polar2YPrimePbPr(polar[0], polar[1], polar[2]);
  2964 }
  2965 
  2966 /** \brief Create polar representation form Y'PbPr
  2967 
  2968     <b> Declaration:</b>
  2969     
  2970     \code
  2971     namespace vigra {
  2972         TinyVector<float, 3> yPrimePbPr2Polar(TinyVector<float, 3> const & ypbpr);
  2973     }
  2974     \endcode
  2975     
  2976     <b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>\><br>
  2977     Namespace: vigra
  2978     
  2979     This realizes the inverse of the transformation described in 
  2980     \ref polar2YPrimePbPr().
  2981 */
  2982 template <class V>
  2983 TinyVector<float, 3>
  2984 yPrimePbPr2Polar(V const & ypbpr)
  2985 {
  2986     TinyVector<float, 3> result;
  2987     result[1] = float(ypbpr[0]);
  2988     double angle = (ypbpr[1] == 0.0 && ypbpr[2] == 0.0)
  2989         ? 0.0
  2990         : VIGRA_CSTD::atan2(-ypbpr[1], ypbpr[2])/M_PI*180.0-18.6481;
  2991     result[0] = angle < 0.0 ?
  2992                     float(angle + 360.0) :
  2993                     float(angle);
  2994     result[2] = float(VIGRA_CSTD::sqrt(ypbpr[1]*ypbpr[1] + ypbpr[2]*ypbpr[2])/0.533887);
  2995     return result;
  2996 }
  2997 
  2998 /** \brief Init Y'CbCr color triple from polar representation.
  2999 
  3000     <b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>\><br>
  3001     Namespace: vigra
  3002     
  3003     <b> Declarations:</b>
  3004     
  3005     \code
  3006     TinyVector<float, 3>
  3007     polar2YPrimeCbCr(double color, double brightness, double saturation);
  3008     
  3009     TinyVector<float, 3>
  3010     polar2YPrimeCbCr(TinyVector<float, 3> const & polar);
  3011     \endcode
  3012     
  3013     \arg color - the color angle in degrees
  3014     \arg brightness - between 0 and 1
  3015     \arg saturation - between 0 and 1
  3016     
  3017     Y'CbCr polar coordinates of some important colors:
  3018     
  3019     \code
  3020     black   = [*, 0, 0]    * - arbitrary
  3021     white   = [*, 1, 0]    * - arbitrary
  3022     
  3023     red     = [      0,  0.299, 0.988419]
  3024     yellow  = [62.1151,  0.886, 0.948831]
  3025     green   = [123.001,  0.587,        1]
  3026     cyan    = [  180.0,  0.701, 0.988419]
  3027     blue    = [242.115,  0.114, 0.948831]
  3028     magenta = [303.001,  0.413,        1]
  3029     \endcode
  3030 */
  3031 inline TinyVector<float, 3>
  3032 polar2YPrimeCbCr(double color, double brightness, double saturation)
  3033 {
  3034     double angle = (color+18.6482)/180.0*M_PI;
  3035     double normsat = saturation*119.591;
  3036     
  3037     TinyVector<float, 3> result;
  3038     result[0] = float(brightness*219.0 + 16.0);
  3039     result[1] = float(-normsat*VIGRA_CSTD::sin(angle)+128.0);
  3040     result[2] = float(normsat*VIGRA_CSTD::cos(angle)+128.0);
  3041     return result;
  3042 }
  3043 
  3044 template <class V>
  3045 TinyVector<float, 3>
  3046 polar2YPrimeCbCr(V const & polar)
  3047 {
  3048     return polar2YPrimeCbCr(polar[0], polar[1], polar[2]);
  3049 }
  3050 
  3051 /** \brief Create polar representation form Y'CbCr
  3052 
  3053     <b> Declaration:</b>
  3054     
  3055     \code
  3056     namespace vigra {
  3057         TinyVector<float, 3> yPrimeCbCr2Polar(TinyVector<float, 3> const & ycbcr);
  3058     }
  3059     \endcode
  3060     
  3061     <b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>\><br>
  3062     Namespace: vigra
  3063     
  3064     This realizes the inverse of the transformation described in 
  3065     \ref polar2YPrimeCbCr().
  3066 */
  3067 template <class V>
  3068 TinyVector<float, 3>
  3069 yPrimeCbCr2Polar(V const & ycbcr)
  3070 {
  3071     TinyVector<float, 3> result;
  3072     result[1] = float((ycbcr[0]-16.0)/219.0);
  3073     double cb = ycbcr[1]-128.0;
  3074     double cr = ycbcr[2]-128.0;
  3075     double angle = (cb == 0.0 && cr == 0.0)
  3076         ? 0.0
  3077         : VIGRA_CSTD::atan2(-cb, cr)/M_PI*180.0-18.6482;
  3078     result[0] = angle < 0.0 ?
  3079                     float(angle + 360.0) :
  3080                     float(angle);
  3081     result[2] = float(VIGRA_CSTD::sqrt(cb*cb + cr*cr)/119.591);
  3082     return result;
  3083 }
  3084 
  3085 /** \brief Init Y'IQ color triple from polar representation.
  3086 
  3087     <b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>\><br>
  3088     Namespace: vigra
  3089     
  3090     <b> Declarations:</b>
  3091     
  3092     \code
  3093     TinyVector<float, 3>
  3094     polar2YPrimeIQ(double color, double brightness, double saturation);
  3095     
  3096     TinyVector<float, 3>
  3097     polar2YPrimeIQ(TinyVector<float, 3> const & polar);
  3098     \endcode
  3099     
  3100     \arg color - the color angle in degrees
  3101     \arg brightness - between 0 and 1
  3102     \arg saturation - between 0 and 1
  3103     
  3104     Y'IQ polar coordinates of some important colors:
  3105     
  3106     \code
  3107     black   = [*, 0, 0]    * - arbitrary
  3108     white   = [*, 1, 0]    * - arbitrary
  3109     
  3110     red     = [      0, 0.299,        1]
  3111     yellow  = [63.5851, 0.886, 0.707681]
  3112     green   = [137.231, 0.587, 0.933362]
  3113     cyan    = [  180.0, 0.701,        1]
  3114     blue    = [243.585, 0.114, 0.707681]
  3115     magenta = [317.231, 0.413, 0.933362]
  3116     \endcode
  3117 */
  3118 inline TinyVector<float, 3>
  3119 polar2YPrimeIQ(double color, double brightness, double saturation)
  3120 {
  3121     double angle = (color-19.5807)/180.0*M_PI;
  3122     double normsat = saturation*0.632582;
  3123     
  3124     TinyVector<float, 3> result;
  3125     result[0] = float(brightness);
  3126     result[1] = float(normsat*VIGRA_CSTD::cos(angle));
  3127     result[2] = float(-normsat*VIGRA_CSTD::sin(angle));
  3128     return result;
  3129 }
  3130 
  3131 template <class V>
  3132 TinyVector<float, 3>
  3133 polar2YPrimeIQ(V const & polar)
  3134 {
  3135     return polar2YPrimeIQ(polar[0], polar[1], polar[2]);
  3136 }
  3137 
  3138 /** \brief Create polar representation form Y'IQ
  3139 
  3140     <b> Declaration:</b>
  3141     
  3142     \code
  3143     namespace vigra {
  3144         TinyVector<float, 3> yPrimeIQ2Polar(TinyVector<float, 3> const & yiq);
  3145     }
  3146     \endcode
  3147     
  3148     <b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>\><br>
  3149     Namespace: vigra
  3150     
  3151     This realizes the inverse of the transformation described in 
  3152     \ref polar2YPrimeIQ().
  3153 */
  3154 template <class V>
  3155 TinyVector<float, 3>
  3156 yPrimeIQ2Polar(V const & yiq)
  3157 {
  3158     TinyVector<float, 3> result;
  3159     result[1] = float(yiq[0]);
  3160     double angle = (yiq[1] == 0.0 && yiq[2] == 0.0)
  3161         ? 0.0
  3162         : VIGRA_CSTD::atan2(-yiq[2], yiq[1])/M_PI*180.0+19.5807;
  3163     result[0] = angle < 0.0 ?
  3164                     float(angle + 360.0) :
  3165                     float(angle);
  3166     result[2] = float(VIGRA_CSTD::sqrt(yiq[1]*yiq[1] + yiq[2]*yiq[2])/0.632582);
  3167     return result;
  3168 }
  3169 
  3170 /** \brief Init Y'UV color triple from polar representation.
  3171 
  3172     <b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>\><br>
  3173     Namespace: vigra
  3174     
  3175     <b> Declarations:</b>
  3176     
  3177     \code
  3178     TinyVector<float, 3>
  3179     polar2YPrimeUV(double color, double brightness, double saturation);
  3180     
  3181     TinyVector<float, 3>
  3182     polar2YPrimeUV(TinyVector<float, 3> const & polar);
  3183     \endcode
  3184     
  3185     \arg color - the color angle in degrees
  3186     \arg brightness - between 0 and 1
  3187     \arg saturation - between 0 and 1
  3188     
  3189     Y'UV polar coordinates of some important colors:
  3190     
  3191     \code
  3192     black   = [*, 0, 0]    * - arbitrary
  3193     white   = [*, 1, 0]    * - arbitrary
  3194     
  3195     red     = [      0, 0.299,        1]
  3196     yellow  = [63.5851, 0.886, 0.707681]
  3197     green   = [137.231, 0.587, 0.933362]
  3198     cyan    = [  180.0, 0.701,        1]
  3199     blue    = [243.585, 0.114, 0.707681]
  3200     magenta = [317.231, 0.413, 0.933362]
  3201     \endcode
  3202 */
  3203 inline TinyVector<float, 3>
  3204 polar2YPrimeUV(double color, double brightness, double saturation)
  3205 {
  3206     double angle = (color+13.4569)/180.0*M_PI;
  3207     double normsat = saturation*0.632324;
  3208     
  3209     TinyVector<float, 3> result;
  3210     result[0] = float(brightness);
  3211     result[1] = float(-normsat*VIGRA_CSTD::sin(angle));
  3212     result[2] = float(normsat*VIGRA_CSTD::cos(angle));
  3213     return result;
  3214 }
  3215 
  3216 template <class V>
  3217 TinyVector<float, 3>
  3218 polar2YPrimeUV(V const & polar)
  3219 {
  3220     return polar2YPrimeUV(polar[0], polar[1], polar[2]);
  3221 }
  3222 
  3223 /** \brief Create polar representation form Y'UV
  3224 
  3225     <b> Declaration:</b>
  3226     
  3227     \code
  3228     namespace vigra {
  3229         TinyVector<float, 3> yPrimeUV2Polar(TinyVector<float, 3> const & yuv);
  3230     }
  3231     \endcode
  3232     
  3233     <b>\#include</b> \<<a href="colorconversions_8hxx-source.html">vigra/colorconversions.hxx</a>\><br>
  3234     Namespace: vigra
  3235     
  3236     This realizes the inverse of the transformation described in 
  3237     \ref polar2YPrimeUV().
  3238 */
  3239 template <class V>
  3240 TinyVector<float, 3>
  3241 yPrimeUV2Polar(V const & yuv)
  3242 {
  3243     TinyVector<float, 3> result;
  3244     result[1] = float(yuv[0]);
  3245     double angle = (yuv[1] == 0.0 && yuv[2] == 0.0)
  3246         ? 0.0
  3247         : VIGRA_CSTD::atan2(-yuv[1], yuv[2])/M_PI*180.0-13.4569;
  3248     result[0] = angle < 0.0 ?
  3249                     float(angle + 360.0) :
  3250                     float(angle);
  3251     result[2] = float(VIGRA_CSTD::sqrt(yuv[1]*yuv[1] + yuv[2]*yuv[2])/0.632324);
  3252     return result;
  3253 }
  3254 
  3255 //@}
  3256 
  3257 } // namespace vigra 
  3258 
  3259 #endif /* VIGRA_COLORCONVERSIONS_HXX */