【问题标题】:Inaccurate values when converting from RGB to L*ab colours从 RGB 转换为 L*ab 颜色时值不准确
【发布时间】:2020-03-25 08:14:56
【问题描述】:

我正在尝试将 sRGB 值(在 Photoshop 中)转换为 L*ab 值(也用于 Photoshop)我在球场上,但没有得到与 EasyRGB 相同的结果转换公式来自。我预计会有四舍五入的错误(不是在最后,我四舍五入到三个地方)。只有我看不见。

  • 输入:sRGB 255、0、255
  • 输出:L*ab: 60.32 , 98.254, -60.843
  • 预期输出 L*ab:60.324 98.234 -60.825

为了方便起见,我删除了所有 Photoshop 代码,所以它只是 JavaScript

var msg = "";

// RGB
// var Red = foregroundColor.rgb.red;
// var Green = foregroundColor.rgb.green;
// var Blue = foregroundColor.rgb.blue;

var Red = 255;
var Green = 0;
var Blue = 255;

msg = "RGB: " + Red + ", " + Green + ", " + Blue + "<br>";
printy(msg);

// user colour converted to XYZ space
var myColXYZ = RGB_to_XYZ(Red, Green, Blue)
var colX = myColXYZ[0];
var colY = myColXYZ[1];
var colZ = myColXYZ[2];

// using CIE L-ab* colour space
var myLab = XYZ_to_LAB(colX, colY, colZ)

//msg = "L*ab: " + myLab[0] + ", " + myLab[1] + ", " + myLab[2] + "<br>";

// b4 rounding: 60.319933664076004, 98.25421868616108, -60.84298422386232


// round to three places
for (var i = 0; i < 3; i++) {
  myLab[i] = round_nicely(myLab[i], 3);
}
msg = "L*ab: " + myLab[0] + ", " + myLab[1] + ", " + myLab[2] + "<br>";
printy(msg);

// results
// RGB: 255, 0, 255
// L*ab: 60.32, 98.254, -60.843


// should be
// CIE-L*ab     =   60.324   98.234  -60.825

// function RGB TO XYZ (R, G, B)
// --------------------------------------------------------
// http://www.easyrgb.com/index.php?X=MATH&H=02#text2
function RGB_to_XYZ(r, g, b) {
  var_R = parseFloat(r / 255); //r from 0 to 255
  var_G = parseFloat(g / 255); //g from 0 to 255
  var_B = parseFloat(b / 255); //b from 0 to 255

  if (var_R > 0.04045) var_R = Math.pow(((var_R + 0.055) / 1.055), 2.4)
  else var_R = var_R / 12.92
  if (var_G > 0.04045) var_G = Math.pow(((var_G + 0.055) / 1.055), 2.4)
  else var_G = var_G / 12.92
  if (var_B > 0.04045) var_B = Math.pow(((var_B + 0.055) / 1.055), 2.4)
  else var_B = var_B / 12.92

  var_R = var_R * 100;
  var_G = var_G * 100;
  var_B = var_B * 100;

  // Observer. = 2°, Illuminant = D65
  X = var_R * 0.4124 + var_G * 0.3576 + var_B * 0.1805;
  Y = var_R * 0.2126 + var_G * 0.7152 + var_B * 0.0722;
  Z = var_R * 0.0193 + var_G * 0.1192 + var_B * 0.9505;
  return [X, Y, Z]
}

