65.9K
CodeProject 正在变化。 阅读更多。
Home

程序员的色彩主题

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.89/5 (87投票s)

2017年8月24日

公共领域

66分钟阅读

viewsIcon

128379

downloadIcon

1460

讨论了程序员在编程中常遇到的色彩空间、色彩生成和其他一般性色彩主题。

引言

本文档概述了许多对程序员普遍感兴趣的常见色彩主题,这些主题可以用于多种不同的编程语言。 提供了 实现本文档中许多方法的示例 Python 代码补充主题 在另一个开源页面中列出。

本文档涵盖的主题包括:

  • 红绿蓝 (RGB) 和其他实用色彩模型。
  • 如何生成具有特定属性的颜色。
  • 色彩差异、色彩映射和色彩混合。
  • 图像的主导颜色。
  • 颜色作为光谱曲线。

本文档不包括:

  • 如何更改或设置颜色 —
    • 在用户界面元素的文本、前景或背景中(例如按钮、文本框和窗口),
    • 在文档(例如 HTML 文档)的文本或背景中,或
    • 生成图形(例如图表和曲线图)时。
  • 确定在用户界面元素、文档、图表或曲线图中使用了哪些颜色,或默认使用了哪些颜色。
  • 颜色选择器,包括如何用它们选择颜色。
  • 设置和获取图像(包括屏幕截图)中像素、调色板和其他颜色的具体方法,但查找主导颜色除外。
  • 命令行输出、终端或 Shell 输出的着色。 “ANSI”图形代码 已在其他地方讨论。
  • 总的来说,特定于编程语言或应用程序编程接口(API)的主题。

目录

符号和定义

  • 本文档使用伪代码约定
  • bpc. 每颜色分量比特数。
  • CIE. 国际照明委员会的法语首字母缩写。
  • 色彩模型. 一般性地描述了理论空间中颜色的关系。
  • 色彩空间. 将颜色映射到数字,遵循特定的色彩模型。
  • D50 光源,D65 光源. CIE daylight 模型,其相关色温分别约为 5000 或 6500 开尔文。(1)
  • D50/2 白点. 由 D50 光源和 CIE 1931 标准观察者确定的白点。
  • D65/2 白点. 由 D65 光源和 CIE 1931 标准观察者确定的白点。
  • IEC. 国际电工委员会。
  • 图像颜色列表. 指的是 —
    • 一个颜色列表(可以有重复),所有颜色都属于同一个色彩空间,或
    • 用于光栅图像像素、矢量图像、三维图像、数字视频或数字文档的颜色(可以有重复)。
  • ISO. 国际标准化组织。
  • 光源. 指 CIE 定义的主要光源光源。大致指发光体,或描述发光体的辐射。
  • 多分量颜色. 以一个或多个颜色分量表示的颜色。颜色分量包括红色分量、绿色分量、亮度因子以及光谱反射曲线上的点。
  • RGB. 红绿蓝。

色觉概述

颜色(2) 只有在存在三样东西时才可能,即 —

  • ,
  • 一个接收光的物体(例如表面),以及
  • 一个观察者观察该物体并解释从该物体接收到的光。

因此,颜色并不存在于光、接收光的物体、光源,甚至眼睛在看到事物时产生的信号中。(3) 在《光学》中,牛顿说,“严格来说,光线并不是彩色的。”

颜色的外观是主观的 — 因为需要解释光 — 并且会随着光源(太阳光、日光、白炽灯等)、物体(材料)、观察者、观看情境或它们的组合而变化。(4)

注意: 使颜色成为可能的三样东西 — 物体观察者 — 可以用跨越可见光谱(光被“看见”的电磁频谱部分)的曲线来建模,如“光谱颜色函数”部分所述。

人类色觉

当一个人观察物体时,它反射的光会到达该人的眼睛。

人眼内层后壁(称为视网膜)充满了三种视锥细胞,每种视锥细胞对光的敏感度不同。

人类视觉系统比较来自视锥细胞的响应,并将其转换为三种信号,即明暗信号以及红色/绿色和蓝色/黄色的两种拮抗信号。正是这些信号,而不是视锥细胞的响应,被传递到大脑。(5)

人脑解释来自眼睛的信号来判断颜色外观,并考虑视觉情境。其中一个过程称为适应,大致来说,人类视觉系统将场景中最亮的东西视为“白色”,并以此为基础在心理上调整它看到的其他颜色,以适应光照差异。因此,适应类似于数码相机的“自动白平衡”。

注释

  1. 视锥细胞的响应可以由三条重叠的“曲线”描述,这些曲线在可见光谱的不同位置达到峰值 — 事实上,其中两条曲线覆盖了整个可见光谱。因此,至少有两种视锥细胞会对光做出反应,而不仅仅是一种。
  2. 由于存在三种视锥细胞,三个数字就足以唯一地识别出人类可以看到的颜色 — 这就是为什么许多 色彩空间 是 3 维的,例如 RGB 或 CIE XYZ 空间。

缺陷色觉和动物色觉

缺陷色觉,包括所谓的“色盲”,会使某些光线比正常色觉更难区分。(6)

除了人类,许多其他动物在不同程度上也拥有色觉。例如,虾蛄 至少有十二种不同的视锥细胞类型,使其色觉比人类敏锐得多。

颜色指定

颜色可以通过以下两种方式之一指定:

  • 作为空间中的一个点,即,一组小的数字(通常是三个数字),显示颜色在色彩空间中的位置。这在实践中很常见。一些色彩空间包括以下内容:
    • RGB 色彩空间描述了“红色”、“绿色”和“蓝色”光点的比例。
    • HSVHSLHWB 色彩空间转换 RGB 颜色,使其呈现更直观,但不是基于感知的。
    • XYZCIELABCIELUV 色彩空间基于人类颜色感知。
    • CMYK 色彩空间尤其用于描述四种特定油墨的比例。
    • Y′CBCR 主要用于视频编码。
  • 作为光谱曲线,它描述了光在电磁频谱上的行为(参见“光谱颜色函数”)。以光谱曲线表示的颜色,不像 RGB 或其他色彩空间中的颜色那样,具有不特定于光照条件的优点,而给定色彩空间中的颜色则假定特定的光照、观看或打印条件。

RGB 色彩模型

红绿蓝 (RGB) 色彩模型是主流计算机编程中最常见的色彩模型。RGB 模型理想上基于“红色”、“绿色”和“蓝色”光点应具有的强度,以在显示设备上重现特定颜色。(7) RGB 模型是一个立方体,一个顶点设置为“黑色”,相对的顶点设置为“白色”,其余顶点设置为“红色”、“绿色”、“蓝色”、“青色”、“黄色”和“品红色”。

RGB 颜色。 RGB 颜色由三个分量组成,顺序如下:“红色”、“绿色”、“蓝色”。

RGBA 颜色。 有些 RGB 颜色还包含第四个分量,称为 Alpha 分量,其范围从完全透明到完全不透明。本文档中此类 RGB 颜色称为 RGBA 颜色。没有 Alpha 分量的 RGB 颜色通常被认为是完全不透明的。

0-1 格式。 在本文档中,当其所有分量都大于等于 0 且小于等于 1 时,RGB 或 RGBA 颜色即为0-1 格式。本文档将所有 RGB 和 RGBA 颜色理解为此格式,除非另有说明。

RGB 色彩空间

存在许多RGB 色彩空间,而非仅一个,它们通常在红、绿、蓝和白点以及颜色分量传递函数(“传递函数”)方面有所不同。

  • 红、绿、蓝和白点。 这些是给定 RGB 色彩空间所认为的“红色”、“绿色”、“蓝色”和“白色”,即该空间分别与 RGB 颜色 (1, 0, 0)、(0, 1, 0)、(0, 0, 1) 和 (1, 1, 1) 相关联。(前三个点通常称为“基色”)。这些点不必是实际的颜色(例如,这在 ACES2065-1 色彩空间 中有说明)。“基色”的例子是 Rec. 601 (NTSC)、Rec. 709 和 DCI-P3。白点的例子是 D50/2 和 D65/2 白点。

  • “传递函数”。 这是一个用于将所谓的线性 RGB 颜色逐分量转换为同一色彩空间中的编码 RGB (R′G′B′) 颜色的函数。例如,包括下面将提到的 sRGB 传递函数;伽马函数,如 c1/γ,其中 c 是红色、绿色或蓝色分量,γ 是正数;以及 PQ 和 HLG 函数。

一般而言,相同的三个数字,例如 (1, 0.5, 0.3),在不同的 RGB 色彩空间中识别出外观不同的 RGB 颜色。在本文档中,唯一详细描述的 RGB 色彩空间是 sRGB。(Lindbloom)(8) 包含许多 RGB 色彩空间的更多信息。

注释

  1. 在本文档中,除非另有说明,所有涉及 RGB 颜色的技术都适用于线性或编码形式的颜色。
  2. 在电视和电影行业中,一些 RGB 色彩空间,包括 sRGB,属于所谓的标准动态范围 (SDR) 色彩空间类别,而其他一些则覆盖更广的颜色范围(宽色域 WCG)、更广的“亮度”范围(高动态范围 HDR),或者两者兼而有之。(Mano 2018)(9) 包含 WCG/HDR 图像的介绍。另请参见国际电信联盟的 Rep. 2390-4,这是一份更高级的概述。
  3. 在图像和视频中编码的 RGB 颜色,或在文档中指定的 RGB 颜色,通常是 8-bpc 或 10-bpc 的编码 RGB 颜色。

sRGB

在 RGB 色彩空间中,最受欢迎的之一是 sRGB 色彩空间。在 sRGB 中 —

  • 选择红色、绿色和蓝色点是为了覆盖典型阴极射线管显示器(如高清标准 Rec. 709)所显示的颜色范围,
  • 选择白点为 D65/2 白点,并且
  • 颜色分量传递函数(在下面实现为 SRGBFromLinear)基于用于阴极射线管监视器的伽马编码。

背景信息请参阅 sRGB 提案,该提案建议将未识别的 RGB 色彩空间中的 RGB 图像数据视为 sRGB。

以下方法可在线性 sRGB 和编码 sRGB 之间转换颜色。(请注意,阈值 0.00313080.4045 是 IEC 61966-2-1,即官方 sRGB 标准的值;sRGB 提案对这些阈值有不同的值。)

// Convert a color component from encoded to linear sRGB
// NOTE: This is not gamma decoding; it's similar to, but
// not exactly, c^2.2.  This function was designed "to
// allow for invertability in integer math", according to
// the sRGB proposal.
METHOD SRGBToLinear(c)
 // NOTE: Threshold here would more properly be
 // 12.92 * 0.0031308 = 0.040449936, but 0.04045
 // is what the IEC standard uses
  if c <= 0.04045: return c / 12.92
  return pow((0.055 + c) / 1.055, 2.4)
END METHOD

// Convert a color component from linear to encoded sRGB
// NOTE: This is not gamma encoding; it's similar to, but
// not exactly, c^(1/2.2).
METHOD SRGBFromLinear(c)
  if c <= 0.0031308: return 12.92 * c
  return pow(c, 1.0 / 2.4) * 1.055 - 0.055
END METHOD

// Convert a color from encoded to linear sRGB
METHOD SRGBToLinear3(c)
   return [SRGBToLinear(c[0]), SRGBToLinear(c[1]), SRGBToLinear(c[2])]
END METHOD

// Convert a color from linear to encoded sRGB
METHOD SRGBFromLinear3(c)
   return [SRGBFromLinear(c[0]), SRGBFromLinear(c[1]), SRGBFromLinear(c[2])]
END METHOD

表示 RGB 颜色

以下显示了线性或编码 RGB 颜色如何表示为整数或文本。

二进制格式

RGB 和 RGBA 颜色通常通过将它们的分量打包为二进制整数来表示,如下所示:

  • RGB 颜色: 具有 RN 位红色分量、GN 位绿色分量和 BN 位蓝色分量,resulting in an integer that's (RN + GN + BN) bits long.
  • RGBA 颜色: 具有 RN 位红色分量、GN 位绿色分量、BN 位蓝色分量和 AN 位 Alpha 分量,resulting in an integer that's (RN + GN + BN + AN) bits long.

对于这两种类型的颜色,每个分量的最小值都是 0,最大值是 2B - 1,其中 B 是该分量的大小(以比特为单位)。

以下是这些格式的示例:

  • 5/6/5 RGB 颜色: 作为 16 位整数(红色和蓝色各 5 位,绿色 6 位)。
  • 5-bpc: 作为 15 位整数(5 bpc [每颜色分量比特数] RGB)。
  • 8-bpc: 作为 24 位整数(8 bpc RGB),或作为带 Alpha 分量的 32 位整数。
  • 10-bpc: 作为 30 位整数(10 bpc RGB),或作为带 Alpha 分量的 40 位整数。
  • 16-bpc: 作为 48 位整数(16 bpc RGB),或作为带 Alpha 分量的 64 位整数。

有许多方法可以将 RGB 和 RGBA 颜色以这些格式存储为整数或 8 位字节序列。例如,RGB 颜色的分量可以是“小端”或“大端”的 8 位字节顺序,或者颜色分量打包成整数的顺序也可能不同。本文档不打算调查可用的 RGB 二进制存储格式。

以下伪代码提供了将 RGB 颜色转换为各种二进制颜色格式(其中 RGB 颜色整数按红/绿/蓝的顺序从低位到高位打包)以及从这些格式转换回 RGB 的方法。

// Converts 0-1 format to N/N/N format as an integer.
METHOD ToNNN(rgb, scale)
   sm1 = scale - 1
   return round(rgb[2]*sm1) * scale * scale + round(rgb[1]*sm1) * scale +
         round(rgb[0]*sm1)
END METHOD

// Converts N/N/N integer format to 0-1 format
METHOD FromNNN(rgb, scale)
   sm1 = scale - 1
   r = rem(rgb, scale)
   g = rem(floor(rgb / scale), scale)
   b = rem(floor(rgb / (scale * scale)), scale)
   return [ r / sm1, g / sm1, b / sm1]
