LED测量

光谱转换为颜色XYZ原理和代码

作者: 管理员

本文介绍了一个 Python 脚本,用于将波长光谱映射到一种颜色的表示。没有独特的方法可以做到这一点,但这里使用的公式基于CIE 颜色匹配函数XYZ。这些模型通过将波长的功率谱 P  映射到一组三刺激值$X$、$Y$ 和 $Z$ 来模拟“标准观察者”的色度响应,类似于实际人眼中三种视锥细胞的反应。

cie-cmf.png

这样,只需要 $x$ 和 $y$ 两个参数来描述光的颜色(更准确地说是色度)。CIE标准色度图如下所示。

Cie_Chart_with_sRGB_gamut_by_spigget.png

将 $(x, y)$ 进一步转换为显示设备输出的 RGB 值需要通过适当的色度矩阵进行转换。在几何上,这将上述颜色“舌头”中的点映射到 RGB“色域”内的点子集,即指示的三角形区域。甲颜色系统可通过的三点基色的色度(三角形的顶点)和一个矩阵来定义的白点的一组限定用于某种目的的“颜色”白色chromaticiy坐标:

$(x,y,z)$ 值的向量乘以该矩阵的倒数,因此给出了描述所使用系统内相应颜色的RGB 值。

并非所有 $(x, y)$ 对都映射到 RGB 色域内的点(它们会为一个或多个组件提供负值):解决此问题的一种方法是通过相等地提高所有组件的值来“降低饱和度”,直到它们都是非负的。

下面的代码定义了一个类,ColourSystem用于表示和使用颜色系统,并实例化了一些特定的例子。CIE 匹配函数从文件cie-cmf.txt读入。


# colour_system.pyimport numpy as npdef xyz_from_xy(x, y):
    """Return the vector (x, y, 1-x-y)."""
    return np.array((x, y, 1-x-y))class ColourSystem:
    """A class representing a colour system.    A colour system defined by the CIE x, y and z=1-x-y coordinates of    its three primary illuminants and its "white point".    TODO: Implement gamma correction    """

    # The CIE colour matching function for 380 - 780 nm in 5 nm intervals
    cmf = np.loadtxt('cie-cmf.txt', usecols=(1,2,3))

    def __init__(self, red, green, blue, white):
        """Initialise the ColourSystem object.        Pass vectors (ie NumPy arrays of shape (3,)) for each of the        red, green, blue  chromaticities and the white illuminant        defining the colour system.        """

        # Chromaticities
        self.red, self.green, self.blue = red, green, blue
        self.white = white
        # The chromaticity matrix (rgb -> xyz) and its inverse
        self.M = np.vstack((self.red, self.green, self.blue)).T 
        self.MI = np.linalg.inv(self.M)
        # White scaling array
        self.wscale = self.MI.dot(self.white)
        # xyz -> rgb transformation matrix
        self.T = self.MI / self.wscale[:, np.newaxis]

    def xyz_to_rgb(self, xyz, out_fmt=None):
        """Transform from xyz to rgb representation of colour.        The output rgb components are normalized on their maximum        value. If xyz is out the rgb gamut, it is desaturated until it        comes into gamut.        By default, fractional rgb components are returned; if        out_fmt='html', the HTML hex string '#rrggbb' is returned.        """

        rgb = self.T.dot(xyz)
        if np.any(rgb < 0):
            # We're not in the RGB gamut: approximate by desaturating
            w = - np.min(rgb)
            rgb += w
        if not np.all(rgb==0):
            # Normalize the rgb vector
            rgb /= np.max(rgb)

        if out_fmt == 'html':
            return self.rgb_to_hex(rgb)
        return rgb

    def rgb_to_hex(self, rgb):
        """Convert from fractional rgb values to HTML-style hex string."""

        hex_rgb = (255 * rgb).astype(int)
        return '#{:02x}{:02x}{:02x}'.format(*hex_rgb)

    def spec_to_xyz(self, spec):
        """Convert a spectrum to an xyz point.        The spectrum must be on the same grid of points as the colour-matching        function, self.cmf: 380-780 nm in 5 nm steps.        """

        XYZ = np.sum(spec[:, np.newaxis] * self.cmf, axis=0)
        den = np.sum(XYZ)
        if den == 0.:
            return XYZ
        return XYZ / den

    def spec_to_rgb(self, spec, out_fmt=None):
        """Convert a spectrum to an rgb value."""

        xyz = self.spec_to_xyz(spec)
        return self.xyz_to_rgb(xyz, out_fmt)illuminant_D65 = xyz_from_xy(0.3127, 0.3291)cs_hdtv = ColourSystem(red=xyz_from_xy(0.67, 0.33),
                       green=xyz_from_xy(0.21, 0.71),
                       blue=xyz_from_xy(0.15, 0.06),
                       white=illuminant_D65)cs_smpte = ColourSystem(red=xyz_from_xy(0.63, 0.34),
                        green=xyz_from_xy(0.31, 0.595),
                        blue=xyz_from_xy(0.155, 0.070),
                        white=illuminant_D65)cs_srgb = ColourSystem(red=xyz_from_xy(0.64, 0.33),
                       green=xyz_from_xy(0.30, 0.60),
                       blue=xyz_from_xy(0.15, 0.06),
                       white=illuminant_D65)


推荐新闻
推荐产品
在线客服
联系方式

热线电话

150 0072 7503(微信同号)

上班时间

Monday to Saturday

公司电话

二维码
线