やってみる

アウトプットすべく己を導くためのブログ。その試行錯誤すらたれ流す。

RGBとLChの色空間を相互変換したい

 Bashで行いたかったが少数計算ができないためPythonで実装する。

成果物

参考

 Lab, XYZ表色系を仲介するようだ。

コード

const lch2rgb = (...args) => {
    args = unpack(args, 'lch');
    const [l,c,h] = args;
    const [L,a,b_] = lch2lab (l,c,h);
    const [r,g,b] = lab2rgb (L,a,b_);
    return [r, g, b, args.length > 3 ? args[3] : 1];
}
const lch2lab = (...args) => {
    let [l,c,h] = unpack(args, 'lch');
    if (isNaN(h)) h = 0;
    h = h * DEG2RAD;
    return [l, cos(h) * c, sin(h) * c]
}
   DEG2RAD: PI / 180,
const lab2rgb = (...args) => {
    args = unpack(args, 'lab');
    const [l,a,b] = args;
    let x,y,z, r,g,b_;

    y = (l + 16) / 116;
    x = isNaN(a) ? y : y + a / 500;
    z = isNaN(b) ? y : y - b / 200;

    y = LAB_CONSTANTS.Yn * lab_xyz(y);
    x = LAB_CONSTANTS.Xn * lab_xyz(x);
    z = LAB_CONSTANTS.Zn * lab_xyz(z);

    r = xyz_rgb(3.2404542 * x - 1.5371385 * y - 0.4985314 * z);  // D65 -> sRGB
    g = xyz_rgb(-0.9692660 * x + 1.8760108 * y + 0.0415560 * z);
    b_ = xyz_rgb(0.0556434 * x - 0.2040259 * y + 1.0572252 * z);

    return [r,g,b_,args.length > 3 ? args[3] : 1];
};

const xyz_rgb = (r) => {
    return 255 * (r <= 0.00304 ? 12.92 * r : 1.055 * pow(r, 1 / 2.4) - 0.055)
}

const lab_xyz = (t) => {
    return t > LAB_CONSTANTS.t1 ? t * t * t : LAB_CONSTANTS.t2 * (t - LAB_CONSTANTS.t0)
}
module.exports = {
    // Corresponds roughly to RGB brighter/darker
    Kn: 18,

    // D65 standard referent
    Xn: 0.950470,
    Yn: 1,
    Zn: 1.088830,

    t0: 0.137931034,  // 4 / 29
    t1: 0.206896552,  // 6 / 29
    t2: 0.12841855,   // 3 * t1 * t1
    t3: 0.008856452,  // t1 * t1 * t1
}

所感

 これくらいライブラリがあっても良かったと思う。たぶん誰かそのうち作ってくれるはず。それまで自前のこれでなんとかする。

対象環境

$ uname -a
Linux raspberrypi 5.4.83-v7l+ #1379 SMP Mon Dec 14 13:11:54 GMT 2020 armv7l GNU/Linux