END METHOD

METHOD To444(rgb): return ToNNN(rgb, 16)
METHOD To555(rgb): return ToNNN(rgb, 32)
METHOD To888(rgb): return ToNNN(rgb, 256)
METHOD To161616(rgb): return ToNNN(rgb, 65536)
METHOD From444(rgb): return FromNNN(rgb, 16)
METHOD From555(rgb): return FromNNN(rgb, 32)
METHOD From888(rgb): return FromNNN(rgb, 256)
METHOD From161616(rgb): return FromNNN(rgb, 65536)

METHOD To565(rgb, scale)
   return round(rgb[2] * 31) * 32 * 64 + round(rgb[1] * 63) * 32 +
         round(rgb[0] * 31)
END METHOD

METHOD From565(rgb, scale)
   r = rem(rgb, 32)
   g = rem(floor(rgb / 32.0), 64)
   b = rem(floor(rgb / (32.0 * 64.0)), 32)
   return [ r / 31.0, g / 63.0, b / 31.0]
END METHOD

HTML 格式和其他文本格式

HTML 颜色格式(也称为“十六进制”格式)中的颜色字符串,它将 8-bpc RGB 颜色表示为文本字符串,由字符“#”组成,然后是红色分量的两个十六进制数字,绿色分量的两个,蓝色分量的两个,按此顺序。

例如,#003F86 表示 8-bpc RGB 颜色 (0, 63, 134)。

以下伪代码提供了将 RGB 颜色转换为 HTML 颜色格式或本节注释 1 中所述的 3 位变体,以及从这些格式转换回 RGB 的方法。

METHOD NumToHex(x)
    if hex < 0 or hex >= 16: return error
    hexlist=["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"]
    return hexlist[x]
END METHOD

METHOD HexToNum(x)
    hexlist=["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"]
    hexdown=["a", "b", "c", "d", "e", "f"]
    i = 0
    while i < 16
            if hexlist[i] == x: return i
            i = i + 1
    end
    i = 0
    while i < 6
            if hexdown[i] == x: return 10 + i
            i = i + 1
    end
    return -1
END METHOD

METHOD ColorToHtml(rgb)
   r = round(rgb[0] * 255)
   g = round(rgb[1] * 255)
   b = round(rgb[2] * 255)
   return ["#",
     NumToHex(rem(floor(r/16),16)), NumToHex(rem(r, 16)),
     NumToHex(rem(floor(g/16),16)), NumToHex(rem(g, 16)),
     NumToHex(rem(floor(b/16),16)), NumToHex(rem(b, 16)),
   ]
END METHOD

METHOD HtmlToColor(colorString)
    if string[0]!="#": return error
    if size(colorString)==7
            r1=HexToNum(colorString[1])
            r2=HexToNum(colorString[2])
            g1=HexToNum(colorString[3])
            g2=HexToNum(colorString[4])
            b1=HexToNum(colorString[5])
            b2=HexToNum(colorString[6])
            if r1<0 or r2<0 or g1<0 or g2<0 or
                    b1<0 or b2<0: return error
            return [(r1*16+r2)/255.0,
                    (g1*16+g2)/255.0,
                    (b1*16+b2)/255.0]
    end
    if size(colorString)==4
            r=HexToNum(colorString[1])
            g=HexToNum(colorString[2])
            b=HexToNum(colorString[3])
            if r<0 or g<0 or b<0: return error
            return [(r*16+r)/255.0,
                    (g*16+g)/255.0,
                    (b*16+b)/255.0]
    end
    return error
END METHOD

其他基于文本的颜色格式包括以下内容(11)

  • CSS 颜色模块 Level 3,它指定了这种格式,还提到了一个3 位变体,由“#”后跟三个十六进制数字组成,分别代表红色、绿色和蓝色分量,按此顺序。转换为 6 位格式涉及复制每个十六进制分量(例如,“#345”在 6 位格式中与“#334455”相同)。

  • Android 操作系统使用的8 位变体由“#”后跟八个十六进制数字组成,分别代表 Alpha、红色、绿色和蓝色分量,按此顺序。因此,这种变体描述了 8-bpc RGBA 颜色。

  • 附加格式在 补充色彩主题 中给出。

注意:CSS 颜色模块 Level 3(例如)中所用,HTML 颜色格式或其 3 位变体中的颜色位于 sRGB 色彩空间(作为编码 RGB 颜色)。

RGB 颜色转换

以下各节讨论了流行的用于转换 RGB 颜色的色彩模型。这些模型中颜色的确切外观因 RGB 色彩空间 而异。

HSV

HSV(也称为 HSB)是一种色彩模型,它转换 RGB 颜色,使其更易于操作和理解。HSV 颜色由三个分量组成,顺序如下:

  • 色相是从红色(0 度)到黄色、绿色、青色、蓝色、品红色再到红色的角度。(12)
  • 一个称为“饱和度”的分量,是颜色与灰色和白色的距离(但不一定是与黑色的距离),其值大于等于 0 且小于等于 1。
  • 一个称为“明度”或“亮度”的分量,是颜色与黑色的距离,其值大于等于 0 且小于等于 1。

以下伪代码在 RGB 和 HSV 之间转换颜色。该转换与 RGB 色彩空间无关,但应使用线性 RGB 颜色进行。

METHOD RgbToHsv(rgb)
    mx = max(max(rgb[0], rgb[1]), rgb[2])
    mn = min(min(rgb[0], rgb[1]), rgb[2])
    // NOTE: "Value" is the highest of the
    // three components
    if mx==mn: return [0,0,mx]
    s=(mx-mn)/mx
    h=0
    if rgb[0]==mx
            h=(rgb[1]-rgb[2])/(mx-mn)
    else if rgb[1]==mx
            h=2+(rgb[2]-rgb[0])/(mx-mn)
    else
            h=4+(rgb[0]-rgb[1])/(mx-mn)
    end
    if h < 0: h = 6 - rem(-h, 6)
    if h >= 6: h = rem(h, 6)
    return [h * (pi / 3), s, mx]
END METHOD

METHOD HsvToRgb(hsv)
    hue=hsv[0]
    sat=hsv[1]
    val=hsv[2]
    if hue < 0: hue = pi * 2 - rem(-hue, pi * 2)
    if hue >= pi * 2: hue = rem(hue, pi * 2)
    hue60 = hue * 3 / pi
    hi = floor(hue60)
    f = hue60 - hi
    c = val * (1 - sat)
    a = val * (1 - sat * f)
    e = val * (1 - sat * (1 - f))
    if hi == 0: return [val, e, c]
    if hi == 1: return [a, val, c]
    if hi == 2: return [c, val, e]
    if hi == 3: return [c, a, val]
    if hi == 4: return [e, c, val]
    return [val, c, a]
END METHOD

注意: HSV 色彩模型不是基于感知的,正如 HWB 文章所承认的(13)

HSL

HSL(也称为 HLS),与 HSV 类似,是一种色彩模型,它转换 RGB 颜色以简化直觉。HSL 颜色由三个分量组成,顺序如下:

  • 色相对于给定的 RGB 颜色与 HSV 中的相同。
  • 一个称为“饱和度”的分量,是颜色与灰色的距离(但不一定是与黑色或白色的距离),其值大于等于 0 且小于等于 1。
  • 一个称为“亮度”、“明度”或“辉度”的分量,大致表示与颜色混合的黑色或白色的量,其值大于等于 0 且小于等于 1,其中 0 表示黑色,1 表示白色,越接近 0 表示越接近黑色,越接近 1 表示越接近白色。

以下伪代码在 RGB 和 HSL 之间转换颜色。该转换与 RGB 色彩空间无关,但应使用线性 RGB 颜色进行。

METHOD RgbToHsl(rgb)
    vmax = max(max(rgb[0], rgb[1]), rgb[2])
    vmin = min(min(rgb[0], rgb[1]), rgb[2])
    vadd = vmax + vmin
    // NOTE: "Lightness" is the midpoint between
    // the greatest and least RGB component
    lt = vadd / 2.0
    if vmax==vmin: return [0, 0, lt]
    vd = vmax - vmin
    divisor = vadd
    if lt > 0.5: divisor = 2.0 - vadd
    s = vd / divisor
    h = 0
    hvd = vd / 2.0
    deg60 = pi / 3
    if rgb[0]==vmax
            h=((vmax-rgb[2])*deg60 + hvd) / vd
            h = h - ((vmax-rgb[1])*deg60+hvd) / vd
    else if rgb[2]==vmax
            h=pi * 4 / 3 + ((vmax-rgb[1])*deg60 + hvd) / vd
            h = h - ((vmax-rgb[0])*deg60+hvd) / vd
    else
            h=pi * 2 / 3 + ((vmax-rgb[0])*deg60 + hvd) / vd
            h = h - ((vmax-rgb[2])*deg60+hvd) / vd
    end
    if h < 0: h = pi * 2 - rem(-h, pi * 2)
    if h >= pi * 2: h = rem(h, pi * 2)
    return [h, s, lt]
END METHOD

METHOD HslToRgb(hsl)
    if hsl[1]==0: return [hsl[2],hsl[2],hsl[2]]
    lum = hsl[2]
    sat = hsl[1]
    bb = 0
    if lum <= 0.5: bb = lum * (1.0 + sat)
    if lum > 0.5: bb= lum + sat - (lum * sat)
    a = lum * 2 - bb
    hueval = hsl[0]
    if hueval < 0: hueval = pi * 2 - rem(-hueval, pi * 2)
    if hueval >= pi * 2: hueval = rem(hueval, pi * 2)
    deg60 = pi / 3
    deg240 = pi * 4 / 3
    hue = hueval + pi * 2 / 3
    hue2 = hueval - pi * 2 / 3
    if hue >= pi * 2: hue = hue - pi * 2
    if hues2 < 0: hues2 = hues2 + pi * 2
    rgb = [a, a, a]
    hues = [hue, hueval, hue2]
    i = 0
    while i < 3
       if hues[i] < deg60: rgb[i] = a + (bb - a) * hues[i] / deg60
       else if hues[i] < pi: rgb[i] = bb
       else if hues[i] < deg240
            rgb[i] = a + (bb - a) * (deg240 - hues[i]) / deg60
       end
       i = i + 1
    end
    return rgb
END METHOD

注释

  • 在某些应用程序和规范中,尤其是在该色彩模型被称为 HLS 时,“饱和度”分量位于“亮度”之前。本文档中并非如此。
  • HSL 色彩模型不是基于感知的,正如 HWB 文章所承认的(13)

HWB

1996 年,HWB 模型发布,旨在比 HSV 或 HSL 更直观(13)。HWB 颜色由三个分量组成,顺序如下:

  • 色相对于给定的 RGB 颜色与 HSV 中的相同。
  • 白度,与颜色混合的白色量,大于等于 0 且小于等于 1。
  • 黑度,与颜色混合的黑色量,大于等于 0 且小于等于 1。

以下给出的转换与 RGB 色彩空间无关,但应使用线性 RGB 颜色进行。

  • 要将 RGB 颜色 color 转换为 HWB,请生成 [RgbToHsv(color)[0], min(min(color[0], color[1]), color[2]), 1 - max(max(color[0], color[1]), color[2])]
  • 要将 HWB 颜色 hwb 转换为 RGB,请生成 HsvToRgb([hwb[0], 1 - hwb[1]/(1-hwb[2]), 1 - hwb[2]]) 如果 hwb[2] < 1,否则为 [hwb[0], 0, 0]

注意: HWB 色彩模型不是基于感知的,正如 HWB 文章所承认的(13)

Y′CBCR 和其他视频色彩格式

RGB 颜色可以转换为专门的形式以改进图像和视频编码。

Y′CBCR(也称为 YCbCr、YCrCb 或 Y′CrCb)是一系列为此目的设计的颜色格式。Y′CBCR 颜色由三个分量组成,顺序如下:

  • Y′,或亮度,表示近似的“亮度”。(14)
  • CB,或蓝色色度,基于蓝色与亮度的差异。
  • CR,或红色色度,基于红色与亮度的差异。

以下伪代码在 RGB 和 Y′CBCR 之间转换颜色。这里显示了三个变体,即 —

  • Rec. 601 变体(用于标清数字视频),如 YCbCrToRgb601RgbToYCbCr601 方法;
  • Rec. 709 变体(用于高清视频),如 YCbCrToRgb709RgbToYCbCr709 方法;以及
  • JPEG 文件交换格式 变体,如 YCbCrToRgbJpegRgbToYCbCrJpeg 方法。

Y′CBCR 转换与 RGB 色彩空间无关,但上面给出的三个变体应使用编码 RGB 颜色而不是线性 RGB 颜色。

// NOTE: Derived from scaled YPbPr using red/green/blue luminance factors
// in the NTSC color space
METHOD RgbToYCbCr601(rgb)
    y = (16.0/255.0+rgb[0]*0.25678824+rgb[1]*0.50412941+rgb[2]*0.097905882)
    cb = (128.0/255.0-rgb[0]*0.1482229-rgb[1]*0.29099279+rgb[2]*0.43921569)
    cr = (128.0/255.0+rgb[0]*0.43921569-rgb[1]*0.36778831-rgb[2]*0.071427373)
    return [y, cb, cr]
END METHOD

// NOTE: Derived from scaled YPbPr using red/green/blue Rec. 709 luminance factors
METHOD RgbToYCbCr709(rgb)
    y = (0.06200706*rgb[2] + 0.6142306*rgb[1] + 0.1825859*rgb[0] + 16.0/255.0)
    cb = (0.4392157*rgb[2] - 0.338572*rgb[1] - 0.1006437*rgb[0] + 128.0/255.0)
    cr = (-0.04027352*rgb[2] - 0.3989422*rgb[1] + 0.4392157*rgb[0] + 128.0/255.0)
    return [y, cb, cr]
END METHOD

