como cmetric.htm el enlace anterior falló para mí, así como muchas otras implementaciones para la distancia de color que encontré (después de una jurney muy larga).) La forma de calcular la mejor distancia de color y .. más científicamente exacta uno: delta E y de 2 RGB() valores usando OpenCV:
Esto requiere 3 conversiones de espacio de color + alguna conversión de código de JavaScript (http://svn.int64.org/viewvc/int64/colors/colors.js) a C++
Y por último el código (parece que funciona nada más sacarlo de la caja, espero que nadie encuentra un error grave allí ... pero parece bien después de una serie de pruebas)
#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);
}
espero que ayuda a alguien :)
que terminó el trazado de algunas de las soluciones a continuación cuando se trata de una situación similar. Otros pueden encontrar las parcelas http://stackoverflow.com/q/5774152/156755 interesante – Basic