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

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

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

html generated using doxygen and Python
vigra 1.7.1 (Wed Mar 12 2014)