Calculate colour temperature in K

前端 未结 6 1016
忘掉有多难
忘掉有多难 2021-01-07 19:55

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 i

相关标签:
6条回答
  • 2021-01-07 20:01

    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));
    
    0 讨论(0)
  • 2021-01-07 20:02

    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.

    0 讨论(0)
  • 2021-01-07 20:08

    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.

    0 讨论(0)
  • 2021-01-07 20:20

    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!

    0 讨论(0)
  • 2021-01-07 20:23

    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.

    0 讨论(0)
  • 2021-01-07 20:24

    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;
    }
    
    0 讨论(0)
提交回复
热议问题