// NOTE: Derived from unscaled YPbPr using red/green/blue luminance factors
// in the NTSC color space
METHOD RgbToYCbCrJpeg(rgb)
    y = (0.299*rgb[0] + 0.587*rgb[1] + 0.114*rgb[2])
    cb = (-0.1687359*rgb[0] - 0.3312641*rgb[1] + 0.5*rgb[2] + 128.0/255.0)
    cr = (0.5*rgb[0] - 0.4186876*rgb[1] - 0.08131241*rgb[2] + 128.0/255.0)
    return [y, cb, cr]
END METHOD

METHOD YCbCrToRgb601(yCbCr)
    cb = yCbCr[1] - 128/255.0
    cr = yCbCr[2] - 128/255.0
    yp = 1.1643836 * (yCbCr[0] - 16/255.0)
    r = yp + 1.5960268 * cr
    g = yp - 0.39176229 * cb - 0.81296765 * cr
    b = yp + 2.0172321 * cb
    return [min(max(r,0),1),min(max(g,0),1),min(max(b,0),1)]
END METHOD

METHOD YCbCrToRgb709(yCbCr)
    cb = yCbCr[1] - 128/255.0
    cr = yCbCr[2] - 128/255.0
    yp = 1.1643836 * (yCbCr[0] - 16/255.0)
    r = yp + 1.7927411 * cr
    g = yp - 0.21324861 * cb - 0.53290933 * cr
    b = yp + 2.1124018 * cb
    return [min(max(r,0),1),min(max(g,0),1),min(max(b,0),1)]
END METHOD

METHOD YCbCrToRgbJpeg(yCbCr)
    cb = yCbCr[1] - 128/255.0
    cr = yCbCr[2] - 128/255.0
    yp = yCbCr[0]
    r = yp + 1.402 * cr
    g = yp - 0.34413629 * cb - 0.71413629 * cr
    b = yp + 1.772 * cb
    return [min(max(r,0),1),min(max(g,0),1),min(max(b,0),1)]
END METHOD

注释

  1. 本文档不打算调查 Y′CBCR 和类似颜色如何构建成图像和视频像素的各种方式。通常,这些方式会考虑人眼对亮度(Y,近似为 Y′,亮度)的空间敏感度通常高于色度敏感度(例如 CB、CR)。
  2. 其他视频色彩格式包括 Rec. 2020 中的“BT.2020 常量亮度”,以及 Rep. 2390-4 中提到的 ICTCP,并在Dolby 白皮书中详细介绍。

其他色彩模型

以下各节讨论了其他实用色彩模型。

CIE XYZ

CIE 1931 标准色彩测量系统(本文档中称为 XYZ 色彩模型)描述了将光谱曲线转换为三维空间中的一个点,进一步在“光谱颜色函数”中解释。XYZ 颜色由三个分量组成,顺序如下:

  • X 是一个没有特殊含义的分量。
  • Y 与颜色的亮度相关。
  • Z 是一个没有特殊含义的分量。

XYZ 颜色的约定包括以下内容:

  • 绝对 XYZ。 在此约定中,Y 分量表示以坎德拉/平方米 (cd/m2) 为单位的绝对亮度
  • 相对 XYZ。 在此约定中,三个分量除以给定白点的亮度。在这种情况下,Y 分量表示亮度因子;白点的亮度因子为 1。(15) (在 sRGB 中,白点的亮度为 80 cd/m2。)

RGB 和 XYZ 之间的转换因 RGB 色彩空间 而异。例如,以下伪代码显示了两个方法,用于在编码 sRGB (rgb) 和相对 XYZ 之间转换颜色。

  • 对于 XYZFromsRGB(rgb)XYZTosRGB(xyz),白点为 D65/2 白点。
  • 对于 XYZFromsRGBD50(rgb)XYZTosRGBD50(xyz),白点为 D50/2 白点。(16)

 

// Applies a 3&times;3 matrix transformation
METHOD Apply3x3Matrix(xyz, xyzmatrix)
    r=xyz[0]*xyzmatrix[0]+xyz[1]*xyzmatrix[1]+xyz[2]*xyzmatrix[2]
    g=xyz[0]*xyzmatrix[3]+xyz[1]*xyzmatrix[4]+xyz[2]*xyzmatrix[5]
    b=xyz[0]*xyzmatrix[6]+xyz[1]*xyzmatrix[7]+xyz[2]*xyzmatrix[8]
    return [r,g,b]
END METHOD

METHOD XYZFromsRGBD50(rgb)
    lin=SRGBToLinear3(rgb)
    // D65/2 sRGB matrix adapted to D50/2
    return Apply3x3Matrix(lin, [
       0.436027535573195, 0.385097932872408, 0.143074531554397,
       0.222478677613186, 0.716902127457834, 0.0606191949289806,
       0.0139242392790820, 0.0970836931437703, 0.714092067577148])
END METHOD

METHOD XYZTosRGBD50(xyz)
    // D65/2 sRGB matrix adapted to D50/2
    rgb=Apply3x3Matrix(xyz, [
       3.13424933163426, -1.61717292521282, -0.490692377104512,
       -0.978746070339639, 1.91611436125945, 0.0334415219513205,
       0.0719490494816283, -0.228969853236611, 1.40540126012171])
    return SRGBFromLinear3(rgb)
END METHOD

METHOD XYZFromsRGB(rgb)
    lin=SRGBToLinear3(rgb)
    // D65/2 sRGB matrix
    return Apply3x3Matrix(lin, [
      0.4123907992659591, 0.35758433938387796, 0.18048078840183424
       0.21263900587151016, 0.7151686787677559, 0.0721923153607337
       0.01933081871559181, 0.11919477979462596, 0.9505321522496605])
END METHOD

METHOD XYZTosRGB(xyz)
    // D65/2 sRGB matrix
    rgb=Apply3x3Matrix(xyz, [
       3.2409699419045235, -1.5373831775700944, -0.49861076029300355,
        -0.9692436362808797, 1.8759675015077204, 0.0415550574071756,
        0.05563007969699365, -0.20397695888897652, 1.0569715142428786])
    return SRGBFromLinear3(rgb)
END METHOD

注释

  1. 在上述伪代码中,使用 3x3 矩阵将线性 RGB 颜色转换为 XYZ 形式或从 XYZ 形式转换回来(参见 “XYZ 和 RGB 之间的转换矩阵”)。
  2. XYZTosRGBXYZTosRGBD50 可以返回分量小于 0 或大于 1 的 sRGB 颜色,以便更容易识别超出范围的 XYZ 颜色。如果不需要,则可以将 sRGB 颜色转换为范围内的颜色。存在许多此类色域映射转换;例如,一种转换涉及使用min(max(compo,0), 1) 的惯用语来钳制 sRGB 颜色的每个分量,其中 compo 是该分量。
  3. 经过黑点补偿的 XYZ 颜色(参见 ISO 18619)可以表示为 Lerp3(wpoint, xyz, (1.0 - blackDest) / (1.0 - blackSrc)),其中 —
    • wpoint 是作为绝对或相对 XYZ 颜色的白点,
    • xyz 是一个相对 XYZ 颜色(相对于 wpoint),并且
    • blackSrcblackDest 是源黑点和目标黑点的亮度因子。

通过 RGB 对 XYZ 进行编码

以下总结了将颜色从(相对)XYZ 转换为 RGB,再到适合图像或视频编码的形式所需的转换。

  1. XYZ 到线性 RGB 的转换。这通常是一个矩阵,使用 RGB 色彩空间的红色、绿色、蓝色和白点生成,但如果 XYZ 和 RGB 色彩空间使用不同的白点,也可能包含色度适应转换(参见上面的 XYZFromsRGBD50XYZTosRGBD50 方法)(17)
  2. 线性到编码 RGB 的转换。这是 RGB 色彩空间的“传递函数”。如果需要线性 RGB 颜色,则可以省略此项。
  3. 像素编码转换。这会将 RGB 颜色转换为Y′CBCR 或其他形式。可以省略此项。
  4. 最终的颜色形式被序列化为二进制、文本或其他表示形式(另请参见“表示 RGB 颜色”)。

到 XYZ 的相应转换然后是上述转换的逆。

XYZ 和 RGB 之间的转换矩阵

以下方法计算一个 3x3 矩阵,用于将线性 RGB 颜色转换为 XYZ 形式(RGBToXYZMatrix)并从 XYZ 形式转换回来(XYZToRGBMatrix),给定 RGB 色彩空间的红色、绿色、蓝色和白点。每个点都表示为具有任意 X 和 Z 分量且 Y 分量为 1 的相对 XYZ 颜色。例如,xrzr 分别是红色点的 X 和 Z 分量。更多信息请参见 brucelindbloom.com

METHOD RGBToXYZMatrix(xr,zr,xg,zg,xb,zb,xw,zw)
 s1=(xb*zg - xb*zw - xg*zb + xg*zw + xw*zb - xw*zg)
 s2=(xb*zg - xb*zr - xg*zb + xg*zr + xr*zb - xr*zg)
 s3=(-xb*zr + xb*zw + xr*zb - xr*zw - xw*zb + xw*zr)
 sz=(-xr*(zg - zr) + xw*(zg - zr) + zr*(xg - xr) -
    zw*(xg - xr)) /
    ((xb - xr)*(zg - zr) - (xg - xr)*(zb - zr))
 sx=s1/s2
 sy=s3/s2
 return [xr*sx,xg*sy,xb*sz,sx,sy,sz,zr*sx,zg*sy,zb*sz]
END METHOD

METHOD XYZToRGBMatrix(xr,zr,xg,zg,xb,zb,xw,zw)
 // NOTE: Inverse of RGBToXYZMatrix
 d1=(xb*zg - xb*zw - xg*zb + xg*zw + xw*zb - xw*zg)
 d2=(xb*zr - xb*zw - xr*zb + xr*zw + xw*zb - xw*zr)
 d3=(xg*zr - xg*zw - xr*zg + xr*zw + xw*zg - xw*zr)
 return [(zb - zg)/d1,(xb*zg - xg*zb)/d1,
  (-xb + xg)/d1, (zb - zr)/d2,
  (xb*zr - xr*zb)/d2,(-xb + xr)/d2,
  (zg - zr)/d3,(xg*zr - xr*zg)/d3,
  (-xg + xr)/d3]
END METHOD

色度坐标

色度坐标 xyz 分别是 XYZ 颜色相应分量与这些分量之和的比率;因此,这三个坐标加起来等于 1。(18) “xyY”形式由 xy 和 XYZ 颜色的 Y 分量组成。“Yxy”形式由 XYZ 颜色的 Y 分量、xy 组成。

CIE 1976 均匀色度图使用坐标 u′v′ 绘制。(19) “u′v′Y”形式由 u′v′ 和 XYZ 颜色的 Y 分量组成。“Yu′v′”形式由 XYZ 颜色的 Y 分量、u′v′ 组成。

在以下伪代码中,XYZToxyYXYZFromxyY 分别将 XYZ 颜色转换为其“xyY”形式并从其“xyY”形式转换回来;XYZTouvYXYZFromuvY 分别将 XYZ 颜色转换为其“u′v′Y”形式并从其“u′v′Y”形式转换回来。

    METHOD XYZToxyY(xyz)
            sum=xyz[0]+xyz[1]+xyz[2]
            if sum==0: return [0,0,0]
            return [xyz[0]/sum, xyz[1]/sum, xyz[1]]
    END METHOD

    METHOD XYZFromxyY(xyy)
            // NOTE: Results undefined if xyy[1]==0
            return [xyy[0]*xyy[2]/xyy[1], xyy[2], xyy[2]*(1 - xyy[0] - xyy[1])/xyy[1]]
    END METHOD

    METHOD XYZTouvY(xyz)
            sum=xyz[0]+xyz[1]*15.0+xyz[2]*3.0
            if sum==0: return [0,0,0]
            return [4.0*xyz[0]/sum,9.0*xyz[1]/sum,xyz[1]]
    END METHOD

    METHOD XYZFromuvY(uvy)
            // NOTE: Results undefined if uvy[1]==0
            su=uvy[2]/(uvy[1]/9.0)
            x=u*su/4.0
            z=(su/3.0)-(x/3.0)-5.0*uvy[2]
            return [x,uvy[2],z]
    END METHOD

CIELAB

CIELAB(也称为 CIE L*a*b* 或 CIE 1976 L*a*b*)是一种用于颜色比较的三维色彩模型。(20) 一般而言,CIELAB 色彩空间在其白点上有所不同。

CIELAB 中的颜色由三个分量组成,顺序如下:

  • L*,或颜色的亮度(与其相比的亮度),范围从 0 到 100,其中 0 是黑色,100 是白色。
  • a* 是红/绿轴的坐标(正值指向红色,负值指向绿色)。
  • b* 是黄/蓝轴的坐标(正值指向黄色,负值指向蓝色)。(21)

L*C*h 形式将 CIELAB 颜色表示为圆柱坐标;三个分量顺序如下:

  • 亮度 (L*) 保持不变。
  • 色度 (C*) 是颜色与“灰色”线的距离。(22)
  • 色相 (h,一个角度)(12) 范围从大约 0 度的品红色到红色、黄色、绿色、青色、蓝色再到品红色。

在以下伪代码中:

  • 以下方法将编码 sRGB 颜色转换为 CIELAB,以及从 CIELAB 转换回编码 sRGB:
    • SRGBToLabSRGBFromLab 将白色视为 D65/2 白点。
    • SRGBToLabD50SRGBFromLabD50 将白色视为 D50/2 白点。(16)
  • XYZToLab(xyz, wpoint)LabToXYZ(lab, wpoint) 分别将 XYZ 颜色转换为 CIELAB 或从 CIELAB 转换,将 wpoint(一个 XYZ 颜色)视为白点。
  • LabToChroma(lab)LabToHue(lab) 分别查找 CIELAB 颜色的色度色相
  • LchToLab(lch) 在给定亮度、色度和色相(L*C*h)的 3 项列表时,查找 CIELAB 颜色。
  • LabHueDifference(lab1, lab2) 计算两个 CIELAB 颜色之间的色相差ΔH*)。返回值可以是正数或负数,但在某些情况下,该返回值的绝对值可能很重要。
  • LabChromaHueDifference(lab1, lab2) 计算两个 CIELAB 颜色之间的色度色相差(ΔCh),如 ISO 13655 所示。

 

