Поиск похожих цветов программно

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

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

Ответ 1

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

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

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

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

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

Ответ 2

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

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

Ответ 3

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

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

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

Ответ 4

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

X = Cos (H) * S * V

Y = Sin (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 второго и cosign - разность theta или 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 много полезен, вам просто нужно знать, какой тип цветового пространства он описывает. Вы не можете просто ударить их в эвклидову функцию и получить что-то последовательное из нее.

Ответ 5

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

Ответ 6

Вероятно, вы вызываете 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-буферизованных изображениях, но я думаю, что это правильно.

Ответ 7

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

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;

Ответ 8

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

Ответ 9

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

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

Вы можете легко найти это с помощью 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)}

Ответ 10

Это аналогичный вопрос #1634206.

Если вы ищете расстояние в пространстве RGB, эвклидово расстояние будет работать, если вы будете одинаково относиться к красным, зеленым и синим значениям.

Если вы хотите весить их по-другому, как это обычно делается при преобразовании цвета /RGB в оттенки серого, вам нужно весить каждый компонент на другую величину. Например, используя популярное преобразование из RGB в оттенки серого 30% красного + 59% зеленого + 11% голубого:

d2 = (30*(r1-r2))**2 + (59*(g1-g2))**2 + (11*(b1-b2))**2;

Чем меньше значение d2, тем ближе друг к другу цвета (r1,g1,b1) и (r2,g2,b2).

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

Ответ 12

Я попробовал. значение HSL/HSV определенно не полезно. например:

  • все цвета с L = 0 являются "черными" (RGB 000000), хотя их различие в HSL может подразумевать большое расстояние цвета.

  • все цвета с S = 0 являются оттенком "серого", хотя их различие в HSL может подразумевать высокое цветовое расстояние.

  • диапазон H (оттенок) начинается и заканчивается оттенком "красного", поэтому H = 0 и H = [max] (360 ° или 100% или 240, в зависимости от приложения) являются красными и относительно похожи друг на друга, но эвклидовое расстояние HSL близко к максимуму.

поэтому я рекомендую использовать эвклидовое расстояние RGB (r2-r1) ² + (g2-g1) ² + (b2-b1) ² без корня. (субъективный) порог 1000 тогда отлично работает для аналогичных цветов. цвета с различиями > 1000 хорошо различимы человеческим глазом. кроме того, он может быть достаточно, чтобы весить компоненты по-разному (см. предыдущую статью).