Продолжение: Нахождение точного «расстояния» между цветами

Оригинальный вопрос

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

  1. Какое цветовое пространство лучше всего отражает человеческое зрение?
  2. Какой показатель расстояния в этом пространстве лучше всего представляет человеческое зрение (евклидово?)
4.08.2008 15:08:13
Я закончил тем, что изобразил некоторые из решений ниже, имея дело с подобной ситуацией. Другие могут найти интересные сюжеты stackoverflow.com/q/5774152/156755
Basic 17.05.2016 13:52:50
8 ОТВЕТОВ
РЕШЕНИЕ

Преобразуйте в La * b * (он же просто "Lab", и вы также увидите ссылку на "CIELAB"). Хорошее быстрое измерение разницы в цвете

(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. В настоящее время я не могу найти некрасивую страницу с формулами преобразования, но я уверен, что кто-то отредактирует эту страницу. ответ, чтобы включить один.

43
4.03.2012 04:33:06
Что касается уродливости формул преобразования: они некрасивы по какой-то причине, поскольку переход от RGB к XYZ к LAB зависит от условий просмотра. cf: (предупреждение, уродство) easyrgb.com/index.php?X=MATH
Gregg Lind 8.10.2008 17:46:52
Возможно, стоило бы добавить описание стандартных метрик цветового расстояния и псевдометрии, определенных CIE: en.wikipedia.org/wiki/Color_difference
BartoszKP 26.09.2013 10:47:53

так как ссылка на 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 );
}

Надеюсь, это поможет кому-то :)

8
17.10.2013 01:39:38

HSL и HSV лучше для человеческого восприятия цвета. Согласно Википедии :

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

Графическое изображение ВПГ

4
9.02.2017 14:01:26
Остерегайтесь: красный - при 0 °, поэтому желтовато-красный - при + 10 °, а голубовато-красный - при -10 ° или 350 °. Вычисление расстояния теперь не так просто, как вычитание двух значений.
Otto Allmendinger 25.10.2012 10:34:28
Не очень полезно в контексте другого ответа. Метрики, определенные CIE, лучше для восприятия цвета человеком, а не HLS и HSV.
BartoszKP 26.09.2013 10:49:15
В этой статье есть формула для цветового расстояния в пространстве HSV citeseerx.ist.psu.edu/viewdoc/…
fyts 29.02.2016 15:27:42

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

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

3
4.08.2008 15:14:39
Просто выглядит как ваш средний сайт 90-х, который, кстати, также является популярным сайтом для академиков 2010+.
Domi 13.06.2014 06:31:00

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

3
24.08.2008 15:38:38

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

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

ImageMagic предоставляет следующие масштабы:

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

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

2
4.08.2008 15:14:40

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

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

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

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

Более того, вы можете увидеть, если кто-нибудь уже сделал это в Интернете ...

2
4.08.2008 15:37:43

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

2
16.09.2008 16:45:50