Поиск похожих цветов программно
У меня есть буферизованное изображение в 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, что может быть лучше подходит для вашей проблемы.
Ответ 11
Восприятие цвета не является линейным потому что человеческий глаз более чувствителен к определенным цветам, чем другие.
Итак jitter ответил правильно
Ответ 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 хорошо различимы человеческим глазом. кроме того, он может быть достаточно, чтобы весить компоненты по-разному (см. предыдущую статью).