Language agnostic 后续行动:找到一个准确的;“距离”;颜色之间
我正在寻找一个函数,试图量化两种颜色之间的“距离”(或区别)。这个问题实际上分为两部分:Language agnostic 后续行动:找到一个准确的;“距离”;颜色之间,language-agnostic,colors,Language Agnostic,Colors,我正在寻找一个函数,试图量化两种颜色之间的“距离”(或区别)。这个问题实际上分为两部分: 什么颜色空间最能代表人类的视觉 该空间中的哪种距离度量最能代表人类视觉(欧几里德?) 最简单的距离当然是把颜色看成是来自同一个原点的三维矢量,并取它们的端点之间的距离。 如果你需要考虑这样的因素,绿色在判断强度方面更为突出,你可以称量这些值。< /P> 提供以下比例: 红色:0.3 绿色:0.6 蓝色:0.1 当然,像这样的值只有在与其他颜色的其他值相关时才有意义,而不是作为对人类有意义的东西,因此您可
- 红色:0.3
- 绿色:0.6
- 蓝色:0.1
当然,像这样的值只有在与其他颜色的其他值相关时才有意义,而不是作为对人类有意义的东西,因此您可以使用这些值进行相似性排序。HSL和HSV更适合人类的颜色感知。根据: 在使用艺术材料、数字化图像或其他媒体时,有时最好使用HSV或HSL颜色模型,而不是RGB或CMYK等替代模型,因为模型模拟人类感知颜色的方式不同。RGB和CMYK分别是加法和减法模型,模拟了原色灯光或颜料(分别)混合时形成新颜色的方式
作为第一点,我认为HSV(色调、饱和度和值)或HSL比RGB或CYMK更能代表人类感知颜色的方式。看 我天真地认为我会在HSL空间中绘制两种颜色的点,并计算差分向量的大小。然而,这意味着亮黄色和亮绿色将被视为与绿色和深绿色一样不同。但是很多人认为红色和粉色是两种不同的颜色。 此外,在该参数空间中相同方向上的差分向量不相等。例如,人眼比其他颜色更能辨别绿色。从绿色到红色的色调偏移量与从红色到绿色的色调偏移量相同,看起来可能更大。另外,饱和度从少量到零的变化是灰色和粉色之间的差异,其他地方的变化是两种红色之间的差异 从程序员的角度来看,您需要绘制差分向量,但通过比例矩阵进行修改,该矩阵将在HSL空间的各个区域相应地调整长度-这将是相当任意的,并且将基于各种颜色理论思想,但根据您想要应用的内容,可以相当任意地进行调整 更妙的是,你可以在网上看到是否有人做过这样的事情。列出了许多颜色空间和距离度量,旨在符合人类对颜色距离的感知。转换为La*b*(也就是普通的“Lab”,你还可以看到对“CIELAB”的引用)。一种快速测量色差的好方法是 (L1-L2)^2+(a1-a2)^2+(b1-b2)^2 颜色科学家还有其他更精确的测量方法,这可能不值得费心,这取决于你所做工作所需的准确度
a
和b
值以类似于锥体工作方式的方式表示相反的颜色,可以是负数或正数。中性色-白色、灰色分别为a=0
、b=0
。L
是以特定的方式定义的亮度,从零(纯黑暗)到任何东西
粗略解释:>>给定一种颜色,我们的眼睛可以区分两种波长范围——蓝色和更长的波长。然后,多亏了最近的一次基因突变,波长较长的球果一分为二,区分了红球果和绿球果
顺便说一句,如果你的职业生涯能够超越那些只知道“RGB”或“CMYK”的颜色穴居人学院,那将是一件非常棒的事情,因为它们对于设备来说很好,但对于严肃的感知工作来说却很糟糕。我为成像科学家工作过,他们对这些东西一无所知
有关色差理论的更多有趣阅读,请尝试:
- 和信息
- 和一般色彩理论的链接,websurf从和开始
关于Lab at的更多细节我现在找不到一个真正有转换公式的不难看的页面,但我相信有人会编辑这个答案,包括一个。作为色盲的人,我认为尝试添加比正常视力更多的分离是好的。最常见的色盲是红/绿色盲。这并不意味着你看不到红色或绿色,这意味着它更难看到,也更难看到差异。因此,色盲者需要更大的距离才能分辨出差异。因为上面的cmetric.htm链接对我来说是失败的,我还发现了许多其他关于颜色距离的实现(经过很长时间的讨论后…)如何计算最佳颜色距离,以及。。科学上最精确的一个:deltaE和使用OpenCV的2个RGB(!)值: 这需要3个颜色空间转换+一些从javascript()到C的代码转换++ 最后是代码(似乎是开箱即用的,希望没有人在那里发现严重的bug…但经过多次测试后,它看起来很好)
#包括
#包括
#包括
#包括
#包括
使用名称空间cv;
使用名称空间std;
#定义参考号95.047;//观察者=2°,光源=D65
#定义参考100.000;
#定义参考编号108.883;
无效bgr2xyz(常量Vec3b和BGR、Vec3d和XYZ);
void xyz2lab(const Vec3d&XYZ、Vec3d&Lab);
void lab2lch(const Vec3d和Lab、Vec3d和LCH);
双三角2000(常数Vec3b和bgr1,常数Vec3b和bgr2);
双三角2000(常数Vec3d和lch1,常数Vec3d和lch2);
无效bgr2xyz(常量Vec3b和BGR、Vec3d和XYZ)
{
#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 );
}