METHOD XYZToLab(xyzval, wpoint)
    xyz=[xyzval[0]/wpoint[0],xyzval[1]/wpoint[1],xyzval[2]/wpoint[2]]
    i=0
    while i < 3
       if xyz[i] > 216.0 / 24389 // See BruceLindbloom.com
          xyz[i]=pow(xyz[i], 1.0/3.0)
       else
           kappa=24389.0/27 // See BruceLindbloom.com
           xyz[i]=(16.0 + kappa*xyz[i]) / 116
       end
       i=i+1
    end
    return [116.0*xyz[1] - 16,
        500 * (xyz[0] - xyz[1]),
        200 * (xyz[1] - xyz[2])]
END METHOD

METHOD LabToXYZ(lab,wpoint)
    fy=(lab[0]+16)/116.0
    fx=fy+lab[1]/500.0
    fz=fy-lab[2]/200.0
    fxcb=fx*fx*fx
    fzcb=fz*fz*fz
    xyz=[fxcb, 0, fzcb]
    eps=216.0/24389 // See BruceLindbloom.com
    if fxcb <= eps: xyz[0]=(108.0*fx/841)-432.0/24389
    if fzcb <= eps: xyz[2]=(108.0*fz/841)-432.0/24389
    if lab[0] > 8 // See BruceLindbloom.com
            xyz[1]=pow(((lab[0]+16)/116.0), 3.0)
    else
            xyz[1]=lab[0]*27.0/24389 // See BruceLindbloom.com
    end
    xyz[0]=xyz[0]*wpoint[0]
    xyz[1]=xyz[1]*wpoint[1]
    xyz[2]=xyz[2]*wpoint[2]
    return xyz
END METHOD

METHOD SRGBToLab(rgb)
    return XYZToLab(XYZFromsRGB(rgb),
      [0.9504559270516716, 1, 1.0890577507598784])
END METHOD

METHOD SRGBFromLab(lab)
    return XYZTosRGB(LabToXYZ(lab,
      [0.9504559270516716, 1, 1.0890577507598784]))
END METHOD

METHOD SRGBToLabD50(rgb)
    return XYZToLab(XYZFromsRGBD50(rgb), [0.9642, 1, 0.8251])
END METHOD

METHOD SRGBFromLabD50(lab)
    return XYZTosRGBD50(LabToXYZ(lab, [0.9642, 1, 0.8251]))
END METHOD

   // -- Derived values from CIELAB colors

METHOD LabToChroma(lab)
        return sqrt(lab[1]*lab[1] + lab[2]*lab[2])
END METHOD

    METHOD LabToHue(lab)
            h = atan2(lab[2], lab[1])
            if h < 0: h = h + pi * 2
            return h
    END METHOD

    METHOD LchToLab(lch)
            return [lch[0], lch[1] * cos(lch[2]), lch[1] * sin(lch[2])]
    END METHOD

METHOD LabHueDifference(lab1, lab2)
  cmul=LabToChroma(lab1)*LabToChroma(lab2)
  h2=LabToHue(lab2)
  h1=LabToHue(lab1)
  hdiff=h2-h1
  if abs(hdiff)>pi
        if h2<=h1: hdiff=hdiff+math.pi*2
        else: hdiff=hdiff-math.pi*2
  end
  return sqrt(cmul)*sin(hdiff*0.5)*2
END METHOD

METHOD LabChromaHueDifference(lab1, lab2)
            da=lab1[1]-lab2[1]
            db=lab1[2]-lab2[2]
            return sqrt(da*da+db*db)
    END METHOD

注意: 两个 CIELAB 颜色之间的亮度、a*b* 或色度(分别称为ΔL*Δa*Δb*ΔC*)的差异仅是第二个 CIELAB 颜色的相应值与其第一个值之间的差。

CIELUV

CIELUV(也称为 CIE L*u*v* 或 CIE 1976 L*u*v*)是第二个用于颜色比较的色彩模型。CIELUV 颜色有三个分量,即 L*,或亮度(与 CIELAB 相同),u*,和 v*,按此顺序。正如B. MacEvoy 解释的,“CIELUV 将两种光的加性混合表示为一条直线”,因此这种色彩模型对于光源特别有用。

在以下伪代码中 —

  • SRGBToLuvSRGBFromLuvSRGBToLuvD50SRGBFromLuvD50XYZToLuvLuvToXYZ 方法执行的涉及 CIELUV 颜色的转换,与CIELAB的同名方法类似,并且
  • LuvToSaturation 方法查找 CIELUV 颜色的饱和度suv)。

 

METHOD XYZToLuv(xyz, wpoint)
    lab=XYZToLab(xyz, wpoint)
    sum=xyz[0]+xyz[1]*15+xyz[2]*3
    lt=lab[0]
    if sum==0: return [lt, 0, 0]
    upr=4*xyz[0]/sum // U-prime
    vpr=9*xyz[1]/sum // V-prime
    sumwhite=wpoint[0]+15*wpoint[1]+wpoint[2]*3
    return [lt,
            lt*13*(upr - 4*wpoint[0]/sumwhite),
            lt*13*(vpr - 9.0*wpoint[1]/sumwhite)]
END METHOD

METHOD LuvToXYZ(luv, wpoint)
    if luv[0]==0: return [0, 0, 0]
    xyz=LabToXYZ([luv[0], 1, 1],wpoint)
    sumwhite=wpoint[0]+15*wpoint[1]+wpoint[2]*3
    u0=4*wpoint[0]/sumwhite
    v0=9.0*wpoint[1]/sumwhite
    lt=luv[0]
    a=(52*lt/(luv[1]+13*u0*lt)-1)/3.0
    d=xyz[1]*(39*lt/(luv[2]+13*v0*lt)-5)
    x=(d+5*xyz[1])/(a+1.0/3)
    z=x*a-5*xyz[1]
    return [x,xyz[1],z]
END METHOD

METHOD SRGBToLuv(rgb)
    return XYZToLuv(XYZFromsRGB(rgb),
      [0.9504559270516716, 1, 1.0890577507598784])
END METHOD

METHOD SRGBFromLuv(lab)
    return XYZTosRGB(LuvToXYZ(lab,
      [0.9504559270516716, 1, 1.0890577507598784]))
END METHOD

METHOD SRGBToLuvD50(rgb)
    return XYZToLuv(XYZFromsRGBD50(rgb), [0.9642, 1, 0.8251])
END METHOD

METHOD SRGBFromuvD50(lab)
    return XYZTosRGBD50(LuvToXYZ(lab, [0.9642, 1, 0.8251]))
END METHOD

METHOD LuvToSaturation(luv)
    if luv[0]==0: return 0
    return sqrt(luv[1]*luv[1]+luv[2]*luv[2])/luv[0]
END METHOD

注释

  • 色相和色度可以从 CIELUV 颜色派生出来,方式类似于从 CIELAB 颜色派生,其中分别使用 u*v* 而不是 a*b*。上一节中的 LabToHueLabToChromaLabHueDifferenceLabChromaHueDifferenceLchToLab 方法对 CIELUV 颜色的处理方式类似于 CIELAB 颜色。
  • 两个 CIELUV 颜色之间的亮度、u*v*、色度或饱和度的差异(分别称为ΔL*Δu*Δv*ΔC*uvΔsuv)仅仅是第二个 CIELUV 颜色的相应值与其第一个值之间的差。

CMYK 和其他油墨混合色彩模型

CMYK 色彩模型,理想情况下,描述了在表面上重现特定颜色所需的青色、品红色、黄色和黑色 (K) 油墨的比例。(23) 然而,由于油墨或其他着色剂的色彩混合非常复杂,任何着色剂配方的确切颜色外观(不仅在 CMYK 上)取决于印刷条件(如 ISO 12647-1 中定义),包括使用的着色剂、印刷方式以及印刷品的表面(例如纸张)。

特性表. 在印刷行业实践中,通过找出给定印刷条件如何使用不同油墨混合来形成颜色,来对其进行特性描述。这通常通过印刷 CMYK 颜色“色块”并使用颜色测量设备在标准化的光照和测量条件下测量它们的CIELAB 颜色来完成。

国际色彩联盟维护一个标准化 CMYK 颜色“色块”转换列表,通常转换为 CIELAB 颜色,用于不同的标准化印刷条件。此类转换通常称为特性数据特性表

给定 CMYK 到 CIELAB 的特性表,可以通过对表中“色块”进行多维插值,将 CMYK 颜色转换为 CIELAB 颜色,或从 CIELAB 颜色转换回来。(24)

粗略转换. 以下伪代码显示了 RGB 颜色 (color) 和 CMYK 颜色 (cmyk) 之间的非常粗略的转换。

    // RGB to CMYK
    k = min(min(1.0 - color[0], 1.0 - color[1]), 1.0 - color[2])
    cmyk=[0, 0, 0, 1]
    if k!=1:
       cmyk=[((1.0 - color[0]) - k) / (1 - k), ((1.0 - color[1]) - k) /
          (1 - k), ((1.0 - color[2]) - k) / (1 - k), k]
    end
    // CMYK to RGB
    ik = 1 - cmyk[3]
    color=[(1 - cmyk[0]) * ik, (1 - cmyk[1]) * ik, (1 - cmyk[2]) * ik]

颜色操作

本节将介绍许多可以对颜色进行的操作。请注意,为了获得最佳效果,这些操作需要使用线性 RGB 颜色而不是编码 RGB 颜色来执行,除非另有说明。

亮度因子(灰度)

亮度因子

  • 是一个单一数字,表示颜色相对于“白色”的亮度,即,当观察该颜色时到达眼睛的光量与“白色”相比。
  • 在本文档中称为Luminance(color)
  • 等同于相对 XYZ 颜色 的 Y 分量,并且
  • 范围从“黑色”的 0 到“白色”的 1。

找到颜色的亮度因子取决于该颜色的色彩空间。

