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

vigra/colorconversions.hxx VIGRA

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