Я ищу функцию, которая пытается количественно определить, насколько «отдалены» (или различны) два цвета. Этот вопрос действительно состоит из двух частей:
- Какое цветовое пространство лучше всего отражает человеческое зрение?
- Какой показатель расстояния в этом пространстве лучше всего представляет человеческое зрение (евклидово?)
Преобразуйте в La * b * (он же просто "Lab", и вы также увидите ссылку на "CIELAB"). Хорошее быстрое измерение разницы в цвете
(L1-L2) ^ 2 + (a1-a2) ^ 2 + (b1-b2) ^ 2
У исследователей цвета есть и другие, более изощренные меры, которые могут не стоить беспокоиться, в зависимости от точности, необходимой для того, что вы делаете.
Значения a
и b
представляют противоположные цвета способом, подобным тому, как работают шишки, и могут быть отрицательными или положительными. Нейтральные цвета - белый, серый есть a=0
, b=0
. L
Это яркость определяется определенным образом, от нуля (чистой темноты) до любой другой .
Грубое объяснение: >> Учитывая цвет, наши глаза различают два широких диапазона длин волн - синий и более длинные. и затем, благодаря более поздней генетической мутации, конусы с большей длиной волны разделились на две части, что отличает нас от красного до зеленого.
Кстати, для вашей карьеры было бы здорово подняться над вашими коллегами-цветными пещерными людьми, которые знают только "RGB" или "CMYK", которые отлично подходят для устройств, но отстой для серьезной работы восприятия. Я работал на ученых, которые не знали ничего об этом!
Чтобы получить больше удовольствия от чтения теории цветовых различий, попробуйте:
- http://white.stanford.edu/~brian/scielab/introduction.html и информация
- и ссылки на теорию цвета в целом, веб-серфинг, начиная с http://www.efg2.com/Lab/Library/Color/ и
- http://www.poynton.com/Poynton-color.html
Более подробную информацию о лаборатории можно найти на http://en.kioskea.net/video/cie-lab.php3. В настоящее время я не могу найти некрасивую страницу с формулами преобразования, но я уверен, что кто-то отредактирует эту страницу. ответ, чтобы включить один.
так как ссылка на cmetric.htm выше не удалась для меня, так же как и для многих других реализаций цветового расстояния, я нашел (после очень долгого приезда), как рассчитать наилучшее цветовое расстояние и ... наиболее научно точный: deltaE и from 2 RGB (!) Значения с использованием OpenCV:
Это потребовало 3 преобразования цветового пространства + некоторое преобразование кода из javascript ( http://svn.int64.org/viewvc/int64/colors/colors.js ) в C ++
И, наконец, код (кажется, работает прямо из коробки, надеюсь, никто не найдет там серьезную ошибку ... но после ряда тестов он кажется нормальным)
#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 );
}
Надеюсь, это поможет кому-то :)
HSL и HSV лучше для человеческого восприятия цвета. Согласно Википедии :
Иногда при работе с художественными материалами, оцифрованными изображениями или другими носителями предпочтительно использовать цветовую модель HSV или HSL над альтернативными моделями, такими как RGB или CMYK, из-за различий в способах, которыми модели подражают восприятие цвета людьми. RGB и CMYK являются аддитивной и вычитающей моделями, соответственно, моделирующими способ, которым основные цвета света или пигменты (соответственно) объединяются, чтобы сформировать новые цвета при смешивании.
Может выглядеть как спам, но нет, эта ссылка действительно интересна для цветовых пространств :)
В статье Википедии о цветовых различиях перечислен ряд цветовых пространств и метрик расстояния, разработанных для соответствия восприятию человеком цветовых расстояний.
Самым простым расстоянием , конечно, было бы просто рассматривать цвета как 3d-векторы, исходящие из одного и того же источника и определяющие расстояние между их конечными точками.
Если вам необходимо учесть такие факторы, что зеленый цвет более важен при оценке интенсивности, вы можете взвесить значения.
ImageMagic предоставляет следующие масштабы:
- красный: 0,3
- зеленый: 0,6
- синий: 0,1
Конечно, такие значения будут иметь смысл только по отношению к другим значениям для других цветов, а не как что-то, что будет иметь значение для людей, поэтому все, для чего вы могли бы использовать значения, это упорядочение подобия.
Ну, в качестве первого пункта я бы сказал, что общие метрики HSV (Hue, Saturation и Value) или HSL лучше отражают то, как люди воспринимают цвет, чем RGB или CYMK. Смотрите HSL, HSV в Википедии .
Я предполагаю, что наивно я нанесу точки в пространстве HSL для двух цветов и вычислю величину вектора разности. Однако это будет означать, что ярко-желтый и ярко-зеленый будут отличаться от зеленого до темно-зеленого. Но тогда многие считают красный и розовый двумя разными цветами.
Более того, разностные векторы в одном и том же направлении в этом пространстве параметров не равны. Например, человеческий глаз воспринимает зеленый гораздо лучше, чем другие цвета. Изменение оттенка от зеленого на ту же величину, что и изменение от красного, может показаться более значительным. Также сдвиг в насыщенности от небольшого значения до нуля - это разница между серым и розовым, в противном случае сдвиг будет разница между двумя оттенками красного.
С точки зрения программистов, вам нужно будет построить разностные векторы, но изменить их с помощью матрицы пропорциональности, которая будет соответствующим образом корректировать длины в различных областях пространства HSL - это будет довольно произвольно и будет основано на различных идеях теории цвета, но быть настроенным довольно произвольно в зависимости от того, к чему вы хотите применить это.
Более того, вы можете увидеть, если кто-нибудь уже сделал это в Интернете ...
Как человек, страдающий дальтонизмом, я считаю, что лучше попытаться добавить больше разделения, чем нормального зрения. Наиболее распространенной формой дальтонизма является красный / зеленый дефицит. Это не означает, что вы не можете видеть красный или зеленый, это означает, что его труднее увидеть и труднее увидеть различия. Таким образом, требуется больше разделения, прежде чем дальтоник может заметить разницу.