Node.JS
Image processing
March 2014 13

Умная обрезка картинок с использованием точки фокуса

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

Идея


Мозг программиста не может существовать без программирования. Любая задача, которая требует повторения рутинных операций более 3 раз, сразу начинает рождать в голове вопросы «Как бы это автоматизировать?» и составлять наброски алгоритмов. Так произошло и на этот раз.

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

Вот иллюстрация, для демонстрации механизма.
image

Итак, точка фокуса — это точка в центре области, содержащей самую важную часть изображения, и которая при обрезке должна остаться в любом случае. Для рядовой фотографии в эту область будет сфокусирован объектив при съемке, особенно хорошо это видно, если съемка велась с малой глубиной резкости. Отсюда, собственно, и название для понятия.

Я решил проверить свои умозаключения и поискать не сделал ли кто-нибудь уже что-то подобное. Нашлась HTML/CSS библиотека для адаптивной обрезки изображений github.com/adamdbradley/focal-point. Тут тоже используется понятие «точки фокуса», значит моя идея верна! Но мне нужна была готовая утилита, которая сможет генерить физические изображения. Такой найти не удалось.

Реализация


Тогда я взялся за Node.js, который хоть и не является моим постоянным рабочим инструментом, но который я очень люблю использовать для автоматизации и небольших утилит.

Алгоритм обрезки нового изображения получился следующим:
  1. Вычисляем пропорции конечного изображения:
    k=Wr/Hr,
    где Wr и Hr — ширина и высота будущей картинки
  2. Определяем максимальный прямоугольник, который впишется в оригинальное изображение:
    if Wr >= Hr
    then Wm = Wi, Hm = Wi/k
    else Hm = Hi, Wm = Hm*k,
    где Wi, Hi — размеры оригинала, а Wm, Hm — размеры максимального прямоугольника.
  3. Вычисляем новые координаты для точки фокуса:
    fx2 = fx*Wm/Wi,
    fy2 = fy*Hm/Hi,
    fx, fx — координаты точки фокуса на оригинальном изображении
  4. Делаем собственно обрезку, смещая прямоугольник на разницу между старыми и новыми координатами точки фокуса:
    crop(Wm, Hm, (fx-fx2), (fy-fy2))
  5. Уменьшаем результат до нужного размера:
    resize(Wr, Hr)

Для обработки изображений я взял модуль GraphicsMagick for node, потому что она обещала беспроблемную работу с графическими библиотеками под Windows. И почти не соврала. ImageMagick вместе с ней мне так и не удалось запустить (причем более старый модуль imagemagick-node работал без проблем), а вот альтернатива в виде GraphicsMagick заработала сразу и без шаманства. Теоретически на другой платформе должен заработать и ImageMagick, какой-то жесткой привязки к библиотеке в модуле gm нет.

В итоговую утилиту я добавил немного оптимизации для веба: из итоговой картинки вырезается вся EXIF, ICM и пр. информация и полученное маленькое изображение прогоняется фильтром резкости. При уменьшении с 3000х4000px до 200x300px это действительно необходимо.

Для удобства работы исходные данные принимаются в виде 2 файлов:
  1. formats.json — файл, в котором перечислены форматы в который нужно обрезать
  2. images.json — файл, в котором перечислены изображения и заданы точки фокуса. Здесь же можно задать куда и в каком качестве сохранять картинки.


Подробное о форматах файлов, установке и дополнительных возможностях можно почитать в репозитории на GitHub github.com/fetis/fcrop. Там же можно найти демку для примеров.

И напоследок, пример работы утилиты
Ссылка на оригинальное изображение 5.4 Mб

image
200х135

image
500х180

image
900х172

+39
28.7k 162
Comments 32
Top of the day