Сравните цвета RGB в c #

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

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

Спасибо!

Изменить:

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

У меня есть пиксельные данные (расположение и цвет) окна приложения размером 800x600, поэтому я могу узнать, открыто ли определенное окно, проверяя каждый интервал x.

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

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


person SaphuA    schedule 19.10.2010    source источник
comment
Как вы определяете похожий?   -  person Klaus Byskov Pedersen    schedule 19.10.2010
comment
Вы действительно должны сказать нам, чего вы хотите здесь достичь? Вы по восприятию человеческого глаза различаетесь или еще что-то в порядке?   -  person Daniel Mošmondor    schedule 19.10.2010


Ответы (8)


То, что вы ищете, называется Delta-E.

http://www.colorwiki.com/wiki/Delta_E:_The_Color_Difference

Это расстояние между двумя цветами в цветовом пространстве LAB. Говорят, что человеческий глаз не может различать цвета ниже 1 DeltaE (я считаю, что мои глаза могут находить различия в цветах ниже 1 DeltaE, каждый человек индивидуален).

Существует 4 формулы «цветового различия».

  • Дельта E (CIE 1976)
  • Дельта E (CIE 1994)
  • Дельта E (CIE 2000)
  • Дельта E (CMC)

Проверьте математическую ссылку на этом сайте:

Итак, правильный ответ - преобразовать ваш RGB в LAB, используя приведенную формулу, а затем использовать DeltaE 1976 для определения «разницы» в ваших цветах. Результат 0 означает идентичные цвета. Любое значение выше 0 можно оценить по правилу «Дельта е, равная 1 или меньше, неотличима для большинства людей».

person ColorEyes    schedule 19.10.2010
comment
Спасибо за ответ, я боялся, что это будет что-то столь же сложное. Я отмечу ваш ответ, поскольку он наиболее точен, хотя, вероятно, я выберу решение, очень похожее на решение Питера. - person SaphuA; 19.10.2010
comment
На этом сайте есть несколько полезных алгоритмов преобразования (см. easyrgb.com/index.php?X=MATH и easyrgb.com/index.php?X=DELT ). - person rsbarro; 28.08.2012
comment
Обратите внимание, что в цветовом пространстве Lab CIE 1976 - это просто евклидово расстояние между точками, поэтому DE = sqrt((L2-L1)^2 + (a2-a1)^2 + (b2-b1)^2). - person hruske; 27.02.2016

Существует библиотека .net с открытым исходным кодом, которая позволяет легко это сделать: https://github.com/hvalidi/ColorMine

Наиболее распространенный метод сравнения цветов - CIE76:

var a = new Rgb { R = 149, G = 13, B = 12 }
var b = new Rgb { R = 255, G = 13, B = 12 }

var deltaE = a.Compare(b,new Cie1976Comparison());
person Joe Zack    schedule 04.02.2013

Цвета имеют разный вес, влияющий на человеческий глаз. Итак, преобразуйте цвета в оттенки серого, используя их рассчитанные веса:

Серый цвет = .11 * B + .59 * G + .30 * R

И ваша разница будет

разница = (GrayColor1 - GrayColor2) * 100,0 / 255,0

с разницей от 0 до 100.

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

-edit - это очень простая формула, которую можно использовать даже в коммерческих приложениях. Если вы хотите углубиться, вы должны проверить методы определения цветового различия: CIE1976, CIE1994, CIE2000 и CMC. Здесь вы можете найти более подробную информацию: http://en.wikipedia.org/wiki/Color_difference

person honibis    schedule 19.10.2010
comment
Ага, это верно. Но это основное, и это работает в реальном мире. Отредактировал ответ с дополнительной информацией. - person honibis; 19.10.2010
comment
Чтобы получить результат от 0 до 100, делитель должен быть 255, а не 256. Я исправлю ответ. - person Rev; 07.05.2020
comment
Диапазон не может быть 0-100, потому что если у вас есть RGB = (0,0,0) и сравнивать его с другим цветом, результат всегда будет отрицательным. Таким образом, фактический диапазон будет от -100 до 100, если какая-либо информация в тексте не отсутствует. - person Devolus; 14.11.2020

