Эффективное создание эскизов с помощью ImageMagick и конвертирование

Я хочу эффективно генерировать миниатюры различных размеров с помощью утилиты ImageMagick convert в Python. Некоторые из моих файлов изображений довольно большие (~ 15 МБ JPG).

Одним из способов сделать это было бы взятие полноразмерного изображения и создание различных миниатюр из полноразмерного изображения следующим образом:

convert sample_image.jpg -resize 1024x768  sample_image-1024x768.jpg
convert sample_image.jpg -resize 800x600   sample_image-800x600.jpg
convert sample_image.jpg -resize 400x300   sample_image-400x300.jpg
convert sample_image.jpg -resize 200x150   sample_image-200x150.jpg

Но другим способом было бы изменить размеры изображений друг от друга:

convert sample_image.jpg           -resize 1024x768  sample_image-1024x768.jpg
convert sample_image-1024x768.jpg  -resize 800x600   sample_image-800x600.jpg
convert sample_image-800x600.jpg   -resize 400x300   sample_image-400x300.jpg
convert sample_image-400x300.jpg   -resize 200x150   sample_image-200x150.jpg

Есть ли недостаток в этом, или, может быть, лучший способ? Похоже, это было бы намного более эффективно.

Как следствие, существуют ли какие-либо флаги или "трюки" для конвертирования, чтобы ускорить процесс?

Ответ 1

У ImageMagick есть несколько трюков с рукавами, которые помогут вам оптимизировать скорость, когда вы хотите обрабатывать большие изображения, и когда вы хотите создать другой вывод из того же оригинала:

  1. Используйте функцию ImageMagick mpr:{name}, которая позволяет временно сохранить входное изображение в регистр mpr:{name} именованной памяти, из которого вы можете позже (во время обработки) читать данные намного быстрее, чем вы могли бы сделать с жесткого диска.

  2. Выполняйте все операции изменения размера в одном процессе, выписывая различные требуемые размеры вывода.

И еще лучшая новость заключается в том, что вы можете объединить оба эти метода в одну команду.

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

Следующий пример также отображает две отдельные области из исходного изображения и создает из них уменьшенные эскизы, чтобы показать, сколько разных операций IM может выполнять в одной командной строке. Он также, конечно, выводит требуемые размеры. (Конечно, вам понадобится действительно крупноформатное входное изображение для работы параметров обрезки).

convert                           \
  huge-original.jpg               \
 -quality 80                      \
 -colorspace rgb                  \
 +profile '*'                     \
 -filter Lanczos                  \
 -write mpr:copy-of-huge-original \
 +delete                          \
  mpr:copy-of-huge-original -crop '3000x2000+0+480'   -resize '200x125!>' -write thumb1-extract.jpg +delete \
  mpr:copy-of-huge-original -crop '2000x1500+280+220' -resize '75x75!>'   -write thumb2-extract.jpg +delete \
  mpr:copy-of-huge-original -resize '1024x768'  -write sample-1024x768.jpg +delete \
  mpr:copy-of-huge-original -resize '800x600'   -write sample-800x600.jpg  +delete \
  mpr:copy-of-huge-original -resize '400x300'   -write sample-400x300.jpg  +delete \
  mpr:copy-of-huge-original -resize '200x150'   -write sample-200x150.jpg  +delete \
  mpr:copy-of-huge-original -resize '163x163!>' -write sample-163x163.jpg

Обновить

Я только сейчас увидел вопрос, заданный @JonathanOng: Как передать поток на <stdout>?

Предположим, вы хотите, чтобы формат, идущий в stdout, также был JPEG, вы можете попробовать следующее:

convert                           \
  huge-original.jpg               \
 -quality 80                      \
 -colorspace rgb                  \
 +profile '*'                     \
 -filter Lanczos                  \
 +write mpr:copy-of-huge-original \
  mpr:copy-of-huge-original -crop '3000x2000+0+480'   -resize '200x125!>' +write thumb1-extract.jpg \
  mpr:copy-of-huge-original -crop '2000x1500+280+220' -resize '75x75!>'   +write thumb2-extract.jpg \
  mpr:copy-of-huge-original -resize '1024x768'  +write jpeg:- \
  mpr:copy-of-huge-original -resize '800x600'   +write jpeg:- \
  mpr:copy-of-huge-original -resize '400x300'   +write jpeg:- \
  mpr:copy-of-huge-original -resize '200x150'   +write jpeg:- \
  mpr:copy-of-huge-original -resize '163x163!>' +write jpeg:-

Таким образом, каждый вариант будет идти в стандартный вывод. Как вы справляетесь с этим потоком последовательных изображений тогда, зависит от вас...