// function XYZ TO LAB (x, y, z)
// --------------------------------------------------------
// http://www.easyrgb.com/index.php?X=MATH&H=16#text16
function XYZ_to_LAB(x, y, z) {
  var ref_X = 95.047;
  var ref_Y = 100.000;
  var ref_Z = 108.883;

  var_X = x / ref_X; //ref_X =  95.047   Observer= 2°, Illuminant= D65
  var_Y = y / ref_Y; //ref_Y = 100.000
  var_Z = z / ref_Z; //ref_Z = 108.883

  if (var_X > 0.008856) var_X = Math.pow(var_X, (1 / 3))
  else var_X = (7.787 * var_X) + (16 / 116)
  if (var_Y > 0.008856) var_Y = Math.pow(var_Y, (1 / 3))
  else var_Y = (7.787 * var_Y) + (16 / 116)
  if (var_Z > 0.008856) var_Z = Math.pow(var_Z, (1 / 3))
  else var_Z = (7.787 * var_Z) + (16 / 116)

  CIE_L = (116 * var_Y) - 16;
  CIE_a = 500 * (var_X - var_Y);
  CIE_b = 200 * (var_Y - var_Z);

  return [CIE_L, CIE_a, CIE_b]
}

// function ROUND NICELY (num number, number of decimal places)
// --------------------------------------------------------
function round_nicely(num, places) {
  // if(! places) places = 3;
  var p = Math.pow(10, places)
  return Math.round(num * p) / p
}

// function PRINTY (str)
// --------------------------------------------------------
function printy(message) {
  var outputDiv = document.getElementById('myPage');
  outputDiv.innerHTML += message;
}
<!-- page content -->
<p id="myPage"></p>

【问题讨论】:

  • EasyRGB ...所以...您从那里提取了哪些公式?
  • RGB_to_XYZ() 中的 parseFloat() 函数是怎么回事?它用于将字符串转换为数字,但括号内的除法结果无论如何已经是浮点数。
  • @kruemi 那是调试过度。 :)
  • 可能是EasyRBG计算错误?还是不是按照 it6 所说的方式计算的?

标签: javascript colors rgb photoshop extendscript


【解决方案1】:

考虑使用 Photoshop 的 ExtendScript/JS API 而不是 EasyRGB 进行准确的颜色转换。

下面gist中的自定义rgbToLab函数演示了如何利用SolidColor类首先创建一个新的RGB颜色(使用给定的颜色分量;R、G、B)以及如何随后获得相应的实验室值。

#target photoshop

/**
 * Converts RGB color values to the Lab color model.
 * @param {Number} red - The red component value (0-255).
 * @param {Number} green - The green component value (0-255).
 * @param {Number} blue - The blue component value (0-255).
 * @returns {Array} The Lab values.
 */
function rgbToLab(red, green, blue) {
  var color = new SolidColor;

  color.rgb.red = red;
  color.rgb.green = green;
  color.rgb.blue = blue;

  return [
    color.lab.l,
    color.lab.a,
    color.lab.b
  ]
}

var labValues = rgbToLab(255, 0, 255);

$.writeln('L*ab: '+ labValues) // --> L*ab: 60.16845703125,92.6736755371094,-60.763671875

