Привет всем,
В каталогах часто необходимо классифицировать объекты по цветам. Это могут быть товары, предметы искусства, художественные фото, да что угодно — важно что пользователи хотят находить только красные, только синие, синие с красным объекты каталога и т.п.
Исходим из того, что в текстовых описаниях объектов отсутствуют упоминания цветов — классифицировать нужно на основе изображений.
Объектов в каталоге достаточно много (>1.000.000), ручная классификация станет в копейку, займет много времени и качество под вопросом. Привлечь профессионалов с правильно поставленным цветовосприятием на такой объем будет проблематично (художник и дня не усидит за такой работой), а случайные люди дадут «случайный» результат — известно, каждый видит цвета по разному, а рутинность работы будет способствовать значительным погрешностям вследствие замыленности взгляда. К тому же хотелось бы выделить не просто один цвет, а N доминантных, в порядке убывания доминанты.
В общем, сразу понятно — на эту работенку неплохо бы взять хорошего дроида, смышлённого и симпотишного как C-3PO. Открывайте статью, будем конструировать.
Выбор цветовой схемы
Сначала нужно определить базовый набор цветов/оттенков и тонов — наш классификатор цветовой схемы. Обычно это небольшой список — несколько десятков. Цветовая модель в общем-то зависит от того, о чем каталог, какие цвета там доминируют. Какие-то наиболее важные диапазоны можно детализировать оттенками (например — оранжевый, коричневый, бежевый и т.п.).
Мы для данной статьи возьмем самую простую модель — КОЖЗГСФ. В практических задачах скорей всего придется добавить суррогатные тона — черный, белый, серый, промежуточные цвета, а также характеристики насыщенности. Но задача эта уже прикладная, зависит от того, что за объекты в каталоге — нужно будет помедитировать над цветовым кругом. Для целей нашей статьи КОЖЗГСФ вполне достаточно.
В нашей программе каждый объект должен получить классификацию от 1 до 3 значений из набора КОЖЗГСФ.
Мат. подготовка
1. В статье нет исходников на каком-либо языке, только алгоритмическое описание. Впрочем, закодировать и отладить это за полдня-день не составит труда в любом подходящем фреймворке — Java/PHP/.NET и т.п… Важно конечно, чтобы выбранный фреймворк содержал библиотеки работы с изображениями, как минимум нужно уметь загрузить изображение из распространенных форматов растровых изображений, затем преобразовать его в массив RGB-пикселей. Итак, вы выбрали некий удобный фреймворк, идем дальше.
2. Алгоритм предполагает попиксельную обработку, поэтому надо бы привести пиксельный размер изображений к какому-нибудь разумному максимуму — скажем, не более 500 пикселей по ширине и высоте. Сделать это можно непосредственно в программе классификации, сразу после загрузки изображения, либо же взять GIMP/BIMP и запустить пакетный scale.
3. Если объекты на изображениях сняты на фоне чего-либо еще — нужно подумать как устранить фон. Хорошо, если фон на всех изображениях одноцветный, равномерный — тогда его несложно убрать парой функций непосредственно в создаваемой программе, либо опять же берем GIMP/BIMP.
Иногда проблемы фона нет — когда объекты занимают целиком всё изображение, скажем, образцы тканей, обоев, сканы рисунков, художественные фото.
Иногда проблему фона можно и проигнорировать — добавится еще один-два доминантных цвета, точность поиска будет ниже. По месту в общем будет видней, сколько стоит эта шкурка, а сколько ее выделка.
Преобразование в HSL
Форматы цветовой кодировки HSV и HSL являются по сравнению с RGB менее распространенным, но намного более естественным для понимания цвета.
Кто не знает деталей — добро пожаловать сюда — в статье по этой ссылке также будут описаны важные для нас принципы и формулы конвертации из RGB в HSL, а немного поискав несложно найти рабочие исходники такой конвертации почти что на любом языке.
Также нам нужно определить диапазоны значения тона (H) для каждого цвета из нашей цветовой модели.
В формате HSL значение H выражается в градусах от 0 до 360 угла на цветовом круге, который соответствует данному тону. Взглянув на круг, получаем следующие диапазоны RANGES
Собственно, алгоритм
1. Заготавливаем массив для подсчета доминанты: int ARR[] = new ARR[6], где КОЖЗГСФ соответствует цифре от 0 до 6.
2. Формируем из картинки пиксельный массив, каждый элемент которого содержит цвет пикселя rgb(r,g,b).
3. Циклим по массиву
3.1. Конвертируем цвет пикселя из rgb(r,g,b) в HSL(H,S,L)
3.2. Берем значение H пикселя, определяем в какой диапазон RANGES оно попадает (например в диапазон Ж), инкрементируем значение массива ARR с соответствующим индексом (ARR[2]++ в случае с Ж).
Таким образом по завершении цикла получим статистику частоты использования каждого из цветов нашей схемы.
4. Выбираем доминантные цвета на основании накопленной статистики, например — в результате цикла получили массив ARR[1010,1200,1505,102,45,33,350], или
5. Подсчитываем общее количество пикселей, например путем сложения всех элементов массива.
6. Выбираем из массива от 1 до 3 элемента с максимальными значения, но при этом чтобы значение элемента превышало минимальный порог (5-7% от общего количества пикселей — отсекаем незначительные, то есть мало используемые на картинке цвета), индексы этих элементов определяют наши доминантные цвета.
Еще один пример с одним доминантным цветом:
Еще пара слов
Алгоритм упрощен для максимально простого его понимания. В реальности конечно всё будет не так безоблачно.
В первую очередь нужно определиться с цветовой схемой, подходящей к вашей задаче классификации.
В реальной схеме будут присутствовать промежуточные цвета, оттенки и насыщенность (зеленый светлый, темный,… ), в этом случае берем массив ARR размерностью побольше, а при определении диапазонов и в цикле обработки пикселей задействуем компоненты S и L модели HSL.
Автор: eugenebartosh