代码之家  ›  专栏  ›  技术社区  ›  Ghoul Fool

RGB到XYZ和LAB颜色转换

  •  21
  • Ghoul Fool  · 技术社区  · 13 年前

    我在将颜色从RGB转换为LAB空间时遇到问题 应该直接使用以下公式 here ,只是我得到了错误的值

    • RGB=56,719132

    • X=8.592

    • Y=8.099
    • Z=22.940

    CIE-L*ab为

    • 长*34.188
    • a*8.072
    • b*32.478

    这是我的代码;但我看不出哪里出了问题。可能是因为这样的浮点 fella 在我面前。谢谢。

    // user colour
    var Red   = 56;
    var Green = 79;
    var Blue  = 132;
    
    // user colour converted to XYZ space
    XYZ = RGBtoXYZ(Red,Green,Blue)
    var colX = XYZ[0];
    var colY = XYZ[1];
    var colZ = XYZ[2];
    
    // alert(XYZ)
    
    LAB = XYZtoLAB(colX, colY, colZ)
    
    alert(LAB)
    
    function RGBtoXYZ(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 = ( ( var_R + 0.055 ) / 1.055 ) ^ 2.4
        else                   var_R = var_R / 12.92
        if ( var_G > 0.04045 ) var_G = ( ( var_G + 0.055 ) / 1.055 ) ^ 2.4
        else                   var_G = var_G / 12.92
        if ( var_B > 0.04045 ) var_B = ( ( 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 XYZtoLAB(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 = var_X ^ ( 1/3 )
        else                    var_X = ( 7.787 * var_X ) + ( 16 / 116 )
        if ( var_Y > 0.008856 ) var_Y = var_Y ^ ( 1/3 )
        else                    var_Y = ( 7.787 * var_Y ) + ( 16 / 116 )
        if ( var_Z > 0.008856 ) var_Z = 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]
    }
    
    4 回复  |  直到 9 年前
        1
  •  24
  •   J. Holmes    13 年前

    我很确定 ^ 是javascript中的按位xor,而不是幂运算符。我想 Math.pow 就是你想要的。

        2
  •  7
  •   catamphetamine    6 年前
    /**
     * Converts RGB color to CIE 1931 XYZ color space.
     * https://www.image-engineering.de/library/technotes/958-how-to-convert-between-srgb-and-ciexyz
     * @param  {string} hex
     * @return {number[]}
     */
    export function rgbToXyz(hex) {
        const [r, g, b] = hexToRgb(hex).map(_ => _ / 255).map(sRGBtoLinearRGB)
        const X =  0.4124 * r + 0.3576 * g + 0.1805 * b
        const Y =  0.2126 * r + 0.7152 * g + 0.0722 * b
        const Z =  0.0193 * r + 0.1192 * g + 0.9505 * b
        // For some reason, X, Y and Z are multiplied by 100.
        return [X, Y, Z].map(_ => _ * 100)
    }
    
    /**
     * Undoes gamma-correction from an RGB-encoded color.
     * https://en.wikipedia.org/wiki/SRGB#Specification_of_the_transformation
     * https://stackoverflow.com/questions/596216/formula-to-determine-brightness-of-rgb-color
     * @param  {number}
     * @return {number}
     */
    function sRGBtoLinearRGB(color) {
        // Send this function a decimal sRGB gamma encoded color value
        // between 0.0 and 1.0, and it returns a linearized value.
        if (color <= 0.04045) {
            return color / 12.92
        } else {
            return Math.pow((color + 0.055) / 1.055, 2.4)
        }
    }
    
    /**
     * Converts hex color to RGB.
     * https://stackoverflow.com/questions/5623838/rgb-to-hex-and-hex-to-rgb
     * @param  {string} hex
     * @return {number[]} [rgb]
     */
    function hexToRgb(hex) {
        const match = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex)
        if (match) {
            match.shift()
            return match.map(_ => parseInt(_, 16))
        }
    }
    
    /**
     * Converts CIE 1931 XYZ colors to CIE L*a*b*.
     * The conversion formula comes from <http://www.easyrgb.com/en/math.php>.
     * https://github.com/cangoektas/xyz-to-lab/blob/master/src/index.js
     * @param   {number[]} color The CIE 1931 XYZ color to convert which refers to
     *                           the D65/2° standard illuminant.
     * @returns {number[]}       The color in the CIE L*a*b* color space.
     */
    // X, Y, Z of a "D65" light source.
    // "D65" is a standard 6500K Daylight light source.
    // https://en.wikipedia.org/wiki/Illuminant_D65
    const D65 = [95.047, 100, 108.883]
    export function xyzToLab([x, y, z]) {
      [x, y, z] = [x, y, z].map((v, i) => {
        v = v / D65[i]
        return v > 0.008856 ? Math.pow(v, 1 / 3) : v * 7.787 + 16 / 116
      })
      const l = 116 * y - 16
      const a = 500 * (x - y)
      const b = 200 * (y - z)
      return [l, a, b]
    }
    
    /**
     * Converts Lab color space to Luminance-Chroma-Hue color space.
     * http://www.brucelindbloom.com/index.html?Eqn_Lab_to_LCH.html
     * @param  {number[]}
     * @return {number[]}
     */
    export function labToLch([l, a, b]) {
        const c = Math.sqrt(a * a + b * b)
        const h = abToHue(a, b)
        return [l, c, h]
    }
    
    /**
     * Converts a and b of Lab color space to Hue of LCH color space.
     * https://stackoverflow.com/questions/53733379/conversion-of-cielab-to-cielchab-not-yielding-correct-result
     * @param  {number} a
     * @param  {number} b
     * @return {number}
     */
    function abToHue(a, b) {
        if (a >= 0 && b === 0) {
            return 0
        }
        if (a < 0 && b === 0) {
            return 180
        }
        if (a === 0 && b > 0) {
            return 90
        }
        if (a === 0 && b < 0) {
            return 270
        }
        let xBias
        if (a > 0 && b > 0) {
            xBias = 0
        } else if (a < 0) {
            xBias = 180
        } else if (a > 0 && b < 0) {
            xBias = 360
        }
        return radiansToDegrees(Math.atan(b / a)) + xBias
    }
    
    function radiansToDegrees(radians) {
        return radians * (180 / Math.PI)
    }
    
    function degreesToRadians(degrees) {
        return degrees * Math.PI / 180
    }
    
    
        3
  •  1
  •   Marcel    3 年前

    以下是RGB的一些函数->XYZ、XYZ->实验室,实验室->XYZ、XYZ->RGB中。

    function RGBtoXYZ([R, G, B]) {
        const [var_R, var_G, var_B] = [R, G, B]
            .map(x => x / 255)
            .map(x => x > 0.04045
                ? Math.pow(((x + 0.055) / 1.055), 2.4)
                : x / 12.92)
            .map(x => x * 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 XYZtoRGB([X, Y, Z]) {
        //X, Y and Z input refer to a D65/2° standard illuminant.
        //sR, sG and sB (standard RGB) output range = 0 ÷ 255
    
        let var_X = X / 100
        let var_Y = Y / 100
        let var_Z = Z / 100
    
        var_R = var_X *  3.2406 + var_Y * -1.5372 + var_Z * -0.4986
        var_G = var_X * -0.9689 + var_Y *  1.8758 + var_Z *  0.0415
        var_B = var_X *  0.0557 + var_Y * -0.2040 + var_Z *  1.0570
    
        return [var_R, var_G, var_B]
            .map(n => n > 0.0031308
                ? 1.055 * Math.pow(n, (1 / 2.4)) - 0.055
                : 12.92 * n)
            .map(n => n * 255)
    }
    
    const ref_X =  95.047;
    const ref_Y = 100.000;
    const ref_Z = 108.883;
    
    function XYZtoLAB([x, y, z]) {
        const [ var_X, var_Y, var_Z ] = [ x / ref_X, y / ref_Y, z / ref_Z ]
            .map(a => a > 0.008856
                ? Math.pow(a, 1 / 3)
                : (7.787 * a) + (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 LABtoXYZ([l, a, b]) {
    
        const var_Y = (l + 16) / 116
        const var_X = a / 500 + var_Y
        const var_Z = var_Y - b / 200
    
        const [X, Y, Z] = [var_X, var_Y, var_Z]
            .map(n => Math.pow(n, 3) > 0.008856
                ? Math.pow(n, 3)
                : (n - 16 / 116) / 7.787)
    
        return [X * ref_X, Y * ref_Y, Z * ref_Z]
    }
    
    

    参考文献: http://www.easyrgb.com/en/math.php

        4
  •  0
  •   ceed    11 年前

    function xyzc(c){return ((c/255)>0.04045)?Math.pow((((c/255)+0.055)/1.055),2.4)*100:(c/255)/12.92*100;}

    此行将rgb通道转换为XYZ