色温(Color Temperature)是一个用来描述光源颜色特征的物理量,通常用开尔文温度(K)表示。它并不是指灯泡或光源的实际温度,而是以绝对黑体辐射为参照的一种度量方式。当一个理想的黑体被加热到特定温度时,它会发出特定颜色的光,这个颜色与光源的颜色相匹配时,该黑体的温度即为该光源的色温。
色温范围及其对应的光色:
- 低于3000K:暖白色,给人以温暖、舒适的感觉,类似于烛光或者白炽灯。
- 3000K至4500K:中性白色,较为柔和,适用于大多数室内环境。
- 4500K至6500K:自然白色或冷白色,接近于日光,能提供清晰明亮的照明效果。
- 高于6500K:日光色,非常冷的色调,常用于需要高度集中注意力的地方如办公室或医院手术室等。
色温计算是白平衡处理的核心环节,用于量化光源的颜色特性。以下是色温计算的完整技术解析和Python实现:
色温计算基本原理
-
色温定义:
-
表示光源颜色的物理量,单位开尔文(K)
-
黑体辐射理论:当黑体加热时,其发光颜色随温度变化的轨迹称为普朗克轨迹
-
-
计算流程:
关键算法实现
1. RGB到色温的转换
import numpy as np
import cv2
def rgb_to_cct(r, g, b):
"""
通过RGB值估算色温(K)
基于Robertson方法实现
:param r,g,b: 归一化的RGB值(0-1)
:return: 色温(K)
"""
# 转换为XYZ色彩空间
x = 0.4124564*r + 0.3575761*g + 0.1804375*b
y = 0.2126729*r + 0.7151522*g + 0.0721750*b
z = 0.0193339*r + 0.1191920*g + 0.9503041*b
# 计算色度坐标
x_chroma = x / (x + y + z)
y_chroma = y / (x + y + z)
# 计算色温(McCamy公式)
n = (x_chroma - 0.3320) / (0.1858 - y_chroma)
cct = 449 * n**3 + 3525 * n**2 + 6823.3 * n + 5520.33
return int(cct)
2. 图像色温估计(完整实现)
def estimate_image_cct(img, method='robertson'):
"""
估计图像整体色温
:param img: BGR格式图像
:param method: 计算方法('robertson'|'kang')
:return: 色温(K)
"""
# 转换为RGB并归一化
rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) / 255.0
# 计算图像平均色
avg_color = np.mean(rgb, axis=(0,1))
r, g, b = avg_color
if method == 'kang':
# Kang算法(高精度)
x = 0.4124564*r + 0.3575761*g + 0.1804375*b
y = 0.2126729*r + 0.7151522*g + 0.0721750*b
z = 0.0193339*r + 0.1191920*g + 0.9503041*b
u = (4*x) / (x + 15*y + 3*z)
v = (6*y) / (x + 15*y + 3*z)
# 查找最近的黑体辐射点
# 这里使用简化计算,实际应使用查找表
cct = 1000000 / (0.27487*u**2 - 2.0915*u + 4.2586)
else:
# Robertson算法(默认)
cct = rgb_to_cct(r, g, b)
return np.clip(cct, 2000, 15000) # 限制在合理范围
色温计算优化
1. 基于色域的精确计算
def precise_cct(x, y):
"""
高精度色温计算(需预计算查找表)
:param x,y: CIE1931色度坐标
:return: 色温(K)
"""
# 等温线插值计算
# 实际实现应包含完整查找表和插值算法
u = (4*x) / (-2*x + 12*y + 3)
v = (6*y) / (-2*x + 12*y + 3)
# 计算与普朗克轨迹的最小距离
# 此处为示例,实际需要完整实现
distance = np.sqrt((u - 0.292)**2 + (v - 0.24)**2)
return int(1/(0.0001*distance + 0.0000001))
2. 区域加权色温计算
def zonal_cct(img, weights=None):
"""
分区加权色温计算
:param img: 输入图像
:param weights: 区域权重矩阵(与img同尺寸)
:return: 加权色温(K)
"""
if weights is None:
# 默认中心加权
h, w = img.shape[:2]
weights = np.zeros((h,w))
cv2.circle(weights, (w//2,h//2), min(w,h)//2, 1, -1)
# 转换为LAB色彩空间
lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB)
l, a, b = cv2.split(lab)
# 计算权重归一化
weights = weights / np.sum(weights)
# 计算加权平均色
weighted_rgb = np.zeros(3)
for i in range(3):
weighted_rgb[i] = np.sum(img[:,:,i] * weights)
return rgb_to_cct(*weighted_rgb/255)
色温计算的实际应用
1. 自动白平衡增益计算
def calculate_wb_gains(cct):
"""
根据色温计算白平衡增益
:param cct: 色温(K)
:return: (r_gain, g_gain, b_gain)
"""
# 基于黑体辐射模型的近似计算
if cct < 4000:
# 暖光环境
r_gain = 1.0
b_gain = 0.5 + (cct / 8000)
elif cct > 7000:
# 冷光环境
r_gain = 1.0 - (cct - 7000) / 20000
b_gain = 1.0
else:
# 中性光
r_gain = 1.0
b_gain = 1.0
# 保持G通道不变
return (r_gain, 1.0, b_gain)
2. 色温可视化工具
def visualize_cct(img):
"""色温可视化工具"""
cct = estimate_image_cct(img)
# 创建色温条
gradient = np.linspace(1000, 10000, 256)
colors = []
for temp in gradient:
r, g, b = color_from_cct(temp)
colors.append([b, g, r]) # OpenCV使用BGR
color_bar = np.array(colors, dtype=np.uint8)
color_bar = cv2.resize(color_bar, (100, img.shape[0]))
# 标记当前色温位置
pos = int((cct - 1000) / (10000-1000) * 255)
cv2.line(color_bar, (0, pos), (100, pos), (0,0,0), 2)
# 合并显示
result = np.hstack([img, color_bar])
cv2.putText(result, f"CCT: {cct}K", (10,30),
cv2.FONT_HERSHEY_SIMPLEX, 1, (255,255,255), 2)
return result
def color_from_cct(cct):
"""根据色温生成对应颜色(简化版)"""
if cct < 2000:
return (255, 150, 50)
elif cct < 4000:
return (255, 200, 150)
elif cct < 6000:
return (255, 255, 200)
elif cct < 8000:
return (200, 220, 255)
else:
return (150, 180, 255)
性能优化技巧
-
查找表预计算:
# 预计算色温查找表 cct_lut = np.zeros((256,256,256)) for r in range(256): for g in range(256): for b in range(256): cct_lut[r,g,b] = rgb_to_cct(r/255, g/255, b/255)
-
GPU加速计算:
import cupy as cp def gpu_cct(img): """GPU加速的色温计算""" img_gpu = cp.asarray(img) rgb_gpu = img_gpu / 255.0 # 并行计算每个像素 x = 0.4124564*rgb_gpu[:,:,0] + 0.3575761*rgb_gpu[:,:,1] + 0.1804375*rgb_gpu[:,:,2] y = 0.2126729*rgb_gpu[:,:,0] + 0.7151522*rgb_gpu[:,:,1] + 0.0721750*rgb_gpu[:,:,2] z = 0.0193339*rgb_gpu[:,:,0] + 0.1191920*rgb_gpu[:,:,1] + 0.9503041*rgb_gpu[:,:,2] x_chroma = x / (x + y + z) y_chroma = y / (x + y + z) n = (x_chroma - 0.3320) / (0.1858 - y_chroma) cct_map = 449 * n**3 + 3525 * n**2 + 6823.3 * n + 5520.33 return int(cp.mean(cct_map).get())
评估与验证
-
色温计算精度测试:
def test_cct_accuracy(): """测试色温计算精度""" test_cases = [ # (RGB值, 预期色温) ((0.95, 0.88, 0.75), 3000), # 白炽灯 ((0.90, 0.95, 1.00), 6500), # 日光 ((0.80, 0.85, 0.95), 7500), # 阴天 ] for rgb, expected in test_cases: calculated = rgb_to_cct(*rgb) error = abs(calculated - expected) / expected print(f"RGB{rgb}: 计算{calculated}K, 预期{expected}K, 误差{error*100:.1f}%")
-
实际图像测试流程:
img = cv2.imread('test_image.jpg') cct = estimate_image_cct(img) gains = calculate_wb_gains(cct) print(f"估计色温: {cct}K") print(f"建议白平衡增益: R={gains[0]:.2f}, G={gains[1]:.2f}, B={gains[2]:.2f}") # 应用白平衡 balanced = img.copy().astype('float32') balanced[:,:,0] *= gains[2] # B balanced[:,:,1] *= gains[1] # G balanced[:,:,2] *= gains[0] # R balanced = np.clip(balanced, 0, 255).astype('uint8') cv2.imshow('Original vs Balanced', np.hstack([img, balanced])) cv2.waitKey(0)
通过以上方法,可以实现精确高效的色温计算,为白平衡处理提供可靠的基础数据。实际应用中建议结合多种方法,并根据具体场景进行参数优化。