Как оценить размер файла GIF?
мы создаем онлайн-сервис для редактирования видео. Одна из функций позволяет пользователям экспортировать короткий сегмент из своего видео в виде анимированного gif. Карт имеет ограничение размера файла 2 Мб на загруженный анимированный gif.
размер файла Gif зависит от количества кадров, глубины цвета и самого содержимого изображения: сплошной плоский цвет приводит к очень легкому gif, в то время как некоторые случайные цвета ТВ-шум анимации будет довольно тяжелым.
сначала я экспортирую каждое видео рамка как PNG конечного размера рамки GIF (фиксированная, 384x216).
затем, чтобы максимизировать качество gif, я предпринимаю несколько попыток рендеринга gif с немного разными параметрами-различным количеством кадров и количеством цветов в палитре gif. Рендеринг, который имеет лучшее качество, оставаясь под ограничением размера файла, загружается в Imgur.
каждый рендер требует времени и ресурсов процессора - это я ищу для оптимизации.
вопрос: что может быть умным способом оценить лучшие настройки рендеринга в зависимости от фактических изображений, максимально приблизиться к пределу размера файла и хотя бы минимизировать количество попыток рендеринга до 2-3?
2 ответов
формат изображения GIF использует сжатие LZW. Печально известный для владельца патента на алгоритм Unisys, агрессивно преследующий выплаты роялти, как только формат изображения стал популярным. Оказалось, что за это мы должны благодарить PNG.
объем, на который LZW может сжимать изображение, чрезвычайно недетерминирован и сильно зависит от содержимого изображения. Вы, в лучшем случае, можете предоставить пользователю эвристику, которая смета окончательный размер файла изображения. Отображающий, скажем, предсказание успеха с цветной полосой. Вы можете раскрасить его довольно быстро, преобразовав только первый кадр. Это не займет много времени на изображении 384x216, которое работает в человеческом времени, долю секунды.
а затем экстраполируйте эффективную скорость сжатия этого первого изображения на последующие кадры. Который должно для кодирования только небольших отличий от исходного кадра, поэтому должны иметь сопоставимые скорости сжатия.
вы не можете действительно знать превышает ли он ограничение размера сайта, пока вы не закодируете всю последовательность. Поэтому не забудьте подчеркнуть в своем дизайне пользовательского интерфейса, что ваш прогноз-это просто оценка, поэтому ваш пользователь не будет слишком разочарован. И, конечно, предоставить ему инструменты, чтобы уменьшить размер, что-то вроде интерполяции ближайшего соседа, которая делает пиксели в изображении больше. Фокусировка на том, чтобы сделать более поздние кадры меньше, также может окупиться, кодеры GIF обычно не делают это хорошо сами себя. YMMV.
на это нет простого ответа. Размер GIF одного кадра в основном зависит от энтропии изображения после квантования, и вы можете попробовать использовать stddev в качестве оценки, используя, например, ImageMagick:
identify -format "%[fx:standard_deviation]" imagename.png
вы можете получить лучшие результаты, запустив сглаживающее ядро на изображении, чтобы устранить некоторые высокочастотные шумы, которые вряд ли будут информационными и, скорее всего, испортят производительность сжатия. Это намного лучше с JPEG, чем с GIF, в любом случае.
тогда, в общем, вы хотите запустить очень много образцов, чтобы придумать что-то в этом роде (скажем, у вас есть один параметр сжатия Q)
STDDEV SIZE W/Q=1 SIZE W/Q=2 SIZE W/Q=3 ...
value1 v1,1 v1,2 v1,3
после запуска нескольких десятков тестов (но вам нужно сделать это только после, а не" во время выполнения"), вы получите как оценку, скажем, , и измерение его ошибки. Затем вы увидите, что изображение с stddev 0.45, которое сжимается до 108 КБ, когда Q=1 сжимается до 91 КБ плюс или минус 5, Когда Q=2, и 88 КБ плюс или минус 3, когда Q=3, и так далее.
в этот момент Вы получаете неизвестное изображение, получаете его stddev и сжатие @Q=1, и вы можете интерполировать вероятный размер, когда Q равен, скажем, 4, без фактического запуска кодировки.
пока ваш сервис, вы можете хранить статистические данные (т. е. после действительно сделайте кодировку, вы храните фактический результаты) для дальнейшего улучшения оценки; в конце концов, вы храните только некоторые номера, а не потенциально конфиденциальную или личную информацию, которая может быть в видео. И приобретение и хранение этих номеров будет почти бесплатным.
фон
возможно, стоит распознавать изображения с фиксированным фоном; в этом случае вы можете запустить некоторые адаптации, чтобы сделать все кадры идентичными в некоторых областях, и алгоритм анимации GIF не хранит эту информацию. Это , когда и если вы получаете такое видео (например, говорящая голова), может привести к огромной экономии (но полностью отбросит оценку параметров, если вы не сможете оценить также фактическую протяженность фоновой области. В этом случае пусть эта область будет B, пусть область кадра будет A, сжатый размер "изображения" для пяти кадров будет A+(A-B)*(5-1) вместо A*5, и вы можете применить этот поправочный коэффициент к оценке).
оптимизация сжатия
затем есть методы оптимизации, которые немного изменяют изображение и адаптируют его для лучшего сжатия, но мы бы отклонились от темы. У меня было несколько алгоритмов, которые очень хорошо работали с paletted PNG, который во многом похож на GIF, но мне нужно было бы проверить, могут ли и какие из них свободно использоваться.
некоторые мысли: алгоритм LZW в строки. Поэтому, когда последовательность из N пикселей" меньше X% " отличается (перцептивно или арифметически) из уже встреченной последовательности перепишите последовательность:
018298765676523456789876543456787654
987678656755234292837683929836567273
здесь последовательность 656765234 в первой строке почти соответствует последовательности 656755234 во второй строке. Изменяя несовпадающие 5 на 6, алгоритм LZW, скорее всего, подберет всю последовательность и сохранит ее с один символ вместо трех (6567,5,5234) или более.
кроме того, LZW работает с bits, а не в байтах. Это значит,очень грубо говоря, чем больше 0 и 1 сбалансированы, тем хуже будет сжатие. Чем более непредсказуема их последовательность, тем хуже результаты.
Итак, если мы сможем найти способ сделать распределение более симметричным, мы выиграем.
и мы можем сделать это, и мы можем сделать это изображение (то же самое работает с PNG). Мы выбираем наиболее распространенный цвет в изображении, как только мы его квантовали. Пусть этот цвет будет цвет с индексом 0. Это 00000000 восемь нулей жира. Теперь мы выбираем наиболее распространенный цвет, который следует за этим, или второй наиболее распространенный цвет; и мы даем ему индекс 1, то есть 00000001. Другой семь нули и один. Следующий цвет будет индексироваться 2, 4, 8, 16, 32, 64 и 128; каждый из них имеет только один бит 1, остальные нули.
поскольку цвета, скорее всего, будут распределены по закону мощности, разумно предположить, что около 20% пикселей будут быть окрашены в первые девять наиболее распространенных цветов; и что 20% потока данных может быть сделано, чтобы быть по крайней мере 87,5% нулей. Большинство из них будут подряд нули, что-то, что LZW оценит без конца.
лучше всего, это вмешательство полностью без потерь; переиндексированные пиксели по-прежнему будут того же цвета, это только палитра, которая будет сдвинута соответственно. Я разработал такой кодек для PNG несколько лет назад, и в моем сценарии использования (PNG street maps) он дал очень хорошие результаты, ~20% прироста в сжатии. С более разнообразными палитрами и алгоритмом LZW результаты будут, вероятно, не так хороши, но обработка выполняется быстро и не слишком сложно реализовать.