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

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