2008-08-04 3 views
44

Original QuestionFollowup: Поиск точного «расстояние» между цветами

Я ищу функцию, которая пытается количественно, как «дальний» (или различные) два цвета. Этот вопрос действительно состоит из двух частей:

  1. Какое цветовое пространство лучше всего представляет человеческое видение?
  2. Какого расстояние метрики в этом пространстве наилучшим образом представляет человеческое зрение (евклидово?)
+1

В конце концов я закончил работу над некоторыми из нижеприведенных решений, имея дело с аналогичной ситуацией. Другие могут найти интересные сюжеты http://stackoverflow.com/q/5774152/156755 – Basic 2016-05-17 13:52:50

ответ

43

Конвертировать в La * b * (aka just plain "Lab", и вы также увидите ссылку на "CIELAB"). Хороший быстрый measaure разница цвета

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

ученые цвета имеют другие более совершенные меры , что, возможно, не стоит беспокоить, в зависимости от точности, необходимой для того, что вы делаете.

Значения a и b представляют противоположные цвета способом, похожим на то, как работают конусы, и могут быть отрицательными или положительными. Нейтральные цвета - белые, серые - a=0, b=0. L - это яркость, определенная определенным образом, от нуля (чистая тьма) до любого.

Краткое описание: >> Учитывая цвет, наши глаза различают два широких диапазона длины волны - синий и более длинные волны. а затем, благодаря более поздней генетической мутации, более длинноволновые конусы, раздвоенные на две части, отличающие нас от красного и зеленого.

Кстати, это будет здорово для вашей карьеры подняться над вашими коллегами цветного пещерного человека, которые знают только «RGB» или «CMYK», которые отлично подходят для устройств, но сосут для серьезного восприятия. Я работал над создателями изображений, которые ничего не знали об этом!

Для большего удовольствия чтения по теории цвета разницы, попробуйте:

Более подробно о Лаборатории в http://en.kioskea.net/video/cie-lab.php3 Я не могу на этот раз найти не уродливую страницу, на которой были формулы преобразования b ut Я уверен, что кто-то отредактирует этот ответ, чтобы включить его.

2

Может выглядеть как спам, но нет, эта связь действительно интересна для цветовых пространств :)

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

+0

Просто выглядит как ваш средний веб-сайт 90-х годов, который, по-совпадению, также является популярным веб-сайтом для академиков 2010+. – Domi 2014-06-13 06:31:00

2

Проще всего расстояние было бы, конечно, просто рассматривать цвета как 3d-векторы, происходящие из одного и того же происхождения, и расстояние между их конечными точками.

Если вам нужно учитывать такие факторы, что зеленый цвет более заметен при оценке интенсивности, вы можете взвесить значения.

ImageMagic обеспечивает следующие шкалы:

  • красный: 0,3
  • зеленый: 0,6
  • синий: 0,1

Конечно, такие значения, как это было бы смысл только в отношении другие ценности для других цветов, а не как что-то, что было бы значимо для людей, поэтому все, что вы могли бы использовать, чтобы значения были бы упорядочены по сходству.

4

HSL и HSV лучше подходят для восприятия человеческого восприятия. По Wikipedia:

Иногда предпочтительнее при работе с художественными материалами, оцифрованными изображениями или другими средствами массовой информации, чтобы использовать модель HSV или HSL цвета над альтернативными моделями, такими как RGB или CMYK, из-за различия в способах модели подражают тому, как люди воспринимают цвет. RGB и CMYK являются аддитивными и субтрактивными моделями, соответственно, моделируя то, как первичные цветные огни или пигменты (соответственно) объединяются, чтобы образовывать новые цвета при смешивании.

Graphical depiction of HSV

+0

Остерегайтесь: красный находится на 0 °, поэтому желтоватый красный цвет находится на + 10 °, а синий - на -10 ° или 350 °. Вычисление расстояния не так просто, как вычесть сейчас два значения. – 2012-10-25 10:34:28

+2

Не очень полезно в контексте другого ответа. Метрики, определенные CIE, лучше подходят для восприятия цвета человека, а не HLS и HSV. – BartoszKP 2013-09-26 10:49:15

2

Ну, как первая точка вызова, я бы сказал, что из общих показателей HSV (Hue, Saturation и Value) или HSL лучше представитель того, как люди воспринимают цвета, чем, скажем RGB или CYMK. См. HSL, HSV on Wikipedia.

Я предполагаю наивно, что я бы построил точки в пространстве HSL для двух цветов и вычислил величину разностного вектора. Однако это означало бы, что ярко-желтый и ярко-зеленый будет считаться столь же разным, как зеленый до темно-зеленого. Но тогда многие считают красным и розовым два разных цвета.

Кроме того, разностные векторы в том же направлении в этом пространстве параметров не равны. Например, человеческий глаз поднимает зеленый цвет намного лучше, чем другие цвета. Изменение оттенка зеленого цвета на ту же величину, что и переход от красного, может показаться большим.Также смещение насыщения от небольшого количества до нуля - разница между серым и розовым, в другом месте сдвиг будет разницей между двумя оттенками красного.

С точки зрения программистов вам нужно будет нанести разностные векторы, но изменить матрицу пропорциональности, которая соответствующим образом регулировала бы длины в разных областях пространства HSL - это было бы довольно произвольно и было бы основано на различных идеи теории цвета, но их можно изменить произвольно в зависимости от того, к чему вы хотели применить это.

Еще лучше, если вы могли бы увидеть, если кто-то уже сделал такую ​​вещь в Интернете ...

3

The Wikipedia article on color differences перечислен ряд цветовых пространств и метрики расстояния, предназначенных согласовать с человеческим восприятием цвета расстояния.

2

Как человек, который является слепым цветом, я считаю, что хорошо попытаться добавить больше разделения, чем нормальное зрение. Наиболее распространенной формой цветовой слепоты является дефицит красного/зеленого. Это не означает, что вы не можете видеть красный или зеленый цвет, это означает, что это труднее увидеть и более трудно увидеть различия. Таким образом, требуется большее разделение, прежде чем цветной слепой человек может отличить эту ситуацию.

8

как ссылка cmetric.htm выше не удалось для меня, а также многих других реализаций для расстояния цвета я нашел (после очень долго jurney ..) Как вычислить лучший цвет расстояния, и .. наиболее научно точным: DeltaE и от 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); 
} 

Надежда это помогает кому-то :)