From Wakapon
Jump to: navigation, search
Line 7: Line 7:
 
Most importantly, ''the conversions between device-dependent color spaces and device-independent color spaces'' must '''always''' be accompanied by a [[Color_Profile|Color Profile]] that appropriately describes the ''dependence to the device''.
 
Most importantly, ''the conversions between device-dependent color spaces and device-independent color spaces'' must '''always''' be accompanied by a [[Color_Profile|Color Profile]] that appropriately describes the ''dependence to the device''.
  
[[File:ColorConversions.png|center|400px]]
+
[[File:ColorConversions.png|center]]
  
 
<!--'''NOTE:''' All conversions assume HDR color values, meaning no boundary in luminance except where indicated.-->
 
<!--'''NOTE:''' All conversions assume HDR color values, meaning no boundary in luminance except where indicated.-->
Line 276: Line 276:
  
 
==RGB (in Adobe RGB) / XYZ==
 
==RGB (in Adobe RGB) / XYZ==
 +
(Source: http://www.adobe.com/digitalimag/pdfs/AdobeRGB1998.pdf)
  
 +
===RGB &rarr; XYZ===
 +
* Input: RGB in [0,1] with Adobe RGB gamma profile
 +
* Output: (Observer. = 2°, Illuminant = D65)
 +
** X in [0, 0.95047]
 +
** Y in [0, 1.00000]
 +
** Z in [0, 1.08883]
 +
 +
// Gamma correction of ~2.2
 +
R = R ^ 2.19921875
 +
G = G ^ 2.19921875
 +
B = B ^ 2.19921875
 +
 +
// Observer. = 2°, Illuminant = D65
 +
X =  0.57667 * R + 0.18556 * G + 0.18823 * B
 +
Y =  0.29734 * R + 0.62736 * G + 0.07529 * B
 +
Z =  0.02703 * R + 0.07069 * G + 0.99134 * B
 +
 +
===XYZ &rarr; RGB===
 +
* Input: (Observer. = 2°, Illuminant = D65)
 +
** X in [0, 0.95047]
 +
** Y in [0, 1.00000]
 +
** Z in [0, 1.08883]
 +
* Output: RGB in [0,1] with Adobe RGB gamma profile
 +
 +
R =  2.04159 * X - 0.56501 * Y - 0.34473 * Z
 +
G = -0.96924 * X + 1.87597 * Y + 0.04156 * Z
 +
B =  0.01344 * X - 0.11836 * Y + 1.01517 * Z
 +
 +
// Gamma correction
 +
R = R ^ (1.0 / 2.19921875)
 +
G = G ^ (1.0 / 2.19921875)
 +
B = B ^ (1.0 / 2.19921875)
  
  
 
==RGB (with custom profile) / XYZ==
 
==RGB (with custom profile) / XYZ==

Revision as of 19:53, 1 January 2012

As seen in the Colorimetry page, it's important to understand the difference between Absolute (or device-independent) Color Space (.e.g. CIEXYZ, CIExyY, CIELAB) and device-dependent colors spaces (e.g. RGB, HSL, HSB, HSV).

For example, it makes sense to convert from a device-dependent RGB space to a HSL space since, even though they are both device-dependent, they are defined in the same "dependent space".

Also, it makes sense to convert from 2 device-independent spaces like CIEXYZ and CIELAB.

Most importantly, the conversions between device-dependent color spaces and device-independent color spaces must always be accompanied by a Color Profile that appropriately describes the dependence to the device.

ColorConversions.png


Device-Dependent Color Space Conversions

Here, we will list the different conversions between device-dependent color spaces.

RGB / HSL

(Source: http://www.easyrgb.com)

RGB → HSL

  • Input: RGB in [0,1]
  • Output: HSL in [0,1]
var_Min = min( R, G, B )    // Min. value of RGB
var_Max = max( R, G, B )    // Max. value of RGB
del_Max = var_Max - var_Min // Delta RGB value

L = ( var_Max + var_Min ) / 2

if ( del_Max == 0 )         // This is a gray, no chroma...
{
   H = 0                    // HSL results from 0 to 1
   S = 0
}
else                        // Chromatic data...
{
   if ( L < 0.5 ) S = del_Max / ( var_Max + var_Min )
   else           S = del_Max / ( 2 - var_Max - var_Min )

   del_R = ( ( ( var_Max - var_R ) / 6 ) + ( del_Max / 2 ) ) / del_Max
   del_G = ( ( ( var_Max - var_G ) / 6 ) + ( del_Max / 2 ) ) / del_Max
   del_B = ( ( ( var_Max - var_B ) / 6 ) + ( del_Max / 2 ) ) / del_Max

   if      ( var_R == var_Max ) H = del_B - del_G
   else if ( var_G == var_Max ) H = ( 1 / 3 ) + del_R - del_B
   else if ( var_B == var_Max ) H = ( 2 / 3 ) + del_G - del_R

   if ( H < 0 ) H += 1
   if ( H > 1 ) H -= 1
}

HSL → RGB

  • Input: HSL in [0,1]
  • Output: RGB in [0,1]
if ( S == 0 )
{
   (R,G,B) = L;
}
else
{
   if ( L < 0.5 ) var_2 = L * ( 1 + S )
   else           var_2 = ( L + S ) - ( S * L )

   var_1 = 2 * L - var_2

   R = Hue_2_RGB( var_1, var_2, H + ( 1 / 3 ) ) 
   G = Hue_2_RGB( var_1, var_2, H )
   B = Hue_2_RGB( var_1, var_2, H - ( 1 / 3 ) )
}

Hue_2_RGB( v1, v2, vH )
{
   if ( vH < 0 ) vH += 1
   if ( vH > 1 ) vH -= 1
   if ( ( 6 * vH ) < 1 ) return ( v1 + ( v2 - v1 ) * 6 * vH )
   if ( ( 2 * vH ) < 1 ) return ( v2 )
   if ( ( 3 * vH ) < 2 ) return ( v1 + ( v2 - v1 ) * ( ( 2 / 3 ) - vH ) * 6 )
   return ( v1 )
}


RGB / HSV

(Source: http://www.easyrgb.com)

RGB → HSV

  • Input: RGB in [0,1]
  • Output: HSV in [0,1]
var_Min = min( R, G, B )    // Min. value of RGB
var_Max = max( R, G, B )    // Max. value of RGB
del_Max = var_Max - var_Min // Delta RGB value 

V = var_Max

if ( del_Max == 0 )          // This is a gray, no chroma...
{
   H = 0                     // HSV results from 0 to 1
   S = 0
}
else                         // Chromatic data...
{
   S = del_Max / var_Max

   del_R = ( ( ( var_Max - var_R ) / 6 ) + ( del_Max / 2 ) ) / del_Max
   del_G = ( ( ( var_Max - var_G ) / 6 ) + ( del_Max / 2 ) ) / del_Max
   del_B = ( ( ( var_Max - var_B ) / 6 ) + ( del_Max / 2 ) ) / del_Max

   if      ( var_R == var_Max ) H = del_B - del_G
   else if ( var_G == var_Max ) H = ( 1 / 3 ) + del_R - del_B
   else if ( var_B == var_Max ) H = ( 2 / 3 ) + del_G - del_R

   if ( H < 0 ) H += 1
   if ( H > 1 ) H -= 1
}

HSV → RGB

  • Input: HSV in [0,1]
  • Output: RGB in [0,1]
if ( S == 0 )                       // HSV from 0 to 1
{
   (R,G,B) = V
}
else
{
   var_h = H * 6
   if ( var_h == 6 ) var_h = 0      // H must be < 1
   var_i = int( var_h )             // Or ... var_i = floor( var_h )
   var_1 = V * ( 1 - S )
   var_2 = V * ( 1 - S * ( var_h - var_i ) )
   var_3 = V * ( 1 - S * ( 1 - ( var_h - var_i ) ) )

   if      ( var_i == 0 ) { R = V     ; G = var_3 ; B = var_1 }
   else if ( var_i == 1 ) { R = var_2 ; G = V     ; B = var_1 }
   else if ( var_i == 2 ) { R = var_1 ; G = V     ; B = var_3 }
   else if ( var_i == 3 ) { R = var_1 ; G = var_2 ; B = V     }
   else if ( var_i == 4 ) { R = var_3 ; G = var_1 ; B = V     }
   else                   { R = V     ; G = var_1 ; B = var_2 }
}


Device-Independent Color Space Conversions

Here, we will list the different conversions between device-independent color spaces.

XYZ / xyY

(Source: http://www.easyrgb.com)

XYZ → xyY

  • Input: (Observer. = 2°, Illuminant = D65)
    • X in [0, 0.95047]
    • Y in [0, 1.00000]
    • Z in [0, 1.08883]
  • Output: xyY in [0,1]
Y = Y
x = X / ( X + Y + Z )
y = Y / ( X + Y + Z )


xyY → XYZ

  • Input: xyY in [0,1]
  • Output: (Observer. = 2°, Illuminant = D65)
    • X in [0, 0.95047]
    • Y in [0, 1.00000]
    • Z in [0, 1.08883]
X = x * ( Y / y )
Y = Y
Z = ( 1 - x - y ) * ( Y / y )


XYZ / Lab

(Source: http://www.easyrgb.com)

Remember that CIE L*a*b* is device-independent but needs a white point reference nevertheless.

Here, the D65 illuminant is used.

XYZ → L*a*b*

  • Input: (Observer. = 2°, Illuminant = D65)
    • X in [0, 0.95047]
    • Y in [0, 1.00000]
    • Z in [0, 1.08883]
  • Output:
    • L* in [0,100]
    • a*, b* in [0,?]
var_X = X / ref_X          // ref_X = 0.95047   Observer= 2°, Illuminant= D65
var_Y = Y / ref_Y          // ref_Y = 1.000
var_Z = Z / ref_Z          // ref_Z = 1.08883

if ( var_X > 0.008856 ) var_X = var_X ^ ( 1/3 )
else                    var_X = ( 7.787 * var_X ) + ( 16 / 116 )
if ( var_Y > 0.008856 ) var_Y = var_Y ^ ( 1/3 )
else                    var_Y = ( 7.787 * var_Y ) + ( 16 / 116 )
if ( var_Z > 0.008856 ) var_Z = var_Z ^ ( 1/3 )
else                    var_Z = ( 7.787 * var_Z ) + ( 16 / 116 )

CIE-L* = ( 116 * var_Y ) - 16
CIE-a* = 500 * ( var_X - var_Y )
CIE-b* = 200 * ( var_Y - var_Z )

L*a*b* → XYZ

  • Input:
    • L* in [0,100]
    • a*, b* in [0,?]
  • Output: (Observer. = 2°, Illuminant = D65)
    • X in [0, 0.95047]
    • Y in [0, 1.00000]
    • Z in [0, 1.08883]
var_Y = ( CIE-L* + 16 ) / 116
var_X = CIE-a* / 500 + var_Y
var_Z = var_Y - CIE-b* / 200

if ( var_Y^3 > 0.008856 ) var_Y = var_Y^3
else                      var_Y = ( var_Y - 16 / 116 ) / 7.787
if ( var_X^3 > 0.008856 ) var_X = var_X^3
else                      var_X = ( var_X - 16 / 116 ) / 7.787
if ( var_Z^3 > 0.008856 ) var_Z = var_Z^3
else                      var_Z = ( var_Z - 16 / 116 ) / 7.787

X = ref_X * var_X     // ref_X = 0.95047     Observer= 2°, Illuminant= D65
Y = ref_Y * var_Y     // ref_Y = 1.00000
Z = ref_Z * var_Z     // ref_Z = 1.08883


Device-dependent / Device-independent Color Space Conversions

RGB (in sRGB) / XYZ

(Source: http://www.easyrgb.com)

Please refer to the sRGB color profile specification to understand the pseudo-gamma correction in the following routines.

RGB → XYZ

  • Input: RGB in [0,1] with sRGB gamma profile
  • Output: (Observer. = 2°, Illuminant = D65)
    • X in [0, 0.95047]
    • Y in [0, 1.00000]
    • Z in [0, 1.08883]
// Apply gamma correction (i.e. conversion to linear-space)
if ( R > 0.04045 ) R = ( ( R + 0.055 ) / 1.055 ) ^ 2.4
else               R = R / 12.92
if ( G > 0.04045 ) G = ( ( G + 0.055 ) / 1.055 ) ^ 2.4
else               G = G / 12.92
if ( B > 0.04045 ) B = ( ( B + 0.055 ) / 1.055 ) ^ 2.4
else               B = B / 12.92

// Observer. = 2°, Illuminant = D65
X = R * 0.4124 + G * 0.3576 + B * 0.1805
Y = R * 0.2126 + G * 0.7152 + B * 0.0722
Z = R * 0.0193 + G * 0.1192 + B * 0.9505

XYZ → RGB

  • Input: (Observer. = 2°, Illuminant = D65)
    • X in [0, 0.95047]
    • Y in [0, 1.00000]
    • Z in [0, 1.08883]
  • Output: RGB in [0,1] with sRGB gamma profile
R = X *  3.2406 + Y * -1.5372 + Z * -0.4986
G = X * -0.9689 + Y *  1.8758 + Z *  0.0415
B = X *  0.0557 + Y * -0.2040 + Z *  1.0570

if ( R > 0.0031308 ) R = 1.055 * ( R ^ ( 1 / 2.4 ) ) - 0.055
else                 R = 12.92 * R
if ( G > 0.0031308 ) G = 1.055 * ( G ^ ( 1 / 2.4 ) ) - 0.055
else                 G = 12.92 * G
if ( B > 0.0031308 ) B = 1.055 * ( B ^ ( 1 / 2.4 ) ) - 0.055
else                 B = 12.92 * B


RGB (in Adobe RGB) / XYZ

(Source: http://www.adobe.com/digitalimag/pdfs/AdobeRGB1998.pdf)

RGB → XYZ

  • Input: RGB in [0,1] with Adobe RGB gamma profile
  • Output: (Observer. = 2°, Illuminant = D65)
    • X in [0, 0.95047]
    • Y in [0, 1.00000]
    • Z in [0, 1.08883]
// Gamma correction of ~2.2
R = R ^ 2.19921875
G = G ^ 2.19921875
B = B ^ 2.19921875

// Observer. = 2°, Illuminant = D65
X =  0.57667 * R + 0.18556 * G + 0.18823 * B
Y =  0.29734 * R + 0.62736 * G + 0.07529 * B
Z =  0.02703 * R + 0.07069 * G + 0.99134 * B

XYZ → RGB

  • Input: (Observer. = 2°, Illuminant = D65)
    • X in [0, 0.95047]
    • Y in [0, 1.00000]
    • Z in [0, 1.08883]
  • Output: RGB in [0,1] with Adobe RGB gamma profile
R =  2.04159 * X - 0.56501 * Y - 0.34473 * Z
G = -0.96924 * X + 1.87597 * Y + 0.04156 * Z
B =  0.01344 * X - 0.11836 * Y + 1.01517 * Z

// Gamma correction
R = R ^ (1.0 / 2.19921875)
G = G ^ (1.0 / 2.19921875)
B = B ^ (1.0 / 2.19921875)


RGB (with custom profile) / XYZ