Создаем мозаику из случайных изображений

Рассказывает Чарльз Ньюи, автор блога blog.assemblyco.de


Если вы следили за новинками современного искусства, вы наверняка видели что-то, похожее на это:

1

Или это:

2

Да, это действительно лицо Барака Обамы, выложенное мозаикой из тостов различной прожарки.

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

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

Шаг 1: поиск и обработка изображений

Я не знал, откуда можно было бы взять картинки — может, из Wikipedia Commons или Flickr? Может, вообще из каких-либо публичных источников? В итоге было решено использовать Flickr. Я написал простенький скрипт на Python, который ищет на Flickr изображения, используя определенный набор тегов (и фильтруя их по наличию лицензии Creative Commons, разумеется), и скачивает их. Другой скрипт обрезает картинки до клеток размера 32х32. Теперь, когда все наши картинки одного размера, их можно использовать в мозаике.

В итоге я скачал и обработал около 500 изображений из Flickr. Это очень небольшой набор, поэтому я не рассчитывал, что результат будет очень хорошим — но в итоге я был приятно удивлен.

Шаг 2: составление мозаики

Этот этап абсолютно прямолинеен. Вот простой алгоритм для расстановки изображений:

  1. Считать целевое изображение (то,из которого мы хотим сделать мозаику).
  2. Считать весь набор картинок.
  3. Для каждой картинки:
    • вычислить средний цвет картинки;
    • сохранить это значение в структуру данных (для последующего использования).
  4. Создать пустое изображение нужного размера для размещения картинок.
  5. Для каждого пикселя целевого изображения:
    • получить его цвет в RGB;
    • найти картинку наиболее подходящего среднего цвета;
    • вставить соответствующую картинку в пустое изображение, созданное ранее.
  6. Сохранить полученное изображение.

Определение наиболее подходящей картинки

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

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

Результат

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

Вот как выглядит исходное изображение:

3

Первая попытка была успешной — вот что получилось:

4

Ура, все работает!… но многочисленные повторы одинаковых картинок режут глаз. А что, если выбирать не наиболее подходящую картинку, а одну из пяти наиболее подходящих?

5

Гораздо лучше! Так точно интереснее. Для закрепления попробуем еще одно лицо — как насчет Мишель Обамы?

6

Отлично. Как насчет (черт, Обамы кончились)… ммм… как насчет моего лица?

Вот как я выгляжу:

7

А вот получившаяся мозаика:

8

Успех! Неплохо для пары дней работы. Если это вас заинтересовало, исходный код можно найти на моем GitHub.

Источник: блог Assemblyco