线性 RGB 颜色的亮度因子是 (color[0] * r + color[1] * g + color[2] * b),其中 rgb 是 RGB 色彩空间的红色、绿色和蓝色点的亮度因子(相对 Y 分量)。(如果应该有一个不同于 RGB 色彩空间常用白点的白点,其亮度因子为 1,则 rgb 是从一个白点到另一个白点的色度适应转换后的相应值。(17)

编码 RGB 颜色需要先转换为线性 RGB(在同一 RGB 色彩空间中),然后再查找其亮度因子。例如,以下伪代码实现了编码 sRGB 颜色的 Luminance(color)LuminanceSRGBLuminanceSRGBD50(16)

// Convert encoded sRGB to luminance factor
METHOD LuminanceSRGB(color)
    // Convert to linear sRGB
    c = SRGBToLinear(color)
    // Find the linear sRGB luminance factor
    return c[0] * 0.2126 + c[1] * 0.7152 + c[2] * 0.0722
END METHOD

// Convert encoded sRGB (with D50/2 white point)
// to luminance factor
METHOD LuminanceSRGBD50(color)
    c = SRGBToLinear(color)
    return c[0] * 0.2225 + c[1] * 0.7169 + c[2] * 0.0606
END METHOD

示例

  1. 灰度。 颜色 color 可以通过计算 [Luminance(color), Luminance(color), Luminance(color)] 来转换为灰度。
  2. 图像颜色列表平均亮度因子通常等同于该图像颜色列表中颜色的平均 Luminance(color) 值。
  3. 应用程序可以将颜色视为暗色,如果 Luminance(color) 低于某个阈值,例如 15。
  4. 应用程序可以将颜色视为亮色,如果 Luminance(color) 高于某个阈值,例如 70。

注意: Luminance(color) 属于一类函数,它们输出一个总结颜色的单个数字,范围从“最小强度”的 0 到“最大强度”的 1。以下是此系列中的其他函数:

  1. 单通道多分量颜色;例如,RGB 颜色分量的红色、绿色或蓝色分量分别为 color[0]color[1]color[2]
  2. 平均值多分量颜色的分量(参见 Alpha 混合)。
  3. 最大值;例如,三成分颜色的 max(max(color[0], color[1]), color[2])
  4. 最小值;例如,三成分颜色的 min(min(color[0], color[1]), color[2])。(对于技术 1-4,另请参见 (Helland)(25)。)
  5. 明暗因子CIELABCIELUV 颜色的亮度 (L*) 除以 100(或在具有明暗维度的其他色彩空间中的类似比率,例如 HSL 的“亮度” (Cook 2009)(26))。

Alpha 混合

Alpha 混合是对两个多分量颜色(例如两个 RGB 颜色)进行的逐分量线性插值。例如,下面的 Lerp3 函数(27) 对两个三成分颜色进行 Alpha 混合,其中 —

  • color1color2 是两种颜色,以及
  • alpha,即 Alpha 分量,通常大于等于 0 且小于等于 1(从 color1color2),但不必如此(Haeberli 和 Voorhees)(28)

 

METHOD Lerp3(color1, color2, alpha)
    return [color1[0]+(color2[0]-color1[0])*alpha, color1[1]+(color2[1]-color1[1])*alpha,
        color1[2]+(color2[2]-color1[2])*alpha]
END METHOD

Alpha 混合可以支持以下颜色操作:

  • 阴影。 通过将该颜色与黑色(例如 RGB 中的 [0, 0, 0])进行 Alpha 混合,可以生成颜色的阴影(与黑色混合)。
  • 色调。 通过将该颜色与白色(例如 RGB 中的 [1, 1, 1])进行 Alpha 混合,可以生成颜色的色调(与白色混合)。
  • 音调。 通过将该颜色与灰色(例如 RGB 中的 [0.5, 0.5, 0.5])进行 Alpha 混合,可以生成颜色的音调(与灰色混合)。
  • 平均。 通过将 alpha 设置为 0.5 的 Alpha 混合来平均两种颜色。
  • 着色。 color1 为黑色,color2 为目标颜色,alpha 是一个总结源颜色的数字,范围从“最小强度”的 0 到“最大强度”的 1。RGB 示例:Lerp3([0, 0, 0], destinationColor, Luminance(srcColor)),其中 Luminance“亮度因子(灰度)”中所述。目标颜色通常对图像中的每个像素都相同。
  • 将 RGBA 颜色转换为白色上的 RGB 颜色可以按以下方式完成:Lerp3([color[0], color[1], color[2]], [1, 1, 1], color[3])
  • 将 RGBA 颜色转换为另一个 RGB 颜色 color2 上的 RGB 颜色可以按以下方式完成:Lerp3([color[0], color[1], color[2]], color2, color[3])

二值化

二值化,也称为阈值处理,涉及将像素或颜色分类到两个类别之一(通常是黑色或白色)。它通过对像素或颜色应用一个函数,如果结果大于阈值则返回 1,否则返回 0。以下是 RGB 颜色(0-1 格式)二值化的示例。

  • 黑白。 如果明暗因子(例如颜色的 CIELAB 亮度 L* 除以 100)大于 0.5,则生成 [1, 1, 1](白色),否则生成 [0, 0, 0](黑色)。
  • 对比色。 如果明暗因子小于 0.5,则生成 [1, 1, 1](白色),否则生成 [0, 0, 0](黑色)。

其他形式的二值化可能会根据像素在图像中的位置至少部分地对其进行分类。

色彩方案和和谐

以下技术生成与现有颜色相关的颜色。

  • 色彩和谐(29) 通过生成在色相(色相角)上有所不同的几种颜色来实现。对于下面给出的每种颜色和谐,以下数字会加到色相角(12) 上,以生成构成该和谐的颜色的色相:
    • 类似色:0、Y、-Y,其中 Y 小于等于 2π/3。一般而言,类似色是指在色相间隔上与中心颜色等距排列的两种、四种或更多偶数种颜色。
    • 互补色:0、π。这是基本色相与其相反色相。
    • 分裂互补色:0、π - Y、π + Y,其中 Y 大于 0 且小于等于 π/2。基本色相和两个接近相反色相的色相。
    • 三元色:0、2π/3、4π/3。基本色相和距离该色相 120 度的两个色相。
    • 双色:0、Y,其中 Y 大于 -π/2 且小于 π/2。基本色相和一个接近的色相。
    • 偏互补色:0、Y,其中 Y 小于等于 -π/2 但大于 -π,或 Y 大于等于 π/2 但小于 π。B. MacEvoy 提到 Y = 2π/3。
    • 双重互补色:0、Y、π、π + Y,其中 Y 大于等于 -π/2 且小于等于 π/2。基本色相和一个接近的色相,以及它们的相反色相。
    • 四色:双重互补色,其中 Y = π/2。
    • N 色:0、2π/N、4π/N、...、(N - 1)2π/N。
  • 单色:具有相同色相的颜色;例如,给定颜色的不同阴影、色调和/或音调是单色。
  • 非彩色:无色相的颜色;即黑色、白色和/或不同灰度的颜色。

两种颜色之间的对比度

查找两种颜色之间对比度的方法有几种。

亮度对比度。 亮度对比度公式量化了前景(文本)颜色在背景颜色上或反之的显示差异,这取决于两种颜色的亮度。一般而言,差异越大,对比度越高。

示例: Web 内容可访问性指南 2.0 (WCAG) 包含一个对比度比公式,在以下伪代码中实现,其中 RelLum(color)

  • 是 WCAG 定义的颜色的“相对亮度”,并且
  • 在不关注 WCAG 合规性的情况下,等同于Luminance(color)

 

METHOD ContrastRatioWCAG(color1, color2)
    rl1=RelLum(color1)
    rl2=RelLum(color2)
    return (max(rl1,rl2)+0.05)/(min(rl1,rl2)+0.05)
END METHOD

对于 8-bpc 编码 sRGB 颜色,RelLum(color) 在功能上等同于 LuminanceSRGB(color),但 WCAG 使用了一个不同的 SRGBToLinear 版本,值为 0.03928(sRGB 提案中使用的值),而不是 0.04045,但这对于 8-bpc 颜色不会影响结果。一般而言,在 WCAG 下,对比色是指其对比度比与其他颜色的比率为 4.5 或更高(或对于更严格的合规性级别为 7 或更高)。

不透明度。 在某些行业中,材料的对比度比不透明度可以通过将测量在黑色表面上的材料的 XYZ 颜色的 Y 分量除以测量在白色表面上的材料的 XYZ 颜色的 Y 分量来获得。测量的细节取决于行业和材料。

Porter–Duff 公式

Porter 和 Duff (1984) 定义了十二种组合(混合)两个 RGBA 颜色的公式(30)。在下面的公式中,假设两个颜色和输出都是 0-1 格式并且已经预乘(也就是说,它们的红色、绿色和蓝色分量已经被其 Alpha 分量预先乘了)。给定 src(源 RGBA 颜色)和 dst(目标 RGBA 颜色),Porter–Duff 公式如下。

  • 源覆盖[src[0]-dst[0]*(src[3] - 1), src[1]-dst[1]*(src[3] - 1), src[2]-dst[2]*(src[3] - 1), src[3]-dst[3]*(src[3] - 1)]
  • 源内在[dst[3]*src[0], dst[3]*src[1], dst[3]*src[2], dst[3]*src[3]]
  • 源排除[src[0]*(1 - dst[3]), src[1]*(1 - dst[3]), src[2]*(1 - dst[3]), src[3]*(1 - dst[3])]
  • 源重叠[dst[0]*src[3] - src[0]*(dst[3] - 1), dst[1]*src[3] - src[1]*(dst[3] - 1), dst[2]*src[3] - src[2]*(dst[3] - 1), src[3]]
  • 目标覆盖[dst[0] - src[0]*(dst[3] - 1), dst[1] - src[1]*(dst[3] - 1), dst[2] - src[2]*(dst[3] - 1), dst[3] - src[3]*(dst[3] - 1)]
  • 目标内在[dst[0]*src[3], dst[1]*src[3], dst[2]*src[3], dst[3]*src[3]]。使用目标颜色/Alpha,将源 Alpha 作为“掩码”。
  • 目标排除[dst[0]*(1 - src[3]), dst[1]*(1 - src[3]), dst[2]*(1 - src[3]), dst[3]*(1 - src[3])]
  • 目标重叠[dst[3]*src[0] - dst[0]*(src[3] - 1), dst[3]*src[1] - dst[1]*(src[3] - 1), dst[3]*src[2] - dst[2]*(src[3] - 1), dst[3]]
  • src
  • 目标dst
  • 清除[0, 0, 0, 0]
  • 异或[-dst[3]*src[0] - dst[0]*src[3] + dst[0] + src[0], -dst[3]*src[1] - dst[1]*src[3] + dst[1] + src[1], -dst[3]*src[2] - dst[2]*src[3] + dst[2] + src[2], -2*dst[3]*src[3] + dst[3] + src[3]]

混合模式

混合模式 接收两个多分量颜色,即源颜色和目标颜色,并将它们混合以创建新颜色。相同的混合模式,或不同的混合模式,可以应用于给定颜色的每个分量。在下面的惯用语中,src 是源颜色的一个分量,dst 是目标颜色同一分量(例如,srcdst 都可以是两个 RGB 颜色的红色分量),并且假定两个分量都大于等于 0 且小于等于 1。以下是混合模式的示例。

  • 正常src
  • 变亮max(src, dst)
  • 变暗min(src, dst)
  • 相加min(1.0, src + dst)
  • 相减max(0.0, src - dst)
  • 相乘(src * dst)
  • 滤色1 - (1 - dst) * (1 - src)
  • 平均src + (dst - src) * 0.5
  • 差值abs(src - dst)
  • 排除src - 2 * src * dst + dst

颜色矩阵

颜色矩阵是用于转换三成分颜色的 9 项(3x3)列表。以下是颜色矩阵的示例:

  • 棕褐色。 棕褐色矩阵可以具有形式 [r*sw[0], g*sw[0], b*sw[0], r*sw[1], g*sw[1], b*sw[1], r*sw[2], g*sw[2], b*sw[2]],其中 rgb 如“亮度因子(灰度)”部分所定义,sw 是“棕褐色白”的 RGB 颜色(任意选择)。线性 sRGB 的示例:[0.207,0.696,0.07,0.212,0.712,0.072,0.16,0.538,0.054]
  • 饱和。 [s+(1-s)*r, (1-s)*g, (1-s)*b, (1-s)*r, s+(1-s)*g,(1-s)*b,(1-s)*r,(1-s)*g,s+(1-s)*b],其中 s 的范围是 0 到 1(s 越大,饱和度越低),而 rgb 如“亮度因子(灰度)”部分所定义(31)
  • 色相旋转。 [-0.37124*sr + 0.7874*cr + 0.2126, -0.49629*sr - 0.7152*cr + 0.7152, 0.86753*sr - 0.0722*cr + 0.0722, 0.20611*sr - 0.2126*cr + 0.2126, 0.08106*sr + 0.2848*cr + 0.7152, -0.28717*sr - 0.072199*cr + 0.0722, -0.94859*sr - 0.2126*cr + 0.2126, 0.65841*sr - 0.7152*cr + 0.7152, 0.29018*sr + 0.9278*cr + 0.0722],其中 sr = sin(rotation)cr = cos(rotation),而 rotation 是色相旋转角度。(31)(32)

在以下伪代码中,TransformColor 使用颜色矩阵 (matrix) 转换 RGB 颜色 (color)。

METHOD TransformColor(color, matrix)
   return [
      min(max(color[0]*matrix[0]+color[1]*matrix[1]+color[2]*matrix[2],0),1),
      min(max(color[0]*matrix[3]+color[1]*matrix[4]+color[2]*matrix[5],0),1),
      min(max(color[0]*matrix[6]+color[1]*matrix[7]+color[2]*matrix[8],0),1) ]
END METHOD

更一般地说 —

  • 可以使用 N×N 矩阵转换 N 分量颜色,并且
  • 可以使用 (N+1)×(N+1) 矩阵转换由 N 个分量后跟数字 1 组成的颜色;如果这样做,则转换后的颜色的前 N 个分量将被除以其最后一个分量。

变亮/变暗

以下方法可以生成颜色的更亮或更暗的版本。在示例中,color 是 0-1 格式的 RGB 颜色,value 为正表示变亮,为负表示变暗,范围在 -1 到 1 之间。

  • RGB 加法。 [min(max(color[0]+value,0),1), min(max(color[1]+value,0),1), min(max(color[2]+value,0),1)]
  • HSL “亮度”加法。 HslToRgb(hsl[0], hsl[1], min(max(hsl[2] + value, 0), 1)),其中 hsl = RgbToHsl(color)
  • CIELAB 亮度加法。 将一个数字加到颜色的 CIELAB 版本的 L* 分量上。例如,给定 CIELAB 颜色 lab,这是:[min(max(lab[0] + (value * 100), 0), 100), lab[1], lab[2]]
  • 色调和阴影。 “色调”是更亮的版本,“阴影”是更暗的版本。参见“Alpha 混合”。

饱和/去饱和

以下方法可以生成颜色的饱和或去饱和版本。在示例中,color 是 0-1 格式的 RGB 颜色,value 为正表示饱和,为负表示去饱和,范围在 -1 到 1 之间。

  • HSV “饱和度”加法。 HsvToRgb(hsv[0], min(max(hsv[1] + color, 0), 1), hsv[2]),其中 hsv = RgbToHsv(color)。(注意 HSL 的“饱和度”在这里效果较差。)
  • 音调,或灰色混合。 “音调”是去饱和的版本。可以通过将颜色与其灰度版本或任意灰色进行Alpha 混合来去饱和颜色。
  • 饱和矩阵。 请参见“颜色矩阵”。

杂项

  1. RGB 颜色 —

    • 如果具有相等的红色、绿色和蓝色分量,则为白色、黑色或灰色(非彩色),并且
    • 如果其红色、绿色和蓝色分量都是 0.2 的倍数,则为“Web 安全色”

    图像颜色列表如果其所有颜色分别为非彩色或“Web 安全色”,则为非彩色或“Web 安全色”。

  2. 背景去除算法,包括色度键,可以替换光栅图像的“背景”像素为其他颜色。此类算法不在本文档的范围内,除非它们仅使用像素颜色来确定该像素是否为“背景”像素(例如,通过检查该颜色与预定背景颜色的颜色差异是否足够小),并在这种情况下,确定该像素使用的颜色。

  3. 应用程序可以对 RGB 或其他多分量颜色的每个分量应用一个函数,包括幂函数(形式为 baseexponent)、反转(对于 0-1 格式的 RGB 颜色,例如 [1.0 - color[0], 1.0 - color[1], 1.0 - color[2]](33))或色调映射曲线。该函数可以是一对一的,但不必如此,只要它将 0 到 1 的数字映射到 0 到 1 的数字即可。
  4. 应用程序可以交换 RGB 或其他多分量颜色的任何两个分量的值,以形成新颜色。以下示例交换 RGB 颜色的蓝色和红色通道:[color[2], color[1], color[0]]
  5. 依赖于邻近像素或图像上下文的栅格图像处理技术基本不在本文档的范围内。这些包括像素邻域滤波器(包括高斯模糊和其他卷积)、形态学处理(包括腐蚀和膨胀)以及超出单个像素的图像分割(包括某些聚类和背景去除算法)。

颜色差异

颜色差异算法用于确定两种颜色是否相似。

在本文档中,COLORDIFF(color1, color2) 是一个计算两种颜色之间颜色差异(也称为“颜色距离”)的函数,这两种颜色必须在同一色彩空间中,数字越低,颜色越接近。但一般来说,使用不同色彩空间或公式计算出的颜色差异不能相互转换。本节给出了一些实现 COLORDIFF 的方法。

欧几里得距离。 以下伪代码实现了两种多分量颜色的欧几里得距离。此颜色差异公式与色彩模型无关。

// Euclidean distance for multicomponent colors
METHOD COLORDIFF(color1, color2)
    ret = 0
    for i in 0...len(color1)
       ret=ret+(color2[i]-color1[i])*(color2[i]-color1[i])
    end
    return sqrt(ret)
END METHOD

注释

  • 对于 CIELAB 或 CIELUV,1976 年的 ΔE*ab(“delta E a b”)或 ΔE*uv 颜色差异方法,分别是两个 CIELAB 颜色或两个 CIELUV 颜色之间的欧几里得距离。(34)
  • 如果仅比较欧几里得距离(例如,两个距离不相加或相乘),则可以省略平方根运算。

Riemersma 方法。 (Riemersma)(35) 建议了一种颜色差异算法,用于处理编码 RGB 颜色

CMC。 以下伪代码实现了 1984 年发布的颜色测量委员会颜色差异公式,主要用于纺织行业。请注意,在此公式中,两个 CIELAB 颜色的顺序很重要(第一个颜色是参考颜色,第二个颜色是测试颜色)。在此,该公式称为 CMC(LPARAM:CPARAM),其中 —

  • LPARAM 是亮度容差,通常为 2 或 1,并且
  • CPARAM 是色度容差,通常为 1。

 

METHOD COLORDIFF(lab1, lab2)
    c1=LabToChroma(lab1)
    c2=LabToChroma(lab2)
    h1=LabToHue(lab1)
    dl=0.511
    if lab1[0]>=16: dl=0.040975*lab1[0]/(1+0.01765*lab1[0])
    dc=0.0638+(0.0638*c1/(0.0131*c1+1))
    f4=pow(c1,4)
    f4=sqrt(f4/(f4+1900))
    dt=0
    if h1>=41*pi/45 and h1<=23*pi/12
       dt=0.56+abs(0.2*cos(h1+14*pi/15))
    else
       dt=0.36+abs(0.4*cos(h1+7*pi/36))
    end
    dh=(dt*f4+1-f4)*dc
    dl=dl*LPARAM
    dc=dc*CPARAM
    da=lab2[1]-lab1[1]
    db=lab2[2]-lab1[2]
    dchr=c2-c1
    dhue=sqrt(max(0,da*da+db*db-dchr*dchr))
    dl=((lab2[0]-lab1[0])/dl)
    dc=(dchr/dc)
    dh=(dhue/dh)
    return sqrt(dl*dl+dc*dc+dh*dh)
END METHOD

CIE94。CIELAB 特定公式在补充色彩主题页面上详细介绍。

CIEDE2000。 以下伪代码实现了 2000 年由 CIE 发布的颜色差异公式,称为 CIEDE2000 或 ΔE*00,用于两个 CIELAB 颜色之间。

METHOD COLORDIFF(lab1, lab2)
    dl=lab2[0]-lab1[0]
    hl=lab1[0]+dl*0.5
    sqb1=lab1[2]*lab1[2]
    sqb2=lab2[2]*lab2[2]
    c1=sqrt(lab1[1]*lab1[1]+sqb1)
    c2=sqrt(lab2[1]*lab2[1]+sqb2)
    hc7=pow((c1+c2)*0.5,7)
    trc=sqrt(hc7/(hc7+6103515625.0))
    t2=1.5-trc*0.5
    ap1=lab1[1]*t2
    ap2=lab2[1]*t2
    c1=sqrt(ap1*ap1+sqb1)
    c2=sqrt(ap2*ap2+sqb2)
    dc=c2-c1
    hc=c1+dc*0.5
    hc7=pow(hc,7)
    trc=sqrt(hc7/(hc7+6103515625.0))
    h1=atan2(lab1[2],ap1)
    if h1<0: h1=h1+pi*2
    h2=atan2(lab2[2],ap2)
    if h2<0: h2=h2+pi*2
    hdiff=h2-h1
    hh=h1+h2
    if abs(hdiff)>pi
      hh=hh+pi*2
      if h2<=h1: hdiff=hdiff+pi*2
      else: hdiff=hdiff-pi*2
    end
    hh=hh*0.5
    t2=1-0.17*cos(hh-pi/6)+0.24*cos(hh*2)
    t2=t2+0.32*cos(hh*3+pi/30)
    t2=t2-0.2*cos(hh*4-pi*63/180)
    dh=2*sqrt(c1*c2)*sin(hdiff*0.5)
    sqhl=(hl-50)*(hl-50)
    fl=dl/(1+(0.015*sqhl/sqrt(20+sqhl)))
    fc=dc/(hc*0.045+1)
    fh=dh/(t2*hc*0.015+1)
    dt=30*exp(-pow(36*hh-55*pi,2)/(25*pi*pi))
    r=0-2*trc*sin(2*dt*pi/180)
    return sqrt(fl*fl+fc*fc+fh*fh+r*fc*fh)
END METHOD

注意: CIEDE2000 的一个改进版本(Huang et al. 2015)(36),最近在 CIE 230:2019 中被推荐用于小颜色差异,但尚未普及。

商业因子。 商业因子 (cf) 是 CMC 和其他颜色差异公式的一个附加参数。COLORDIFF 结果除以 cf(通常为 1)得到最终颜色差异。

最近似的颜色

最近似的颜色算法用于例如对颜色进行分类或减少图像使用的颜色数量。

在下面的伪代码中,方法 NearestColorIndex 找到给定颜色(color)在给定颜色列表(list)中最接近的颜色的索引,所有颜色都与 color 处于同一色彩空间。NearestColorIndex 与色彩模型无关。

METHOD NearestColorIndex(color, list)
   if size(list) == 0: return error
   if size(list) == 1: return 0
   i = 0
   best = -1
   bestIndex = 0
   while i < size(list)
       dist = COLORDIFF(color,list[i])
       if i == 0 or dist < best
          best = dist
          bestIndex = i
       end
       i = i + 1
   end
   return bestIndex
END METHOD

示例

  • 要查找颜色列表(list)中最接近 color 的颜色,请生成 nearestColor = list[NearestColorIndex(color, list)]
  • 将颜色排序到颜色类别中可以通过所谓的“硬聚类”算法完成,例如k-means 聚类(另请参见Wikipedia 文章),该算法涉及 —

    1. 定义一个包含 k 个颜色点(例如,可以是红色、蓝色、黑色、白色等的代表性颜色,或者可以随机选择颜色)的列表(repColors),然后
    2. 对于要分类的每种颜色(color),找到该颜色在 k 个颜色点中最接近的颜色(例如,通过调用 NearestColorIndex(color, repColors)),然后
    3. repColors 中的每个颜色点替换为其新的平均颜色(基于该点分类的颜色),然后
    4. 重复步骤 2 和 3,直到所有颜色点发生的变化可以忽略不计。

    如果使用了代表性颜色,则可以省略步骤 3 和 4,或者仅省略步骤 4。否则,应省略 repColors 中未对任何颜色进行分类的颜色点。

图像的主导颜色

有几种方法可以找到图像颜色列表中最突出的颜色类型。为了获得最佳效果,这些技术需要使用线性 RGB而不是编码 RGB 颜色来执行。

  1. 颜色量化。在此技术中,将图像颜色列表的颜色减少到一小组颜色(例如,十到二十种)。量化算法包括 k-means 聚类(参见上一节)、递归细分和八叉树。

  2. 直方图分箱。 要使用此技术(与色彩模型无关)查找主导颜色 —

    • 生成或提供一个颜色列表,该列表能很好地覆盖颜色空间。这就是颜色调色板。一个很好的例子是“Web 安全色”列表。
    • 创建一个包含零的列表,其长度等于调色板中的颜色数量。这就是直方图
    • 对于图像颜色列表中的每种颜色,找到它在颜色调色板中的最近似的颜色,并在直方图中增加相应颜色的值 1。
    • 找到颜色调色板中具有最高直方图值的颜色或颜色,并将这些颜色作为主导颜色返回。
  3. 海报化。 这包括将多分量颜色的每个分量四舍五入到最接近的 1/n 的倍数,其中 n 是所需通道级别数加 1。舍入可以是向上、向下或其他方式。

注释

  1. 缩小比例:对于所有这些技术,在栅格图像的情况下,实现可以在继续查找其主导颜色之前缩小该图像。然而,调整图像大小或“重采样”图像的算法超出了此页面的范围。
  2. 颜色减少:减少图像中的颜色数量通常涉及查找该图像的主导颜色,然后 —
    • 应用“最近邻”方法(将该图像的颜色替换为其最近的主导颜色),或
    • 应用“抖动”技术(尤其是在某些情况下减少不期望的颜色“条带”时),但这也超出了本文档的范围。(37)
  3. 唯一颜色:查找图像颜色列表中唯一颜色的数量可以通过将这些颜色存储为哈希表中的键,然后计算以这种方式存储的键的数量来完成。(38)
  4. 取消合格的主导颜色:应用程序可以取消某些类型的颜色作为主导颜色的资格,并在没有主导颜色剩余时使用替代颜色作为主导颜色。例如,应用程序可以忽略图像背景中的颜色或靠近图像边缘的颜色,可以忽略某些类型的颜色(例如,灰色或近乎灰色的颜色)而在采样图像颜色列表时,或可以从主导颜色列表中删除某些颜色。
  5. 逐个分量地平均图像的颜色,可能会导致无意义的结果,尤其是在图像中存在色彩多样性(请参阅 stackoverflow.com/questions/43111029)的情况下。
  6. 提取场景的“真实色彩”:对于匹配现实世界色彩至关重要的应用,需要使用颜色测量设备来测量颜色,或从场景参考图像数据(39) 计算得出。PNG 和许多其他图像格式默认存储的图像数据通常被解释为sRGB;然而,sRGB 是一个输出参考 色彩空间,而不是场景参考色彩空间(它基于阴极射线管显示器的色彩输出),因此 sRGB 图像在没有进一步处理的情况下不适用于现实世界的色彩匹配。
    从数码相机(包括智能手机相机)获取场景参考图像数据并非易事,本文档未详细讨论。它需要了解相机是否提供原始图像数据访问权限、原始数据的格式,以及相机是否进行色彩渲染(这发生在生成输出参考图像数据之前)等信息。可以使用原始图像的彩色校准图(测试目标)的原始图像或采用其他技术来估算原始图像的颜色。ISO 17321 系列和 IEC 61966-9 涉及了这一主题。

颜色映射

色彩映射(或颜色调色板)是颜色的列表,这些颜色通常是相关的。色彩映射中的所有颜色都可以处于任何一个色彩空间中,但除非另有说明,否则应使用线性 RGB 颜色而不是编码的 RGB 颜色。

示例:一个灰度色彩映射由编码的 RGB 颜色 [[0, 0, 0], [0.5, 0.5, 0.5], [1, 1, 1]] 组成。

颜色映射的种类

ColorBrewer 2.0 网站提供的色彩映射建议主要用于在陆地地图上可视化数据。对于此类目的,ColorBrewer 2.0 的创建者 C. Brewer 确定了三种 适用的色彩映射类型。

  • 渐变色彩映射用于显示“从低到高递增的有序数据”。ColorBrewer 2.0 中的渐变色彩映射使用相同色相或两个接近色相的不同色调。
  • 发散色彩映射用于显示具有明确中点(“临界值”)的连续数据,并且低值和高值之间的差异在视觉上也重要。ColorBrewer 2.0 中的发散色彩映射使用两种“对比色相”的不同色调,两端各有一种色相,中间的色调较浅。当此类色彩映射用于 3D 可视化时,K. Moreland 建议“将色彩映射限制在合理明亮的颜色内”。
  • 定性色彩映射用于显示离散数据类别(另请参阅“视觉上不同的颜色”)。ColorBrewer 2.0 中的定性色彩映射使用不同的色相。

注意:ColorBrewer 2.0 将其中一些色彩映射标识为“打印友好”(40) 和/或“色盲友好”,这表明这两个因素在生成上述三种类型的色彩映射时可能很重要。

颜色集合

如果色彩映射中的每种颜色都有关联的名称、数字或代码,则该色彩映射也称为颜色集合。名称的示例包括“red”、“vivid green”、“orange”、“lemonchiffon”和“5RP 5/6”(41)。本文档不涵盖颜色集合或颜色图的调查,但我将在我的HTML 3D 库的颜色教程 中详细讨论其中一些。

将颜色(例如 RGB 颜色)转换为颜色名称可以通过以下方式完成—

  • 在哈希表中检索以该颜色为键的名称(如果该颜色不存在于哈希表中,则返回错误)(38),或
  • 在命名颜色中查找与该颜色最接近的颜色,并返回通过此方式找到的颜色的名称。

将颜色名称转换为颜色可以通过检索以该名称(或其小写形式)为键的颜色(或可选地)在哈希表中,或在不存在此类颜色时返回错误来实现。(38)

如果颜色映射中的每个名称、数字或代码都与一种或多种颜色相关联,并且可选地为每种颜色设置了权重因子,则该颜色映射也称为颜色词典(Venn 等人)(42)

注释

  • CSS Color Module Level 3 中所述,该模块中定义的命名颜色表示为sRGB 色彩空间中的编码 RGB 颜色。
  • 如果颜色名称标识色彩空间中的点(如“5RP 5/6”示例),则可以通过多维插值已知颜色点来将具有相似格式的颜色名称(例如,“5.6PB 7.1/2.5”)转换为颜色。(24)

视觉上区分度高的颜色

色彩映射可以列出用于标识不同项目的颜色。因此,许多应用程序需要使用人眼容易区分的颜色。在这方面—

  • K. Kelly (1965) 提出了一个“二十二种最大对比度颜色”的列表(43),其中前九种颜色是为具有正常和有缺陷色觉的读者准备的,
  • B. Berlin 和 P. Kay 在 1969 年发表的一项工作中,确定了十一个基本颜色词:黑色、白色、灰色、紫色、粉红色、红色、绿色、蓝色、黄色、橙色和棕色。

一般来说,使用的颜色越多,它们就越难相互区分。任何需要区分许多项目(特别是超过 22 个项目,即 Kelly 列表中的颜色数量)的应用,都应除了颜色之外,还应使用其他视觉手段(或者说而不是颜色)来帮助用户识别它们。(请注意,根据Web 内容可访问性指南 2.0 A 级标准,颜色可能不是“传达信息的唯一视觉手段”。)

一般来说,任何旨在选择在特定色彩空间中距离最大的颜色的方法(即,使它们之间最小的色差 [COLORDIFF] 尽可能最大化)都可以用来选择视觉上不同的颜色。这些颜色可以预先生成或在运行时生成,并且可以将这些颜色限制在特定色彩范围内。这里,色差方法应该是ΔE*ab 或其他考虑人类颜色感知的色差方法。(另请参阅 (Tatarize)(44)。)

伪代码

在以下伪代码中 —

  • ColorMapContinuous 从色彩映射 (colormap) 中提取连续颜色(混合颜色),
  • ColorMapDiscrete 从色彩映射 (colormap) 中提取离散颜色(最接近的颜色),

其中 value 是一个大于等于 0 且小于等于 1 的数字(0 和 1 分别是色彩映射的起点和终点)。

    METHOD ColorMapContinuous(colormap, value)
        nm1 = size(colormap) - 1
        index = (value * nm1) - floor(value * nm1)
        if index >= nm1: return colormap[index]
        fac = (value * nm1) - index)
        list1 = colormap[index]
        list2 = colormap[index + 1]
        return [list1[0]+(list2[0]-list1[0])*fac, list1[1]+(list2[1]-list1[1])*fac,
            list1[2]+(list2[2]-list1[2])*fac]
    END METHOD

    METHOD ColorMapDiscrete(colormap, value)
       return colormap[round(value * (N - 1))]
    END METHOD

