1515namespace color
1616{
1717
18- namespace detail
19- {
20-
21- template <class T >
22- static T f (T t)
23- {
24- return (t > std::pow<T>(6 . / 29 ., 3 .))
25- ? std::pow<T>(t, 1 . / 3 .)
26- : (1 . / 3 .) * std::pow<T>(29 . / 6 ., 2 .) * t + (4 . / 29 .);
27- }
28-
29- template <class T >
30- static T fi (T t)
31- {
32- return (t > 6 . / 29 .) ? std::pow<T>(t, 3 .)
33- : 3 . * std::pow<T>(6 . / 29 ., 2 .) * (t - (4 . / 29 .));
34- }
35- } // namespace detail
36-
3718/* *
3819 * @brief Class that holds color conversion functions with reference to a given
3920 * white point (illuminant).
4021 *
22+ * Only data types of the template form vec<Type, size_t> are supported. Only
23+ * floating points and data types with 3 components are supported.
24+ *
4125 * Most of the conversion and constants were taken from
4226 * http://brucelindbloom.com/index.html (last accessed 2019 April 14th)
4327 * Credits to that guy!
4428 *
45- * @tparam T precision
29+ * @tparam Scalar Data type of each component. Only floating point values
30+ * supported.
31+ *
32+ * @tparam N Number of components. Has to be equal to 3.
33+ *
34+ * @tparam Vec The data structure template class of the form Vec<Scalar, 3UL>
4635 */
47- template <class Scalar , template <class , size_t > class Vec >
36+ template <class Scalar , size_t N, template <class , size_t > class Vec ,
37+ typename std::enable_if_t <
38+ std::is_floating_point<Scalar>::value && (N == 3UL ), int > = 0 >
4839class ColorConverter
4940{
50- using Vec3 = Vec<Scalar, 3UL >;
41+ using Vec3 = Vec<Scalar, N >;
5142
52- public:
53- /* *
54- * @brief Represents conversion source2target.
55- */
56- enum class Conversion
57- {
58- CIELab_2_XYZ,
59- XYZ_2_CIELab,
60- CIELab_2_LCHab, // CIE LCHab
61- LCH_ab_2_CIELab,
62- ryb_2_rgb, // http://en.wikipedia.org/wiki/RYB_color_model,
63- // http://threekings.tk/mirror/ryb_TR.pdf
64- rgb_2_cmy,
65- cmy_2_rgb,
66- rgb_2_XYZ, // uses sRGB chromatic adapted matrix
67- XYZ_2_rgb, // uses sRGB chromatic adapted matrix
68- srgb_2_rgb, // make linear rgb, no chromatic adaption
69- rgb_2_srgb, // make sRGB, with gamma
70- CIELab_2_srgb, // Lab (whitepoint) -> XYZ -> rgb (D65) -> sRGB (D65)
71- srgb_2_CIELab, // sRGB (D65) -> rgb (D65) -> XYZ -> Lab (whitepoint)
72- srgb_2_CIELCHab, // sRGB (D65) -> rgb (D65) -> XYZ -> Lab (whitepoint)
73- CIELCHab_2_srgb, // sRGB (D65) -> rgb (D65) -> XYZ -> Lab (whitepoint)
74- rgb_2_CIELCHab,
75- CIELCHab_2_rgb,
76- CIELab_2_rgb, // Lab (whitepoint) -> XYZ -> rgb (D65)
77- rgb_2_CIELab, // rgb (D65) -> XYZ -> Lab (D50)
78- XYZ_2_srgb, // XYZ -> rgb (D65) -> sRGB (D65)
79- hsv_2_srgb, // [0..1] -> [0..1]
80- srgb_2_hsv, // [0..1] -> [0..1]
81- srgb_2_XYZ, // sRGB (D65) -> XYZ
82- XYZ_2_xyY,
83- xyY_2_XYZ,
84- Luv_2_XYZ,
85- XYZ_2_Luv,
86- Luv_2_LCH_uv, // CIE LCHuv
87- LCH_uv_2_Luv,
88- Yuv_2_rgb, // Y Cb Cr
89- rgb_2_Yuv
90- };
43+ static constexpr Scalar Pi =
44+ static_cast <Scalar>(3.1415926535897932384626433832795 );
9145
46+ public:
9247 static constexpr std::array<Scalar, 3U > IM_ILLUMINANT_A = {1.09850 , 1.00000 ,
9348 0.35585 };
9449 static constexpr std::array<Scalar, 3U > IM_ILLUMINANT_B = {0.99072 , 1.00000 ,
@@ -134,20 +89,18 @@ public:
13489 void lab2xyz (const Vec3& Lab, Vec3& XYZ) const
13590 {
13691 // chromatic adaption, reference white
137- XYZ[1 ] = illuminant[1 ] * detail:: fi ((1 . / 116 .) * (Lab[0 ] + 16 .)); // Y
138- XYZ[0 ] = illuminant[0 ] * detail::fi (( 1 . / 116 .) * (Lab[ 0 ] + 16 .) +
139- (1 . / 500 .) * Lab[1 ]); // X
140- XYZ[2 ] = illuminant[2 ] * detail::fi (( 1 . / 116 .) * (Lab[ 0 ] + 16 .) -
141- (1 . / 200 .) * Lab[2 ]); // Z
92+ XYZ[1 ] = illuminant[1 ] * fi ((1 . / 116 .) * (Lab[0 ] + 16 .)); // Y
93+ XYZ[0 ] = illuminant[0 ] *
94+ fi (( 1 . / 116 .) * (Lab[ 0 ] + 16 .) + (1 . / 500 .) * Lab[1 ]); // X
95+ XYZ[2 ] = illuminant[2 ] *
96+ fi (( 1 . / 116 .) * (Lab[ 0 ] + 16 .) - (1 . / 200 .) * Lab[2 ]); // Z
14297 }
14398
14499 void xyz2lab (const Vec3& XYZ, Vec3& Lab) const
145100 {
146- Lab[0 ] = 116 . * detail::f (XYZ[1 ] / illuminant[1 ]) - 16 .;
147- Lab[1 ] = 500 . * (detail::f (XYZ[0 ] / illuminant[0 ]) -
148- detail::f (XYZ[1 ] / illuminant[1 ]));
149- Lab[2 ] = 200 . * (detail::f (XYZ[1 ] / illuminant[1 ]) -
150- detail::f (XYZ[2 ] / illuminant[2 ]));
101+ Lab[0 ] = 116 . * f (XYZ[1 ] / illuminant[1 ]) - 16 .;
102+ Lab[1 ] = 500 . * (f (XYZ[0 ] / illuminant[0 ]) - f (XYZ[1 ] / illuminant[1 ]));
103+ Lab[2 ] = 200 . * (f (XYZ[1 ] / illuminant[1 ]) - f (XYZ[2 ] / illuminant[2 ]));
151104 }
152105
153106 void lab2LCHab (const Vec3& Lab, Vec3& LCHab) const
@@ -158,17 +111,17 @@ public:
158111 LCHab[2 ] = std::atan2 (Lab[2 ], Lab[1 ]);
159112 if (LCHab[2 ] < 0 )
160113 {
161- LCHab[2 ] += M_PI * 2 .; // [0, 2pi]
114+ LCHab[2 ] += Pi * 2 .; // [0, 2pi]
162115 }
163116 }
164117
165118 void LCHab2lab (const Vec3& LCHab, Vec3& Lab) const
166119 {
167120 Lab[0 ] = LCHab[0 ];
168121 Scalar h = LCHab[2 ];
169- if (h > M_PI )
122+ if (h > Pi )
170123 {
171- h -= M_PI * 2 .; // [0, 2pi]
124+ h -= Pi * 2 .; // [0, 2pi]
172125 }
173126 Lab[1 ] = LCHab[1 ] * std::cos (h);
174127 Lab[2 ] = LCHab[1 ] * std::sin (h);
@@ -546,6 +499,20 @@ public:
546499private:
547500 const std::array<Scalar, 3U > illuminant;
548501
502+ static Scalar f (Scalar t)
503+ {
504+ return (t > std::pow<Scalar>(6 . / 29 ., 3 .))
505+ ? std::pow<Scalar>(t, 1 . / 3 .)
506+ : (1 . / 3 .) * std::pow<Scalar>(29 . / 6 ., 2 .) * t + (4 . / 29 .);
507+ }
508+
509+ static Scalar fi (Scalar t)
510+ {
511+ return (t > 6 . / 29 .)
512+ ? std::pow<Scalar>(t, 3 .)
513+ : 3 . * std::pow<Scalar>(6 . / 29 ., 2 .) * (t - (4 . / 29 .));
514+ }
515+
549516 /* *
550517 * @brief Simple fuzzy comparison of floating point values.
551518 *
@@ -580,8 +547,6 @@ private:
580547 Scalar asample = lab2[1 ];
581548 Scalar bsample = lab2[2 ];
582549
583- constexpr Scalar pi = 3.1415926535897932384626433832795 ;
584-
585550 Scalar Cabstd = std::sqrt (astd * astd + bstd * bstd);
586551 Scalar Cabsample = std::sqrt (asample * asample + bsample * bsample);
587552
@@ -602,11 +567,11 @@ private:
602567 // Ensure hue is between 0 and 2pi
603568 Scalar hpstd = std::atan2 (bstd, apstd);
604569 if (hpstd < 0 )
605- hpstd += 2 . * pi ; // rollover ones that come -ve
570+ hpstd += 2 . * Pi ; // rollover ones that come -ve
606571
607572 Scalar hpsample = std::atan2 (bsample, apsample);
608573 if (hpsample < 0 )
609- hpsample += 2 . * pi ;
574+ hpsample += 2 . * Pi ;
610575 if (fuzzy ((fabs (apsample) + fabs (bsample)), 0 .))
611576 hpsample = 0 .;
612577
@@ -615,10 +580,10 @@ private:
615580
616581 // Computation of hue difference
617582 Scalar dhp = (hpsample - hpstd);
618- if (dhp > pi )
619- dhp -= 2 . * pi ;
620- if (dhp < -pi )
621- dhp += 2 . * pi ;
583+ if (dhp > Pi )
584+ dhp -= 2 . * Pi ;
585+ if (dhp < -Pi )
586+ dhp += 2 . * Pi ;
622587 // set chroma difference to zero if the product of chromas is zero
623588 if (fuzzy (Cpprod, 0 .))
624589 dhp = 0 .;
@@ -640,11 +605,11 @@ private:
640605 // where needed
641606 Scalar hp = (hpstd + hpsample) / 2 .;
642607 // Identify positions for which abs hue diff exceeds 180 degrees
643- if (fabs (hpstd - hpsample) > pi )
644- hp -= pi ;
608+ if (fabs (hpstd - hpsample) > Pi )
609+ hp -= Pi ;
645610 // rollover ones that come -ve
646611 if (hp < 0 )
647- hp += 2 . * pi ;
612+ hp += 2 . * Pi ;
648613
649614 // Check if one of the chroma values is zero, in which case set
650615 // mean hue to the sum which is equivalent to other value
@@ -654,14 +619,14 @@ private:
654619 Scalar Lpm502 = (Lp - 50 .) * (Lp - 50 .);
655620 Scalar Sl = 1 . + 0 .015f * Lpm502 / std::sqrt (20 .0f + Lpm502);
656621 Scalar Sc = 1 . + 0 .045f * Cp;
657- Scalar Ta = 1 . - 0 .17f * std::cos (hp - pi / 6 .) +
622+ Scalar Ta = 1 . - 0 .17f * std::cos (hp - Pi / 6 .) +
658623 0 .24f * std::cos (2 . * hp) +
659- 0 .32f * std::cos (3 . * hp + pi / 30 .) -
660- 0 .20f * std::cos (4 . * hp - 63 . * pi / 180 .);
624+ 0 .32f * std::cos (3 . * hp + Pi / 30 .) -
625+ 0 .20f * std::cos (4 . * hp - 63 . * Pi / 180 .);
661626 Scalar Sh = 1 . + 0 .015f * Cp * Ta;
662627 Scalar delthetarad =
663- (30 . * pi / 180 .) *
664- std::exp (-std::pow (((180 . / pi * hp - 275 .) / 25 .), 2 .));
628+ (30 . * Pi / 180 .) *
629+ std::exp (-std::pow (((180 . / Pi * hp - 275 .) / 25 .), 2 .));
665630 Scalar Rc =
666631 2 . * std::sqrt (std::pow (Cp, 7 .) / (std::pow (Cp, 7 .) + std::pow (25 ., 7 .)));
667632 Scalar RT = -std::sin (2 .0f * delthetarad) * Rc;
0 commit comments