Python光学仿真:波长与颜色的对应关系及CIE色度系统实现

Miles
Miles
发布时间:2026-10-15 | 4人浏览过
原创

本文解析Python实现波长与颜色对应关系的原理,涵盖人眼对光的明度、色调和饱和度感知机制。重点介绍CIE RGB与XYZ色度系统的转换逻辑,并提供Python代码实现色品图绘制、光谱颜色生成及光谱图展示,帮助开发者理解光学仿真中的色彩映射算法。

光的颜色

颜色并非光本身的固有属性,而是人眼在可见光频率范围内产生的生理感应,属于视觉系统的特性。人眼对光的感知主要包含三个维度:明度、色调和饱和度。

具体而言,

  • 明度取决于光的强度,
  • 色调反映光的频率信息,
  • 饱和度则表征图像颜色与标准光谱色的接近程度。

若忽略色调与饱和度(设为0),仅保留明度,则色彩感知消失,呈现黑白或更严谨意义上的灰度图像。

色调与饱和度虽间接反映光的频率,但本质上是人眼对光的反馈特性,与光的物理频率不同。这种对应关系由人眼感光细胞决定。由于自然界缺乏严格单色光,人类的色觉实际上是两种感光细胞信号混合的结果。

这意味着,不同基准频率的光按特定饱和度混合,人眼会感知到颜色变化或新颜色的产生。实验证实,任意三种无法相互转换的颜色,通过混合即可一一对应光谱色。这三种光被称为三原色,通常选取红、绿、蓝(RGB)。

由于三原色已归一化,已知其中两个值即可确定色品。以r为横坐标、g为纵坐标,可绘制出所有可能的色品分布图。此类图表常见于手机发布会,此处我们绘制类似的色品图。


def CIE_RGB():
    rgb = np.zeros([1000,1000,3])
    r = np.arange(0,1,0.001)
    r,g = np.meshgrid(r,r)
    rgb[:,:,0] = r
    rgb[:,:,1] = g
    rgb[:,:,2] = 1-r-g
    over = rgb[:,:,2]<0
    rgb[over,:]=[1,1,1]
    #将色品转化成RGB
    maxVal = np.max(rgb,2)
    for i in [0,1,2]:
        rgb[:,:,i] /= maxVal
    #rgb[rgb<0]=0
    ax = plt.gca()
    ax.imshow(rgb)
    ax.invert_yaxis()    #plt显示图片时y轴从上到下,所以反置
    # 坐标映射
    plt.xticks(range(0,1001,200),['0','0.2','0.4','0.6','0.8','1'])
    plt.yticks(range(0,1001,200),['0','0.2','0.4','0.6','0.8','1'])
    plt.show()

然而实验发现,RGB系统的刺激值存在负数,意味着前述色品图并未涵盖所有颜色。因此,CIE推荐了XYZ色度学系统,它是对RGB系统的线性变换,确保刺激值均为正数。其转换公式为:

Python实现代码如下:


#dWave为波长;maxPix为最大值;gamma为调教参数
def getRGB(dWave,maxPix=1,gamma=1):
    waveArea = [380,440,490,510,580,645,780]
    minusWave = [0,440,440,510,510,645,780]
    deltWave = [1,60,50,20,70,65,35]
    for p in range(len(waveArea)):
        if dWave<waveArea[p]:
            break
    pVar = abs(minusWave[p]-dWave)/deltWave[p]
    rgbs = [[0,0,0],[pVar,0,1],[0,pVar,1],[0,1,pVar],
            [pVar,1,0],[1,pVar,0],[1,0,0],[0,0,0]]
        #在光谱边缘处颜色变暗
    if (dWave>=380) & (dWave<420):
        alpha = 0.3+0.7*(dWave-380)/(420-380)
    elif (dWave>=420) & (dWave<701):
        alpha = 1.0
    elif (dWave>=701) & (dWave<780):
        alpha = 0.3+0.7*(780-dWave)/(780-700)
    else:
        alpha = 0       #非可见区
    return [maxPix*(c*alpha)**gamma for c in rgbs[p]]

绘制光谱颜色分布


def drawSpec():
    pic = np.zeros([100,360,3])
    rgb = [getRGB(d) for d in range(400,760)]
    pic = pic+rgb
    plt.imshow(pic)
    plt.yticks([])      #隐藏y坐标轴
    plt.xticks(range(0,360,50),['400','450','500','550','600','650','700','750'])
    plt.show()

以上为Python光学仿真中波长与颜色对应关系的详细解析,更多相关技术内容请关注本站其他文章。

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表