Я искал методы поворота изображения без потерь и наткнулся на этот вопрос, который объясняет это довольно хорошо:
Являются ли повороты «Windows Photo Viewer» без потерь?
Поэтому я создал JPEG 256×256 со случайными пикселями (облачный фильтр Photoshop), а затем повернул его с помощью Windows Picture Viewer. После вращения размер файла действительно увеличился, но только при первом вращении. При каждом последующем вращении размер файла оставался неизменным. Я знаю, что он вращается без потерь, потому что я поворачивал его несколько раз без заметной потери качества, тогда как изображение 257 × 257, повернутое 20 раз, стало с большими потерями.
Это, скорее всего, вызвано энтропийным кодированием , которое является последней стадией сжатия JPEG без потерь после квантования данных изображения для уменьшения его размера.
Когда изображение JPEG вращается без потерь, этот последний слой кодирования без потерь должен быть отменен, распакованные коэффициенты DCT перетасованы, а затем перемешанные коэффициенты необходимо снова закодировать энтропийно. Поскольку эффективность уровня энтропийного кодирования зависит от порядка коэффициентов DCT в каждом блоке, который будет меняться при повороте изображения, не следует удивляться тому, что повернутый файл изображения может быть на несколько процентов меньше или больше исходного.
Существует также несколько различных способов выполнения шага энтропийного кодирования, поэтому вполне возможно, что размер файла одного и того же изображения JPEG может различаться в зависимости от программного обеспечения, выполняющего кодирование. Некоторые из потенциальных различий между кодировщиками включают:
Кроме того, «файлы JPEG», с которыми обычно работают люди, на самом деле содержат данные изображения, сжатые в формате JPEG, упакованные в контейнер JFIF или Exif , который объединяет данные изображения с одним или несколькими блоками метаданных и вводит свой собственный набор осложнений. Даже если программное обеспечение, которое поворачивает изображение, на самом деле не вносит существенных изменений в метаданные JFIF/Exif, простое изменение порядка данных потенциально может повлиять на размер файла на несколько байтов.
В частности, метаданные JFIF/Exif могут содержать одну или несколько миниатюр полноразмерного изображения, и программное обеспечение, которое поворачивает изображения, действительно должно регенерировать (или также вращать без потерь!) миниатюры, чтобы они соответствовали новой ориентации полноразмерного изображения. размер изображения. Одно это может легко объяснить наблюдаемую разницу в размерах.
Я пошел дальше и повторил эксперимент, чтобы посмотреть, смогу ли я понять, что происходит.
Я сгенерировал случайное RGB-изображение размером 256 на 256 пикселей, используя фильтр «Сплошной шум» в GIMP (Фильтры > Рендеринг > Облака > Сплошной шум...), используя настройки по умолчанию (показаны ниже):
И результат:
Затем я сохранил изображение в формате JPEG, используя настройки по умолчанию:
Затем я перенес изображение в Windows и открыл его с помощью средства просмотра фотографий Windows, щелкнув изображение правой кнопкой мыши в проводнике и выбрав в меню « Предварительный просмотр ». Затем я повернул изображение с помощью кнопок внизу и сохранил изображение, перейдя к следующему изображению с помощью клавиш со стрелками.
Для каждого из приведенных ниже тестов я начал с копии исходного изображения и повернул (нажал кнопку поворота) соответствующее количество раз перед сохранением. Вот оставшиеся размеры ( ls -l -r
):
size in bytes last-modified date
VVVVV VVVVV
-rwxrwx--- 1 root vboxsf 6258 Nov 8 11:24 original.jpg
-rwxrwx--- 1 root vboxsf 23645 Nov 8 11:30 cw.jpg
-rwxrwx--- 1 root vboxsf 23636 Nov 8 11:30 cw-cw.jpg
-rwxrwx--- 1 root vboxsf 23649 Nov 8 11:30 cw-cw-cw.jpg
-rwxrwx--- 1 root vboxsf 6258 Nov 8 11:27 cw-cw-cw-cw.jpg
-rwxrwx--- 1 root vboxsf 23649 Nov 8 11:31 cw-cw-cw-cw-cw.jpg
-rwxrwx--- 1 root vboxsf 23649 Nov 8 11:29 ccw.jpg
-rwxrwx--- 1 root vboxsf 23636 Nov 8 11:29 ccw-ccw.jpg
-rwxrwx--- 1 root vboxsf 23645 Nov 8 11:29 ccw-ccw-ccw.jpg
-rwxrwx--- 1 root vboxsf 6258 Nov 8 11:27 ccw-ccw-ccw-ccw.jpg
-rwxrwx--- 1 root vboxsf 23649 Nov 8 11:30 ccw-ccw-ccw-ccw-ccw.jpg
Использование cmp -l
на файлах, которые должны иметь одинаковое содержимое, позволяет нам увидеть, чем файлы отличаются.
robert@unity ../jpeg-rotate-test % cmp -l cw.jpg ccw-ccw-ccw.jpg
2223 63 62
2224 60 71
2226 60 64
2227 60 66
robert@unity ../jpeg-rotate-test % cmp -l cw-cw.jpg ccw-ccw.jpg
2223 63 62
2224 60 71
2226 60 64
2227 62 64
robert@unity ..jpeg-rotate-test % cmp -l ccw.jpg cw-cw-cw.jpg
2223 62 63
2224 71 60
2226 64 60
2227 61 64
robert@unity ../jpeg-rotate-test % cmp -l cw.jpg cw-cw-cw-cw-cw.jpg
2221 60 61
2223 63 61
2224 60 66
2226 60 61
2227 60 61
robert@unity ../jpeg-rotate-test % cmp -l ccw.jpg ccw-ccw-ccw-ccw-ccw.jpg
2223 62 63
2224 71 60
2226 64 65
2227 61 64
Эти файлы отличаются всего четырьмя байтами (фактически временной меткой), что означает, что WPV каждый раз делает одно и то же; теперь нам нужно только выяснить, что это такое.
Для этого я использовал JPEGsnoop , чтобы увидеть, что именно есть на изображениях.
Поскольку результаты довольно длинные, я связал их как gist . Вот краткое изложение различий:
GIMP использует только сегмент APP0
(JFIF) и COM
(комментарий) для метаданных. WPV оставляет APP0
сегмент нетронутым, но, что любопытно, добавляет к комментарию нулевой байт (чтобы он заканчивался нулем).
WPV добавляет два APP1
сегмента: метаданные Exif и XMP. Эти сегменты имеют размер 4286 и 12726 байт соответственно. Вместе они составляют почти все увеличение размера файла.
GIMP создает прогрессивный JPEG, а WPV создает базовый (непрогрессивный) JPEG. По этой причине изображение GIMP имеет несколько сегментов сканирования, а изображение WPV — только один. По моему опыту, прогрессивное изображение иногда немного меньше.
GIMP использовал субдискретизацию цветности 1 × 1, а WPV использовал субдискретизацию 2 × 2. Это наводит меня на мысль, что WPV не использует «настоящее» вращение без потерь, если только он каким-то образом не может определить, что это черно-белое изображение.
Чтобы решить эти проблемы, я провел второй тест.
Я следовал тем же шагам, что и в первом тесте. Я создал случайное RGB-изображение размером 256×256 с использованием фильтра «Шум RGB» («Фильтры» > «Нос» > «Нос RGB...») со следующими настройками:
Вот результат:
Я экспортировал файл в формате JPEG, используя следующие настройки:
Прогрессивный режим отключен, но субдискретизация по-прежнему установлена на 4:4:4 (другое название субдискретизации 1×1). Качество повышено до 98.
Я скопировал изображение и повернул копию по часовой стрелке; затем скопировал повернутую версию и повернул эту копию против часовой стрелки, чтобы мы могли напрямую сравнить качество между оригиналом и обработанной копией WPV.
-rwxrwx--- 1 root vboxsf 159774 Nov 8 16:21 original-random.jpg
-rwxrwx--- 1 root vboxsf 222404 Nov 8 16:24 cw-random.jpg
-rwxrwx--- 1 root vboxsf 222467 Nov 8 16:24 cw-ccw-random.jpg
Хотя увеличение на этот раз меньше в относительном выражении (около 40%), абсолютное увеличение еще больше — около 62 КБ. Это говорит о том, что WMV использует менее эффективную кодировку.
Я буду использовать ImageMagick для сравнения двух изображений:
robert@unity ../jpeg-rotate-test % compare -verbose -metric AE original-random.jpg cw-ccw-random.jpg null:
original-random.jpg JPEG 256x256 256x256+0+0 8-bit sRGB 160KB 0.000u 0:00.009
cw-ccw-random.jpg JPEG 256x256 256x256+0+0 8-bit sRGB 222KB 0.010u 0:00.010
Image: original-random.jpg
Channel distortion: AE
red: 0
green: 0
blue: 0
all: 0
original-random.jpg=> JPEG 256x256 256x256+0+0 8-bit sRGB 0.050u 0:00.020
Между оригиналом и повернутой копией нет разницы в пикселях . Таким образом, даже если WPV не использует «настоящее» вращение без потерь, он выполняет свою работу достаточно хорошо. Я подозреваю, что знаю, что происходит, и чтобы объяснить, я немного отвлекусь на математику, лежащую в основе сжатия JPEG.
Алгоритм сжатия JPEG разбивает изображение на блоки размером 8×8 пикселей. Затем каждый из этих блоков подвергается дискретному косинусному преобразованию (DCT) . Полученные коэффициенты DCT описывают блок как сумму волн разной частоты. Затем алгоритм «отбрасывает» некоторую информацию в высокочастотных волнах, которая соответствует шуму и очень мелким деталям. Процесс декодирования переворачивает DCT, складывая сохраненные волны вместе, чтобы получить обратно блок.
Можно вращать «волны» DCT, фактически не отменяя и не повторяя преобразование (в основном вы превращаете все горизонтальные волны в вертикальные волны и наоборот). Я думаю, что в WPV происходит то, что изображение фактически декодируется, поворачивается, а затем повторно кодируется. В процессе перекодирования, поскольку размер нашего изображения кратен 8 в обоих измерениях, каждый новый блок соответствует одному из исходных блоков. Важно отметить, что, поскольку в каждом блоке нет высокочастотных компонентов, алгоритм не отбрасывает никакой информации и находит именно те компоненты DCT, которые были бы у «настоящего» вращения без потерь.
Наконец, я снова рассмотрю компоненты файлов JPEG. Результаты снова связаны как суть . Сравнивая два:
Изображение WPV содержит дополнительные 4286+2 байта метаданных Exif, 1 дополнительный байт в комментарии и 12 726+2 байта метаданных XMP. Это в общей сложности 17 017 байт дополнительных метаданных. Для чего используются все эти данные? Я заглянул в файл своим верным шестнадцатеричным редактором и копией соответствующих стандартов:
Метаданные Exif структурированы так же, как изображение TIFF, которое содержит ряд тегов (тут гораздо больше сложностей , но я их пропущу). Большая часть байтов в сегменте Exif содержится в двух одинаковых тегах с номером тега EA1C
(59 932 десятичных числа). Этот номер тега не задокументирован нигде, что я мог найти. Оба тега содержат 2060 байтов типа «undefined», которые являются нулевыми байтами, за исключением первых шести ( 1C EA 00 00 00 08
). Я понятия не имею, что это за теги, почему их два и почему они должны быть по 2 КБ каждый.
Метаданные XMP на самом деле представляют собой целый встроенный XML-документ с пространством имен и длинными UUID, который просто содержит строку версии WPV (которая уже была в метаданных Exif). Однако это составляет всего около 400 байт. Оставшаяся часть сегмента состоит из 122 повторений по 100 пробелов, за которыми следует новая строка . Это более 12 000 байт полностью потраченного впустую пространства.
Как и в предыдущем тесте, и GIMP, и WPV используют одни и те же таблицы квантования DCT. Это означает, что они должны рассчитывать одни и те же коэффициенты DCT, поэтому изображения абсолютно одинаковы. Я не уверен, что WPV просто использует одни и те же таблицы квантования или копирует таблицы из ввода.
В отличие от предыдущего теста, на этот раз WPV использует подвыборку 1 × 1, поэтому он может фактически определять, что это цветное изображение (или, по крайней мере, для повторного кодирования изображения без потерь необходимы более высокие выборки).
GIMP и WPV используют разные таблицы Хаффмана (часть шага энтропийного кодирования). Таблицы для WPV больше всего на 279 байт и в одном случае содержат в 7 раз больше кодов.
Глядя на статистику JPEGsnoop, мы видим, что некоторые из этих кодов используются редко. Например, в ID: 1, Class: AC
таблице из 119 определенных 16-битных кодов фактически используются только 23. В целом, фактический сегмент сканирования на 28,5% больше в версии WPV.
Возможно, WPV не выполняет "настоящие" ротации без потерь, но ротации кажутся практически без потерь.
Дополнительный размер частично связан с фиксированным объемом добавляемых метаданных, а частично — с менее эффективным энтропийным кодированием.
ОС (Linux) ( uname -a
):
Linux unity 3.16.0-4-amd64 #1 SMP Debian 3.16.36-1+deb8u1 (2016-09-03) x86_64 GNU/Linux
ОС (Виндовс):
GIMP (Linux): 2.8.14 (из пакета gimp
, версия 2.8.14-1+deb8u1
)
Окно просмотра фотографий (согласно метаданным изображения):
Microsoft Windows Photo Viewer 10.0.10586.0
РЕДАКТИРОВАТЬ : этот ответ был опубликован до того, как я узнал, что размер файлов увеличился примерно на 9 КБ (9055 байт для изображения 256 × 256, 9612 КБ для изображения 512 × 512).
По всей вероятности, когда вы впервые повернули изображение, Windows Picture Viewer сделал одно (или оба) из следующих действий:
Это увеличило размер файла из-за дополнительного тега EXIF (и/или дополнительных данных к существующим тегам).
Последующие ротации не увеличивали размер файла, потому что все теги и/или данные тегов, которые WPV добавила/изменила, уже были там. Изменилось только значение тега ориентации (и, возможно, также значения тега даты/времени).
РЕДАКТИРОВАТЬ : почти наверняка это объяснение не может учитывать около 9 КиБ дополнительных данных в файле. Кроме того, при отсутствии каких-либо других причин для увеличения размера это объяснение предполагает, что увеличение размера будет более или менее постоянным (по модулю некоторых различий в длине между строковыми представлениями числовых данных, возможно, в несколько байтов). Это явно не то, что здесь происходит, по крайней мере, не полное объяснение.
Без реверс-инжиниринга кодировщика/декодера jpeg невозможно сказать наверняка. На самом деле существует несколько стандартов jpeg, и, вопреки распространенному мнению, не все из них можно изменить без перекодирования.
Вполне возможно, что первое сохранение — это перезапись с потерями в предпочитаемый формат jpeg, а последующие повороты — это простая настройка метаданных или операция непосредственно в таблице DCT (что возможно для некоторых схем кодирования).
Увеличение размера файла может также включать некоторые дополнительные метаданные, хотя 9k кажется большим, это возможно. Увеличение также может быть связано с добавлением миниатюры, которой могло не быть в выводе GIMP. Возможно, мы сможем получить больше информации непосредственно из файлов (до WPV и после).
В любом случае, пытаться работать с jpeg без потерь — на самом деле глупая затея, так как это полезно только с изображениями определенных размеров, не все декодеры и кодировщики идентичны, и для этого требуется, чтобы эти редакторы работали напрямую с содержимым jpeg, на которое вы не можете полагаться. случае ... То, что это происходит сейчас, не означает, что так будет и в будущем.
Лучше всего работать с форматом без потерь и полностью избежать боли.
Вращение JPEG без потерь возможно только без введения граничных артефактов, если размеры изображения кратны размеру блока (обычно[/всегда?] 8). См . справочную страницу jpegtran (извините, у меня нет хорошей канонической ссылки для нее; не стесняйтесь редактировать, если найдете ее) для получения подробной информации о том, что задействовано:
Преобразование транспонирования не имеет ограничений относительно
размеров изображения. Другие преобразования работают довольно странно, если размеры изображения не кратны размеру iMCU (обычно 8 или 16 пикселей), потому что они могут только преобразовывать полные блоки данных коэффициентов DCT желаемым образом.Поведение jpegtran по умолчанию при преобразовании изображения нечетного размера
предназначено для сохранения точной обратимости и математической
согласованности набора преобразований. Как уже говорилось, транспонирование
может перевернуть всю область изображения. Горизонтальное зеркальное отображение оставляет любой частичный столбец iMCU на правом краю нетронутым, но может перевернуть все строки изображения. Точно так же вертикальное зеркальное отображение оставляет нетронутой любую частичную строку iMCU на нижнем краю, но может перевернуть все столбцы. Другие преобразования могут быть построены как последовательности операций транспонирования и переворачивания; для согласованности их действия с краевыми пикселями определяются как конечные результаты соответствующей последовательности транспонирования и отражения.Для практического использования вы можете предпочесть отбросить все непреобразуемые
краевые пиксели, а не иметь странную полосу вдоль
правого и/или нижнего края преобразованного изображения. Для этого добавьте ключ -trim:
Я подозреваю, что Windows Photo Viewer избегает этой проблемы, выполняя декомпрессию и повторное сжатие чрезвычайно высокого качества, чтобы имитировать поведение без потерь, когда размеры изображения не кратны 8, а не фактически выполняя вращение без потерь. Хорошая утилита просто делала бы фактически без потерь, с артефактами и всем остальным, или отбрасывала бы несколько пикселей, а не портила бы качество всего изображения (и увеличивала размер файла).
У меня нет определенного ответа, но есть несколько возможных теорий, почему это произошло. Некоторые типы файлов работают таким образом, что два разных кода для изображения этого типа файла не обязательно создают разные изображения. Например, тип файла PNG работает таким образом, потому что он допускает прозрачный фон, но изображение с прозрачным фоном и такое же изображение, за исключением того, что тот же фон белый, отображаются точно так же. Файл изображения считается сжатым, если он занимает менее 3 байт памяти на пиксель. Я считаю, что за исключением файлов с прозрачным фоном, никакие два файла PNG не создают одно и то же изображение. Когда вы когда-либо сохраняете изображение в формате PNG, оно преобразует его в код, который генерирует исходное изображение, и, за исключением очень необычных изображений, таких как изображение, где каждый пиксель представляет собой случайный цвет всех 2 ^ 24 цветов, код будет занимать меньше памяти, чем 3 байта на пиксель, поэтому сохранение в формате PNG считается сжатием без потерь. С другой стороны, для экономии памяти код файла изображения JPEG может генерировать только определенные изображения. Вероятно, существует более одного типа файла JPEG, и я не знаю, обладает ли какой-либо из них свойством, согласно которому два разных изображения этого типа файла могут генерировать одно и то же изображение. Я предполагаю, что несколько раз вы просто поворачивали изображение, затем сохраняли его в формате JPEG и давали объяснение того, что произошло, исходя из предположения, что это то, что вы сделали, что я не знаю, верно ли это. Поворот, который вы сделали, не имеет потерь, если есть способ вернуть точно такой же код файла изображения, который у вас был до того, как вы его повернули и сохранили. Возможно, вы ошибаетесь в том, что действительно сделали вращение без потерь. Если бы это действительно было без потерь,
Причин этому несколько
способ кодирования и сжатия изображений изменит размер просто из-за алгоритма сжатия. вы можете проверить это, сохранив его как растровое изображение, а затем повернув его. В этом формате или любом необработанном формате размер должен оставаться прежним. Если это не так, программа, сохраняющая изображение, добавляет новые данные, возможно, какие-то метаданные или что-то в этом роде.
Но почему вы поворачиваете jpeg 20 раз?
Из-за того, как работает сжатие изображений . Любой формат, такой как PNG или JPG, в целом не сохраняет размер файла после поворота.
Для компрессора повернутое изображение — это просто другое изображение, из-за того, как работает эвристика сжатия , нет гарантии, что оно будет сжимать повернутое изображение так же .
Конечно, если сжатие без потерь, если вы повернете изображение 4 раза, в 4-й раз изображение снова останется тем же (повернуто до тех пор, пока оно не станет наклонено как исходное): в этом случае оно должно снова стать того же сжатого размера, если нет, то это связано с одной из следующих причин :
Сжатие изображений работает путем сжатия изображений в фрагменты 4x4 или других размеров. В общем, компрессор видит повернутое изображение как другое изображение, однако, поскольку сжатый фрагмент пикселя представляет собой просто линейную декомпозицию, если фрагменты на изображении одинаковы, можно просто транспонировать/отразить матрицы линейной декомпозиции, эффективно сохраняя то же самое. качественный:
Обратите внимание, что это должно быть реализовано для каждой функции , и это также объясняет начальное увеличение размера => при первом вращении он просто пытается сжать изображение фрагментами, которые можно вращать:
В случае успеха размер увеличивается только один раз, после чего каждое вращение сохраняет одинаковое качество.
Эта операция успешна только в том случае, если изображение состоит из равных частей. (размер изображения кратен размеру чанка).
Ответ scottbb неверен, и вы можете выполнить простой тест:
Вы увидите, что изображение изменилось (оно повторно сжимается при первом повороте). Однако это изменение ограничено по времени, теперь вы можете снова повернуть его без потери качества (если размер изображения кратен 8).
Чтобы напрямую ответить OP:
Я знаю, что он вращается без потерь
Нет, это не вращение без потерь, оно теряет качество по крайней мере один раз (при первом вращении: потому что оно должно сначала сжать его таким образом, чтобы его можно было вращать), затем оно сохраняет свое качество.
<?xpacket
тегах.<?xpacket
добавлен огромный кусок почти пустого. У меня нет правильного двоичного diff, поэтому я не могу сказать. После того, как я загрузил оба на verexif.com, они вернулись идентичными друг другу, но не оригиналу. Но, как я уже сказал, я сравниваю их вручную в шестнадцатеричном редакторе, поэтому, вероятно, многое упустил. Windows 8.1
Джеймс Снелл
колеблющийся кретин
колеблющийся кретин
Скоттбб
Скоттбб
Карл Виттофт
КодыInChaos
Джеймс Снелл
0xFF
CoffeDeveloper
Джакомо Катенацци
Агент_L
Джошуа