Обратите внимание, что вместо имени -write filename +delete вы можете использовать имя +write filename. Это эквивалентно такому же эффекту.

Ответ 2

Я пробовал время vipsthumbnail против @KurtPfeifle отличный ответ. Я запустил это с изображением RGB JPG размером 10k x 10k (около 15 МБ):

convert                           \
  /data/john/pics/wtc.jpg         \
 -quality 80                      \
 -colorspace rgb                  \
 +profile '*'                     \
 -filter Lanczos                  \
 -write mpr:copy-of-huge-original \
 +delete                          \
  mpr:copy-of-huge-original -resize '1024x768'  -write sample-1024x768.jpg +delete \
  mpr:copy-of-huge-original -resize '800x600'   -write sample-800x600.jpg  +delete \
  mpr:copy-of-huge-original -resize '400x300'   -write sample-400x300.jpg  +delete \
  mpr:copy-of-huge-original -resize '200x150'   -write sample-200x150.jpg  +delete \
  mpr:copy-of-huge-original -resize '163x163!>' -write sample-163x163.jpg  x.jpg

Я обнаружил, что мне нужно дополнительное x.jpg в конце, я не знаю, почему. На этой машине (E5-1650 3,2 ГГц, IM 6.8.9-9) Я вижу:

$ time ./m.sh 
real    0m6.560s
user    0m31.908s
sys     0m0.264s
peak RES 711MB

Это (я думаю) эквивалент с vipsthumbnail:

img=/data/john/pics/wtc.jpg
icc=/usr/share/color/argyll/ref/sRGB.icm

for size in 1024x768 800x600 400x300 200x150 163x163; do
  vipsthumbnail $img --size $size --eprofile $icc -o vips-sample-$size.jpg[Q=80]
done

vipsthumbnail умолчанию Lanczos3. Сроки с vips-8.4.4 Я вижу:

$ time ./n.sh
real    0m2.376s
user    0m2.412s
sys     0m0.108s
peak RES 70MB

Таким образом, полезное ускорение и значительное снижение использования памяти.

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

img=/data/john/pics/wtc.jpg
icc=/usr/share/color/argyll/ref/sRGB.icm

parallel vipsthumbnail $img \
  --size {} --eprofile $icc -o vips-sample-{}.jpg[Q=80] ::: \
  1024x768 800x600 400x300 200x150 163x163

Теперь я вижу:

$ time ./n.sh 
real    0m0.593s
user    0m1.960s
sys     0m0.100s
peak RES 280MB

Более 10 раз быстрее, чем ImageMagick.

Ответ 3

Для моей точки зрения, и после тестирования, изменение размера с 1024x768 до 800x600 плохо для алгоритма масштабирования. Следующий размер более прост, из-за кратного целого числа (2).

Итак, по качественной причине, я лично делаю это, это лучше:

convert sample_image.jpg -resize 1024x768  sample_image-1024x768.jpg
convert sample_image.jpg -resize 800x600   sample_image-800x600.jpg
convert sample_image-800x600.jpg   -resize 400x300   sample_image-400x300.jpg
convert sample_image-400x300.jpg   -resize 200x150   sample_image-200x150.jpg

Ответ 4

15MB JPG действительно большие. Я бы сначала изменил его размер до разумного размера (скажем 2500x2500) с самым быстрым параметром -sample, и это уменьшенное изображение затем изменит размер на разные миниатюры.

Вы можете сделать разумное решение на основе размера изображения и выбрать правильный способ изменения размера.

Я бы рекомендовал сосредоточиться на качестве эскизов вместо скорости преобразования, поэтому, пожалуйста, посмотрите на различные фильтры (-filter), резкость (-unsharp) и рекомендуемые методы понижающей дискретизации

Ответ 5

Я thumbnailing ~ 50MB JPG файлы. Единственный вариант, который сделал наибольшую разницу (~ 5x speedup), был "-define jpeg: размер 128x128" перед входным именем файла. Пример, приведенный здесь:

http://www.imagemagick.org/Usage/formats/#jpg_read

... сделал огромную разницу:

convert -define jpeg:size=128x128 jpeg_large.jpg -thumbnail 64x64  jpeg_thumbnail.jpg

-define jpeg: размер позволяет ImageMagick считывать только столько данных, сколько нужно с диска, что значительно сокращает время загрузки для очень больших изображений.

Как показывает связанная страница, используйте jpeg: size = дважды ваш окончательный размер эскиза, чтобы избежать наложения псевдонимов.

Опция -thumbnail, описанная здесь:

http://www.imagemagick.org/Usage/resize/#thumbnail

... образцы и полоски изображения, ускоряя процесс.