Как сгруппировать цветовые коды RGB или HEX для больших наборов цветовых групп?

#image-processing #computer-vision #classification

#обработка изображений #компьютерное зрение #классификация

Вопрос:

Я анализирую очень большое количество изображений и извлекаю доминирующие цветовые коды.

Я хочу сгруппировать их в диапазоны общих названий цветов, таких как зеленый, темно-зеленый, светло-зеленый, синий, темно-синий, светло-голубой и так далее.

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

Комментарии:

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

Ответ №1:

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

введите описание изображения здесь

Чтобы определить доминирующий цвет изображения, необходимо рассчитать расстояние между каждым из его пикселей и всеми цветами в таблице. Обратите внимание, что это расстояние вычисляется в цветовом пространстве RGB. Для вычисления расстояния между ij-м пикселем изображения и k-м цветом таблицы можно использовать следующее уравнение:

 d_ijk = sqrt((r_ij-r_k)^2 (g_ij-g_k)^2 (b_ij-b_k)^2)
  

На следующем шаге для каждого пикселя выбирается ближайший цвет в таблице. Это концепция, используемая для сжатия изображения с использованием индексированных цветов (за исключением того, что здесь палитра одинакова для всех изображений и не рассчитывается для каждого, чтобы минимизировать разницу между исходным и индексированным изображением). Теперь, как указал @jairoar, мы можем получить гистограмму изображения (не путать с гистограммой RGB или гистограммой интенсивности) и определить цвет, который имеет наибольшее количество повторений.
Чтобы показать результат этих шагов, я использовал случайные обрезки этого произведения искусства! мое:

введите описание изображения здесь
Так выглядят изображения до и после индексации (слева: оригинал, справа: индексированный): введите описание изображения здесьи это наиболее повторяющиеся цвета (слева: индексированный, справа: доминирующий цвет): введите описание изображения здесь

Но поскольку вы сказали, что количество изображений велико, вы должны знать, что эти вычисления занимают относительно много времени. Но хорошая новость заключается в том, что есть способы повысить производительность. Например, вместо использования евклидова расстояния (формула выше) можно использовать городской квартал или расстояние Чебышева. Вы также можете рассчитать расстояние только для части пикселей вместо того, чтобы вычислять его для всех пикселей изображения. Для этой цели вы можете сначала масштабировать изображение до гораздо меньшего размера (например, 32 на 32) и выполнить вычисления для пикселей этого уменьшенного изображения. Если вы решили изменить размер изображений, не утруждайте себя использованием билинейных или бикубических интерполяций, это не стоит дополнительных вычислений. Вместо этого перейдите к ближайшему соседу, который фактически выполняет выборку прямоугольной решетки на исходном изображении. введите описание изображения здесь

Хотя упомянутые изменения значительно увеличат скорость вычислений, но ничего хорошего не дается бесплатно. Это компромисс между производительностью и точностью. Например, на предыдущих двух изображениях мы видим, что изображение, которое изначально было распознано как оранжевое (код 20), после изменения его размера было распознано как розовое (код 26).
Чтобы определить параметры алгоритма (измерение расстояния, алгоритм уменьшения размера изображения и масштабирования), необходимо сначала выполнить операцию классификации для нескольких изображений с максимально возможной точностью и сохранить результаты как достоверные. Затем с помощью нескольких экспериментов получите комбинацию параметров, которые не делают ошибку классификации больше максимально допустимого значения.

Комментарии:

1. Я понимаю, так что вы могли бы использовать квантование цвета ( en.wikipedia.org/wiki/Color_quantization ), чтобы уменьшить информацию об изображении, а затем использовать евклидово расстояние для сопоставления цвета с предопределенным списком

2. @GeorgeKaf если под «уменьшить информацию об изображении» вы подразумеваете только изменение размера изображения, тогда да. Как указано на странице, на которую вы ссылаетесь, «Большинство стандартных методов рассматривают квантование цвета как проблему кластеризации точек в трехмерном пространстве». Я предлагаю рассматривать это как проблему классификации. Нам не нужно знать, какие цвета в «пространстве RGB» лучше всего описывают изображение, вместо этого нам интересно найти, какие цвета «предопределенной палитры» лучше всего описывают его. Все дело в том, что когда палитра известна, мы можем опустить фазу кластеризации.

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

Ответ №2:

Фантастический ответ @ saastn предполагает, что у вас есть набор предопределенных цветов, по которым вы хотите отсортировать свои изображения. Реализация проще, если вы просто хотите классифицировать изображения по одному цвету из некоторого набора X равноудаленных цветов, а-ля гистограмма.

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

Вот моя реализация этого в Python:

 import cv2
import numpy as np

#Set this to the number of colors that you want to classify the images to
number_of_colors = 8

#Verify that the number of colors chosen is between the minimum possible and maximum possible for an RGB image.
assert 8 <= number_of_colors <= 16777216

#Get the cube root of the number of colors to determine how many bins to split each channel into.
number_of_values_per_channel = number_of_colors ** ( 1 / 3 )

#We will divide each pixel by its maximum value divided by the number of bins we want to divide the values into (minus one for the zero bin).
divisor = 255 / (number_of_values_per_channel - 1)

#load the image and convert it to float32 for greater precision. cv2 loads the image in BGR (as opposed to RGB) format.
image = cv2.imread("image.png", cv2.IMREAD_COLOR).astype(np.float32)

#Divide each pixel by the divisor defined above, round to the nearest bin, then convert float32 back to uint8.
image = np.round(image / divisor).astype(np.uint8)

#Flatten the columns and rows into just one column per channel so that it will be easier to compare the columns across the channels.
image = image.reshape(-1, image.shape[2])

#Find and count matching rows (pixels), where each row consists of three values spread across three channels (Blue column, Red column, Green column).
uniques = np.unique(image, axis=0, return_counts=True)

#The first of the two arrays returned by np.unique is an array compromising all of the unique colors.
colors = uniques[0]

#The second of the two arrays returend by np.unique is an array compromising the counts of all of the unique colors.
color_counts = uniques[1]

#Get the index of the color with the greatest frequency
most_common_color_index = np.argmax(color_counts)

#Get the color that was the most common
most_common_color = colors[most_common_color_index]

#Multiply the channel values by the divisor to return the values to a range between 0 and 255
most_common_color = most_common_color * divisor

#If you want to name each color, you could also provide a list sorted from lowest to highest BGR values comprising of
#the name of each possible color, and then use most_common_color_index to retrieve the name.
print(most_common_color)
  

Комментарии:

1. Я полагаю, вы используете Image.open('image.png').convert('RGB').getcolors() для получения фактического number_of_colors ?

2. number_of_colors — это количество цветовых классов, к которым вы хотите классифицировать свои изображения. Это число, которое вы должны решить. Например, если вы хотите классифицировать свои изображения по следующим 8 категориям: [«черный», «красный», «зеленый», «синий», «голубой», «фиолетовый», «желтый», «белый»], вы должны ввести 8.

3. Функция getcolors() PIL для вычисления гистограмм работает только для черно-белых изображений, и она не позволяет вам устанавливать количество ячеек. Функция гистограммы CV2 позволяет задавать количество ячеек, но не позволяет использовать цветные изображения. С CV2 вам пришлось бы разделить каналы, а затем объединить полученные гистограммы, что кажется более сложным в реализации, чем то, что я сделал. Где-то в какой-то библиотеке должна быть функция, которая делает то, что я сделал, но я об этом не знаю. Также я беспокоился, что слишком большая зависимость от библиотеки затруднит реализацию на другом языке.