Я пытаюсь преобразовать цветовое пространство CIE XYZ в sRGB в качестве промежуточного звена между цветовым пространством CIELAB и sRGB. Я использую формы в http://www.brucelindbloom.com/ и https://en.wikipedia.org/wiki/SRGB#From_sRGB_to_CIE_XYZ.
Значения, полученные в результате моей текущей попытки, неверны (например, сравните https://www.nixsensor.com/free-color-converter/), и мне пришлось абсолютизировать линейные значения RGB, чтобы формула работала. Может ли кто-нибудь сказать мне, как это должно быть сделано или где я ошибаюсь?
// Convert XYZ to sRGB
function xyz2rgb(xyz){
const r = 3.2404542*xyz.x + -1.5371385*xyz.y + -0.4985314*xyz.z
const g = -0.9692660*xyz.x + 1.8760108*xyz.y + 0.0415560*xyz.z
const b = 0.0556434*xyz.x + -0.2040259*xyz.y + 1.0572252*xyz.z
//convert to srgb
function adj(C) {
C = Math.abs(C)
let v
if (C <= 0.0031308) {
v = 12.92 * C
} else {
v = 1.055 * C**(1/24) - 0.055
}
return Math.round(v*255)
}
const R = adj(r)
const G = adj(g)
const B = adj(b)
return { 'r':R, 'g':G, 'b':B }
}
const xyz = {x:0.02, y:0.18, z:1.08}
const rgb = xyz2rgb(xyz)
console.info(rgb)
Редактировать: jsfiddle: https://jsfiddle.net/058e36ac/2/



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


При преобразовании в вашем коде возникло несколько проблем. Во-первых, вы применили логику гамма-коррекции без ограничения линейных значений RGB.
Другая проблема заключается в том, что вы не обработали отрицательные значения RGB, и, как вы знаете, гамма-коррекция должна применяться только к значениям в диапазоне [0, 1], а отрицательные значения требуют специальной обработки.
Исправления, которые я сделал:
var clamp = function (value) {
return Math.max(0, Math.min(1, value));
};
var transfer = function (c) {
if (c <= 0.0031308) {
return 12.92 * c;
} else {
return 1.055 * Math.pow(c, 1 / 2.4) - 0.055;
}
};
var R = clamp(transfer(rLinear));
var G = clamp(transfer(gLinear));
var B = clamp(transfer(bLinear));
return {
r: Math.round(R * 255),
g: Math.round(G * 255),
b: Math.round(B * 255)
};
Вот полная функция преобразования xyz в srgb:
function xyz_to_srgb(xyz) {
var xsm = [
[3.2406255, -1.537208, -0.4986286],
[-0.9689307, 1.8757561, 0.0415175],
[0.0557101, -0.2040211, 1.0569959]
];
var rLinear = xyz.x * xsm[0][0] + xyz.y * xsm[0][1] + xyz.z * xsm[0][2];
var gLinear = xyz.x * xsm[1][0] + xyz.y * xsm[1][1] + xyz.z * xsm[1][2];
var bLinear = xyz.x * xsm[2][0] + xyz.y * xsm[2][1] + xyz.z * xsm[2][2];
// Clamp values between 0 and 1
var clamp = function (value) {
return Math.max(0, Math.min(1, value));
};
// Apply gamma correction
var transfer = function (c) {
if (c <= 0.0031308) {
return 12.92 * c;
} else {
return 1.055 * Math.pow(c, 1 / 2.4) - 0.055;
}
};
// Apply gamma correction and clamp
var R = clamp(transfer(rLinear));
var G = clamp(transfer(gLinear));
var B = clamp(transfer(bLinear));
// Convert to 0-255 range
return {
r: Math.round(R * 255),
g: Math.round(G * 255),
b: Math.round(B * 255)
};
}
const xyz = { x: 0.02, y: 0.18, z: 1.08 };
const rgb = xyz_to_srgb(xyz);
console.info(rgb);
Вот результат приведенного выше кода:
{
b: 255,
g: 162,
r: 0
}
Обратитесь к этой сути для большей ясности того, как реализовать преобразование: конвертация xyz в srgb
Большое спасибо! установка мин/макс 0-1 для c перед регулировкой, в частности, устранила проблему для меня!