PCL
RGBColorSystem.h
Go to the documentation of this file.
1 // ____ ______ __
2 // / __ \ / ____// /
3 // / /_/ // / / /
4 // / ____// /___ / /___ PixInsight Class Library
5 // /_/ \____//_____/ PCL 2.4.0
6 // ----------------------------------------------------------------------------
7 // pcl/RGBColorSystem.h - Released 2020-07-31T19:33:04Z
8 // ----------------------------------------------------------------------------
9 // This file is part of the PixInsight Class Library (PCL).
10 // PCL is a multiplatform C++ framework for development of PixInsight modules.
11 //
12 // Copyright (c) 2003-2020 Pleiades Astrophoto S.L. All Rights Reserved.
13 //
14 // Redistribution and use in both source and binary forms, with or without
15 // modification, is permitted provided that the following conditions are met:
16 //
17 // 1. All redistributions of source code must retain the above copyright
18 // notice, this list of conditions and the following disclaimer.
19 //
20 // 2. All redistributions in binary form must reproduce the above copyright
21 // notice, this list of conditions and the following disclaimer in the
22 // documentation and/or other materials provided with the distribution.
23 //
24 // 3. Neither the names "PixInsight" and "Pleiades Astrophoto", nor the names
25 // of their contributors, may be used to endorse or promote products derived
26 // from this software without specific prior written permission. For written
27 // permission, please contact info@pixinsight.com.
28 //
29 // 4. All products derived from this software, in any form whatsoever, must
30 // reproduce the following acknowledgment in the end-user documentation
31 // and/or other materials provided with the product:
32 //
33 // "This product is based on software from the PixInsight project, developed
34 // by Pleiades Astrophoto and its contributors (http://pixinsight.com/)."
35 //
36 // Alternatively, if that is where third-party acknowledgments normally
37 // appear, this acknowledgment must be reproduced in the product itself.
38 //
39 // THIS SOFTWARE IS PROVIDED BY PLEIADES ASTROPHOTO AND ITS CONTRIBUTORS
40 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
41 // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PLEIADES ASTROPHOTO OR ITS
43 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
44 // EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, BUSINESS
45 // INTERRUPTION; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; AND LOSS OF USE,
46 // DATA OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
47 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
48 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
49 // POSSIBILITY OF SUCH DAMAGE.
50 // ----------------------------------------------------------------------------
51 
52 #ifndef __PCL_RGBColorSystem_h
53 #define __PCL_RGBColorSystem_h
54 
56 
57 #include <pcl/Defs.h>
58 
59 #include <pcl/Math.h>
60 #include <pcl/ReferenceCounter.h>
61 #include <pcl/Vector.h>
62 
63 #define _1_3 3.333333333333333e-01 // 1/3
64 #define _1_6 1.666666666666667e-01 // 1/6
65 #define _2_3 6.666666666666667e-01 // 2/3
66 #define _16_116 1.379310344827586e-01 // 16/116
67 #define CIEEpsilon 8.856451679035631e-03 // 216/24389
68 #define CIEKappa 9.032962962962963e+02 // 24389/27
69 #define CIEKappa116 7.787037037037037e+00 // CIEKappa/116
70 #define sRGBEpsilon 0.04045
71 #define sRGBEpsilonInv 0.0031308
72 #define sRGBGamma 2.4
73 #define sRGBGammaInv 4.166666666666667e-01 //1/sRGBGamma
74 
75 namespace pcl
76 {
77 
78 // ----------------------------------------------------------------------------
79 
104 class PCL_CLASS RGBColorSystem
105 {
106 public:
107 
112  typedef double sample;
113 
123  : m_data( RGBColorSystem::sRGB.m_data )
124  {
125  if ( m_data != nullptr )
126  m_data->Attach();
127  else
128  m_data = new Data( 2.2F/*gamma*/, true/*issRGB*/, sRGB_x, sRGB_y, sRGB_Y );
129  }
130 
138  : m_data( s.m_data )
139  {
140  m_data->Attach();
141  }
142 
162  RGBColorSystem( float gamma, bool issRGB, const FVector& x, const FVector& y, const FVector& Y )
163  {
164  m_data = new Data( gamma, issRGB, x, y, Y );
165  }
166 
186  RGBColorSystem( float gamma, bool issRGB, const float* x, const float* y, const float* Y )
187  {
188  m_data = new Data( gamma, issRGB, FVector( x, 3 ), FVector( y, 3 ), FVector( Y, 3 ) );
189  }
190 
198  virtual ~RGBColorSystem()
199  {
200  if ( m_data != nullptr )
201  {
202  DetachFromData();
203  m_data = nullptr;
204  }
205  }
206 
211  bool IsUnique() const
212  {
213  return m_data->IsUnique();
214  }
215 
223  bool IsAliasOf( const RGBColorSystem& s ) const
224  {
225  return m_data == s.m_data;
226  }
227 
237  {
238  if ( !IsUnique() )
239  {
240  Data* newData = new Data( *m_data );
241  DetachFromData();
242  m_data = newData;
243  }
244  }
245 
253  float Gamma() const
254  {
255  return m_data->gamma;
256  }
257 
261  bool IsSRGB() const
262  {
263  return m_data->issRGB;
264  }
265 
271  bool IsLinear() const
272  {
273  return m_data->isLinear;
274  }
275 
287  const Vector& RGBToXYZMatrix() const
288  {
289  return m_data->M;
290  }
291 
303  const Vector& XYZToRGBMatrix() const
304  {
305  return m_data->M_;
306  }
307 
315  {
316  return m_data->x;
317  }
318 
326  {
327  return m_data->y;
328  }
329 
337  {
338  return m_data->Y;
339  }
340 
346  friend bool operator ==( const RGBColorSystem& S1, const RGBColorSystem& S2 )
347  {
348  return S1.IsAliasOf( S2 ) || *S1.m_data == *S2.m_data;
349  }
350 
359  void Assign( const RGBColorSystem& s )
360  {
361  s.m_data->Attach();
362  DetachFromData();
363  m_data = s.m_data;
364  }
365 
371  RGBColorSystem& operator =( const RGBColorSystem& s )
372  {
373  Assign( s );
374  return *this;
375  }
376 
385  sample Lightness( sample R, sample G, sample B ) const
386  {
387  XYZLab( R = m_data->CIEY( R, G, B ) );
388  return sample( (1.16 * R) - 0.16 );
389  }
390 
391  // ### Deprecated - retained for compatibility -> suppress in PCL 2.x
392  sample Luminance( sample R, sample G, sample B ) const
393  {
394  return Lightness( R, G, B );
395  }
396 
400  sample CIEL( sample R, sample G, sample B ) const
401  {
402  return Lightness( R, G, B );
403  }
404 
414  void RGBToGray( sample& K, sample R, sample G, sample B ) const
415  {
416  K = Lightness( R, G, B );
417  }
418 
428  sample Value( sample R, sample G, sample B ) const
429  {
430  return pcl::Max( pcl::Max( R, G ), B );
431  }
432 
445  sample Intensity( sample R, sample G, sample B ) const
446  {
447  return sample( 0.5*( pcl::Min( pcl::Min( R, G ), B )
448  + pcl::Max( pcl::Max( R, G ), B ) ) );
449  }
450 
464  sample Hue( sample R, sample G, sample B ) const
465  {
466  sample max = pcl::Max( pcl::Max( R, G ), B );
467  sample delta = max - pcl::Min( pcl::Min( R, G ), B );
468  if ( delta != 0 )
469  {
470  sample H;
471  if ( R == max )
472  H = (G - B)/delta; // between yellow & magenta
473  else if ( G == max )
474  H = 2 + (B - R)/delta; // between cyan & yellow
475  else
476  H = 4 + (R - G)/delta; // between magenta & cyan
477 
478  H /= 6;
479  if ( H < 0 )
480  H += 1;
481  return H;
482  }
483 
484  // Achromatic case: R = G = B
485  // Hue is undefined (H is set to 0 conventionally)
486  return 0;
487  }
488 
498  sample HSVSaturation( sample R, sample G, sample B ) const
499  {
500  sample max = pcl::Max( pcl::Max( R, G ), B );
501  sample delta = max - pcl::Min( pcl::Min( R, G ), B );
502  return sample( (1.0 + max != 1.0) ? delta/max : 0.0 );
503  }
504 
517  sample HSISaturation( sample R, sample G, sample B ) const
518  {
519  sample min = pcl::Min( pcl::Min( R, G ), B );
520  sample max = pcl::Max( pcl::Max( R, G ), B );
521  sample delta = max - min;
522  if ( delta != 0 )
523  {
524  sample sum = min + max;
525  return delta/((sum <= 1) ? sum : 2-sum);
526  }
527  return sample( 0 );
528  }
529 
538  sample Saturation( sample R, sample G, sample B ) const
539  {
540  return HSVSaturation( R, G, B );
541  }
542 
559  static void RGBToHSV( sample& H, sample& S, sample& V, sample R, sample G, sample B )
560  {
561  V = pcl::Max( pcl::Max( R, G ), B ); // V = Value( R, G, B );
562 
563  sample delta = V - pcl::Min( pcl::Min( R, G ), B );
564  if ( delta != 0 )
565  {
566  S = delta/V;
567 
568  if ( R == V )
569  H = (G - B)/delta; // between yellow & magenta
570  else if ( G == V )
571  H = 2 + (B - R)/delta; // between cyan & yellow
572  else
573  H = 4 + (R - G)/delta; // between magenta & cyan
574 
575  H /= 6;
576  if ( H < 0 )
577  H += 1;
578  }
579  else
580  {
581  // Achromatic case: R = G = B
582  // S = 0, and H is undefined (H is set to 0 conventionally)
583  S = H = 0;
584  }
585  }
586 
606  static void RGBToHSI( sample& H, sample& S, sample& I, sample R, sample G, sample B )
607  {
608  sample min = pcl::Min( pcl::Min( R, G ), B );
609  sample max = pcl::Max( pcl::Max( R, G ), B );
610  sample delta = max - min;
611  sample sum = min + max;
612 
613  I = 0.5*sum;
614 
615  if ( delta != 0 )
616  {
617  S = delta/((sum <= 1) ? sum : 2-sum);
618 
619  if ( R == max )
620  H = (G - B)/delta; // between yellow & magenta
621  else if ( G == max )
622  H = 2 + (B - R)/delta; // between cyan & yellow
623  else
624  H = 4 + (R - G)/delta; // between magenta & cyan
625 
626  H /= 6;
627  if ( H < 0 )
628  H += 1;
629  }
630  else
631  {
632  // Achromatic case: R = G = B
633  // S = 0, and H is undefined (H is set to 0 conventionally)
634  S = H = 0;
635  }
636  }
637 
655  void RGBToHSVL( sample& H, sample& S, sample& V, sample& L, sample R, sample G, sample B ) const
656  {
657  RGBToHSV( H, S, V, R, G, B );
658  L = Lightness( R, G, B );
659  }
660 
681  void RGBToHSIL( sample& H, sample& S, sample& I, sample& L, sample R, sample G, sample B ) const
682  {
683  RGBToHSI( H, S, I, R, G, B );
684  L = Lightness( R, G, B );
685  }
686 
695  void RGBToCIEXYZ( sample& X, sample& Y, sample& Z, sample R, sample G, sample B ) const
696  {
697  m_data->RGBToCIEXYZ( X, Y, Z, R, G, B );
698  }
699 
712  void RGBToCIEXZ( sample& X, sample& Z, sample R, sample G, sample B ) const
713  {
714  m_data->RGBToCIEXZ( X, Z, R, G, B );
715  }
716 
722  sample CIEX( sample R, sample G, sample B ) const
723  {
724  return m_data->CIEX( R, G, B );
725  }
726 
732  sample CIEY( sample R, sample G, sample B ) const
733  {
734  return m_data->CIEY( R, G, B );
735  }
736 
742  sample CIEZ( sample R, sample G, sample B ) const
743  {
744  return m_data->CIEZ( R, G, B );
745  }
746 
752  sample CIEYToCIEL( sample Y ) const
753  {
754  XYZLab( Y ); return 1.16*Y - 0.16;
755  }
756 
762  sample CIELToCIEY( sample L ) const
763  {
764  LabXYZ( L = (L + 0.16)/1.16 ); return L;
765  }
766 
775  void RGBToCIELab( sample& L, sample& a, sample& b, sample R, sample G, sample B ) const
776  {
777  sample X, Y, Z;
778  m_data->RGBToCIEXYZ( X, Y, Z, R, G, B );
779  CIEXYZToCIELab( L, a, b, X, Y, Z );
780  }
781 
794  void RGBToCIEab( sample& a, sample& b, sample R, sample G, sample B ) const
795  {
796  sample X, Y, Z;
797  m_data->RGBToCIEXYZ( X, Y, Z, R, G, B );
798  XYZLab( X ); XYZLab( Y ); XYZLab( Z );
799  a = (5*(X - Y) + m_data->abOffset)/m_data->abDelta;
800  b = (2*(Y - Z) + m_data->abOffset)/m_data->abDelta;
801  }
802 
812  sample CIEa( sample R, sample G, sample B ) const
813  {
814  sample X, Y;
815  m_data->RGBToCIEXY( X, Y, R, G, B );
816  XYZLab( X ); XYZLab( Y );
817  return (5*(X - Y) + m_data->abOffset)/m_data->abDelta;
818  }
819 
829  sample CIEb( sample R, sample G, sample B ) const
830  {
831  sample Y, Z;
832  m_data->RGBToCIEYZ( Y, Z, R, G, B );
833  XYZLab( Y ); XYZLab( Z );
834  return (2*(Y - Z) + m_data->abOffset)/m_data->abDelta;
835  }
836 
846  sample CIEc( sample R, sample G, sample B ) const
847  {
848  sample X, Y, Z;
849  m_data->RGBToCIEXYZ( X, Y, Z, R, G, B );
850  XYZLab( X ); XYZLab( Y ); XYZLab( Z );
851  sample a = 5*(X - Y);
852  sample b = 2*(Y - Z);
853  return pcl::Sqrt( a*a + b*b )/m_data->cDelta;
854  }
855 
869  sample CIEh( sample R, sample G, sample B ) const
870  {
871  return CIEhr( R, G, B )/Const<sample>::_2pi();
872  }
873 
885  sample CIEhr( sample R, sample G, sample B ) const
886  {
887  sample X, Y, Z;
888  m_data->RGBToCIEXYZ( X, Y, Z, R, G, B );
889  XYZLab( X ); XYZLab( Y ); XYZLab( Z );
890  sample h = ArcTan( 2*(Y - Z), 5*(X - Y) );
891  if ( h < 0 )
892  h += Const<sample>::_2pi();
893  return h;
894  }
895 
904  void RGBToCIELch( sample& L, sample& c, sample& h, sample R, sample G, sample B ) const
905  {
906  sample X, Y, Z;
907  m_data->RGBToCIEXYZ( X, Y, Z, R, G, B );
908  XYZLab( X ); XYZLab( Y ); XYZLab( Z );
909  L = sample( (1.16 * Y) - 0.16 );
910  sample a = 5*(X - Y);
911  sample b = 2*(Y - Z);
912  c = pcl::Sqrt( a*a + b*b )/m_data->cDelta;
913  h = ArcTan( b, a );
914  if ( h < 0 )
915  h += Const<sample>::_2pi();
916  h /= Const<sample>::_2pi();
917  }
918 
935  void RGBToCIELabc( sample& L, sample& a, sample& b, sample& c, sample R, sample G, sample B ) const
936  {
937  sample X, Y, Z;
938  m_data->RGBToCIEXYZ( X, Y, Z, R, G, B );
939  XYZLab( X ); XYZLab( Y ); XYZLab( Z );
940  L = sample( (1.16 * Y) - 0.16 );
941  a = ((X = 5*(X - Y)) + m_data->abOffset)/m_data->abDelta;
942  b = ((Z = 2*(Y - Z)) + m_data->abOffset)/m_data->abDelta;
943  c = pcl::Sqrt( X*X + Z*Z )/m_data->cDelta;
944  }
945 
961  static void HSVToRGB( sample& R, sample& G, sample& B, sample H, sample S, sample V )
962  {
963  if ( S != 0 )
964  {
965  H *= 6; // degrees -> quadrant index
966 
967  int i = TruncInt( Floor( H ) ); // i = sector 0 to 5
968  sample f = H - i; // f = fractional part of H
969  sample p = V*(1 - S);
970  sample q = V*(1 - S*f);
971  sample t = V*(1 - S*(1 - f));
972 
973  switch( i )
974  {
975  case 0: R = V; G = t; B = p; break;
976  case 1: R = q; G = V; B = p; break;
977  case 2: R = p; G = V; B = t; break;
978  case 3: R = p; G = q; B = V; break;
979  case 4: R = t; G = p; B = V; break;
980  case 5: R = V; G = p; B = q; break;
981  default: R = G = B = V; break; // out-of-range H argument
982  }
983  }
984  else
985  R = G = B = V; // achromatic
986  }
987 
1015  void HSVLToRGB( sample& R, sample& G, sample& B, sample H, sample S, sample V, sample L ) const
1016  {
1017  HSVToRGB( R, G, B, H, S, V );
1018 #define a H
1019 #define b S
1020  RGBToCIEab( a, b, R, G, B );
1021  CIELabToRGB( R, G, B, L, a, b );
1022 #undef a
1023 #undef b
1024  }
1025 
1044  static void HSIToRGB( sample& R, sample& G, sample& B, sample H, sample S, sample I )
1045  {
1046  if ( S != 0 )
1047  {
1048  sample v2 = (I < 0.5) ? I*(1 + S) : I + S - S*I;
1049  sample v1 = I+I - v2;
1050  R = HSIH2RGB( v1, v2, H+_1_3 );
1051  G = HSIH2RGB( v1, v2, H );
1052  B = HSIH2RGB( v1, v2, H-_1_3 );
1053  }
1054  else
1055  R = G = B = I; // achromatic
1056  }
1057 
1088  void HSILToRGB( sample& R, sample& G, sample& B, sample H, sample S, sample I, sample L ) const
1089  {
1090  HSIToRGB( R, G, B, H, S, I );
1091 #define a H
1092 #define b S
1093  RGBToCIEab( a, b, R, G, B );
1094  CIELabToRGB( R, G, B, L, a, b );
1095 #undef a
1096 #undef b
1097  }
1098 
1107  void CIEXYZToRGB( sample& R, sample& G, sample& B, sample X, sample Y, sample Z ) const
1108  {
1109  m_data->CIEXYZToRGB( R, G, B, X, Y, Z );
1110  }
1111 
1120  void CIEXYZToCIELab( sample& L, sample& a, sample& b, sample X, sample Y, sample Z ) const
1121  {
1122  XYZLab( X ); XYZLab( Y ); XYZLab( Z );
1123  L = sample( (1.16 * Y) - 0.16 );
1124  a = (5*(X - Y) + m_data->abOffset)/m_data->abDelta;
1125  b = (2*(Y - Z) + m_data->abOffset)/m_data->abDelta;
1126  }
1127 
1136  void CIELabToRGB( sample& R, sample& G, sample& B, sample L, sample a, sample b ) const
1137  {
1138  sample X, Y, Z;
1139  CIELabToCIEXYZ( X, Y, Z, L, a, b );
1140  m_data->CIEXYZToRGB( R, G, B, X, Y, Z );
1141  }
1142 
1151  void CIELabToCIEXYZ( sample& X, sample& Y, sample& Z, sample L, sample a, sample b ) const
1152  {
1153  Y = sample( (L + 0.16)/1.16 );
1154  X = (m_data->abDelta*a - m_data->abOffset)/5 + Y;
1155  Z = Y - (m_data->abDelta*b - m_data->abOffset)/2;
1156  LabXYZ( X ); LabXYZ( Y ); LabXYZ( Z );
1157  }
1158 
1171  void CIELabToCIELch( sample& L, sample& c, sample& h, sample L0, sample a, sample b ) const
1172  {
1173  L = L0;
1174  a = m_data->abDelta*a - m_data->abOffset;
1175  b = m_data->abDelta*b - m_data->abOffset;
1176  c = Sqrt( a*a + b*b )/m_data->cDelta;
1177  h = ArcTan( b, a )/Const<sample>::pi();
1178  if ( h < 0 )
1179  h += 1;
1180  }
1181 
1190  void CIELchToRGB( sample& R, sample& G, sample& B, sample L, sample c, sample h ) const
1191  {
1192  sample a, b;
1193  SinCos( h*Const<sample>::_2pi(), b, a );
1194  c *= m_data->cDelta;
1195  a *= c;
1196  b *= c;
1197  sample Y = sample( (L + 0.16)/1.16 );
1198  sample X = a/5 + Y;
1199  sample Z = Y - b/2;
1200  LabXYZ( X ); LabXYZ( Y ); LabXYZ( Z );
1201  m_data->CIEXYZToRGB( R, G, B, X, Y, Z );
1202  }
1203 
1216  void CIELchToCIELab( sample& L, sample& a, sample& b, sample L0, sample c, sample h ) const
1217  {
1218  L = L0;
1219  SinCos( h*Const<sample>::_2pi(), b, a );
1220  c *= m_data->cDelta;
1221  a = (c*a + m_data->abOffset)/m_data->abDelta;
1222  b = (c*b + m_data->abOffset)/m_data->abDelta;
1223  }
1224 
1225 protected:
1226 
1227  struct Data : public ReferenceCounter
1228  {
1229  float gamma, gammaInv; // gamma, 1/gamma
1230  bool issRGB; // true if sRGB gamma function is being used
1231  bool isLinear; // true if gamma=1.0 and is not sRGB, for optimization
1232 
1233  /*
1234  * Chromaticity coordinates w.r.t. the D50 reference white
1235  */
1236  FVector x, y;
1237 
1238  /*
1239  * Luminance coefficients w.r.t. the D50 reference white
1240  */
1241  FVector Y;
1242 
1243  /*
1244  * RGB <-> CIE XYZ transformation matrices
1245  */
1246  Vector M; // RGB -> CIE XYZ
1247  Vector M_; // CIE XYZ -> RGB
1248 
1249  /*
1250  * Normalization coefficients for X and Z coordinates
1251  */
1252  sample mX, mZ;
1253 
1254  /*
1255  * Normalization of CIE a*, b* and c* components
1256  */
1257  sample abOffset;
1258  sample abDelta;
1259  sample cDelta;
1260 
1261  Data( float, bool, const FVector&, const FVector&, const FVector& );
1262  Data( float, bool, const float*, const float*, const float* );
1263  Data( const Data& ) = default;
1264 
1265  void Initialize();
1266 
1267  bool operator ==( const RGBColorSystem::Data& data ) const
1268  {
1269  return gamma == data.gamma &&
1270  issRGB == data.issRGB &&
1271  Y == data.Y &&
1272  x == data.x && y == data.y;
1273  }
1274 
1275  /*
1276  * Primary gamma functions
1277  */
1278 
1279  void LinearRGB( sample& x ) const
1280  {
1281  x = issRGB ?
1282  ((x > sRGBEpsilon) ?
1283  Pow( sample( (x + 0.055)/1.055 ), sample( sRGBGamma ) ) : sample( x/12.92 )) :
1284  Pow( x, sample( gamma ) );
1285  }
1286 
1287  void GammaRGB( sample& x ) const
1288  {
1289  x = issRGB ?
1290  ((x > sRGBEpsilonInv) ?
1291  sample( 1.055*Pow( x, sample( sRGBGammaInv ) ) - 0.055 ) : sample( 12.92*x )) :
1292  Pow( x, sample( gammaInv ) );
1293  }
1294 
1295  /*
1296  * Primary linear transformations
1297  */
1298 
1299  void RGBToCIEXYZ( sample& X, sample& Y, sample& Z, sample R, sample G, sample B ) const
1300  {
1301  if ( !isLinear )
1302  {
1303  LinearRGB( R );
1304  LinearRGB( G );
1305  LinearRGB( B );
1306  }
1307 
1308  X = Range( (R*M[0] + G*M[1] + B*M[2])/mX );
1309  Y = Range( R*M[3] + G*M[4] + B*M[5] );
1310  Z = Range( (R*M[6] + G*M[7] + B*M[8])/mZ );
1311  }
1312 
1313  void CIEXYZToRGB( sample& R, sample& G, sample& B, sample X, sample Y, sample Z ) const
1314  {
1315  X *= mX;
1316  Z *= mZ;
1317  R = Range( X*M_[0] + Y*M_[1] + Z*M_[2] );
1318  G = Range( X*M_[3] + Y*M_[4] + Z*M_[5] );
1319  B = Range( X*M_[6] + Y*M_[7] + Z*M_[8] );
1320 
1321  if ( !isLinear )
1322  {
1323  GammaRGB( R );
1324  GammaRGB( G );
1325  GammaRGB( B );
1326  }
1327  }
1328 
1329  /*
1330  * Utility functions for fast partial luminance/chrominance calculations
1331  */
1332 
1333  sample CIEX( sample R, sample G, sample B ) const
1334  {
1335  if ( !isLinear )
1336  {
1337  LinearRGB( R );
1338  LinearRGB( G );
1339  LinearRGB( B );
1340  }
1341 
1342  return Range( (R*M[0] + G*M[1] + B*M[2])/mX );
1343  }
1344 
1345  sample CIEY( sample R, sample G, sample B ) const
1346  {
1347  if ( !isLinear )
1348  {
1349  LinearRGB( R );
1350  LinearRGB( G );
1351  LinearRGB( B );
1352  }
1353 
1354  return Range( R*M[3] + G*M[4] + B*M[5] );
1355  }
1356 
1357  sample CIEZ( sample R, sample G, sample B ) const
1358  {
1359  if ( !isLinear )
1360  {
1361  LinearRGB( R );
1362  LinearRGB( G );
1363  LinearRGB( B );
1364  }
1365 
1366  return Range( (R*M[6] + G*M[7] + B*M[8])/mZ );
1367  }
1368 
1369  void RGBToCIEXY( sample& X, sample& Y, sample R, sample G, sample B ) const
1370  {
1371  if ( !isLinear )
1372  {
1373  LinearRGB( R );
1374  LinearRGB( G );
1375  LinearRGB( B );
1376  }
1377 
1378  X = Range( (R*M[0] + G*M[1] + B*M[2])/mX );
1379  Y = Range( R*M[3] + G*M[4] + B*M[5] );
1380  }
1381 
1382  void RGBToCIEYZ( sample& Y, sample& Z, sample R, sample G, sample B ) const
1383  {
1384  if ( !isLinear )
1385  {
1386  LinearRGB( R );
1387  LinearRGB( G );
1388  LinearRGB( B );
1389  }
1390 
1391  Y = Range( R*M[3] + G*M[4] + B*M[5] );
1392  Z = Range( (R*M[6] + G*M[7] + B*M[8])/mZ );
1393  }
1394 
1395  void RGBToCIEXZ( sample& X, sample& Z, sample R, sample G, sample B ) const
1396  {
1397  if ( !isLinear )
1398  {
1399  LinearRGB( R );
1400  LinearRGB( G );
1401  LinearRGB( B );
1402  }
1403 
1404  X = Range( (R*M[0] + G*M[1] + B*M[2])/mX );
1405  Z = Range( (R*M[6] + G*M[7] + B*M[8])/mZ );
1406  }
1407 
1408  static bool ValidateParameters( const FVector& x, const FVector& y, const FVector& Y );
1409 
1410  static sample Range( const sample& x ) // Ensure nominal [0,1] range
1411  {
1412  return pcl::Range( x, sample( 0 ), sample( 1 ) );
1413  }
1414  };
1415 
1416  Data* m_data = nullptr;
1417 
1418  void DetachFromData()
1419  {
1420  if ( !m_data->Detach() )
1421  delete m_data;
1422  }
1423 
1424  static void XYZLab( sample& x )
1425  {
1426  x = (x > CIEEpsilon) ? Pow( x, sample( _1_3 ) ) : sample( CIEKappa116*x + _16_116 );
1427  }
1428 
1429  static void LabXYZ( sample& x )
1430  {
1431  sample x3 = x*x*x;
1432  x = (x3 > CIEEpsilon) ? x3 : sample( (x - _16_116)/CIEKappa116 );
1433  }
1434 
1435  static sample HSIH2RGB( sample v1, sample v2, sample H )
1436  {
1437  if ( H < 0 )
1438  H += 1;
1439  else if ( H > 1 )
1440  H -= 1;
1441 
1442  if ( H < _1_6 )
1443  return v1 + 6*H*(v2 - v1);
1444 
1445  if ( H < 0.5 )
1446  return v2;
1447 
1448  if ( H < _2_3 )
1449  return v1 + 6*(_2_3 - H)*(v2 - v1);
1450 
1451  return v1;
1452  }
1453 
1454  friend struct Data;
1455 
1456 public:
1457 
1461  static const float sRGB_x[ 3 ];
1462 
1466  static const float sRGB_y[ 3 ];
1467 
1471  static const float sRGB_Y[ 3 ];
1472 
1476  static const RGBColorSystem sRGB;
1477 
1478 #ifdef __PCL_WITH_STANDARD_RGB_WORKING_SPACES
1479 
1480  /*
1481  * Adobe RGB 1998
1482  */
1483  static const float AdobeRGB1998_x[ 3 ];
1484  static const float AdobeRGB1998_y[ 3 ];
1485  static const float AdobeRGB1998_Y[ 3 ];
1486 
1487  /*
1488  * Apple RGB
1489  */
1490  static const float AppleRGB_x[ 3 ];
1491  static const float AppleRGB_y[ 3 ];
1492  static const float AppleRGB_Y[ 3 ];
1493 
1494  /*
1495  * Best RGB
1496  */
1497  static const float BestRGB_x[ 3 ];
1498  static const float BestRGB_y[ 3 ];
1499  static const float BestRGB_Y[ 3 ];
1500 
1501  /*
1502  * Beta RGB (by Bruce Lindbloom)
1503  */
1504  static const float BetaRGB_x[ 3 ];
1505  static const float BetaRGB_y[ 3 ];
1506  static const float BetaRGB_Y[ 3 ];
1507 
1508  /*
1509  * Bruce RGB
1510  */
1511  static const float BruceRGB_x[ 3 ];
1512  static const float BruceRGB_y[ 3 ];
1513  static const float BruceRGB_Y[ 3 ];
1514 
1515  /*
1516  * CIE RGB
1517  */
1518  static const float CIERGB_x[ 3 ];
1519  static const float CIERGB_y[ 3 ];
1520  static const float CIERGB_Y[ 3 ];
1521 
1522  /*
1523  * Color Match RGB
1524  */
1525  static const float ColorMatchRGB_x[ 3 ];
1526  static const float ColorMatchRGB_y[ 3 ];
1527  static const float ColorMatchRGB_Y[ 3 ];
1528 
1529  /*
1530  * NTSC RGB
1531  */
1532  static const float NTSCRGB_x[ 3 ];
1533  static const float NTSCRGB_y[ 3 ];
1534  static const float NTSCRGB_Y[ 3 ];
1535 
1536  /*
1537  * PAL/SECAM RGB
1538  */
1539  static const float PALSECAMRGB_x[ 3 ];
1540  static const float PALSECAMRGB_y[ 3 ];
1541  static const float PALSECAMRGB_Y[ 3 ];
1542 
1543  /*
1544  * ProPhoto RGB
1545  */
1546  static const float ProPhotoRGB_x[ 3 ];
1547  static const float ProPhotoRGB_y[ 3 ];
1548  static const float ProPhotoRGB_Y[ 3 ];
1549 
1550  /*
1551  * SMPTE-C RGB
1552  */
1553  static const float SMPTECRGB_x[ 3 ];
1554  static const float SMPTECRGB_y[ 3 ];
1555  static const float SMPTECRGB_Y[ 3 ];
1556 
1557  /*
1558  * Wide Gamut RGB
1559  */
1560  static const float WideGamutRGB_x[ 3 ];
1561  static const float WideGamutRGB_y[ 3 ];
1562  static const float WideGamutRGB_Y[ 3 ];
1563 
1564 #endif // __PCL_WITH_STANDARD_RGB_WORKING_SPACES
1565 
1566 };
1567 
1568 // ----------------------------------------------------------------------------
1569 
1570 } // pcl
1571 
1572 #undef _1_3
1573 #undef _1_6
1574 #undef _2_3
1575 #undef _16_116
1576 #undef CIEEpsilon
1577 #undef CIEKappa
1578 #undef CIEKappa116
1579 #undef sRGBEpsilon
1580 #undef sRGBEpsilonInv
1581 #undef sRGBGamma
1582 #undef sRGBGammaInv
1583 
1584 #endif // __PCL_RGBColorSystem_h
1585 
1586 // ----------------------------------------------------------------------------
1587 // EOF pcl/RGBColorSystem.h - Released 2020-07-31T19:33:04Z
void RGBToCIELch(sample &L, sample &c, sample &h, sample R, sample G, sample B) const
static void HSVToRGB(sample &R, sample &G, sample &B, sample H, sample S, sample V)
bool IsLinear() const
Fundamental numeric constants.
Definition: Constants.h:72
constexpr T ArcTan(T x)
Definition: Math.h:501
bool IsAliasOf(const RGBColorSystem &s) const
const Vector & XYZToRGBMatrix() const
static constexpr T pi()
Definition: Constants.h:94
void HSVLToRGB(sample &R, sample &G, sample &B, sample H, sample S, sample V, sample L) const
PCL root namespace.
Definition: AbstractImage.h:76
RGBColorSystem(const RGBColorSystem &s)
void RGBToHSIL(sample &H, sample &S, sample &I, sample &L, sample R, sample G, sample B) const
void RGBToCIELabc(sample &L, sample &a, sample &b, sample &c, sample R, sample G, sample B) const
A colorimetrically defined RGB working color space.
sample Intensity(sample R, sample G, sample B) const
Complex< T > Sqrt(const Complex< T > &c)
Definition: Complex.h:676
sample CIEc(sample R, sample G, sample B) const
static void HSIToRGB(sample &R, sample &G, sample &B, sample H, sample S, sample I)
static void RGBToHSI(sample &H, sample &S, sample &I, sample R, sample G, sample B)
sample CIEL(sample R, sample G, sample B) const
sample CIEYToCIEL(sample Y) const
sample Saturation(sample R, sample G, sample B) const
const FVector & ChromaticityXCoordinates() const
constexpr const T & Range(const T &x, const T &a, const T &b)
Definition: Utility.h:190
bool IsUnique() const
void RGBToGray(sample &K, sample R, sample G, sample B) const
void CIELchToCIELab(sample &L, sample &a, sample &b, sample L0, sample c, sample h) const
sample Hue(sample R, sample G, sample B) const
constexpr const T & Max(const T &a, const T &b)
Definition: Utility.h:119
sample CIEb(sample R, sample G, sample B) const
sample HSVSaturation(sample R, sample G, sample B) const
void RGBToCIEXYZ(sample &X, sample &Y, sample &Z, sample R, sample G, sample B) const
int TruncInt(T x)
Definition: Math.h:1107
constexpr T Floor(T x)
Definition: Math.h:603
constexpr const T & Min(const T &a, const T &b)
Definition: Utility.h:90
void Assign(const RGBColorSystem &s)
void CIEXYZToCIELab(sample &L, sample &a, sample &b, sample X, sample Y, sample Z) const
const Vector & RGBToXYZMatrix() const
static void RGBToHSV(sample &H, sample &S, sample &V, sample R, sample G, sample B)
void RGBToCIELab(sample &L, sample &a, sample &b, sample R, sample G, sample B) const
sample CIEY(sample R, sample G, sample B) const
static const RGBColorSystem sRGB
void CIELabToRGB(sample &R, sample &G, sample &B, sample L, sample a, sample b) const
static constexpr T _2pi()
Definition: Constants.h:114
void HSILToRGB(sample &R, sample &G, sample &B, sample H, sample S, sample I, sample L) const
RGBColorSystem(float gamma, bool issRGB, const float *x, const float *y, const float *Y)
64-bit floating point real vector.
void CIELchToRGB(sample &R, sample &G, sample &B, sample L, sample c, sample h) const
const FVector & ChromaticityYCoordinates() const
sample CIEh(sample R, sample G, sample B) const
sample Value(sample R, sample G, sample B) const
void CIELabToCIELch(sample &L, sample &c, sample &h, sample L0, sample a, sample b) const
sample CIEa(sample R, sample G, sample B) const
sample CIEZ(sample R, sample G, sample B) const
void SinCos(T x, T &sx, T &cx)
Definition: Math.h:1005
const FVector & LuminanceCoefficients() const
bool operator==(const Array< T, A > &x1, const Array< T, A > &x2)
Definition: Array.h:2092
void RGBToCIEXZ(sample &X, sample &Z, sample R, sample G, sample B) const
void CIELabToCIEXYZ(sample &X, sample &Y, sample &Z, sample L, sample a, sample b) const
sample CIEX(sample R, sample G, sample B) const
sample CIELToCIEY(sample L) const
sample CIEhr(sample R, sample G, sample B) const
sample HSISaturation(sample R, sample G, sample B) const
32-bit floating point real vector.
sample Lightness(sample R, sample G, sample B) const
void CIEXYZToRGB(sample &R, sample &G, sample &B, sample X, sample Y, sample Z) const
float Gamma() const
void RGBToCIEab(sample &a, sample &b, sample R, sample G, sample B) const
Thread-safe reference counter for copy-on-write data structures.
Complex< T1 > Pow(const Complex< T1 > &c, T2 x)
Definition: Complex.h:749
RGBColorSystem(float gamma, bool issRGB, const FVector &x, const FVector &y, const FVector &Y)
void RGBToHSVL(sample &H, sample &S, sample &V, sample &L, sample R, sample G, sample B) const