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

标签 javascript php image colors rgb

为了检查灰度中的两种颜色是否太近而无法被人眼识别。我希望能够在选择“危险”颜色时向用户发出警告。因此,根据结果,我们可以决定是否为视力不好的人将两种颜色之一更改为白色或黑色,以增强可读性。

例如,十六进制颜色#9d5fb0(紫色)和#318261(绿色)将变成几乎相同的灰色调。在HSB中看到的B值彼此之间仅相差1%,因此,健康的人眼无法真正看到此差异。或者,对于这种情况,相同的8位K值相差2%。

我了解到,亮度法是判断人眼所见颜色的灰色调的一种更为复杂的方法。但是,如何以编程方式执行此操作超出了我目前的理解。我理解数学后就可以用PHPJS编写它。

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

就像是:

$result = grayScaleDifference('#9d5fb0','#318261');

要么
$result = 8bitK_difference('#9d5fb0','#318261');

要么
$result = luminanceDifference('#9d5fb0','#318261');

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

最佳答案

后续回答

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

定义:

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

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

亮度:(记为 L Y ):光线的线性度量或表示形式(即,无 Gamma 曲线)。作为度量,通常为cd / m2。作为表示,在CIEXYZ中为Y,通常为0(黑色)到100(白色)。亮度具有光谱加权,这是基于人类对不同波长的光的感知。但是,亮度在明暗方面是线性的-也就是说,如果100个光子测得10个光子,那么20个将是200个光子。

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

亮度与L *: 0和100在亮度(Y或L,写为L *)和亮度(L *)上是相同的,但在中间它们是非常不同的。我们确定为中间灰色的是位于L *的中间50,但与亮度(Y)的18.4有关。在sRGB中为#777777或46.7%。

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

从sRGB得出亮度(Y)

步骤零(非十六进制)

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

步骤一(8位至十进制)

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

R´decimal = R´8bit / 255 G´decimal = G´8bit / 255 B´decimal = B´8bit / 255

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

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

将每个颜色通道提高到2.2的幂,与sRGB显示器相同。这对于大多数应用程序来说都是很好的。但是,如果您需要多次往返sRGB gamma编码空间,请使用以下更准确的版本。

R´^ 2.2 = Rlin G´^ 2.2 = Glin B´^ 2.2 = Blin

第二步(线性化,准确版本)

如果您要进行图像处理以及 Gamma 编码空间的多次往返操作,请使用此版本而不是上面的简单^ 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));
        }
    }

第三步(光谱加权亮度)

正常的人眼具有三种对红色,绿色和蓝色光敏感的视锥细胞。但是我们的光谱灵敏度并不均匀,因为我们对绿色(555 nm)最敏感,而蓝色是遥远的最后位置。使用以下系数对亮度进行光谱加权以反射(reflect)这一点:

Rlin * 0.2126 + Glin * 0.7152 + Blin * 0.0722 = Y = L

将每个线性化色彩通道的系数乘以它们,然后将它们总和求和,得出L,亮度。

第四步(对比度确定)

确定对比度的方法有很多,还有各种标准。根据特定的应用,某些方程比其他方程更有效。

WCAG
WCAG 2.0和2.1中列出的当前网页标准是简单的对比:

C =((较轻+ 0.05)/(较暗+ 0.05)):1

这给出一个比率,WCAG的标准将非文本指定为3:1,将文本指定为4.5:1。

但是,由于多种原因,这是一个微不足道的例子。我在指出当前GitHub问题(695)中的缺陷时在记录中,并且一直在研究替代方法。

修改后的Weber
Hwang/Peli Modified Weber适用于计算机显示器/ sRGB,可以提供更好的对比度评估。

C =(较浅– Ldarker)/(较浅+ 0.1)

请注意,根据最近的一些实验,我选择了耀斑系数0.1而不是0.05。该值虽然是TBD,但不同的值可能更好。

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;
        }
    }

将L转换为L *之后,一个有用的对比图就是:

C = L *较浅– L *较暗

这里的结果可能需要缩放以类似于其他方法。大约1.6或1.7的缩放比例似乎效果很好。

还有许多其他方法可用于确定对比度,但这是最常见的方法。但是,某些应用程序将与其他对比度方法相比更好。其他一些是迈克尔逊对比度,感知对比度长度(PCL)和Bowman / Sapolinski。

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

旁注:

平均RGB No Bueno!

OP 2x2p提到了一个常用的等式,用于使颜色的灰度级为:

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

他指出了它看起来有多么不准确,并且-确实是完全错误的。 R,G和B的频谱加权很大,不能忽略。绿色的亮度比蓝色的亮度高。您不能仅将所有三个通道加在一起并除以三,而得到与特定颜色的实际亮度相近的任何值。

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

OP的样品颜色

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

enter image description here

两者都接近#777777的中间灰色。还要注意,亮度L仅为18时,感知亮度L *为50。

关于javascript - 计算RGB值的人眼对比度差异的有效方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56198778/

相关文章:

javascript - 您可以使用数组的值作为比较吗

javascript - 如何在jquery中通过类名获取输入元素值

php - 在 Controller 中找不到 fllashMessenger() 说 phpStorm 但正在工作

php - Laravel 8 迁移 "General error: 1215 Cannot add foreign key constraint"

html - 将矩形图像显示为正方形裁剪图像 css

javascript - 具有自定义输入的 Angular 2 模板驱动表单

JavaScript 目标。

php - 我有 mysql,我想检查一个值是否在数组中,如果有值 = x,如果没有值 = y

CSS图像和文本对齐

html - 如何确保 <td> 的高度恰好是 200px?