示例:成语 ColorMapContinuous(colormap, 1 - value) 从反转的色彩映射中获取连续颜色。

生成随机颜色

以下技术可用于生成随机颜色。本节中

  • RNDRANGERNDU01RNDINTRNDINTEXC 是在我关于随机数生成方法的文章中定义的方法。
  • 此处的一些技术涉及亮度–暗度因子。此因子可以通过以下任何一种方式实现,按首选顺序从高到低排列。

    1. 颜色的CIELAB 明度 (L*) 除以 100,或从 0 到 1 的另一个值,该值表示颜色的明度(根据人类感知)。
    2. 亮度(颜色).
    3. 任何其他汇总颜色并范围从 0(“最低强度”)到 1(“最高强度”)的单个数字。
  • 为获得最佳效果,这些技术需要使用线性 RGB 颜色而不是编码的 RGB 颜色,除非另有说明。

技术如下。

  • 生成 HTML 格式的随机字符串可以通过生成长度为 6 的随机十六进制字符串,然后在该字符串开头插入“#”来实现。
  • 生成 0-1 格式的随机三分量颜色可以按以下方式进行:[RNDU01(), RNDU01(), RNDU01()]
  • 生成随机8 位编码 RGB 颜色可以按以下方式进行:From888(RNDINT(16777215))
  • 要生成随机暗 RGB 颜色,可以执行以下任一操作—
    • 生成 color = [RNDU01(), RNDU01(), RNDU01()] 直到亮度–暗度因子小于给定阈值,例如 0.5,或
    • 生成 color = [RNDRANGE(0, maxComp), RNDRANGE(0, maxComp), RNDRANGE(0, maxComp)],其中 maxComp 是每个颜色分量的最大值,例如 0.5。
  • 要生成随机亮 RGB 颜色,可以执行以下任一操作—
    • 生成 color = [RNDU01(), RNDU01(), RNDU01()] 直到亮度–暗度因子大于给定阈值,例如 0.5,或
    • 生成 color = [minComp + RNDU01() * (1.0 - minComp), minComp + RNDU01() * (1.0 - minComp), minComp + RNDU01() * (1.0 - minComp)],其中 minComp 是每个颜色分量的最小值,例如 0.5。
  • 生成随机柔和 RGB 颜色的一种方法是生成 color = [RNDU01(), RNDU01(), RNDU01()] 直到亮度–暗度因子大于 0.75 且小于 0.9。
  • 要生成两个颜色之间(或之上)的随机三分量颜色color1color2),请生成 Lerp3(color1, color2, RNDU01())
  • 要生成给定 RGB 颜色的随机阴影,请生成 Lerp3(color1, [0, 0, 0], RNDRANGE(0.2, 1.0))
  • 要生成给定 RGB 颜色的随机色调,请生成 Lerp3(color1, [1, 1, 1], RNDRANGE(0.0, 0.9))
  • 要生成给定 RGB 颜色的随机色调(tone),请生成 Lerp3(color1, [0.5, 0.5, 0.5], RNDRANGE(0.0, 0.9))
  • 要生成随机单色 RGB 颜色,请生成 HslToRgb(H, RNDU01(),RNDU01()),其中 H 是任意色相
  • 随机颜色采样
  • 相似的随机颜色:通过生成随机颜色(color1),直到 COLORDIFF(color1, color2)前面定义)小于预定阈值,其中 color2 是要比较的颜色,即可生成与另一种颜色相似的随机颜色。
  • 图像噪点:这会改变颜色,使用随机数,例如通过将随机数加到或乘以该颜色。例如,在均匀噪点中,多分量颜色的每个分量被更改为 min(1,max(0,c+RNDRANGE(-level, level))),其中 c 是前一个分量的值,level 是噪点级别。其他类型的图像噪点包括遵循高斯、泊松或其他概率分布的噪点,以及以预定概率将每个像素替换为黑色或白色的椒盐噪点