Преобразование цвета RGB в цветовое пространство HSL часто дает хорошие результаты. Поищите в Википедии формулу преобразования. Вы должны присвоить вес различиям в H, цвете, S, том, насколько «глубокий» цвет и L, насколько он яркий.

person Hans Passant    schedule 19.10.2010
comment
Вес L точно тяжелее остальных. Наши глаза гораздо более чувствительны к изменениям яркости, чем к изменениям цвета. - person Brad; 19.10.2010

Что-то вроде этого:

    public static int CompareColors(Color a, Color b)
    {
        return 100 * (int)(
            1.0 - ((double)(
                Math.Abs(a.R - b.R) +
                Math.Abs(a.G - b.G) +
                Math.Abs(a.B - b.B)
            ) / (256.0 * 3))
        );
    }
person Pieter van Ginkel    schedule 19.10.2010
comment
Спасибо, я думаю, что пока могу работать с этим, хотя мне нужно будет увидеть, насколько это точно. Однако в вашем коде есть несколько ошибок (256 должно быть 255, и преобразование результата в int тоже не очень умно: D) - person SaphuA; 19.10.2010
comment
Хотя это математически разумно, это не очень хорошая идея, поскольку она не принимает во внимание восприятие цветов. Вы можете легко найти пары цветов, которые похожи, но дадут низкую оценку, и цвета, которые не похожи, но дадут высокую оценку. - person Hannes Ovrén; 19.10.2010
comment
Да, ты прав. Вы можете сделать все возможное, но это быстрый и грязный способ получить приблизительную разницу. Думаю, правильные методы сравнения заняли бы несколько страниц :). - person Pieter van Ginkel; 19.10.2010
comment
Я не согласен с тем, кто проголосовал против этого ответа. Хотя это и не так точно, как ответ ColorEyes, это все же было для меня полезно. - person SaphuA; 19.10.2010
comment
@SaphuA: В некоторых случаях это может быть правильно, но все равно очень неверно. Для быстрого примера, цвета 0x7f0000 и 0x007f00 дадут (приблизительно) те же результаты, что и при сравнении 0xb2b2b2 и 0xffffff. Другими словами: ярко-красный и ярко-зеленый считаются такими же близкими, как белый и довольно светло-серый. Это вряд ли желаемый результат. - person Hannes Ovrén; 10.08.2011

Я нашел интересный подход под названием Цветовая метрика и адаптировал его к C #.

public static double ColourDistance(Color e1, Color e2)
{
    long rmean = ((long)e1.R + (long)e2.R) / 2;
    long r = (long)e1.R - (long)e2.R;
    long g = (long)e1.G - (long)e2.G;
    long b = (long)e1.B - (long)e2.B;
    return Math.Sqrt((((512 + rmean) * r * r) >> 8) + 4 * g * g + (((767 - rmean) * b * b) >> 8));
}
person fubo    schedule 18.11.2015

Восприятие цвета зависит от многих факторов, и сходство можно измерить разными способами. Простое сравнение того, насколько похожи компоненты R, G и B, обычно дает результаты, с которыми люди не согласятся.

Есть несколько общих материалов по сравнению цветов в Википедии и по работе с естественные цветовые пространства в C # в этот вопрос.

person Pontus Gagge    schedule 19.10.2010

Я перевел код DeltaE2000 на странице Брюса Линдблума на C.

