Как объединить 2 JPEG без потерь без декодирования с помощью шестнадцатеричного редактора?

StackOverflow https://stackoverflow.com/questions/609586

  •  03-07-2019
  •  | 
  •  

Вопрос

Я пытаюсь написать программу (например, в java), чтобы без потерь объединить несколько jpeg-файлов без предварительного декодирования.

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

Сначала я извлекаю данные изображения в формате jpeg B и добавляю его в формат jpeg A. Изменяя размеры, указанные в заголовках, я получаю новое распознаваемое изображение (jpeg A + jpeg B, добавленное к оси Y), которое можно отображать в режиме dip -lay. Однако, несмотря на то, что данные изображения из jpeg B четко распознаются, кажется, что они потеряли много информации о цвете и явно неверны.

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

Я потратил некоторое время на чтение спецификаций jpeg, заголовков и т. д., но, если честно, я не в своей тарелке и действительно могу сделать с указателем или двумя!

Большое спасибо за любую помощь.

<Ч>

Спасибо за все предложения. Да, это определенно возможно, я должен был упомянуть jpegtran в моем первоначальном вопросе. Я в основном пытаюсь воспроизвести этот аспект функциональности jpegtran, но использую его в своей собственной программе. Думаю, мне стоит взглянуть на исходный код jpegtran, но я ничего не знаю о C и не очень много знаю о программировании в целом, поэтому исходный код для обратного инжиниринга легче сказать, чем сделать!

Это было полезно?

Решение 2

Хорошо, я выяснил, где я шел не так.

1) данные сканирования изображения сохраняются в байтах, но фактическая важная информация кодируется в виде битовых строк переменной длины. Это означает, что конец фактических данных изображения не обязательно должен находиться на границе байта. Когда кодировщику jpeg необходимо заполнить число битов, чтобы сделать границу байта, он просто добавляет последовательность из 1 с.

2) способ хранения фактической информации о пикселях немного сложен (по крайней мере для меня), чтобы объяснить, но в основном все кодируется в MCU, минимальных единицах кодирования или чем-то еще. Они различаются по размеру в зависимости от подвыборки цветности, размеры по горизонтали и вертикали составляют 8 или 16 пикселей. Для каждого MCU есть части постоянного и переменного тока, которые составляют один компонент яркости, Y или цветности, Cb и Cr. Проблема заключалась в том, что компоненты постоянного тока хранятся в виде значений по отношению к соответствующему значению постоянного тока предыдущего MCU. Поэтому, когда я добавил новые данные изображения из jpg B, он сохранил свои значения DC относительно 0 (потому что не было никаких предыдущих MCU), но ему нужно было принять во внимание окончательные значения DC последнего MCU из jpg A. (надеюсь, что это имеет смысл).

Решение:

Вам необходимо выполнить первоначальное декодирование (Хаффмана + длина пробега) данных изображения, чтобы точно определить, где заканчиваются данные изображения, а затем убрать завершающие 1 с. Вам также необходимо соответствующим образом изменить начальные значения DC во втором jpg. Затем вам нужно перекодировать соответствующие биты, добавить 1, чтобы соответствовать границе байта, и т. Д.

Если вы хотите добавить к оси X, это немного сложнее. Вы должны переставить MCU так, чтобы они сканировали в правильном порядке. Сканирование JPG слева направо, затем сверху вниз и затем отрегулируйте значения DC соответствующим образом.

До сих пор я проверял это только на одном jpgs MCU, но теоретически он должен работать и с более крупными.

Кстати, я разработал это только благодаря владельцу этого превосходного jpg-ресурса / блога

Другие советы

Это очень выполнимо. Я сделал это на многих изображениях карты Google, чтобы объединить их и создать изображение размером с плакат. Существует пакет для Unix, который называется JPEG Tools и предназначен именно для этого. Программа называется jpegjoin . Чистый источник C, с двоичными файлами Windows . При компиляции он создает приложение командной строки, которое при запуске объединяет два изображения в формате JPEG без потерь среди многих других вещей. Он НЕ распаковывает изображения, просто объединяет сжатые данные и соответственно исправляет заголовок. Я использовал его для объединения 100 изображений, чтобы создать 50 полос, а затем снова объединил эти полосы, чтобы создать большое изображение.

Дополнительную информацию можно найти на http://en.wikipedia.org/wiki/Lossy_compression #Lossless_editing

Исходный код

Исходный код для базовой библиотеки jpegtran можно найти здесь . Пример сценария для имитации jpegjoin : здесь .

jpeg - как mp3 - обычно стабилен при повторном сжатии (используя тот же алгоритм).

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

Два подхода:

1) декодировать оба исходных изображения JPEG, объединить получившиеся растровые изображения и снова кодировать как JPEG. Недостатком здесь является повторное сжатие.

2) Убедитесь, что ширина и высота исходного изображения кратны 16, возможно, обрезая изображения. Не декодируйте изображения, а вместо этого соберите целевой JPEG из исходных блоков MCU (размер 16 x 16 пикселей, следовательно, обрезка).

Я предлагаю вам рассмотреть маркеры DRI и RSTn, хотя это требует много предварительных условий, но это работает для меня: добавление PPM (растрового формата) к jpeg, который кодируется с использованием DRI и RSTn, оба находятся в одинаковой ширины, и оба кратны MCU.

Я просто вырезал данные jpeg после последнего маркера RSTn (если есть), декодировал их в PPM и соединял два PPM в одну строку MCU, кодировал их с теми же параметрами с оригинальным jpeg, переставлял RST в результирующем формате JPEG в соответствии с исходным форматом JPEG, затем добавив результат к исходному формату JPEG. Используя этот метод, он не позволяет мне декодировать весь оригинальный JPEG и кодировать его снова.

Для декодирования и кодирования я использую libjpeg.

Вместо добавления изображений по горизонтали, возможно, проще повернуть каждое изображение на 90 градусов, затем соединить их вертикально, а затем повернуть полученное изображение на -90 градусов назад.

Операции с JPEG без потерь в значительной степени оксюморон. Вы можете сделать некоторую хитрость, например вращение, но на этом все.

Я бы посоветовал вам получить исходные изображения без потерь (на ум приходят TIFF или PNG) или пересмотреть требования к качеству изображений & # 8211; Повторная сэмплирование JPEG еще раз с учетом приличных оригинальных файлов неразличимо для подавляющего большинства людей.

То, что вы пытаетесь сделать, в принципе невозможно.
Кодировка файла JPEG несколько сложна, и если вы изменяете содержимое пикселей, то кодировка будет изменена. Вы можете получить изображение, которое будет меньше или больше суммы двух изображений, которые вы объединяете. Единственные операции, которые возможны без потерь, это те, которые поддерживают взаимно-однозначное соответствие с пикселями исходного изображения. это в основном сводится к поворотам на 90 градусов.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top