Changeset 2193


Ignore:
Timestamp:
Jan 2, 2013, 1:54:08 PM (7 years ago)
Author:
sam
Message:

color: implement HSV to RGB transformation and a CIEDE2000 distance
function for CIE L*a*b* values.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/lol/image/color.h

    r2189 r2193  
    2929     * Convert linear RGB to sRGB
    3030     */
    31     static vec3 LinearRGBTosRGB(vec3 c)
    32     {
    33         vec3 ret = 12.92f * c;
    34         if (c.r > 0.0031308f)
    35             ret.r = 1.055f * pow(c.r, 1.0f / 2.4f) - 0.055f;
    36         if (c.g > 0.0031308f)
    37             ret.g = 1.055f * pow(c.g, 1.0f / 2.4f) - 0.055f;
    38         if (c.b > 0.0031308f)
    39             ret.b = 1.055f * pow(c.b, 1.0f / 2.4f) - 0.055f;
     31    static vec3 LinearRGBTosRGB(vec3 src)
     32    {
     33        vec3 ret = 12.92f * src;
     34        if (src.r > 0.0031308f)
     35            ret.r = 1.055f * pow(src.r, 1.0f / 2.4f) - 0.055f;
     36        if (src.g > 0.0031308f)
     37            ret.g = 1.055f * pow(src.g, 1.0f / 2.4f) - 0.055f;
     38        if (src.b > 0.0031308f)
     39            ret.b = 1.055f * pow(src.b, 1.0f / 2.4f) - 0.055f;
    4040        return ret;
    4141    }
    4242
    43     static vec4 LinearRGBTosRGB(vec4 c)
    44     {
    45         return vec4(LinearRGBTosRGB(c.rgb), c.a);
     43    static vec4 LinearRGBTosRGB(vec4 src)
     44    {
     45        return vec4(LinearRGBTosRGB(src.rgb), src.a);
    4646    }
    4747
     
    4949     * Convert sRGB to linear RGB
    5050     */
    51     static vec3 sRGBToLinearRGB(vec3 c)
    52     {
    53         vec3 ret = 1.0f / 12.92f * c;
    54         if (c.r > 0.04045f)
    55             ret.r = pow(c.r + 0.055f, 2.4f) / pow(1.055f, 2.4f);
    56         if (c.g > 0.04045f)
    57             ret.g = pow(c.g + 0.055f, 2.4f) / pow(1.055f, 2.4f);
    58         if (c.b > 0.04045f)
    59             ret.b = pow(c.b + 0.055f, 2.4f) / pow(1.055f, 2.4f);
     51    static vec3 sRGBToLinearRGB(vec3 src)
     52    {
     53        vec3 ret = 1.0f / 12.92f * src;
     54        if (src.r > 0.04045f)
     55            ret.r = pow(src.r + 0.055f, 2.4f) / pow(1.055f, 2.4f);
     56        if (src.g > 0.04045f)
     57            ret.g = pow(src.g + 0.055f, 2.4f) / pow(1.055f, 2.4f);
     58        if (src.b > 0.04045f)
     59            ret.b = pow(src.b + 0.055f, 2.4f) / pow(1.055f, 2.4f);
    6060        return ret;
    6161    }
    6262
    63     static vec4 sRGBToLinearRGB(vec4 c)
    64     {
    65         return vec4(sRGBToLinearRGB(c.rgb), c.a);
     63    static vec4 sRGBToLinearRGB(vec4 src)
     64    {
     65        return vec4(sRGBToLinearRGB(src.rgb), src.a);
     66    }
     67
     68    /*
     69     * Convert linear HSV to linear RGB
     70     */
     71    static vec3 HSVToLinearRGB(vec3 src)
     72    {
     73        vec3 tmp = abs(fract(vec3(src.x) + vec3(3.f, 2.f, 1.f) / 3.f) * 6.f - vec3(3.f));
     74        return mix(vec3(1.f), clamp(tmp - vec3(1.f), 0.f, 1.f), src.y) * src.z;
     75    }
     76
     77    static vec4 HSVToLinearRGB(vec4 src)
     78    {
     79        return vec4(HSVToLinearRGB(src.rgb), src.a);
    6680    }
    6781
     
    6983     * Convert linear RGB to CIE XYZ
    7084     */
    71     static vec3 LinearRGBToCIEXYZ(vec3 c)
     85    static vec3 LinearRGBToCIEXYZ(vec3 src)
    7286    {
    7387        mat3 m(vec3(3.2406f, -0.9689f, 0.0557f),
    7488               vec3(-1.5372f, 1.8758f, -0.2040f),
    7589               vec3(-0.4986f, 0.0415f, 1.0570f));
    76         return m * c;
    77     }
    78 
    79     static vec4 LinearRGBToCIEXYZ(vec4 c)
    80     {
    81         return vec4(LinearRGBToCIEXYZ(c.rgb), c.a);
     90        return m * src;
     91    }
     92
     93    static vec4 LinearRGBToCIEXYZ(vec4 src)
     94    {
     95        return vec4(LinearRGBToCIEXYZ(src.rgb), src.a);
    8296    }
    8397
     
    8599     * Convert CIE XYZ to linear RGB
    86100     */
    87     static vec3 CIEXYZToLinearRGB(vec3 c)
     101    static vec3 CIEXYZToLinearRGB(vec3 src)
    88102    {
    89103        mat3 m(vec3(0.4124f, 0.2126f, 0.0193f),
    90104               vec3(0.3576f, 0.7152f, 0.1192f),
    91105               vec3(0.1805f, 0.0722f, 0.9505f));
    92         return m * c;
    93     }
    94 
    95     static vec4 CIEXYZToLinearRGB(vec4 c)
    96     {
    97         return vec4(CIEXYZToLinearRGB(c.rgb), c.a);
     106        return m * src;
     107    }
     108
     109    static vec4 CIEXYZToLinearRGB(vec4 src)
     110    {
     111        return vec4(CIEXYZToLinearRGB(src.rgb), src.a);
    98112    }
    99113
    100114    /*
    101115     * Convert CIE XYZ to CIE L*a*b*
    102      */
    103     static vec3 CIEXYZToCIELab(vec3 col)
    104     {
    105         using std::pow;
    106 
    107         float const a = 8.85645167903563081e-3; /* (6/29)^3 */
    108         float const b = 7.78703703703703703;    /* 1/3 (29/6)^2 */
    109         float const c = 1.37931034482758620e-1; /* 4/29 */
    110 
    111         vec3 f = b * col + vec3(c);
    112         if (col.x > a)
    113             f.x = pow(col.x, 1.0 / 3.0);
    114         if (col.y > a)
    115             f.y = pow(col.y, 1.0 / 3.0);
    116         if (col.z > a)
    117             f.z = pow(col.z, 1.0 / 3.0);
    118 
    119         return vec3(116.0 * f.y - 16.0,
    120                     500.0 * (f.x - f.y),
    121                     200.0 * (f.y - f.z));
    122     }
    123 
    124     static vec4 CIEXYZToCIELab(vec4 c)
    125     {
    126         return vec4(CIEXYZToLinearRGB(c.rgb), c.a);
     116     * Note: XYZ values should be normalised, ie. divided by the
     117     * corresponding components for white.
     118     */
     119    static vec3 CIEXYZToCIELab(vec3 src)
     120    {
     121        float const a = (6.0 * 6.0 * 6.0) / (29 * 29 * 29);
     122        float const b = (29.0 * 29.0) / (3 * 6 * 6);
     123        float const c = 4.0 / 29;
     124        float const d = 1.0 / 3;
     125
     126        vec3 f = b * src + vec3(c);
     127        if (src.x > a)
     128            f.x = pow(src.x, d);
     129        if (src.y > a)
     130            f.y = pow(src.y, d);
     131        if (src.z > a)
     132            f.z = pow(src.z, d);
     133
     134        return vec3(116.f * f.y - 16.f,
     135                    500.f * (f.x - f.y),
     136                    200.f * (f.y - f.z));
     137    }
     138
     139    static vec4 CIEXYZToCIELab(vec4 src)
     140    {
     141        return vec4(CIEXYZToLinearRGB(src.rgb), src.a);
     142    }
     143
     144    /*
     145     * Return distance using the CIEDE2000 metric,
     146     * input should be in CIE L*a*b*.
     147     */
     148    static float DistanceCIEDE2000(vec3 lab1, vec3 lab2)
     149    {
     150        float const deg2rad = 6.28318530718f / 360.f;
     151        float const rad2deg = 360.f / 6.28318530718f;
     152
     153        float C1 = length(lab1.yz);
     154        float C2 = length(lab2.yz);
     155        float C_ = 0.5f * (C1 + C2);
     156
     157        float L1 = lab1.x;
     158        float L2 = lab2.x;
     159        float dLp = L2 - L1;
     160        float L_ = 0.5f * (L1 + L2);
     161
     162        float tmp1 = pow(C_, 7.f);
     163        float tmp2 = 1.5f - 0.5f * sqrt(tmp1 / (tmp1 + pow(25.f, 7.f)));
     164        float ap1 = lab1.y * tmp2;
     165        float ap2 = lab2.y * tmp2;
     166        float Cp1 = sqrt(ap1 * ap1 + lab1.z * lab1.z);
     167        float Cp2 = sqrt(ap2 * ap2 + lab2.z * lab2.z);
     168        float dCp = Cp2 - Cp1;
     169        float Cp_ = 0.5f * (Cp1 + Cp2);
     170
     171        float hp1 = fmod(atan2(lab1.z, ap1) * rad2deg, 360.f);
     172        if (hp1 < 0.f)
     173            hp1 += 360.f;
     174        float hp2 = fmod(atan2(lab2.z, ap2) * rad2deg, 360.f);
     175        if (hp2 < 0.f)
     176            hp2 += 360.f;
     177        float dhp;
     178        if (abs(hp1 - hp2) <= 180.f)
     179            dhp = hp2 - hp1;
     180        else if (hp2 <= hp1)
     181            dhp = hp2 - hp1 + 360.f;
     182        else
     183            dhp = hp2 - hp1 - 360.f;
     184        float dHp = 2.f * sqrt(Cp1 * Cp2) * sin(dhp / 2.f * deg2rad);
     185        float Hp_;
     186        if (abs(hp1 - hp2) > 180.f)
     187            Hp_ = 0.5f * (hp1 + hp2 + 360.f);
     188        else
     189            Hp_ = 0.5f * (hp1 + hp2);
     190
     191        float T = 1.f - 0.17f * cos((Hp_ - 30.f) * deg2rad)
     192                      + 0.24f * cos(2 * Hp_ * deg2rad)
     193                      + 0.32f * cos((3.f * Hp_ + 6.f) * deg2rad)
     194                      - 0.20f * cos((4.f * Hp_ - 63.f) * deg2rad);
     195        float SL = 1.f + 0.015f * (L_ - 50) * (L_ - 50)
     196                                / sqrt(20.f + (L_ - 50) * (L_ - 50));
     197        float SC = 1.f + 0.045f * Cp_;
     198        float SH = 1.f + 0.015f * Cp_ * T;
     199        float RT = -2.f * sqrt(pow(Cp_, 7.f) / (pow(Cp_, 7.f) + pow(25.f, 7.f)))
     200                        * sin(60.f * deg2rad * exp(-pow((Hp_ - 275.f) / 25.f, 2.f)));
     201
     202        dLp /= SL;
     203        dCp /= SC;
     204        dHp /= SH;
     205
     206        return sqrt(dLp * dLp + dCp * dCp + dHp * dHp + RT * dCp * dHp);
    127207    }
    128208};
Note: See TracChangeset for help on using the changeset viewer.