注意:本节中的方法也可以通过使用哈希函数将任意数据转换为“随机”位来实现,这些位可以直接使用,或者用于初始化一个可以生成更多“随机”位的伪随机数生成器。例如,From888(MD5_24("Hello World"))(其中 MD5_24() 是 MD5 哈希的前 24 位)可以解释为 8 位编码 RGB 颜色。

光谱颜色函数

如前所述,颜色需要物体观察者的存在。这三者可以指定如下

  • 光。光源可以指定为光谱功率分布 (SPD),一个描述光源在电磁光谱上的强度的“曲线”。
  • 物体。有两种“物体”:“反射”(不透明)和“透射”(半透明或透明)。反射率曲线透射率曲线分别描述了光被物体反射或穿过物体的分数。
  • 观察者。观察者的视觉响应可以通过三个颜色匹配函数来建模。

SPD、反射率或透射率曲线以及颜色匹配函数会转换为三个数字(称为三刺激值),这些数字唯一地标识了感知的颜色。

下面的伪代码包含一个 SpectrumToTristim 方法,用于计算三刺激值。在该方法中

  • lightFunc(wl)reflFunc(wl)cmfFunc(wl) 是接下来描述的任意函数。这三者都接受波长wl)以纳米 (nm) 为单位,并返回该波长对应的所有值。(另请参阅本节后面的注释 1。
  • lightFunc(wl)光源的 SPD 进行建模;它返回光源在波长 wl 处的相对强度。lightFunc 的选择包括—
    • CIE 日光照明器,例如 D65 或 D50 照明器(请参阅Python 示例代码以了解实现),
    • 色温》中给出的 BlackbodySPD 方法,以及
    • LED、荧光灯或其他人工光源的 SPD。
  • reflFunc(wl)反射率或透射率曲线进行建模,并返回该曲线在波长 wl 处的值;该值大于等于 0,通常小于等于 1。(对于光学增白和其他光致发光和荧光材料,曲线的值可能大于 1。)
  • cmfFunc(wl) 对三个颜色匹配函数进行建模,并返回这些函数在波长 wl 处的值。cmfFunc 的选择决定了 SpectrumToTristim 返回的三刺激值类型。cmfFunc 的选择包括 CIE 1931 或 1964 标准观察者,分别用于生成基于 2 度或 10 度视场看到的颜色刺激的XYZ 颜色(1)

 

METHOD SpectrumToTristim(reflFunc, lightFunc, cmfFunc)
    i = 360 // Start of relevant part of spectrum
    xyz=[0,0,0]
    weight = 0
    // Sample at 5 nm intervals
    while i <= 830 // End of relevant part of spectrum
             cmf=cmfFunc(i)
             refl=reflFunc(i)
             spec=lightFunc(i)
             weight=weight+cmf[1]*spec*5
             xyz[0]=xyz[0]+refl*spec*cmf[0]*5
             xyz[1]=xyz[1]+refl*spec*cmf[1]*5
             xyz[2]=xyz[2]+refl*spec*cmf[2]*5
             i = i + 5
    end
    if weight==0: return xyz
    // NOTE: Note that `weight` is constant for a given
    // color-matching function set and light source together,
    // so that `weight` can be precomputed if they will
    // not change.
    // NOTE: If `weight` is 1/683, `cmfFunc` outputs XYZ
    // values, and `reflFunc` always returns 1, then SpectrumToTristim
    // will output XYZ values where Y is a value in cd/m^2.
    xyz[0] = xyz[0] / weight
    xyz[1] = xyz[1] / weight
    xyz[2] = xyz[2] / weight
    return xyz
END METHOD

// Models a perfect reflecting diffuser or
// perfect transmitting diffuser
METHOD PerfectWhite(wavelength)
    return 1
END METHOD

注释

  1. 虽然 lightFuncreflFunccmfFunc 实际上是连续函数,但在实践中,三刺激值是基于离散波长处的测量值计算的。例如,CIE Publication 15 建议使用 5 nm 的波长间隔。对于 10 nm 和 20 nm 间隔的光谱数据,可以使用 ISO 13655 或 ASTM International E308 和 E2022 中描述的实践来计算三刺激值(特别是,E308 包含常见 cmfFunclightFunc 组合的权重因子表)。就色彩复制而言,在实践中仅与 360-780 nm(0.36-0.78 μm)范围内的波长相关。
  2. 同色异谱发生在两种材料在一种观察情况(例如光源、lightFunc 和/或观察者、cmfFunc)下匹配相同的颜色,但在另一种情况下不匹配。如果发生这种情况,则两种材料的反射率或透射率曲线(reflFunc)被称为同色异谱。对于涉及现实世界颜色匹配的应用,同色异谱是为什么反射率和透射率曲线(reflFunc)比三种三刺激值形式的颜色(例如 XYZ 或 RGB 颜色)更不容易产生歧义的原因。(另请参阅 B. MacEvoy 的原理 38。)

示例:在这些示例中,D65 是 D65 照明器,D50 是 D50 照明器,CIE1931 是 CIE 1931 标准观察者,refl 是任意反射率曲线。

  1. SpectrumToTristim(refl, D65, CIE1931) 计算反射率曲线的XYZ 颜色(其中 Y 值为 1 是 D65/2 白点)。
  2. SpectrumToTristim(refl, D50, CIE1931) 相同,只是白点是 D50/2 白点。
  3. SpectrumToTristim(PerfectWhite, light, cmf) 计算给定照明器 light 和颜色匹配函数 cmf 的白点。
  4. SpectrumToTristim(PerfectWhite, D65, CIE1931) 计算 D65/2 白点。
  5. XYZTosRGB(SpectrumToTristim(refl, D65, CIE1931)) 计算反射率曲线的编码 sRGB 颜色。
  6. XYZTosRGB(CIE1931(wl)) 计算仅在波长 wl 发射光的(单色刺激)光源的编码 sRGB 颜色,其中波长以 nm 为单位。

色温

黑体是一种理想化的材料,它仅根据其温度发光。随着黑体的温度升高,其色度从红色变为橙色,再变为浅黄色,直至天蓝色。

下面的 Planckian 方法模拟了给定温度(开尔文)(其色温)的黑体的光谱功率分布 (SPD)。下面的 BlackbodySPD 方法使用该方法(其中 TEMP 是所需的色温)。(45)。请注意,阳光、日光、烛光和白炽灯等常见光源可以由适当的黑体 SPD 很好地描述。

METHOD Planckian(wl, temp)
    num = pow(wl, -5)
    // NOTE: 0.014... was calculated based on
    // 2017 versions of Planck and Boltzmann constants
    return num / (exp(0.0143877687750393/(wl*pow(10, -9)*temp)) - 1)
END METHOD

METHOD BlackbodySPD(wl) # NOTE: Relative only
    t=TEMP
    if t<60: t=60 # For simplicity, in very low temperature
    return Planckian(wl, t) * 100.0 /
        Planckian(560, wl)
END METHOD

注意:如果 TEMP 为 2856,则上面的 BlackbodySPD 函数大致等同于 CIE 照明器 A。

“色温”的概念仅适用于黑体色度。对于接近黑体的色度,CIE 定义了相关色温 (CCT),即具有最接近(u, v)坐标的黑体的温度(19)。CCT 计算使用 CIE 1931 标准观察者。(根据 CIE 的说法,如果两个 (u, v) 点之间的直线距离大于 0.05,则 CCT 没有意义。)

下面的方法(XYZToCCT)计算来自XYZ 颜色的近似 CCT,该方法基于 McCamy 在 1992 年的公式。

METHOD XYZToCCT(xyz)
    xyy = XYZToxyY(xyz)
    c = (xyy[0] - 0.332) / (0.1858 - xyy[1])
    return ((449*c+3525)*c+6823.3)*c+5520.33
END METHOD

注意:此处使用的色温不应与颜色分为暖色(通常是红色、黄色和橙色)和冷色(通常是蓝色和蓝绿色)的范畴相混淆,这是一个主观划分,存在很大的差异。但总的来说,在光源的上下文中,CCT 越低,光线看起来越“暖”,CCT 越高,看起来越“冷”。然而,CCT(或与光源相关的任何其他单个数字)通常不足以单独描述光源如何渲染颜色。

色彩混合

两种着色剂的混合非常复杂,有几种方法可以模拟这种颜色混合。

  • 正如S. A. Burns 指出,两个或多个反射率曲线(每条代表一种颜料或着色剂)可以通过计算它们的加权几何平均值来混合,该平均值考虑了这些着色剂在混合物中的相对比例;结果是一条新的反射率曲线,可以将其转换为 RGB 颜色。(46)
  • 正如B. MacEvoy 指出,两种或多种透射材料的光谱曲线可以通过简单地将它们相乘来混合;结果是混合材料的新光谱曲线。
  • 另一种颜色配方方法,基于Kubelka–Munk 理论,为每种着色剂使用两条曲线:一条吸收系数曲线(K 曲线)和一条散射系数曲线(S 曲线)。吸收与散射之比 (K/S) 在 Kubelka–Munk 理论中与反射率因子有简单的关系。Python 示例代码实现了 Kubelka–Munk 方程。E. Walowit 在 1985 年描述了一种使用该理论预测颜色配方的方法(47)。ISO 18314-2 也是相关文档。

为方便起见,下面的 WGM 方法计算一个或多个数字的加权几何平均值,其中—

  • values 是值的列表(例如,多个反射率曲线在同一点的单个值),并且
  • weights 是这些值对应的权重的列表(例如,这些曲线的混合比例)。

 

METHOD WGM(values, weights)
    if size(values)!=size(weights): return error
    if size(values)==0: return values[0]
    sum=0
    i=0
    while i < size(weights)
      sum=sum+weights[i]
      i=i+1
    end
    if sum<=0: return error
    ret=1
    while i < size(values)
      ret=ret*pow(values[i],weights[i]/sum)
      i=i+1
    end
    return ret
END METHOD

结论

本页讨论了许多与编程相关的颜色主题。

欢迎随时发送评论。它们可能有助于改进此页面。特别是,欢迎对本页上提供的任何方法进行更正。

我谨向—

  • CodeProject 用户 Mike-MadBadger,他建议对色彩空间和颜色模型进行补充说明,
  • 来自 pixls.us 讨论论坛的“RawConvert”,
  • Elle Stone,和
  • Thomas Mansencal 表示感谢。

根据读者的兴趣,将来可能会添加以下主题

  • CAM02 颜色外观模型。
  • 光源的显色指标,包括显色指数 (CRI) 和照明工程学会 TM-30-15 中给出的指标。

以下主题将极大地丰富本文档

  • 一种使用智能手机相机以及可能的色彩校准卡和/或白平衡卡进行色彩校准和颜色匹配的方法,前提是该方法不受任何有效专利或待审专利申请的涵盖。
  • 参照源代码,提供一种给定纸张的光谱反射率曲线以及以不同浓度使用的油墨的光谱反射率曲线来匹配纸张上所需颜色的方法,前提是该方法不受任何有效专利或待审专利申请的涵盖。

注释

  • (1) CIE 在其网站上发布了 D65 照明器和 CIE 1931 和 1964 标准观察者的制表数据。在某些情况下,可以使用 Wyman、Sloan 和 Shirley 在《"Simple analytic approximations to the CIE XYZ color matching functions"》(Journal of Computer Graphics Techniques 2(2), 2013, pp. 1-11)中给出的方法来近似 CIE 1931 标准观察者。
  • (2) 本概述不包含涉及“红、黄、蓝”、“原色/二次色/三次色”或使用“色轮”来“预测”颜色混合的颜色教学的沉重负担。故意遗漏的还有对颜色心理学、“颜色预测”或自然语言中颜色的讨论,这些话题通常与编程无关。
  • (3) 谈论“红光”、“绿光”、“蓝光”、“白光”等是不准确的。
  • (4) 颜色感知受到使颜色成为可能的三种事物的影响
    • 光。例如,自然日光和阳光会根据一天中的时间和年份、地点和天气改变其色彩渲染。
    • 物体。材料的表面属性,如光泽、透明度、雾度等,都会影响颜色感知。
    • 观察者。不同的观察者由于年龄、文化、色觉缺陷、个人经验、观察者类型(人、相机、镜头、动物等)等原因,“看到”颜色的方式不同。B. MacEvoy 记录了即使是具有正常色觉的人之间也存在广泛的观察者差异

有关涉及人类色觉现象的详细概述,请参阅 Kirk, R.,“Standard Colour Spaces”,FilmLight Technical Note,版本 4.0,2004-2018,第 9 节。

  • (5) 例如,亮度-暗度信号大致是三个视锥细胞响应的总和。相对颜色理论主要归功于 E. Hering 的工作,并在 20 世纪中叶与三视锥细胞理论相结合(例如,通过 Hurvich 和 Jameson 的工作)。
  • (6) 有关如何模拟色觉缺陷的信息,请参阅 Jim 的《色盲模拟研究》。
  • (7) 尽管过去大多数彩色显示设备每像素使用三个点(“红”、“绿”和“蓝”),但如今这种情况可能已不多见。如今,最近的显示设备和灯具可能使用三个以上的像素点——例如“红”、“绿”、“蓝”和“白”,或 RGBW——理想情况下,遵循RGBW 颜色模型或类似颜色模型的颜色空间能够描述再现某些颜色应有的点强度。然而,这类颜色空间对于大多数程序员来说,除了固态照明、灯具或显示设备的硬件和驱动程序开发之外,尚不具有实际意义。
  • (8) B. Lindbloom,“RGB 工作空间信息”。
  • (9) Mano, Y., 等人。“Enhancing the Netflix UI Experience with HDR”,Netflix Technology Blog,Medium.com,2018 年 9 月 24 日。
  • (10) 16 进制数字,按顺序为 0 到 9,然后是 A 到 F。数字 A 到 F 可以是大写或小写。
  • (11) CSS Color Module Level 4 的工作草案提到了两种额外的格式,即—
    • 8 位格式,由“#”后面跟着八个 16 进制数字组成,分别为红、绿、蓝和 alpha 分量各两位,顺序如此,以及
    • 4 位格式,由“#”后面跟着四个 16 进制数字组成,分别为红、绿、蓝和 alpha 分量各一位,顺序如此(例如,“#345F”在 8 位格式中等于“#334455FF”)。
  • (12) 色相角以弧度为单位,角度大于等于 0 且小于 2π。弧度可以通过乘以 180 / pi 转换为度。度可以通过乘以 pi / 180 转换为弧度。
  • (13) Smith, A.R. 和 Lyons, E.R., 1996. HWB—一种更直观的基于色相的颜色模型。Journal of graphics tools, 1(1), pp. 3-17。
  • (14) 质数符号出现在 Y 附近,因为从 RGB 转换通常涉及编码 RGB 颜色,因此 Y′(亮度)不等于亮度 (Y)。(参见 C. Poynton 的YUV亮度被视为有害”。) 然而,为了方便起见,该符号在函数名和其他名称中省略了。
  • (15) 在室内和建筑设计中,亮度因子乘以 100 也称为光反射率 (LRV)。
  • (16) 尽管 D65/2 白点是 sRGB 的常用白点,但在以下情况下(除其他外)可能更方便使用其他白点
    • 使用白点 [0.9642, 1, 0.8249] 可以提高与使用国际颜色联盟 (ICC) 版本 2 或 4 配置文件的应用程序的互操作性(这对应于 CIE Publication 15 修正前给出的 D50/2 白点)。
    • 出于历史原因,印刷行业使用 D50 照明器(参见 A. Kraushaar,“Why the printing industry is not using D65?”,2009)。
  • (17) 色度适应变换包括线性 Bradford 变换,但本文档未进一步详述。(另请参阅 E. Stone,“The Luminance of an sRGB Color”,2013。)
  • (18) 任何三维笛卡尔颜色空间(不仅仅是 XYZ)(例如,RGB 的 (r, g, b) 色度坐标)都可以定义色度坐标。这些坐标的计算方式类似于 (x, y, z) 坐标。
  • (19) CIE Technical Note 001:2014 称,色度差 (Δu′v′) 应计算为两个 u′v′ 对之间的欧几里得距离,并且色度差 0.0013 被视为“50% 概率下”即可被察觉。

(u, v) 坐标是 u′v′ 的早期 1960 版本,通过取 uu′v 为 (v′ * 2.0 / 3) 来获得。

  • (20) 尽管 CIELAB 颜色模型也经常被称为“感知均匀”——
    • 根据B. Lindbloom 的说法,CIELAB“不是为了获得进行色域映射所需的感知质量而设计的”,并且
    • P. Kovesi(P. Kovesi,“Good Colour Maps: How to Design Them”,arXiv:1509.03700 [cs.GR], 2015)认为,这种说法“实际上仅适用于非常低的空间频率”。
  • (21) L*a*b* 轴的放置与亮度-暗度信号以及红色/绿色和蓝色/黄色这两个相对信号有关。另请参阅注释 6。
  • (22) 术语明度彩度相对于看起来像白色的区域。相应的术语亮度饱和度分别是主观术语:亮度是感知到的反射或发出的光量,饱和度是感知到的色度强度(色彩度)相对于其亮度的比例。(另请参阅 CIE 的国际照明词汇表。)然而,CIELAB 没有正式的饱和度公式(参见维基百科上的色彩度)。
  • (23) 本节重点介绍 CMYK,因为涉及非青色、品红色、黄色和黑色油墨的印刷系统(特别是“扩展色域”五色或更多油墨的系统,以及使用自定义“专色”油墨的系统)尚未引起程序员的普遍兴趣。
  • (24) 本页不详细介绍多维插值的工作原理,但一个例子是 SciPy 的griddata 方法。
  • (25) T. Helland,“七种灰度转换算法(附带伪代码和 VB6 源代码)”。
  • (26) J. Cook,“将颜色转换为灰度”,2009 年 8 月 24 日。
  • (27) Lerp3 等同于 OpenGL 着色语言 (GLSL) 中的 mix。通过使 alpha 成为函数(例如,Lerp3(color1, color2, FUNC(...)),其中 FUNC 是一个或多个变量的任意函数)的输出,可以实现特殊的非线性混合。此类混合(插值)在另一页面中有更详细的描述。
  • (28) P. Haeberli 和 D. Voorhees,“通过插值和外插进行图像处理”。
  • (29) B. MacEvoy 将这些称为色相协调。另请参阅他关于和谐颜色关系的总结。
  • (30) Porter, T., and Duff. T. "Compositing Digital Images". Computer Graphics 18(3), p 253 ff., 1984。
  • (31) P. Haeberli,“图像处理的矩阵运算”,1993。给出的色相旋转矩阵是通过“在保持亮度的色相旋转”一节中的技术生成的,常数四舍五入到五位有效数字,并且 rwgt=0.2126gwgt=0.7152bwgt = 0.0722,分别是红色、绿色和蓝色点的 sRGB 亮度因子。对于饱和度和色相旋转矩阵,使用的是 sRGB 亮度因子而不是源推荐的值。
  • (32) 色相旋转角度以弧度为单位,角度大于 -2π 且小于 2π。可以通过乘以 pi / 180 将度转换为弧度。
  • (33) 这通常被称为 RGB 颜色的“CMY”(“青色–品红色–黄色”)版本(尽管结果颜色不一定基于青色、品红色和黄色油墨的比例;另请参阅“CMYK 和其他油墨混合颜色模型”)。如果使用此操作,则“CMY”和 RGB 之间的转换完全相同。
  • (34) 这里的“E”代表德语单词Empfindung
  • (35) T. Riemersma,“颜色度量”,章节“低成本近似”。
  • (36) Huang, M., Cui, G., 等人。(2015)。"Power functions improving the performance of color-difference formulas." Optical Society of America, 23(1), 597–610。
  • (37) 实现抖动的一种方法在 C. Peters 的《Free blue noise textures》,Moments in Graphics,2016 年 12 月 22 日中提到。
  • (38) 本文档不包含如何实现哈希表的详细信息。
  • (39) 场景参考图像数据的示例是数码相机的原始图像,在应用 Academy Procedure P-2013-001 中定义的输入设备变换后。场景参考图像数据未经过诸如查找修改变换(如 P-2013-001 中定义)、色调映射、色域映射或其他色彩渲染等操作。
  • (40) 通常,如果一种颜色位于在给定或标准化印刷条件下可复制的颜色范围(色彩范围)之内,则该颜色可被视为“打印友好”(另请参阅“CMYK 和其他油墨混合颜色模型”)。
  • (41) 许多颜色集合以印刷或染色的色样表示和/或在印刷的“色卡”中找到。然而,大多数此类颜色集合是专有的。“5RP 5/6”是 20 世纪早期一个著名颜色系统和色彩空间中的一个例子。
  • (42) Venn, A., 等人。“Das Farbwörterbuch / The Colour Dictionary”。
  • (43)HTML 格式中,按顺序编码 sRGB 的颜色的近似值如下:“#F0F0F1”、“#181818”、“#F7C100”、“#875392”、“#F78000”、“#9EC9EF”、“#C0002D”、“#C2B280”、“#838382”、“#008D4B”、“#E68DAB”、“#0067A8”、“#F99178”、“#5E4B97”、“#FBA200”、“#B43E6B”、“#DDD200”、“#892610”、“#8DB600”、“#65421B”、“#E4531B”、“#263A21”。该列表是通过使用 Python colour 包将 Munsell 重命名(以及黑色的类似重命名)转换为 sRGB 而生成的。
  • (44) Tatarize,“颜色分布方法学”。
  • (45) 另请参阅 J. Walker,“光谱的色彩渲染”。
  • (46) 正如B. MacEvoy 解释(在“材料混合中的其他因素”部分)所指出的,影响两种着色剂混合的因素包括它们的“折射率、粒径、晶体形态、遮盖力”和“着色力”(另请参阅他的原理 39 到 41),以及“载体(例如纸张或画布)的材料属性和油漆应用方法”也与此相关。这些因素,如果反射率曲线未考虑在内,则在本方法中不处理。
  • (47) Walowit, E. "Spectrophotometric color formulation based on two-constant Kubelka-Munk theory". Thesis, Rochester Institute of Technology, 1985。
© . All rights reserved.