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

vigra/colorconversions.hxx VIGRA

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

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

html generated using doxygen and Python
vigra 1.9.0 (Tue Nov 6 2012)