Line 3: | Line 3: | ||
For example, it makes sense to convert from a device-dependent [[Colorimetry#RGB|RGB]] space to a [[Colorimetry#HSL_and_HSV|HSL]] space since, even though they are both device-dependent, they are defined in the same "dependent space". | For example, it makes sense to convert from a device-dependent [[Colorimetry#RGB|RGB]] space to a [[Colorimetry#HSL_and_HSV|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. | + | Also, it makes sense to convert from 2 device-independent spaces like [[Colorimetry#CIE_XYZ|CIEXYZ]] and [[Colorimetry#CIE_LAB|CIELAB]]. |
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''. | ||
− | '''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 26: | Line 26: | ||
L = ( var_Max + var_Min ) / 2 | L = ( var_Max + var_Min ) / 2 | ||
− | if ( del_Max == 0 ) | + | if ( del_Max == 0 ) // This is a gray, no chroma... |
{ | { | ||
− | H = 0 | + | H = 0 // HSL results from 0 to 1 |
S = 0 | S = 0 | ||
} | } | ||
− | else | + | else // Chromatic data... |
{ | { | ||
if ( L < 0.5 ) S = del_Max / ( var_Max + var_Min ) | if ( L < 0.5 ) S = del_Max / ( var_Max + var_Min ) | ||
Line 92: | Line 92: | ||
V = var_Max | V = var_Max | ||
− | if ( del_Max == 0 ) | + | if ( del_Max == 0 ) // This is a gray, no chroma... |
{ | { | ||
− | H = 0 | + | H = 0 // HSV results from 0 to 1 |
S = 0 | S = 0 | ||
} | } | ||
− | else | + | else // Chromatic data... |
{ | { | ||
S = del_Max / var_Max | S = del_Max / var_Max | ||
Line 117: | Line 117: | ||
* Output: RGB in [0,1] | * Output: RGB in [0,1] | ||
− | if ( S == 0 ) //HSV from 0 to 1 | + | if ( S == 0 ) // HSV from 0 to 1 |
{ | { | ||
(R,G,B) = V | (R,G,B) = V | ||
Line 124: | Line 124: | ||
{ | { | ||
var_h = H * 6 | var_h = H * 6 | ||
− | if ( var_h == 6 ) var_h = 0 //H must be < 1 | + | if ( var_h == 6 ) var_h = 0 // H must be < 1 |
− | var_i = int( var_h ) //Or ... var_i = floor( var_h ) | + | var_i = int( var_h ) // Or ... var_i = floor( var_h ) |
var_1 = V * ( 1 - S ) | var_1 = V * ( 1 - S ) | ||
var_2 = V * ( 1 - S * ( var_h - var_i ) ) | var_2 = V * ( 1 - S * ( var_h - var_i ) ) | ||
Line 137: | Line 137: | ||
else { R = V ; G = var_1 ; B = var_2 } | else { R = V ; G = var_1 ; B = var_2 } | ||
} | } | ||
− | |||
− | |||
− | |||
Line 146: | Line 143: | ||
==XYZ / xyY== | ==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== | ==XYZ / Lab== | ||
+ | (Source: http://www.easyrgb.com) | ||
+ | |||
+ | Remember that [[Colorimetry#CIE_LAB|CIE L*a*b*]] is device-independent but needs a [[Colorimetry#White_Point|white point]] reference nevertheless. | ||
+ | |||
+ | Here, the [[Colorimetry#White_points_of_standard_illuminants|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 | ||
+ | |||
Revision as of 18:04, 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.
Contents
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