23

I have written a lib for working with colours and stuck trying to calculate Tc(k). From what I have read working in the CIE 1931 XYZ colour space is the way to go and it can be obtained using xyY.

So far I have got everything correct to the point of figuring out the correct x and y from :

          X                 Y
x = ____________  y = ____________
    ( X + Y + Z)      ( X + Y + Z)

The numbers much up to the chart, but cant find anything that details how you go from x and y to Tc(K)

enter image description here

eg: For #FF0000 I get the following.

x: 0.64007449945677
y: 0.32997051063169

I have read a number of papers on the topic and litterally all the wikipedia articles. All the questions I have come across on SO simply link to a wiki article on colours, not seen one that has the actual formula for calculating Tc(k)

dogmatic69
  • 7,574
  • 4
  • 31
  • 49
  • 1
    You could try one of these [approximations for color temperature](http://en.wikipedia.org/wiki/Color_temperature#Approximation). For the other way you're looking for the [Planckian locus](http://en.wikipedia.org/wiki/Planckian_locus#Approximation). – user7116 Dec 20 '12 at 16:17
  • The colour of a black body is actually a spectrum, not a pure spectral colour. For example, the colour can be white, even though the peak colour may be green. Any formula would have to involve determining the equivalent CIE colour by analysing the response of the rods and cones of the eye. – UncleO Dec 20 '12 at 16:19
  • 1
    see [Star B-V color index to apparent RGB color](https://stackoverflow.com/a/22630970/2521214) – Spektre Sep 22 '22 at 08:57

6 Answers6

3

Based on the Wikipedia article I entered the approximated formula for Color Temperature calculation into Excel as

=(-449*((R1-0,332)/(S1-0,1858))^3)+(3525*((R1-0,332)/(S1-0,1858))^2)-(6823,3*((R1-0,332)/(S1-0,1858)))+(5520,33)

R1 is color space x coordinate from 0 to 1
S1 is color space y coordinate from 0 to 1

Works fine!

achedeuzot
  • 4,164
  • 4
  • 41
  • 56
Tarmo
  • 31
  • 2
1

If I understand you correctly please see this pdf where a number of methods (briefly :( ) described. From this PDF:

[CCT1] Calculations are performed using CIE 1960 uniform color space coordinates u and v. Coordinates u and v are derived from x and y using the formulae: u = 4x/(12y-2x+3) and v = 6y/(12y-2x+3) The correlated color temperature is defined as the temperature of a blackbody that lies closest to the u,v coordinates of the test source. Two separate methods provide results: one is an iterative method based on the definition, and the other is the commonly used Robertson’s method involving interpolation based on a table of 30 pre-calculated u, v and inverse-slope parameters. Iteration If uS and vS are the values for a test source, and uT and vT are the blackbody values at temperature T, the correlated color temperature is the value of T where:

sqrt( (uS - uT)^2 + (vS - vT)^2 )

is minimized. Adjusting the temperature T to obtain the minimum of this function was done using spreadsheets (Quattro Pro 8 and Excel 97). Both spreadsheets gave identical values.

Don't know if it actually helps you.

maverik
  • 5,508
  • 3
  • 35
  • 55
1

I done some digging in some open source apps and found something in UFRaw. I have not quite figured out what is going on exactly.

Also found a paper that seems to cover the topic quite well.

Converted to php and this is what I have so far:

$temp = array(9500, 7000, 5500, 3750, 3000, 2700, 2250, 1800, 1500);
$hex = array('9DBEFF', 'E4EEFF', 'FFE4BE', 'FFA04C', 'FF7A26', 'FF6A19', 'FF500B', 'FF3403', 'FF2300');

echo '<h3>K -> RGB</h3>';
foreach ($temp as $k) {
    $rgb = ColourConverter::temperature2rgb($k);
    echo sprintf('<div style="background-color:rgb(%s); text-align: center; width: 100px; height: 25px; clear: both;">%s</div>', implode(', ', $rgb), $k);
}

echo '<h3>RGB -> K</h3>';
foreach ($hex as $v) {
    $rgb = array_values(ColourConverter::hex2rgb($v));
    $k = round(ColourConverter::rgb2temperature($rgb[0], $rgb[1], $rgb[2]));
    echo sprintf('<div style="background-color:rgb(%s); text-align: center; width: 100px; height: 25px; clear: both;">%s</div>', implode(', ', $rgb), $k);
}

Reference

My output:

output

Pretty close but not 100% yet. (Found a bug in my code and it is now almost perfect)

  • The colours are slightly off going from k -> rgb
  • It does not work doing k -> rgb -> k. You don't get back to the same value.

Code

UFRaw line 246-294

void Temperature_to_RGB(double T, double RGB[3])
{
    int c;
    double xD, yD, X, Y, Z, max;
    // Fit for CIE Daylight illuminant
    if (T <= 4000) {
        xD = 0.27475e9 / (T * T * T) - 0.98598e6 / (T * T) + 1.17444e3 / T + 0.145986;
    } else if (T <= 7000) {
        xD = -4.6070e9 / (T * T * T) + 2.9678e6 / (T * T) + 0.09911e3 / T + 0.244063;
    } else {
        xD = -2.0064e9 / (T * T * T) + 1.9018e6 / (T * T) + 0.24748e3 / T + 0.237040;
    }
    yD = -3 * xD * xD + 2.87 * xD - 0.275;

    // Fit for Blackbody using CIE standard observer function at 2 degrees
    //xD = -1.8596e9/(T*T*T) + 1.37686e6/(T*T) + 0.360496e3/T + 0.232632;
    //yD = -2.6046*xD*xD + 2.6106*xD - 0.239156;

    // Fit for Blackbody using CIE standard observer function at 10 degrees
    //xD = -1.98883e9/(T*T*T) + 1.45155e6/(T*T) + 0.364774e3/T + 0.231136;
    //yD = -2.35563*xD*xD + 2.39688*xD - 0.196035;

    X = xD / yD;
    Y = 1;
    Z = (1 - xD - yD) / yD;
    max = 0;
    for (c = 0; c < 3; c++) {
        RGB[c] = X * XYZ_to_RGB[0][c] + Y * XYZ_to_RGB[1][c] + Z * XYZ_to_RGB[2][c];
        if (RGB[c] > max) max = RGB[c];
    }
    for (c = 0; c < 3; c++) RGB[c] = RGB[c] / max;
}

void RGB_to_Temperature(double RGB[3], double *T, double *Green)
{
    double Tmax, Tmin, testRGB[3];
    Tmin = 2000;
    Tmax = 23000;
    for (*T = (Tmax + Tmin) / 2; Tmax - Tmin > 0.1; *T = (Tmax + Tmin) / 2) {
        Temperature_to_RGB(*T, testRGB);
        if (testRGB[2] / testRGB[0] > RGB[2] / RGB[0])
            Tmax = *T;
        else
            Tmin = *T;
    }
    *Green = (testRGB[1] / testRGB[0]) / (RGB[1] / RGB[0]);
    if (*Green < 0.2) *Green = 0.2;
    if (*Green > 2.5) *Green = 2.5;
}
dogmatic69
  • 7,574
  • 4
  • 31
  • 49
1

Found the Temperature to RGB solution written in JavaScript and converted it into PHP.

<?php
function colorTemperatureToRGB($kelvin)
{
    $temp = $kelvin / 100;

    $red = null;
    $green = null;
    $blue = null;

    if ($temp <= 66)
    {
        $red = 255; 

        $green = $temp;
        $green = 99.4708025861 * log($green) - 161.1195681661;


        if ($temp <= 19)
        {
            $blue = 0;
        }
        else
        {
            $blue = $temp - 10;
            $blue = 138.5177312231 * log($blue) - 305.0447927307;
        }

    }
    else
    {
        $red = $temp - 60;
        $red = 329.698727446 * pow($red, -0.1332047592);

        $green = $temp - 60;
        $green = 288.1221695283 * pow($green, -0.0755148492);

        $blue = 255;
    }

    return [
        'r' => clamp($red,   0, 255),
        'g' => clamp($green, 0, 255),
        'b' => clamp($blue,  0, 255)
    ];
}

function clamp($x, $min, $max)
{
    if ($x < $min)
        return $min;

    if ($x > $max)
        return $max;

    return $x;
}

var_dump(colorTemperatureToRGB(7000));
NXT
  • 1,981
  • 1
  • 24
  • 30
  • You've referenced a script on gist that it self references another sorce. You could have simply refered to that as it is very thourough http://www.tannerhelland.com/4435/convert-temperature-rgb-algorithm-code/ – dogmatic69 Nov 28 '19 at 09:46
  • 1
    @dogmatic69 Not exactly, the GIST offers ready-made solution in JavaScript, but yeah, the source link is worth mentioning - thanks – NXT Nov 29 '19 at 10:24
0

The Wikipedia states that the color temperature is calculated by considering the u-v chromaticities, not x-y, so you have to perform a translation. That said, I recommend using an approximation (also explained in the Wikipedia) as suggested by @sixlettervariables.

The real question is, what are you trying to find the color temperature of?. I see a reference (#FF0000) to RGB colors, which are meaningless without stating a color space. Supposing you are in sRGB (so I can point you at Wikipedia again), you have to first obtain the linear RGB co-ordinates before proceeding to XYZ.

Emre
  • 5,976
  • 7
  • 29
  • 42
0

I realize this is an old question, but I was struggling to find an answer as well. I finally came across this nifty calculator that also posts the formula as follows:

n = (x-0.3320)/(0.1858-y)

CCT = 437*n^3 + 3601*n^2 + 6861*n + 5517

Hope this helps anyone else who's still looking.