47 votes

Suivi: recherche d'une "distance" précise entre les couleurs

Question originale

Je cherche une fonction qui tente de quantifier la différence de distance entre deux couleurs. Cette question est vraiment en deux parties:

  1. Quel espace colorimétrique représente le mieux la vision humaine?
  2. Quelle métrique de distance dans cet espace représente le mieux la vision humaine (euclidienne?)

43voto

DarenW Points 7817

Convertir de La*b* (aka tout simplement "Laboratoire", et vous verrez aussi référence à "CIELAB"). Un bon rapide measaure de différence de couleur est

(L1-L2)^2 + (a1-a2)^2 + (b1-b2)^2

Les spécialistes de la couleur ont d'autres plus raffinés mesures, qui peuvent ne pas être en vaut la peine, en fonction de l'exactitude nécessaire pour ce que vous faites.

L' a et b représentent les valeurs des couleurs opposées d'une manière similaire à la façon dont les cônes de travail, et peut être positive ou négative. Couleurs neutres de blanc, de gris sont a=0,b=0. L' L luminosité est définie d'une manière particulière, à partir de zéro (obscurité pure) jusqu'à ce que.

Brut explication :>> Donné une couleur, nos yeux la distinction entre les deux grandes gammes de longueur d'onde bleu - vs plus longues longueurs d'onde. et puis, grâce à une plus récente mutation génétique, plus la longueur d'onde des cônes scindé en deux, en distinguant pour nous rouge vs vert.

Par la manière, il sera idéal pour votre carrière, pour s'élever au-dessus de la couleur de l'homme des cavernes collègues qui connaissent seulement "RVB" ou "CMYK" qui sont grands pour les appareils mais sucer pour de graves perception du travail. J'ai travaillé pour l'imagerie des scientifiques qui ne sait pas une chose à propos de ce genre de choses!

Pour plus de plaisir de la lecture sur la différence de couleur de la théorie, essayez:

Plus de détails sur les Laboratoire de http://en.kioskea.net/video/cie-lab.php3 je ne peux pas en ce moment de trouver un non-vilaine page qui en fait avait la conversion des formules, mais je suis sûr que quelqu'un va modifier cette réponse de façon à inclure un.

8voto

rub Points 55

comme cmetric.htm lien ci-dessus a échoué pour moi, ainsi que de nombreuses autres implémentations pour la couleur de la distance que j'ai trouvé (après une très longue jurney..) comment calculer la meilleure couleur de la distance et de .. plus scientifiquement exacte: deltaE et de 2 RGB (!) les valeurs à l'aide d'OpenCV:

Ce 3 couleur des conversions d'espace + un code de conversion à partir de javascript (http://svn.int64.org/viewvc/int64/colors/colors.js) à C++

Et enfin le code (qui semble tout droit sorti de la boîte, espère que personne ne trouve un bug grave là ... mais il semble très bien, après un certain nombre de tests)

#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/photo/photo.hpp>
#include <math.h>

using namespace cv;
using namespace std;

#define REF_X 95.047; // Observer= 2°, Illuminant= D65
#define REF_Y 100.000;
#define REF_Z 108.883;

void bgr2xyz( const Vec3b& BGR, Vec3d& XYZ );
void xyz2lab( const Vec3d& XYZ, Vec3d& Lab );
void lab2lch( const Vec3d& Lab, Vec3d& LCH );
double deltaE2000( const Vec3b& bgr1, const Vec3b& bgr2 );
double deltaE2000( const Vec3d& lch1, const Vec3d& lch2 );


void bgr2xyz( const Vec3b& BGR, Vec3d& XYZ )
{
    double r = (double)BGR[2] / 255.0;
    double g = (double)BGR[1] / 255.0;
    double b = (double)BGR[0] / 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 *= 100.0;
    g *= 100.0;
    b *= 100.0;
    XYZ[0] = r * 0.4124 + g * 0.3576 + b * 0.1805;
    XYZ[1] = r * 0.2126 + g * 0.7152 + b * 0.0722;
    XYZ[2] = r * 0.0193 + g * 0.1192 + b * 0.9505;
}

void xyz2lab( const Vec3d& XYZ, Vec3d& Lab )
{
    double x = XYZ[0] / REF_X;
    double y = XYZ[1] / REF_X;
    double z = XYZ[2] / REF_X;
    if( x > 0.008856 )
        x = pow( x , .3333333333 );
    else
        x = ( 7.787 * x ) + ( 16.0 / 116.0 );
    if( y > 0.008856 )
        y = pow( y , .3333333333 );
    else
        y = ( 7.787 * y ) + ( 16.0 / 116.0 );
    if( z > 0.008856 )
        z = pow( z , .3333333333 );
    else
        z = ( 7.787 * z ) + ( 16.0 / 116.0 );
    Lab[0] = ( 116.0 * y ) - 16.0;
    Lab[1] = 500.0 * ( x - y );
    Lab[2] = 200.0 * ( y - z );
}