Здесь:

     //
     //  deltae2000.c
     //
     //  Translated by Dr Cube on 10/1/16.
     //  Translated to C from this javascript code written by Bruce LindBloom:
     //    http://www.brucelindbloom.com/index.html?Eqn_DeltaE_CIE2000.html
     //    http://www.brucelindbloom.com/javascript/ColorDiff.js

     #include <stdio.h>
     #include <math.h>

     #define Lab2k struct Lab2kStruct
     Lab2k
     {
        float L;
        float a;
        float b;
     };

     // function expects Lab where: 0 >= L <=100.0 , -100 >=a <= 100.0  and  -100 >= b <= 100.0

     float
     DeltaE2000(Lab2k Lab1,Lab2k Lab2)
     {
        float kL = 1.0;
        float kC = 1.0;
        float kH = 1.0;
        float lBarPrime = 0.5 * (Lab1.L + Lab2.L);
        float c1 = sqrtf(Lab1.a * Lab1.a + Lab1.b * Lab1.b);
        float c2 = sqrtf(Lab2.a * Lab2.a + Lab2.b * Lab2.b);
        float cBar = 0.5 * (c1 + c2);
        float cBar7 = cBar * cBar * cBar * cBar * cBar * cBar * cBar;
        float g = 0.5 * (1.0 - sqrtf(cBar7 / (cBar7 + 6103515625.0)));  /* 6103515625 = 25^7 */
        float a1Prime = Lab1.a * (1.0 + g);
        float a2Prime = Lab2.a * (1.0 + g);
        float c1Prime = sqrtf(a1Prime * a1Prime + Lab1.b * Lab1.b);
        float c2Prime = sqrtf(a2Prime * a2Prime + Lab2.b * Lab2.b);
        float cBarPrime = 0.5 * (c1Prime + c2Prime);
        float h1Prime = (atan2f(Lab1.b, a1Prime) * 180.0) / M_PI;
        float dhPrime; // not initialized on purpose

        if (h1Prime < 0.0)
           h1Prime += 360.0;
        float h2Prime = (atan2f(Lab2.b, a2Prime) * 180.0) / M_PI;
        if (h2Prime < 0.0)
           h2Prime += 360.0;
        float hBarPrime = (fabsf(h1Prime - h2Prime) > 180.0) ? (0.5 * (h1Prime + h2Prime + 360.0)) : (0.5 * (h1Prime + h2Prime));
        float t = 1.0 -
        0.17 * cosf(M_PI * (      hBarPrime - 30.0) / 180.0) +
        0.24 * cosf(M_PI * (2.0 * hBarPrime       ) / 180.0) +
        0.32 * cosf(M_PI * (3.0 * hBarPrime +  6.0) / 180.0) -
        0.20 * cosf(M_PI * (4.0 * hBarPrime - 63.0) / 180.0);
        if (fabsf(h2Prime - h1Prime) <= 180.0)
           dhPrime = h2Prime - h1Prime;
        else
           dhPrime = (h2Prime <= h1Prime) ? (h2Prime - h1Prime + 360.0) : (h2Prime - h1Prime - 360.0);
        float dLPrime = Lab2.L - Lab1.L;
        float dCPrime = c2Prime - c1Prime;
        float dHPrime = 2.0 * sqrtf(c1Prime * c2Prime) * sinf(M_PI * (0.5 * dhPrime) / 180.0);
        float sL = 1.0 + ((0.015 * (lBarPrime - 50.0) * (lBarPrime - 50.0)) / sqrtf(20.0 + (lBarPrime - 50.0) * (lBarPrime - 50.0)));
        float sC = 1.0 + 0.045 * cBarPrime;
        float sH = 1.0 + 0.015 * cBarPrime * t;
        float dTheta = 30.0 * expf(-((hBarPrime - 275.0) / 25.0) * ((hBarPrime - 275.0) / 25.0));
        float cBarPrime7 = cBarPrime * cBarPrime * cBarPrime * cBarPrime * cBarPrime * cBarPrime * cBarPrime;
        float rC = sqrtf(cBarPrime7 / (cBarPrime7 + 6103515625.0));
        float rT = -2.0 * rC * sinf(M_PI * (2.0 * dTheta) / 180.0);
        return(sqrtf(
                           (dLPrime / (kL * sL)) * (dLPrime / (kL * sL)) +
                           (dCPrime / (kC * sC)) * (dCPrime / (kC * sC)) +
                           (dHPrime / (kH * sH)) * (dHPrime / (kH * sH)) +
                           (dCPrime / (kC * sC)) * (dHPrime / (kH * sH)) * rT
                      )
         );
     }
person EddingtonsMonkey    schedule 01.10.2016