-
-
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() | |
With increasing temperature, output seems like red becoming less saturated, passing through white, and becoming more saturated blue. I expected red turning to orange, yellow, becoming less saturated and turning into white, then becoming more saturated blue. I don't see that yellow part here. It does match https://en.wikipedia.org/wiki/Color_temperature so I guess it is correct. But I was expecting something more like the heated metal colour discussed at: https://physics.stackexchange.com/questions/304299/how-heated-metal-colors-relate-to-black-body-color-at-the-same-temperature. The heated metal colour matches colour temperature of light bulbs more closely.
Edit: For using an RGB led to approximate colour temperature, https://github.com/carpdiem/Color-Match gave better results. Note that there you need to know the wavelength of LEDs to get accurate results.
Edit: Another source is https://github.com/jonls/redshift/blob/master/src/colorramp.c. It uses a lookup table and interpolation, and is much faster than Color-Match.
@dreamlayers Thx for all the links, especially the redhift one really helped be get this going for my ESPHome project. For anyone interested, see: https://github.com/markusressel/CustomRGBWLight/blob/master/components/ColorTempRGBWLight/ColorTempRGBWLight.h
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
mainso 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.
Thank you - useful for cases when np is available, I think both pure-python and numpy based versions are useful for different scenarios
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.