void lab2lch( const Vec3d& Lab, Vec3d& LCH )
{
    LCH[0] = Lab[0];
    LCH[1] = sqrt( ( Lab[1] * Lab[1] ) + ( Lab[2] * Lab[2] ) );
    LCH[2] = atan2( Lab[2], Lab[1] );
}

double deltaE2000( const Vec3b& bgr1, const Vec3b& bgr2 )
{
    Vec3d xyz1, xyz2, lab1, lab2, lch1, lch2;
    bgr2xyz( bgr1, xyz1 );
    bgr2xyz( bgr2, xyz2 );
    xyz2lab( xyz1, lab1 );
    xyz2lab( xyz2, lab2 );
    lab2lch( lab1, lch1 );
    lab2lch( lab2, lch2 );
    return deltaE2000( lch1, lch2 );
}

double deltaE2000( const Vec3d& lch1, const Vec3d& lch2 )
{
    double avg_L = ( lch1[0] + lch2[0] ) * 0.5;
    double delta_L = lch2[0] - lch1[0];
    double avg_C = ( lch1[1] + lch2[1] ) * 0.5;
    double delta_C = lch1[1] - lch2[1];
    double avg_H = ( lch1[2] + lch2[2] ) * 0.5;
    if( fabs( lch1[2] - lch2[2] ) > CV_PI )
        avg_H += CV_PI;
    double delta_H = lch2[2] - lch1[2];
    if( fabs( delta_H ) > CV_PI )
    {
        if( lch2[2] <= lch1[2] )
            delta_H += CV_PI * 2.0;
        else
            delta_H -= CV_PI * 2.0;
    }

    delta_H = sqrt( lch1[1] * lch2[1] ) * sin( delta_H ) * 2.0;
    double T = 1.0 -
            0.17 * cos( avg_H - CV_PI / 6.0 ) +
            0.24 * cos( avg_H * 2.0 ) +
            0.32 * cos( avg_H * 3.0 + CV_PI / 30.0 ) -
            0.20 * cos( avg_H * 4.0 - CV_PI * 7.0 / 20.0 );
    double SL = avg_L - 50.0;
    SL *= SL;
    SL = SL * 0.015 / sqrt( SL + 20.0 ) + 1.0;
    double SC = avg_C * 0.045 + 1.0;
    double SH = avg_C * T * 0.015 + 1.0;
    double delta_Theta = avg_H / 25.0 - CV_PI * 11.0 / 180.0;
    delta_Theta = exp( delta_Theta * -delta_Theta ) * ( CV_PI / 6.0 );
    double RT = pow( avg_C, 7.0 );
    RT = sqrt( RT / ( RT + 6103515625.0 ) ) * sin( delta_Theta ) * -2.0; // 6103515625 = 25^7
    delta_L /= SL;
    delta_C /= SC;
    delta_H /= SH;
    return sqrt( delta_L * delta_L + delta_C * delta_C + delta_H * delta_H + RT * delta_C * delta_H );
}

Espérons que cela aide quelqu'un :)

4voto

huseyint Points 8196

LGV et HSV sont mieux pour la perception humaine de la couleur. Selon Wikipedia:

Il est parfois préférable de travailler avec les matériaux de l'art, des images numérisées, ou d'autres médias, à utiliser le HSV ou HSL modèle de couleur par rapport à d'autres modèles tels que RVB ou CMJN, en raison de différences dans la manière dont les modèles à imiter la façon dont les humains perçoivent les couleurs. RVB et CMJN sont additives et soustractives modèles, respectivement, de la modélisation de la façon dont la couleur primaire des lumières ou des pigments (respectivement) se combinent pour former de nouvelles couleurs lors du mélange.

Graphical depiction of HSV

3voto

palm3D Points 1991

L' article de Wikipedia sur les différences de couleur répertorie un certain nombre d'espaces colorimétriques et de métriques de distance conçus pour s'accorder avec la perception humaine des distances de couleur.

3voto

Vincent Robert Points 16530

Peut ressembler à du spam mais non, ce lien est vraiment intéressant pour les espaces colorimétriques :)

http://www.compuphase.com/cmetric.htm

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X