计算 RGB 值的人眼对比度差异的有效方法是什么?

2x2*_*x2p 3 javascript php rgb image colors

为了检查灰度中的两种颜色是否太接近而无法被人眼区分。如果选择了“危险”颜色,我希望能够向用户发出警告。因此,根据结果,我们可以决定对于视力不好的人是否应该将两种颜色之一更改为白色或黑色以增强可读性对比度。例如,十六进制颜色#9d5fb0(紫色)和#318261(绿色)将变成几乎相同的灰色调。在 HSB 中,B 值与其他值仅相差 1%,因此健康的人眼无法真正看出差异。或者对于相同的情况,这种情况下的 8 位 K 值相差 2%。

我了解到亮度方法是一种更复杂的方法,可以像人眼看到颜色一样判断灰色调。然而,如何以编程方式做到这一点超出了我目前的理解。我可以写它,PHP或者JS一旦我理解了数学。

为了CSS从屏幕pixel或文件中选择值作为图像object,我想我们应该始终将输入处理为 RGB 对吗?

就像是:

$result = grayScaleDifference('#9d5fb0','#318261');
Run Code Online (Sandbox Code Playgroud)

或者

$result = 8bitK_difference('#9d5fb0','#318261');
Run Code Online (Sandbox Code Playgroud)

或者

$result = luminanceDifference('#9d5fb0','#318261');
Run Code Online (Sandbox Code Playgroud)

那么在不更改或转换实际图像或颜色对象的情况下比较它们的最佳脚本样式公式是什么?

Myn*_*dex 6

亮度对比度和感知

\n\n

您正在寻找的是如何评估亮度对比度。

\n\n

你绝对走在正确的道路上 \xe2\x80\x94 6% 的男性有色盲,他们依赖的是亮度对比度而不是颜色对比度。我这里有一张图表展示了这个问题。

\n\n

仅供参考,该术语是“亮度”而不是光度。光度是指随着时间的推移发出的光推移发出的光,常用于天文学。当我们谈论比色法时,我们使用术语亮度,这是一种不同的光测量方法,由 CIEXYZ (CIE 1931) 定义。

\n\n

碰巧我正在研究对比评估方法,以提供一些新的、更准确的标准。您可以关注GitHub和我的感知研究上的一些进展

\n\n

它并不像人们想象的那么简单,因为有很多因素会影响人类对对比度的感知。目前 GitHub 线程中有很多关于 zt 的讨论。

\n\n

确定亮度

\n\n

亮度是光的光谱加权但其他线性测量。光谱加权基于人类三色视觉如何感知不同波长的光。这是 CIE 1931 实验和由此产生的色彩空间(例如 CIEXYZ)中测量的一部分(亮度是 XYZ 中的 Y)。

\n\n

虽然 XYZ 是光的线性模型,但人类的感知却是非线性的。因此,XYZ 在感知上并不统一。然而,出于您的目的,您只想知道颜色与灰色色块的等效亮度是多少。

\n\n

假设您从 sRGB 视频(即网络和计算机标准色彩空间)开始,您首先需要删除伽玛编码,然后应用光谱加权。

\n\n

我在 Stack 上发表了很多关于 gamma 的帖子,但如果您想要明确的解释,我推荐Poynton 的 Gamma FAQ。

\n\n

将 sRGB 转换为线性(伽玛 1.0)。

\n\n

1)通过将每个通道单独除以 255,将 R\xc2\xb4G\xc2\xb4B\xc2\xb4 值从 8 位整数 (0-255) 转换为十进制 (0.0 - 1.0)。R \xc2\xb4G\xc2 \xb4B\xc2\xb4 值必须为 0 到 1,以下数学运算才能起作用。另外,这里有一个帖子的链接,其中包含用于将单个数字(如 6 位十六进制)转换为 RGB 通道的代码片段。

\n\n

2)线性化对每个通道懒惰的方法是应用 2.2 的功率曲线,这就是计算机显示器显示图像数据 \xe2\x80\x94 的方式,以判断颜色的亮度,这很好:

\n\n

R\xc2\xb4^2.2 = R G\xc2\xb4^2.2 = G B\xc2\xb4^2.2 = B

\n\n

3)替代(更准确)方法:如果您正在进行图像处理并从 sRGB 到线性来回,那么有一种更准确的方法,可以在维基百科上找到。而且,这是我的电子表格中的代码片段,我将其用于类似的目的:

\n\n
  =IF( A1 <= 0.04045 ; A1 / 12.92 ; POWER((( A1 + 0.055)/1.055) ; 2.4))\n
Run Code Online (Sandbox Code Playgroud)\n\n

这显示的是对于低于 0.04045 的值,您只需除以 12.92,但对于高于 0.04045 的值,您偏移并应用 2.4 \xe2\x80\x94 的幂,请注意,在“惰性方式”中,我们使用了 2.2,但曲线几乎接近由于偏移/线性化而相同。

