Question

Question originale

Je recherche une fonction qui tente de quantifier à quel point deux couleurs sont « éloignées » (ou distinctes).Cette question comporte en réalité deux parties :

  1. Quel espace colorimétrique représente le mieux la vision humaine ?
  2. Quelle mesure de distance dans cet espace représente le mieux la vision humaine (euclidienne ?)
Était-ce utile?

La solution

Convertissez en La*b* (alias simplement "Lab", et vous verrez également une référence à "CIELAB").Une bonne mesure rapide de la différence de couleur est

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

Les spécialistes des couleurs disposent d'autres mesures plus raffinées, qui peuvent ne pas en valoir la peine, en fonction de la précision requise pour ce que vous faites.

Le a et b les valeurs représentent des couleurs opposées d'une manière similaire au fonctionnement des cônes et peuvent être négatives ou positives.Couleurs neutres - blanc, les gris sont a=0,b=0.Le L la luminosité est-elle définie d'une manière particulière, de zéro (obscurité pure) jusqu'à n'importe quoi.

Explication grossière :>> Étant donné une couleur, nos yeux font la distinction entre deux larges gammes de longueurs d'onde : le bleu et les longueurs d'onde plus longues.puis, grâce à une mutation génétique plus récente, les cônes de longueur d'onde plus longue se sont bifurqués en deux, distinguant pour nous le rouge du rouge.vert.

Soit dit en passant, ce serait formidable pour votre carrière de dépasser vos collègues hommes des cavernes des couleurs qui ne connaissent que « RVB » ou « CMJN », qui sont parfaits pour les appareils mais sont nuls pour un travail de perception sérieux.J'ai travaillé pour des scientifiques en imagerie qui ne connaissaient rien à ce genre de choses !

Pour une lecture plus amusante sur la théorie des différences de couleurs, essayez :

Plus de détails sur le laboratoire sur http://fr.kioskea.net/video/cie-lab.php3 Je ne parviens pas pour le moment à trouver une page non moche contenant réellement les formules de conversion, mais je suis sûr que quelqu'un modifiera cette réponse pour en inclure une.

Autres conseils

comme le lien cmetric.htm ci-dessus a échoué pour moi, ainsi que de nombreuses autres implémentations de distance de couleur, j'ai trouvé (après un très long voyage ..) comment calculer la meilleure distance de couleur, et ..le plus précis scientifiquement : deltaE et à partir de 2 valeurs RVB (!) en utilisant OpenCV :

Cela nécessitait 3 conversions d'espace colorimétrique + une conversion de code à partir de javascript (http://svn.int64.org/viewvc/int64/colors/colors.js) en C++

Et enfin le code (semble fonctionner dès la sortie de la boîte, j'espère que personne n'y trouvera de bug sérieux...mais ça semble bien après plusieurs 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 );
}

J'espère que ça aidera quelqu'un :)

HSL et HSV sont meilleurs pour la perception humaine des couleurs.Selon Wikipédia:

Il est parfois préférable, lorsque l'on travaille avec des matériaux artistiques, des images numérisées ou d'autres médias, d'utiliser le modèle de couleur HSV ou HSL plutôt que des modèles alternatifs tels que RVB ou CMJN, en raison des différences dans la manière dont les modèles émulent la façon dont les humains perçoivent la couleur.RVB et CMJN sont respectivement des modèles additifs et soustractifs, modélisant la manière dont les lumières ou pigments de couleurs primaires (respectivement) se combinent pour former de nouvelles couleurs lorsqu'ils sont mélangés.

Graphical depiction of HSV

Le Article Wikipédia sur les différences de couleur répertorie un certain nombre d'espaces colorimétriques et de mesures de distance conçus pour correspondre à la perception humaine des distances de couleurs.

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

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

Le plus facile distance serait bien sûr de simplement considérer les couleurs comme des vecteurs 3D provenant de la même origine, et prenant la distance entre leurs points extrêmes.

Si vous devez prendre en compte des facteurs tels que le vert est plus important pour juger de l'intensité, vous pouvez peser les valeurs.

ImageMagique fournit les échelles suivantes :

  • rouge:0,3
  • vert:0,6
  • bleu:0,1

Bien sûr, des valeurs comme celle-ci n'auraient de sens que par rapport à d'autres valeurs pour d'autres couleurs, et non comme quelque chose qui aurait un sens pour les humains, donc tout ce que vous pourriez utiliser pour les valeurs serait un ordre de similarité.

Eh bien, comme premier point d'appel, je dirais que les métriques courantes HSV (Teinte, Saturation et Valeur) ou HSL sont mieux représentatives de la façon dont les humains perçoivent la couleur que, par exemple, RVB ou CMJN.Voir HSL, HSV sur Wikipédia.

Je suppose que je tracerais naïvement les points dans l'espace HSL pour les deux couleurs et calculerais l'ampleur du vecteur de différence.Cependant, cela signifierait que le jaune vif et le vert vif seraient considérés comme tout aussi différents que le vert et le vert foncé.Mais beaucoup considèrent le rouge et le rose comme deux couleurs différentes.

De plus, les vecteurs de différence dans la même direction dans cet espace de paramètres ne sont pas égaux.Par exemple, l’œil humain perçoit bien mieux le vert que les autres couleurs.Un changement de teinte par rapport au vert d’autant qu’un changement par rapport au rouge peut sembler plus important.De plus, un changement de saturation d'une petite quantité à zéro correspond à la différence entre le gris et le rose, ailleurs, le changement serait la différence entre deux nuances de rouge.

Du point de vue des programmeurs, vous auriez besoin de tracer les vecteurs de différence mais modifiés par une matrice de proportionnalité qui ajusterait les longueurs en conséquence dans diverses régions de l'espace HSL - cela serait assez arbitraire et serait basé sur diverses idées de théorie des couleurs mais être modifié assez arbitrairement en fonction de ce à quoi vous souhaitez l'appliquer.

Mieux encore, vous pourrez voir si quelqu'un a déjà fait une telle chose en ligne...

En tant que daltonien, je pense qu'il est bon d'essayer d'ajouter plus de séparation que la vision normale.La forme la plus courante de daltonisme est la carence en rouge/vert.Cela ne veut pas dire que vous ne pouvez pas voir le rouge ou le vert, cela signifie qu'il est plus difficile de voir et plus difficile de voir les différences.Il faut donc une plus grande séparation avant qu’une personne daltonienne puisse faire la différence.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top