别再死记硬背xyY了用Python和Matplotlib亲手绘制你的第一张CIE 1931色度图色彩科学中CIE 1931色度图是理解颜色空间的基础工具。这张著名的马蹄形图表不仅定义了人类可见光的全部色域更是现代显示技术、色彩管理的基石。但大多数教程仅展示最终图像很少揭示其背后的数学原理和生成过程。本文将带你用Python代码一步步构建色度图从原始光谱数据到可视化呈现彻底掌握色彩坐标的底层逻辑。1. 理解CIE XYZ色彩空间的本质CIE 1931标准观察者数据是色度学的核心。这套数据来源于1920年代Wright和Guild的颜色匹配实验记录了人类视觉系统对380-780nm可见光谱的响应特性。实验发现任何颜色都可以通过三种原色的线性组合来匹配——这就是著名的三刺激值X、Y、Z的由来。三刺激值的物理意义X模拟人眼对长波红色的敏感度Y同时代表中波绿色敏感度和明度感知Z对应短波蓝色响应实验原始数据通常以5nm为间隔存储格式如下表所示波长(nm)x̄(λ)ȳ(λ)z̄(λ)3800.00140.00000.00653850.00220.00010.0105............7800.00020.00000.0000提示现代Python生态中colour-science库已内置标准观察者数据避免手动输入数百行数据。2. 搭建Python计算环境我们需要以下工具链pip install numpy matplotlib colour-science核心计算流程分为三步加载CIE标准观察者数据计算色度坐标(x,y)可视化结果首先导入必要的库import numpy as np import matplotlib.pyplot as plt from colour import MSDS_CMFS, SDS_ILLUMINANTS加载CIE 1931 2°标准观察者数据cmfs MSDS_CMFS[CIE 1931 2 Degree Standard Observer] wavelengths cmfs.wavelengths x_bar, y_bar, z_bar cmfs.values.T3. 从光谱到色度坐标的数学转换色度坐标的计算公式看似简单却蕴含重要物理意义x X / (X Y Z) y Y / (X Y Z)其中X、Y、Z通过对光谱功率分布积分获得。对于等能白光E光源的特殊情况计算简化为X np.sum(x_bar) Y np.sum(y_bar) Z np.sum(z_bar) x X / (X Y Z) y Y / (X Y Z)实际计算时需要处理几个关键细节波长范围限定在380-780nm数据间隔应为5nm或1nm需对离散数据采用梯形法积分完整计算函数def calculate_chromaticity(wavelengths, x, y, z): 计算CIE 1931色度坐标 delta wavelengths[1] - wavelengths[0] X np.trapz(x, dxdelta) Y np.trapz(y, dxdelta) Z np.trapz(z, dxdelta) x_chroma X / (X Y Z) y_chroma Y / (X Y Z) return x_chroma, y_chroma4. 构建完整的色度图轮廓真正的挑战在于生成马蹄形边界。这需要计算单色光轨迹光谱轨迹和紫红边界# 计算光谱轨迹 spectral_locus [] for wl in range(380, 781): idx np.where(wavelengths wl)[0][0] x, y, _ x_bar[idx], y_bar[idx], z_bar[idx] spectral_locus.append(calculate_chromaticity(wavelengths, x, y, z)) # 连接紫红边界 purples [ spectral_locus[0], # 380nm (紫色) spectral_locus[-1] # 780nm (红色) ]将计算结果可视化时有几个专业技巧使用fill()绘制色域区域添加sRGB三角形标记设置等比例坐标轴防止变形完整绘图代码plt.figure(figsize(10, 8)) plt.fill(*zip(*spectral_locus purples), colorwhite, alpha0.2) # 绘制光谱轨迹 plt.plot(*zip(*spectral_locus), colorblack, linewidth2) # 添加sRGB色域三角形 srgb_vertices [(0.64, 0.33), (0.30, 0.60), (0.15, 0.06)] plt.fill(*zip(*srgb_vertices), colornone, edgecolorred, linestyle--) plt.xlim(0, 0.8) plt.ylim(0, 0.9) plt.gca().set_aspect(equal) plt.xlabel(x chromaticity) plt.ylabel(y chromaticity) plt.title(CIE 1931 Chromaticity Diagram) plt.grid(True)5. 高级应用色域映射与色彩管理实战理解色度图的直接应用是进行色域转换。以下代码演示如何检查RGB值是否在sRGB色域内def rgb_to_xy(rgb, cmfs, illuminantE): 转换RGB到CIE xy坐标 from colour.models import RGB_to_XYZ, XYZ_to_xy xyz RGB_to_XYZ(rgb, sRGB, sRGB, illuminant) return XYZ_to_xy(xyz)实际工作中常见的色域问题超出色域的颜色无法准确显示需要色域映射算法如相对色度、饱和度优先HDR内容需要扩展色域处理通过这种从底层构建的方式你不仅能理解色度图的数学本质还能灵活应用于显示设备色彩校准印刷品色彩管理影视调色工作流程跨平台色彩一致性维护