The RGB color value of an infinitely hot blackbody approaches a very pale blue as temperature increases. This theoretical limit is calculated using blackbody radiation principles and color science. Below is a detailed explanation and Python code that illustrates this process.
Key References:
- SI Brochure: Provides constants for Planck's law.
- CIE XYZ CMFs (2006): Essential for converting blackbody spectra into CIE XYZ values.
- XYZ to RGB Transformation Matrix: Converts XYZ to linear RGB.
- Gamma Correction Function: Adjusts linear RGB values to match typical display characteristics.
- Baby Universe (#8bb1ff): The calculated color for extremely high temperatures, roughly
rgb(139, 177, 255)
.
Python Implementation:
The following Python code calculates the RGB value for a blackbody at an extremely high temperature (e.g., (10^7) K). The result is a pale blue, indicative of the color limit as temperature approaches infinity.
import requests
from io import BytesIO
import numpy as np
import pandas as pd
from mpmath import mp, mpf, exp
import matplotlib.pyplot as plt
# Set the precision to 7 decimal places
mp.dps = 7
# High precision constants for Planck's law using exact values
h = mpf("6.62607015e-34") # Planck constant (J·s)
c = mpf("299792458") # Speed of light in vacuum (m/s)
k = mpf("1.380649e-23") # Boltzmann constant (J/K)
# Load CIE XYZ data
csv_response = requests.post(
url="http://www.cvrl.org/xyzcmfrequest_2.php",
data={"xyz_steps": "fine", "xyz_format": "csv", "button": "Submit"},
)
cie_xyz_data = pd.read_csv(BytesIO(csv_response.content)) # 7 significant figures
wavelengths = (
cie_xyz_data.iloc[:, 0].values.astype(float) * 1e-9
) # Convert nm to meters
X_values = cie_xyz_data.iloc[:, 1].values
Y_values = cie_xyz_data.iloc[:, 2].values
Z_values = cie_xyz_data.iloc[:, 3].values
# Transformation matrices for RGB to XYZ and XYZ to RGB
matrix_XYZ_to_RGB = np.array(
[
[3.240969941904523, -1.537383177570094, -0.498610760293003],
[-0.969243636280880, 1.875967501507721, 0.041555057407176],
[0.055630079696994, -0.203976958888977, 1.056971514242879],
]
)
def plot_rgb_square(rgb):
"""Plots a square filled with the specified RGB color and labels it with the RGB values."""
normalized_rgb = [x / 255.0 for x in rgb]
square = np.ones((10, 10, 3)) * normalized_rgb
plt.imshow(square)
plt.axis("off")
rgb_text = f"rgb({round(rgb[0])}, {round(rgb[1])}, {round(rgb[2])})"
plt.text(
5,
5,
rgb_text,
color="white" if sum(rgb) < 400 else "black",
fontsize=12,
ha="center",
va="center",
weight="bold",
)
plt.show()
def blackbody_spectrum(wavelengths, temperature):
"""Calculate the blackbody spectrum using mpmath for arbitrary precision."""
return (2 * h * c**2 / wavelengths**5) / (
exp(h * c / (wavelengths * k * temperature)) - 1
)
def temperature_to_xyz(temperature):
"""Convert a temperature in Kelvin to CIE XYZ values using mpmath."""
spectrum = np.array([blackbody_spectrum(w, temperature) for w in wavelengths])
# Integrate the spectrum with the CIE XYZ color matching functions
X = np.trapezoid(spectrum * X_values, wavelengths)
Y = np.trapezoid(spectrum * Y_values, wavelengths)
Z = np.trapezoid(spectrum * Z_values, wavelengths)
# Normalize by Y to obtain chromaticity values
XYZ = np.array([X, Y, Z])
XYZ_normalized = XYZ / XYZ.sum()
return XYZ_normalized
def xyz_to_rgb(XYZ):
"""Convert CIE XYZ values to linear RGB using the transformation matrix."""
RGB = np.dot(matrix_XYZ_to_RGB, XYZ)
# Clip and normalize RGB values
RGB = np.clip(RGB, 0, None)
RGB /= RGB.max()
return RGB
def gamma_correct(rgb):
"""Apply gamma correction based on the sRGB transfer function."""
corrected_rgb = np.where(
rgb <= 0.0031308, 12.92 * rgb, 1.055 * np.power(rgb, 1 / 2.4) - 0.055
)
return np.clip(corrected_rgb, 0, 1)
def temperature_to_rgb(temperature):
"""Convert a temperature in Kelvin to RGB color using mpmath and the sRGB transfer function."""
XYZ = temperature_to_xyz(temperature)
linear_rgb = xyz_to_rgb(XYZ)
sRGB = gamma_correct(linear_rgb)
return np.round((sRGB * 255).astype(float))
# Calculate the RGB value for a very high temperature (e.g., 1e7 K)
color_largest_temp = temperature_to_rgb(mpf("1e7"))
print(f"rgb({', '.join(map(str, map(round, color_largest_temp.tolist())))})")
# rgb(139, 177, 255)
plot_rgb_square(color_largest_temp)
Result:
This script computes the RGB value for an extremely hot blackbody as rgb(139, 177, 255)
, a blue-white color. This result represents the theoretical color limit on the Planckian locus as temperature approaches infinity.