【讨论】:

    【解决方案2】:

    出现这种差异是因为 Photoshop 使用 D50 光源进行 Lab 转换 (source) 而 EasyRGB 颜色转换器在从 sRGB 转换时使用 D65(请注意在 sRGB 和 XYZ 行中提到了“D65/2°”转换结果,D65 光源也被硬编码在their pseudocode 中用于此转换)。据我所知,从 sRGB 开始时,无法让 EasyRGB 使用不同的光源。

    至于提供的 JavaScript 代码,我可以看出您正在使用与 D65 光源相对应的值,因此您的代码将生成与 EasyRGB 给出的 Lab 值匹配,但与 Photoshop 给出的值不匹配。

    如果要编写同时支持 D50 和 D65 光源的代码,则需要使用不同的值。以下值来自this source。在上面的 JavaScript 代码中,这些值的“D65 光源,RGB 到 XYZ”集被硬编码到 RGB_to_XYZ 函数中。

    D65 光源,sRGB 工作空间,RGB 转 XYZ:
    0.4124564 0.3575761 0.1804375
    0.2126729 0.7151522 0.0721750
    0.0193339 0.1191920 0.9503041

    D65 光源,sRGB 工作空间,XYZ 转 RGB:
    3.2404542 -1.5371385 -0.4985314
    -0.9692660 1.8760108 0.0415560
    0.0556434 -0.2040259 1.0572252

    D50 光源,sRGB(适用于 Bradford)工作空间,RGB 转 XYZ:
    0.4360747 0.3850649 0.1430804
    0.2225045 0.7168786 0.0606169
    0.0139322 0.0971045 0.7141733

    D50 光源,sRGB(适用于 Bradford)工作空间,XYZ 转 RGB:
    3.1338561 -1.6168667 -0.4906146
    -0.9787684 1.9161415 0.0334540
    0.0719453 -0.2289914 1.4052427

    在 XYZ 到 Lab 和 Lab 到 XYZ 的转换过程中,还可以使用不同的白点值,具体取决于您的光源。在上面的 JavaScript 代码中,这些变量被命名为 ref_Xref_Yref_Z

    D65 光源,用于 XYZ 到实验室和实验室到 XYZ 的转换 (source)
    X: 95.047
    Y: 100.0
    Z: 108.883

    D50 光源,用于 XYZ 到实验室和实验室到 XYZ 的转换(source 1source 2
    X: 96.42
    Y: 100.0
    Z: 82.49

    我自己用这些值测试了转换,它们确实解决了您注意到的 EasyRGB 转换和 Photoshop 转换之间的差异。使用任一组值,您可以成功地从 RGB -> XYZ -> Lab -> XYZ -> RGB (转换后恢复原始 RGB 值)。如果光源是 D65,XYZ 和 Lab 值将与 EasyRGB 给出的值匹配。如果光源是 D50,Lab 值将与 Photoshop 给出的值匹配。

    最后,关于我所引用的转换算法的一点上下文:

    • 从 sRGB 转换为 Lab 颜色时,必须使用 XYZ 作为中间格式。没有直接转换。
    • EasyRGB 网站上有pseudocode examples of conversion formulas,但几乎没有注释。我发现公式here 更容易阅读。它们使用 C#。
    • 我包含了从 Lab -> XYZ -> sRGB 转换时所需的值集,尽管原始问题中的代码仅来自 sRGB -> XYZ -> Lab。我认为最好能够双向转换以确认您的代码正常工作。
    • 需要注意的一点是 Photoshop 的拾色器工具不显示 Lab 值的小数位。因此,如果您从输入 RGB 值开始,记下拾色器工具中的 Lab 值,然后再次输入相同的 Lab 值,您可能会得到一组与开始时略有不同的 RGB 值。

    【讨论】:

      【解决方案3】:

      显然,EasyRBG RGBXYZ 的转换存在缺陷。它不遵守自己的规则。 让我们一步一步来:

      输入数据是

      R: 255 G: 0 B: 255

      第一步是通过除以 255 将它们映射到零到一个范围。产生这个

      var_R: 1 var_G: 0 var_B: 1

      下一步是一些操作,这似乎是一些色域调整。但这些操作在极端情况下都有固定点,这意味着输入值 10 在此操作中不会改变。所以我们还在

      var_R: 1 var_G: 0 var_B: 1

      下一步是将所有内容缩放 100

      var_R: 100 var_G: 0 var_B: 100

      然后有一个向量(R,G,B)(X,Y,Z)的矩阵乘法,这是一个RGB向量的加权线性组合

      X = 42.24 + 18.05 = 60.29
      Y = 21.26 + 7.22 = 28.48
      Y = 1.93 + 95.05 = 96.98

      EasyRGB 从RGBXYZ 的转换有一些不同的结果

      X: 59.289, Y: 28.485, Z: 96.964

      【讨论】:

        猜你喜欢
        • 2013-12-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-02-08
        • 2013-06-15
        • 2014-02-02
        • 1970-01-01
        • 2017-09-11
        相关资源
        最近更新 更多