найти похожие цвета программно - PullRequest
13 голосов
/ 13 ноября 2009

У меня есть буферизованное изображение в java, и я хочу записать, насколько каждый пиксель похож на другой в зависимости от значения цвета. поэтому пиксели с «похожими» цветами будут иметь более высокое значение сходства. например, красный и розовый будут иметь значение сходства 1000, а красный и синий будут иметь что-то вроде 300 или меньше.

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

Ответы [ 12 ]

21 голосов
/ 13 ноября 2009

Во-первых, как вы получаете целочисленное значение?

Как только вы получите значения RGB, вы можете попробовать

((r2 - r1) 2 + (g2 - g1) 2 + (b2 - b1) 2 ) 1/2

Это даст вам расстояние в трехмерном пространстве от двух точек, каждая из которых обозначена (r1, g1, b1) и (r2, g2, b2).

Или есть более сложные способы использования значения цвета HSV.

9 голосов
/ 13 ноября 2009

Предлагаю вам начать читать здесь

Формулы различий в цвете , если вы хотите сделать это правильно. В нем поясняются формулы ΔE*ab, ΔE*94, ΔE*00 и ΔE*CMC для расчета цветовых различий.

8 голосов
/ 13 ноября 2009

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

Расстояние в пространстве L * a * b представляет фактическое полученное расстояние в соответствии с прогнозами, полученными из этих экспериментов.

После преобразования в L * a * b вам просто нужно измерить линейное расстояние в трехмерном пространстве.

5 голосов
/ 24 февраля 2011

Если вы собираетесь использовать HSV, вы должны понимать, что HSV - это не точки в трехмерном пространстве, а угол, величина и расстояние от вершины конуса. Чтобы вычислить расстояние для значения HSV, вам нужно либо определить свои точки в трехмерном пространстве путем преобразования.

X = Cos (H) * S * V

Y = Грех (H) * S * V

Z = V

Для обеих точек, а затем взять евклидово расстояние между ними:

Sqrt((X0 - X1)*(X0 - X1) + (Y0 - Y1)*(Y0 - Y1) + (Z0 - Z1)*(Z0 - Z1))

По стоимости 2 Cos, 2 Sin и квадратный корень.

В качестве альтернативы вы можете на самом деле вычислить расстояние немного легче, если вы настолько склонны, понимая, что при сведении к 2D-пространству у вас просто есть два вектора от начала координат, и применяя закон косинус, чтобы найти расстояние в пространстве XY:

C² = A² + B² + 2*A*B*Cos(Theta)

Где A = S * V первого значения, а B = S * V второго и косинус - разность тета или H0-H1

Затем вы учитываете Z, чтобы расширить 2D-пространство в 3D-пространство.

A = S0*V0
B = S1*V1
dTheta = H1-H0
dZ = V0-V1
distance = sqrt(dZ*dZ + A*A + B*B + 2*A*B*Cos(dTheta);

Обратите внимание, что, поскольку закон косинусов дает нам C², мы просто подключаем его к изменениям Z. Это стоит 1 Cos и 1 Sqrt. HSV очень полезен, вам просто нужно знать, какой тип цветового пространства он описывает. Вы не можете просто вставить их в евклидову функцию и получить из этого что-то связное.

2 голосов
/ 13 ноября 2009

Вы можете получить отдельные байты следующим образом:

int rgb = bufferedImage.getRGB(x, y); // Returns by default ARGB.
int alpha = (rgb >>> 24) & 0xFF;
int red = (rgb >>> 16) & 0xFF;
int green = (rgb >>> 8) & 0xFF;
int blue = (rgb >>> 0) & 0xFF;
2 голосов
/ 13 ноября 2009

Вы, вероятно, вызываете getRGB () для каждого пикселя, который возвращает цвет в виде 4 8-битных байтов, старшего байта альфа, следующего байта красного, следующего байта зеленого, следующего байта синего. Вы должны выделить каналы. Даже в этом случае схожесть цветов в пространстве RGB не так велика - вы можете получить намного лучшие результаты, используя пространство HSL или HSV. См. здесь для кода преобразования.

Другими словами:

int a = (argb >> 24) & 0xff;
int r = (argb >> 16) & 0xff;
int g = (argb >> 8) & 0xff;
int b = argb & 0xff;

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

2 голосов
/ 13 ноября 2009

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

1 голос
/ 31 декабря 2011

Есть интересная статья, посвященная именно этой проблеме:

Новое воспринимаемое однородное цветовое пространство с соответствующей мерой цветового сходства для поиска изображений и видео на основе содержимого М. Сарифуддин и Рокия Миссауи

Вы можете легко найти это, используя Google или, в частности, [Google Scholar.] [1]

Подводя итог, некоторые цветовые пространства (например, RGB, HSV, Lab) и меры расстояния (такие как среднее геометрическое и евклидово расстояние) являются лучшими представлениями человеческого восприятия цветового сходства, чем другие. В статье говорится о новом цветовом пространстве, которое лучше, чем остальные, но оно также обеспечивает хорошее сравнение общих существующих цветовых пространств и мер расстояния. Качественно *, кажется, лучшая мера для воспринимаемого расстояния с использованием общедоступных цветовых пространств: цветовое пространство HSV и цилиндрическая мера расстояния.

* По крайней мере, согласно рисунку 15 в ссылочной статье.

Цилиндрическая мера расстояния (в латексной записи):

D_ {cyl} = \ sqrt {\ Delta V ^ {2} + S_1 ^ {2} + S_2 ^ {2} -2S_1S_2cos (\ Delta H)}

1 голос
/ 13 ноября 2009

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

0 голосов
/ 21 октября 2013
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...