\n\n

执行步骤2 或步骤 3,但不能同时执行这两个步骤。

\n\n

4) 最后,应用频谱加权系数,并将三个通道相加:

\n\n

R线性* 0.2126 + G线性* 0.7152 + B线性* 0.0722 = Y

\n\n

这样就得到了 Y,即给定颜色的亮度。亮度也称为L,但不要与 L* (Lstar) 混淆,L* 是感知亮度,而不是亮度。

\n\n

确定感知对比度

\n\n

现在,如果您想确定两个样本之间的差异,有多种方法。韦伯对比度本质上是 \xce\x94L/L,自 19 世纪以来一直是标准。但对于计算机显示器显示的刺激,我建议一些更现代的方法。例如,为了获得更好的感知结果,进行以下修改:

\n\n

(L较亮\xe2\x80\x93 L较暗) / (L较亮+ 0.1)

\n\n

还有“感知对比长度”,鲍曼-萨波林斯基,以及其他人,包括我正在研究的一些。您还可以转换为(L*a*b*) 基于人类感知的 CIELAB,只需从 L* 2中减去 L* 1即可。

\n\n

此外,还有许多其他因素会影响对比度感知,例如字体大小和粗细、填充(请参阅 Bartleson\xe2\x80\x93Breneman 环绕效果)和其他因素。

\n\n

请让我知道,如果你有任何问题。

\n


Myn*_*dex 5

后续回答

我将此作为后续答案发布,不仅要澄清我的初始答案(我也刚刚编辑过),还要添加各种概念的代码片段。R´G´B´to Y 过程中的每一步都很重要,也必须按照描述的顺序进行,否则结果将失败。

定义:

sRGB : sRGB 是一种三色刺激颜色模型,它是 Web 的标准,用于大多数计算机显示器。它使用与 HDTV 标准 Rec709 相同的原色和白点。sRGB 与 Rec709 的不同之处仅在于传输曲线,通常称为伽马。

Gamma:这是用于存储和传输的各种图像编码方法的曲线。它通常类似于人类视觉的感知曲线。在数字中,伽马的作用是赋予图像较暗区域更多的权重,使它们由更多位定义,以避免出现诸如“条带”之类的伪影。

亮度:(标记为LY):光的线性度量或表示(即无伽马曲线)。作为衡量标准,它通常是 cd/m 2。作为表示,它是 CIEXYZ 中的 Y,通常是 0 (黑色)到 100 (白色)。亮度具有光谱加权,基于人类对不同波长光的感知。然而,亮度在亮度/暗度方面是线性的——也就是说,如果 100 个光子等于 10,那么 20 就是 200 个光子。

L*(又名 Lstar):感知亮度,由 CIELAB 定义 (L*a*b*) 其中亮度在光量方面是线性的,L* 基于感知,因此在光量方面是非线性的,其曲线旨在匹配人眼的明视觉(大约 gamma 为 ^0.43)。

亮度VS大号 * 0和100是相同的两个亮度(写入Y或L)和亮度(书面L *),但在它们中间有很大的不同。我们认为中间灰色位于 L* 50 的正中间,但这与亮度 (Y) 的 18.4 相关。在 sRGB 中为 #777777 或 46.7%。

对比度:用于定义两个 L 或两个 Y 值之间差异的术语。对比有多种方法和标准。一种常用的方法是韦伯对比,即?L/L。对比度通常以比率 (3:1) 或百分比 (70%) 表示。

从 sRGB 得出亮度 (Y)

步骤零 (un - HEX)

如果需要,将 HEX 颜色值转换为整数值的三元组,其中#00 = 0#FF = 255

第一步(8 位到十进制)

通过除以 255 将 8 位 sRGB 值转换为十进制:

   十进制= R´ 8bit / 255 G´十进制= G´ 8bit / 255 B´十进制= B´ 8bit / 255

如果您的 sRGB 值是 16 位,则通过除以 65535 转换为十进制。

第二步(线性化,简单版)

将每个颜色通道提高到 2.2 的幂,与 sRGB 显示器相同。这适用于大多数应用程序。但是,如果您需要在 sRGB 伽马编码空间内进行多次声音旅行,请使用以下更准确的版本。

   R´^2.2 = R lin    G´^2.2 = G lin    B´^2.2 = B lin

第二步(线性化,精确版)

如果您要进行图像处理和进出伽马编码空间的多次往返,请使用此版本而不是上面的简单 ^2.2 版本。

function sRGBtoLin(colorChannel) {
        // Send this function a decimal sRGB gamma encoded color value
        // between 0.0 and 1.0, and it returns a linearized value.

    if ( colorChannel <= 0.04045 ) {
            return colorChannel / 12.92;
        } else {
            return Math.pow((( colorChannel + 0.055)/1.055),2.4));
        }
    }
