LINUX.ORG.RU

Преобразование цвета RGB -> XYZ

 , ,


1

1

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

Что может быть проще? RGB -> XYZ -> L*a*b и дальше вот сюда: https://ru.wikipedia.org/wiki/Формула_цветового_отличия

Проблема возникла на самом первом этапе. Я взял матрицу вот отсюда: http://www.cs.rit.edu/~ncs/color/t_convert.html поумножал и получил некоторые цифры. Решил проверить правильность результата: http://www.wolframalpha.com/input/?i=color r:124 g:124 b:124

На вольфраме вижу XYZ: 0.19, 0.20, 0.16
У себя получаю XYZ: 0.31011415 0.3262745 0.35525745
Может быть вольфрам врет. Проверил еще и тут http://colorscheme.ru/color-converter.html

Нет, видимо не врет. Значит я что-то не так делаю?


Ответ на: комментарий от BattleCoder
private void colorToXyz(int color, float[] xyz) {
        if (xyz.length != 3) {
            throw new IllegalArgumentException("xyz must be 3 element array");
        }

        float[] coef = new float[]{
                0.412453f,  0.357580f,  0.180423f,
                0.212671f,  0.715160f,  0.072169f,
                0.019334f,  0.119193f,  0.950227f,
        };


        float a = 0.65f*Color.alpha(color) / 255.0f;
        float r = 0.65f*Color.red(color) / 255.0f;
        float g = 0.65f*Color.green(color) / 255.0f;
        float b = 0.65f*Color.blue(color) / 255.0f;

        xyz[0] = coef[0]*r + coef[1]*g + coef[2]*b;
        xyz[1] = coef[3]*r + coef[4]*g + coef[5]*b;
        xyz[2] = coef[6]*r + coef[7]*g + coef[8]*b;
//        xyz[0] = (float) ((r * 0.5767309) + (g * 0.1855540) + (b * 0.1881852));
//        xyz[1] = (float) ((r * 0.2973769) + (g * 0.6273491) + (b * 0.0752741));
//        xyz[2] = (float) ((r * 0.0270343) + (g * 0.0706872) + (b * 0.9911085));

        log.e("convertez1 color red:%s green:%s blue:%s xyz:%s %s %s rgb: %s %s %s",
                Color.red(color),  Color.green(color),  Color.blue(color),
                xyz[0],xyz[1],xyz[2],
                r, g , b);
    }
g0t0 ()
Ответ на: комментарий от g0t0

Осталось понять, как применить эти знания для Android's Color RGB. Можно как-то понять, где там белая точка?

А надо ли? Для того, чтобы проверить правильность своего расчёта, следует взять матрицу для пространства RGB, которое использует вольфрам (вероятно CIE).

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

Elyas ★★★★★ ()
Ответ на: комментарий от Elyas

Для CIE по твоей ссылке:
rgb=(0.5, 0.5, 0.5)
X = 0,5×0,488718 + 0,5 × 0,31068 + 0,5 × 0,200 = 0.499699

Вольфрам говорит: http://www.wolframalpha.com/input/?i=color r:0,5 g:0,5 b:0,5
X=0.20

Я глазами все матрицы пробежал, такое ощущение, что X=0.2 там получить для rgb(0.5, 0.5, 0.5) вообще не реально, т.к. элемент (0 , 0) везде слишком большой и даст уже в первом члене для X слишком большое число.

g0t0 ()
Ответ на: комментарий от g0t0

1. In order to properly use this matrix, the RGB values must be linear and in the nominal range [0.0, 1.0]. In many cases, RGB values may first need conversion (for example, dividing by 255 and then raising them to a power).

Elyas ★★★★★ ()
Ответ на: комментарий от Elyas

Я правильно понимаю, что мне необходимо просто каждый компонент (r, g, b) после деления на 255 возвести в степень 2.2? У меня после этого X и Y очень похожие на вольфрамовские стали, а вот Z до сих пор не попадает.

g0t0 ()
Ответ на: комментарий от g0t0

Я правильно понимаю, что мне необходимо просто каждый компонент (r, g, b) после деления на 255 возвести в степень 2.2?

В первом приближении верно. Если точнее, надо пользоваться гамма-кривой для sRGB скорее всего.

Elyas ★★★★★ ()

В итоге плюнул я на это дело и наговнякал свою реализацию на HSV.

g0t0 ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.