How to calculate the distance between ofColors in openframeworks

前端 未结 1 1749
感动是毒
感动是毒 2020-12-20 08:30

What I was thinking to do is to convert ofColor to l*a*b color space and measure the euclidean distance. But I don\'t know how should I do it in openframeworks?

1条回答
  •  囚心锁ツ
    2020-12-20 08:45

    I'm not very experienced with c++ but I ported this snippet over:

    //ported from http://cookbooks.adobe.com/post_Useful_color_equations__RGB_to_LAB_converter-14227.html
    struct Color{
        float R,G,B,X,Y,Z,L,a,b;
    };
    
    #define REF_X 95.047; // Observer= 2°, Illuminant= D65
    #define REF_Y 100.000;
    #define REF_Z 108.883;
    
    Color rgb2xyz(int R,int G,int B){
        float r = R / 255.0;
        float g = G / 255.0;
        float b = B / 255.0;
    
        if (r > 0.04045){ r = pow((r + 0.055) / 1.055, 2.4); }
        else { r = r / 12.92; }
        if ( g > 0.04045){ g = pow((g + 0.055) / 1.055, 2.4); }
        else { g = g / 12.92; }
        if (b > 0.04045){ b = pow((b + 0.055) / 1.055, 2.4); }
        else {  b = b / 12.92; }
    
        r = r * 100;
        g = g * 100;
        b = b * 100;
        //Observer. = 2°, Illuminant = D65
        Color xyz;
        xyz.X = r * 0.4124 + g * 0.3576 + b * 0.1805;
        xyz.Y = r * 0.2126 + g * 0.7152 + b * 0.0722;
        xyz.Z = r * 0.0193 + g * 0.1192 + b * 0.9505;
        return xyz;
    }
    Color xyz2lab(float X,float Y, float Z){
        float x = X / REF_X;
        float y = Y / REF_X;
        float z = Z / REF_X;
    
        if ( x > 0.008856 ) { x = pow( x , .3333333333f ); }
        else { x = ( 7.787 * x ) + ( 16/116.0 ); }
        if ( y > 0.008856 ) { y = pow( y , .3333333333f ); }
        else { y = ( 7.787 * y ) + ( 16/116.0 ); }
        if ( z > 0.008856 ) { z = pow( z , .3333333333f ); }
        else { z = ( 7.787 * z ) + ( 16/116.0 ); }
    
        Color lab;
        lab.L = ( 116 * y ) - 16;
        lab.a = 500 * ( x - y );
        lab.b = 200 * ( y - z );
        return lab;
    }
    Color lab2xyz(float l, float a, float b){
        float y = (l + 16) / 116;
        float x = a / 500 + y;
        float z = y - b / 200;
    
        if ( pow( y , 3 ) > 0.008856 ) { y = pow( y , 3 ); }
        else { y = ( y - 16 / 116 ) / 7.787; }
        if ( pow( x , 3 ) > 0.008856 ) { x = pow( x , 3 ); }
        else { x = ( x - 16 / 116 ) / 7.787; }
        if ( pow( z , 3 ) > 0.008856 ) { z = pow( z , 3 ); }
        else { z = ( z - 16 / 116 ) / 7.787; }
    
        Color xyz;
        xyz.X = x * REF_X;
        xyz.Y = y * REF_Y;
        xyz.Z = z * REF_Z;
        return xyz;
    }
    Color xyz2rgb(float X,float Y,float Z){
        //X from 0 to  95.047      (Observer = 2°, Illuminant = D65)
        //Y from 0 to 100.000
        //Z from 0 to 108.883
        X = ofClamp(X, 0, 95.047);
    
        float x = X * .01;
        float y = Y * .01;
        float z = Z * .01;
    
        float r = x * 3.2406 + y * -1.5372 + z * -0.4986;
        float g = x * -0.9689 + y * 1.8758 + z * 0.0415;
        float b = x * 0.0557 + y * -0.2040 + z * 1.0570;
    
        if ( r > 0.0031308 ) { r = 1.055 * pow( r , ( 1 / 2.4f ) ) - 0.055; }
        else { r = 12.92 * r; }
        if ( g > 0.0031308 ) { g = 1.055 * pow( g , ( 1 / 2.4f ) ) - 0.055; }
        else { g = 12.92 * g; }
        if ( b > 0.0031308 ) { b = 1.055 * pow( b , ( 1 / 2.4f ) ) - 0.055; }
        else { b = 12.92 * b; }
    
        Color rgb;
        rgb.R = round( r * 255 );
        rgb.G = round( g * 255 );
        rgb.B = round( b * 255 );
        return rgb;
    }
    Color rgb2lab(int R,int G,int B){
        Color xyz = rgb2xyz(R, G, B);
        return xyz2lab(xyz.X, xyz.Y, xyz.Z);
    }
    Color lab2rgb(int L,int a,int b){
        Color xyz = lab2xyz(L, a, b);
        return xyz2rgb(xyz.X, xyz.Y, xyz.Z);
    }
    

    Measuring the distance would be something as trivial as:

    float distLab(Color c1,Color c2){
        float dL = c1.L - c2.L;
        float da = c1.a - c2.a;
        float db = c1.b - c2.b;
        return sqrt(dL*dL + da*da + db*db);
    }
    

    or ofVec3f(c1.L,c1.a,c1.b).distance(ofVec3f(c2.L,c2.a,c2.b));

    Also see this answer for an openframeworks basic example. image by colour search

    0 讨论(0)
提交回复
热议问题