Run Code Online (Sandbox Code Playgroud)

编辑添加澄清:我上面引用的 sRGB 线性化使用来自官方 IEC 标准的正确阈值,而旧的 WCAG2 数学使用不正确的阈值(一个已知的开放错误)。尽管如此,阈值差异并不影响 WCAG 2 结果,而是受到其他因素的困扰。

第三步(光谱加权亮度)

正常人眼具有三种类型的视锥细胞,它们对红光、绿光和蓝光敏感。但是我们的光谱灵敏度并不统一,因为我们对绿色 (555 nm) 最敏感,而蓝色则遥遥领先。使用以下系数对亮度进行光谱加权以反映这一点:

   R lin * 0.2126 + G lin * 0.7152 + B lin * 0.0722 = Y = L

将每个线性化颜色通道乘以其系数并将它们加在一起以找到 L,亮度。

第四步(对比度测定)

有许多不同的方法来确定对比度,以及各种标准。根据特定的应用程序,一些方程比其他方程更有效。

WCAG 2.x
WCAG 2.0 和 2.1 中列出的当前网页对比指南是带有偏移量的简单对比:

   C = ((L+ 0.05) / (L更暗+ 0.05)) : 1

这给出了一个比率,WCAG 规定非文本为 3:1,文本为 4.5:1 以达到“AA”级别。

然而,由于各种原因,它是一个薄弱的例子。我在记录中指出了当前 GitHub 问题(WCAG #695)中的缺陷,并且一直在研究替代方案。

编辑添加(2021 年 1 月):

旧 WCAG 2 对比的替代品是APCA:

先进适用P erceptual Ç ontrastlgorithm”

新 WCAG 3 的一部分。这是一个实质性的飞跃。虽然稳定,我仍然认为它是测试版,因为它有点复杂,暂时链接到SAPC/APCA GitHub 存储库可能更好。

文献中其他一些先前开发的对比方法:

改性韦伯
黄/改性的Peli韦伯提供的对比度更好的评估,因为它适用于计算机监视器/ sRGB的。

   C = (L– L) / (L+ 0.1)

请注意,我根据最近的一些实验选择了 0.1 而不是 0.05 的耀斑因子。不过,该值是待定的,不同的值可能会更好。

LAB 差异
我碰巧比其他人更喜欢的另一种选择是将线性化亮度 ( L )转换为L*,即感知亮度,然后从另一个中减去一个以找到差异。

将 Y 转换为 L*:

function YtoLstar(Y) {
        // Send this function a luminance value between 0.0 and 1.0,
        // and it returns L* - perceptual lightness

    if ( Y <= (216/24389) {       // The CIE standard states 0.008856 but 216/24389 is the intent for 0.008856451679036
            return Y * (24389/27);  // The CIE standard states 903.3, but 24389/27 is the intent, making 903.296296296296296
        } else {
            return Math.pow(Y,(1/3)) * 116 - 16;
        }
    }
Run Code Online (Sandbox Code Playgroud)

将 L 转换为 L* 后,一个有用的对比图很简单:

    C = L较浅– L较深**

此处的结果可能需要缩放以与其他方法类似。大约 1.6 或 1.7 的缩放似乎效果很好。

还有许多其他方法可以确定对比度,但这些是最常见的。但是,某些应用程序使用其他对比方法会做得更好。其他一些是 Michaelson Contrast、Perceptual Contrast Length (PCL) 和 Bowman/Sapolinski。

此外,如果您正在寻找亮度或亮度差异之外的颜色差异,那么 CIELAB 在这方面有一些有用的方法。

边注:

平均 RGB 没有 Bueno!

OP 2x2p 提到了一个常见的用于制作颜色灰度的公式:

    灰色 = 圆((R + G + B)/ 3);

他指出这看起来多么不准确,而且确实——这是完全错误的。R、G 和 B 的频谱权重很大,不容忽视。绿色的亮度比蓝色高,按大小顺序排列。您不能只是将所有三个通道相加并除以三,然后得到接近特定颜色实际亮度的任何值。

我相信对此的困惑可能来自一种称为HSI (色相、饱和度、强度)的颜色控制。但是这种控制并不是(也从来没有打算)在感知上是统一的!!!HSI 与 HSV 一样,只是用于在计算机中操作颜色值的“便利”。两者在感知上都不是统一的,并且它们使用的数学严格用于支持在软件中调整颜色值的“简单”方法。

OP 的样本颜色

2x2p 使用“#318261”、“#9d5fb0”作为测试颜色发布了他的代码。以下是它们在我的电子表格上的显示方式,以及转换过程中每个步骤中的每个值(使用“准确”的 sRGB 方法):

在此处输入图片说明

两者都接近#777777 的中间灰色。另请注意,虽然亮度 L 仅为 18,但感知亮度 L* 为 50。