Преобразование XYZ в sRGB

Я пытаюсь преобразовать цветовое пространство 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/

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
0
71
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

При преобразовании в вашем коде возникло несколько проблем. Во-первых, вы применили логику гамма-коррекции без ограничения линейных значений RGB.

Другая проблема заключается в том, что вы не обработали отрицательные значения RGB, и, как вы знаете, гамма-коррекция должна применяться только к значениям в диапазоне [0, 1], а отрицательные значения требуют специальной обработки.

Исправления, которые я сделал:

  1. Добавлена ​​функция фиксации для фиксации значений от 0 до 1.
var clamp = function (value) {
  return Math.max(0, Math.min(1, value));
};
  1. Добавлена ​​функция гамма-коррекции для фиксации линейных значений RGB:
var transfer = function (c) {
 if (c <= 0.0031308) {
   return 12.92 * c;
 } else {
   return 1.055 * Math.pow(c, 1 / 2.4) - 0.055;
 }
};
  1. Применена гамма-коррекция и ограничение, а затем масштабировано до диапазона 0–255:
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 перед регулировкой, в частности, устранила проблему для меня!

M.L. 29.05.2024 21:08

Другие вопросы по теме