language agnostic - Suivi: Trouver une "distance" précise entre les couleurs

Translate

Question originale

Je recherche une fonction qui tente de quantifier à quel point deux couleurs sont "distantes" (ou distinctes). 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?)
This question and all comments follow the "Attribution Required."

Toutes les réponses

Translate

Convertissez en La * b * (aka tout 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 scientifiques de la couleur ont d'autres mesures plus raffinées, qui peuvent ne pas valoir la peine, selon la précision nécessaire à ce que vous faites.

leaetbles 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 - le blanc, les gris sonta=0,b=0. leLest la luminosité définie d'une manière particulière, de zéro (obscurité pure) à quoi que ce soit.

Explication grossière: >> Compte tenu d'une couleur, nos yeux distinguent deux larges gammes de longueurs d'onde - bleu vs longueurs d'onde plus longues. puis, grâce à une mutation génétique plus récente, les cônes de plus grande longueur d'onde se sont divisés en deux, distinguant pour nous le rouge du vert.

Au fait, ce sera formidable pour votre carrière de s'élever au-dessus de vos collègues hommes des cavernes de couleur qui ne connaissent que «RVB» ou «CMJN», qui sont parfaits pour les appareils, mais qui craignent pour un travail de perception sérieux. J'ai travaillé pour des scientifiques en imagerie qui ne savaient rien de tout ça!

Pour une lecture plus amusante de la théorie de la différence de couleur, essayez:

Plus de détails sur Lab àhttp://en.kioskea.net/video/cie-lab.php3Je ne peux pas pour le moment trouver une page non laide qui contenait réellement les formules de conversion, mais je suis sûr que quelqu'un modifiera cette réponse pour en inclure une.

La source
Berton Lee
Translate

comme le lien cmetric.htm ci-dessus a échoué pour moi, ainsi que de nombreuses autres implémentations pour la distance de couleur, j'ai trouvé (après un très long jurney ..) comment calculer la meilleure distance de couleur, et ... la plus précise scientifiquement:deltaEet à 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 bogue sérieux ... mais ça semble 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 );
}

J'espère que cela aide quelqu'un :)

La source
Translate

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

Il est parfois préférable, lorsque vous travaillez avec du matériel artistique, des images numérisées ou d'autres supports, 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 façon dont les modèles émulent la perception de la couleur par les humains. RVB et CMJN sont des modèles additifs et soustractifs, respectivement, modélisant la façon dont les lumières ou les pigments de couleur primaire (respectivement) se combinent pour former de nouvelles couleurs lorsqu'ils sont mélangés.

Graphical depiction of HSV

La source
Translate

leArticle Wikipédia sur les différences de couleurrépertorie un certain nombre d'espaces colorimétriques et de mesures de distance conçus pour s'accorder avec la perception humaine des distances chromatiques.

La source
Translate

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

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

La source
Translate

Le plus faciledistanceserait 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 extrémités.

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

ImageMagicfournit les échelles suivantes:

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

Bien sûr, des valeurs comme celles-ci n'auraient de sens que par rapport à d'autres valeurs pour d'autres couleurs, pas comme quelque chose qui aurait du sens pour les humains, donc tout ce que vous pourriez utiliser pour les valeurs serait l'ordre de similitude.

La source
Translate

Eh bien, comme premier point d'appel, je dirais que les métriques communes HSV (Hue, Saturation and Value) ou HSL sont mieux représentatives de la façon dont les humains perçoivent la couleur que de dire RVB ou CYMK. VoirHSL, HSV sur Wikipedia.

Je suppose naïvement que je tracerais les points dans l'espace HSL pour les deux couleurs et calculerais la magnitude 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 au vert foncé. Mais alors, 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 capte bien mieux le vert que les autres couleurs. Un changement de teinte du vert du même montant qu'un changement du rouge peut sembler plus important. De plus, un décalage de la saturation d'une petite quantité à zéro est la différence entre le gris et le rose, ailleurs, le décalage 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 - ce serait assez arbitraire et serait basé sur diverses idées de théorie des couleurs mais être modifié de manière assez arbitraire en fonction de ce à quoi vous vouliez l'appliquer.

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

La source
Translate

En tant que daltonien, je pense qu'il est bon d'essayer d'ajouter plus de séparation qu'une vision normale. La forme la plus courante de daltonisme est la carence rouge / verte. Cela ne signifie pas 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.

La source