vigra - vigra/colorconversions.hxx Source File

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

vigra/colorconversions.hxx |

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

© Ullrich Köthe (ullrich.koethe@iwr.uni-heidelberg.de) Heidelberg Collaboratory for Image Processing, University of Heidelberg, Germany | html generated using doxygen and Python vigra 1.9.0 (Tue Nov 6 2012)