-
-
Save petrklus/b1f427accdf7438606a6 to your computer and use it in GitHub Desktop.
""" | |
Based on: http://www.tannerhelland.com/4435/convert-temperature-rgb-algorithm-code/ | |
Comments resceived: https://gist.github.com/petrklus/b1f427accdf7438606a6 | |
Original pseudo code: | |
Set Temperature = Temperature \ 100 | |
Calculate Red: | |
If Temperature <= 66 Then | |
Red = 255 | |
Else | |
Red = Temperature - 60 | |
Red = 329.698727446 * (Red ^ -0.1332047592) | |
If Red < 0 Then Red = 0 | |
If Red > 255 Then Red = 255 | |
End If | |
Calculate Green: | |
If Temperature <= 66 Then | |
Green = Temperature | |
Green = 99.4708025861 * Ln(Green) - 161.1195681661 | |
If Green < 0 Then Green = 0 | |
If Green > 255 Then Green = 255 | |
Else | |
Green = Temperature - 60 | |
Green = 288.1221695283 * (Green ^ -0.0755148492) | |
If Green < 0 Then Green = 0 | |
If Green > 255 Then Green = 255 | |
End If | |
Calculate Blue: | |
If Temperature >= 66 Then | |
Blue = 255 | |
Else | |
If Temperature <= 19 Then | |
Blue = 0 | |
Else | |
Blue = Temperature - 10 | |
Blue = 138.5177312231 * Ln(Blue) - 305.0447927307 | |
If Blue < 0 Then Blue = 0 | |
If Blue > 255 Then Blue = 255 | |
End If | |
End If | |
""" | |
import math | |
def convert_K_to_RGB(colour_temperature): | |
""" | |
Converts from K to RGB, algorithm courtesy of | |
http://www.tannerhelland.com/4435/convert-temperature-rgb-algorithm-code/ | |
""" | |
#range check | |
if colour_temperature < 1000: | |
colour_temperature = 1000 | |
elif colour_temperature > 40000: | |
colour_temperature = 40000 | |
tmp_internal = colour_temperature / 100.0 | |
# red | |
if tmp_internal <= 66: | |
red = 255 | |
else: | |
tmp_red = 329.698727446 * math.pow(tmp_internal - 60, -0.1332047592) | |
if tmp_red < 0: | |
red = 0 | |
elif tmp_red > 255: | |
red = 255 | |
else: | |
red = tmp_red | |
# green | |
if tmp_internal <=66: | |
tmp_green = 99.4708025861 * math.log(tmp_internal) - 161.1195681661 | |
if tmp_green < 0: | |
green = 0 | |
elif tmp_green > 255: | |
green = 255 | |
else: | |
green = tmp_green | |
else: | |
tmp_green = 288.1221695283 * math.pow(tmp_internal - 60, -0.0755148492) | |
if tmp_green < 0: | |
green = 0 | |
elif tmp_green > 255: | |
green = 255 | |
else: | |
green = tmp_green | |
# blue | |
if tmp_internal >=66: | |
blue = 255 | |
elif tmp_internal <= 19: | |
blue = 0 | |
else: | |
tmp_blue = 138.5177312231 * math.log(tmp_internal - 10) - 305.0447927307 | |
if tmp_blue < 0: | |
blue = 0 | |
elif tmp_blue > 255: | |
blue = 255 | |
else: | |
blue = tmp_blue | |
return red, green, blue | |
if __name__ == "__main__": | |
print("Preview requires matplotlib") | |
from matplotlib import pyplot as plt | |
step_size = 100 | |
for i in range(0, 15000, step_size): | |
color = list(map(lambda div: div/255.0, convert_K_to_RGB(i))) + [1] | |
print(color) | |
plt.plot((i, i), (0, 1), linewidth=step_size/2.0, linestyle="-", color=color) | |
plt.show() | |
Thank you so much for this!
Oh bother, I found this minutes after I write a conversion myself. Oh well, great practice! Do you happen to have a pointer on linking colour temperature to time of day? I'm wanting to use this for a circadian clock project.
do you have by any change the reverse function?
hi @xalbertoisorna , I had a similar use-case and I've just eye-balled it - used around 5500K or even a little bluer for midday, then progressively going down.
No algorithm I am afraid.
I suggest using numpy for a much shorter code:
import numpy as np
def convert_K_to_RGB(colour_temperature: float) -> np.ndarray:
"""
Converts from K to RGB, algorithm courtesy of
http://www.tannerhelland.com/4435/convert-temperature-rgb-algorithm-code/
"""
# Range check.
colour_temperature = np.clip(colour_temperature, 1000, 40000)
tmp_internal = colour_temperature / 100.0
# Red.
if tmp_internal <= 66:
red = 255
else:
red = 329.698727446 * (tmp_internal - 60)**-0.1332047592
# Green.
if tmp_internal <= 66:
green = 99.4708025861 * np.log(tmp_internal) - 161.1195681661
else:
green = 288.1221695283 * (tmp_internal - 60)**-0.0755148492
# Blue.
if tmp_internal >= 66:
blue = 255
elif tmp_internal <= 19:
blue = 0
else:
blue = 138.5177312231 * np.log(tmp_internal - 10) - 305.0447927307
return np.clip((red, green, blue), 0, 255)
I have also changed your main
so that we can zoom in infinitely without seeing empty space between the color bars.
if __name__ == "__main__":
from matplotlib import pyplot as plt
STEP_SIZE = 100
temperatures = np.arange(0, 15000, STEP_SIZE)
colors = [convert_K_to_RGB(temperature)/255 for temperature in temperatures]
fig, ax = plt.subplots()
ax.set_xlim(temperatures[0], temperatures[-1])
ax.set_ylim(0, 1)
ax.bar(temperatures, height=1, width=STEP_SIZE, align="edge", color=colors)
fig.show()
With 10 more minutes of work, we could make the function support polymorphism so that it works on a whole numpy array at once.
If you are interested in the rgb_to_kelvin()
I just reversed the values, with a step size of 100K, find it below as a header file to run it in C.
// temperature.h
#include <stdint.h>
#define HEIGHT 150
#define WIDTH 4
const unsigned colorTable[HEIGHT][WIDTH] = {
{181,205,255,14900},
{182,205,255,14800},
{182,206,255,14500},
{182,206,255,14600},
{182,206,255,14700},
{183,206,255,14300},
{183,206,255,14400},
{183,207,255,14200},
{184,207,255,13900},
{184,207,255,14000},
{184,207,255,14100},
{185,207,255,13800},
{185,208,255,13600},
{185,208,255,13700},
{186,208,255,13300},
{186,208,255,13400},
{186,208,255,13500},
{187,209,255,13000},
{187,209,255,13100},
{187,209,255,13200},
{188,209,255,12900},
{188,210,255,12700},
{188,210,255,12800},
{189,210,255,12400},
{189,210,255,12500},
{189,210,255,12600},
{190,211,255,12200},
{190,211,255,12300},
{191,211,255,12000},
{191,211,255,12100},
{192,212,255,11700},
{192,212,255,11800},
{192,212,255,11900},
{193,213,255,11500},
{193,213,255,11600},
{194,213,255,11300},
{194,213,255,11400},
{195,214,255,11100},
{195,214,255,11200},
{196,214,255,11000},
{196,215,255,10900},
{197,215,255,10700},
{197,215,255,10800},
{198,216,255,10600},
{199,216,255,10500},
{199,217,255,10400},
{200,217,255,10200},
{200,217,255,10300},
{201,218,255,10100},
{202,218,255,9900},
{202,218,255,10000},
{203,219,255,9800},
{204,219,255,9700},
{205,220,255,9500},
{205,220,255,9600},
{206,221,255,9400},
{207,221,255,9300},
{208,222,255,9200},
{209,222,255,9100},
{210,223,255,9000},
{211,223,255,8900},
{212,224,255,8800},
{213,225,255,8700},
{214,225,255,8600},
{215,226,255,8500},
{216,227,255,8400},
{217,227,255,8300},
{218,228,255,8200},
{220,229,255,8100},
{221,230,255,8000},
{223,231,255,7900},
{224,232,255,7800},
{226,233,255,7700},
{228,234,255,7600},
{230,235,255,7500},
{232,236,255,7400},
{234,237,255,7300},
{237,239,255,7200},
{240,240,255,7100},
{243,242,255,7000},
{246,244,255,6900},
{250,246,255,6800},
{254,249,255,6700},
{255,68,0,0},
{255,68,0,100},
{255,68,0,200},
{255,68,0,300},
{255,68,0,400},
{255,68,0,500},
{255,68,0,600},
{255,68,0,700},
{255,68,0,800},
{255,68,0,900},
{255,68,0,1000},
{255,77,0,1100},
{255,86,0,1200},
{255,94,0,1300},
{255,101,0,1400},
{255,108,0,1500},
{255,115,0,1600},
{255,121,0,1700},
{255,126,0,1800},
{255,132,0,1900},
{255,137,14,2000},
{255,142,27,2100},
{255,146,39,2200},
{255,151,50,2300},
{255,155,61,2400},
{255,159,70,2500},
{255,163,79,2600},
{255,167,87,2700},
{255,170,95,2800},
{255,174,103,2900},
{255,177,110,3000},
{255,180,117,3100},
{255,184,123,3200},
{255,187,129,3300},
{255,190,135,3400},
{255,193,141,3500},
{255,195,146,3600},
{255,198,151,3700},
{255,201,157,3800},
{255,203,161,3900},
{255,206,166,4000},
{255,208,171,4100},
{255,211,175,4200},
{255,213,179,4300},
{255,215,183,4400},
{255,218,187,4500},
{255,220,191,4600},
{255,222,195,4700},
{255,224,199,4800},
{255,226,202,4900},
{255,228,206,5000},
{255,230,209,5100},
{255,232,213,5200},
{255,234,216,5300},
{255,236,219,5400},
{255,237,222,5500},
{255,239,225,5600},
{255,241,228,5700},
{255,243,231,5800},
{255,244,234,5900},
{255,246,237,6000},
{255,248,240,6100},
{255,249,242,6200},
{255,251,245,6300},
{255,253,248,6400},
{255,254,250,6500},
{255,255,255,6600}
};
// function that takes an RGB value,
// checks the lowest distance to the colorTable and returns the temperature
unsigned rgb_to_kelvin(unsigned r, unsigned g, unsigned b) {
unsigned minDist = 0xFFFFFF;
unsigned minTemp = 0;
for (unsigned i = 0; i < HEIGHT; i++) {
unsigned rT = colorTable[i][0];
unsigned gT = colorTable[i][1];
unsigned bT = colorTable[i][2];
unsigned dist = (r-rT)*(r-rT) + (g-gT)*(g-gT) + (b-bT)*(b-bT);
if (dist < minDist) {
minDist = dist;
minTemp = colorTable[i][3];
}
}
return minTemp;
}
Awesome, thanks :)