Стиснення Lepton стиснення


17

Нещодавно Dropbox випустив Lepton ( GitHub ) - метод, який без втрат стискає зображення JPEG у зворотному напрямку, економлячи в середньому 22%.

Через принцип голубої дуги не можна гарантувати , що будь-який загальний алгоритм стиснення призведе до отримання меншого файлу ( загального, оскільки він не застосовується до входів, обмежених певним форматом). Лептон використовує загальні характеристики JPEG-файлів, які, якщо їх підривати, можуть заглибити його, щоб створити файл, більший за джерело.

Вимоги

Напишіть програму, яка генерує:

  • Дійсне зображення JPEG / JFIF,
  • розміром від 0,5 МБ до 1 Мб,
  • не менше 256 × 256 пікселів,
  • не більше 4096 × 4096 пікселів,
  • впізнаваний Лептоном (він може успішно «стискати» .lepзображення) та
  • декомпресується на ідентичний .jpg (як вхідний).
  • APPx, COMта інших метаданих, розділи неграфічного маркера обмежені в JPEG (введення в зображення довільних кількостей випадкових байтів для асимптотичного наближення стискання 1: 1 є кульгавим.)
    • APP0JFIF маркер допускається , але не з слайдами не допускається (повинно бути рівно 16 байт)
    • tl; dr. Якщо ви навмисно не переміщуєте метадані в сегмент EXIF ​​і ви відключаєте будь-яку мініатюру, яку бажана бібліотека мови вводить у зображення, це повинно бути добре.

Опублікуйте код і зображення.

Якщо ви хочете написати програму, яка створює зображення Лептона, яка при перетворенні дає JPEG, що відповідає критеріям, це добре. Він повинен залишатися однаковим у довільно багатьох циклах JPEG → Лептон → JPEG → ...

Оцінка балів

Розмір байтів зображення Лептона, розділений на вихідне зображення JPEG. Чим вища (гірша компресія Лептона), тим краще. Запустіть Лептон за допомогою стандартних прапорів та перемикачів.


Отримання Лептона

5-секундний збійний курс для складання Лептона:

git clone https://github.com/dropbox/lepton.git
cd lepton
./autogen.sh && ./configure && make

# fish shell: ./autogen.sh ;and ./configure ;and make

Тоді ./lepton --helpслід розповісти вам речі.


Я думаю, що це можна переосмислити на проблему з кодовим гольфом, де ви пишете код, який генерує зображення, яке не дає змоги принаймні на якусь константу. Насправді, можливо, достатньо просто поставити верхню межу розміру коду, який набагато менший, ніж розмір для жорсткого кодування jpeg, але достатньо великий для розумної програми.
xnor

3
Чи є якась причина очікувати, що однаково випадкові пікселі - не найкраща відповідь?
feersum

@feersum ти маєш на увазі так само, як мій приклад?
Нік Т

1
Крім того, оскільки JPEG - це формат з втратою, існує багато, багато способів (наприклад, "якість" серед іншого) для стиснення заданого зображення. Кожен файл JPEG містить кілька таблиць, які диктують, як декодується решта зображення, і ці таблиці в основному можуть бути будь-якими. Якщо ви зберігаєте зображення BMP в різних програмах, воно, ймовірно, буде ідентичним. Якщо ви зберігаєте JPG в різних програмах, якщо вони не використовують одну і ту ж саму бібліотеку, можливо, це не так.
Нік Т

2
Рівномірний випадковий вхід в компресор JPEG не призводить до рівномірного випадкового виходу, і саме такий результат працює на лептоні. Якщо ви можете придумати вхід, який спричиняє компресор JPEG виробляти рівномірно випадковий вихід, це, мабуть, буде корисним тут і в інших місцях.
Спарр

Відповіді:


4

Python 3 + mozjpeg + / dev / urandom, 720 × 720: сер. оцінка 102%

Залежить від mozjpegпакета, код передбачає, що він встановлений /usr/local/opt/mozjpeg. (В ОС X тривіально встановлювати, просто запустіть brew install mozjpeg)

Також це залежить від /dev/urandomспеціального файлу, він використовується для генерації випадкових даних.

Код просто подає випадкові дані до mozjpegкомпресора (у форматі TGA, оскільки cjpeg це розуміє і має дуже простий заголовок), і дозволяє створювати оптимізований файл jpeg. Якість встановлюється на максимумі, оскільки це робить коефіцієнти DCT найменш стислими, і не має великого значення, який алгоритм використовується для стиснення даних, що не стискаються.

Я перевірив, що цикл jpeg-> lepton-> jpeg без втрат - це правда.

import subprocess
from subprocess import PIPE

c_mozjpeg_path = '/usr/local/opt/mozjpeg/bin/cjpeg'
cjpeg_params = '-quality 100 -dc-scan-opt 2 -dct float -targa'
image_size = 720


def write_random_tga_image(w, h, of, rf):
    def wb(value, size):
        of.write(int.to_bytes(value, size, 'little'))

    wb(0, 2)
    wb(3, 1)
    wb(0, 9)
    wb(w, 2)
    wb(h, 2)
    wb(8, 1)
    wb(0, 1)

    data_size = w * h
    while data_size > 0:
        data_size -= of.write(rf.read(data_size))


def main():
    with open('/dev/urandom', 'rb') as rf:
        with open('oops.jpg', 'wb') as f:
            p = subprocess.Popen((c_mozjpeg_path,) + tuple(cjpeg_params.split(' ')), stdin=PIPE, stdout=f)
            write_random_tga_image(image_size, image_size, p.stdin, rf)
            p.communicate()


if __name__ == '__main__':
    main()

Код, очевидно, не гольф.

Приклад зображення:

Факт забави: згенерований файл JPEG більший, ніж вихідне нестиснене зображення TGA, навіть якщо JPEG використовує стиснення втрат.

Факт 2 веселощів: Imgur (розміщення зображень за замовчуванням для SO) виконує дуже погану роботу в цьому файлі - чомусь він надає його на нижчу якість, хоча він менший за 1 Мб. Тому я використав Github для завантаження прикладу зображення.

Факт веселості 3: Загалом, mozjpeg дійсно робить кращу компресію JPEG, залишаючись сумісною з існуючими JPEG-декодерами. І він також має інструмент для беззбиткової оптимізації файлів JPEG теж - jpegtran.


Я міг би використовувати крос-платформний RNG (наприклад, SystemRandom клас), але я був занадто ледачий. Це банально і має дати подібні результати.
Відображати ім’я

1

Наївний шум, 1024 × 1024: оцінка 85,55%

Добрий приклад в Python, щоб отримати кульку. Не оптимізований жодним чином; ймовірні недоліки:

  • Поняття не має, що таке якість якості за замовчуванням.
  • Кожен блок розміром 8х8 має практично таке саме середнє значення (~ 50%) до прилеглого до нього: Лептон каже, що вони використовують цю інформацію для економії місця.
  • Повністю за замовчуванням квантування та таблиці Хаффмана (що б бібліотека не вирішила використовувати).

import numpy as np
from PIL import Image

np.random.seed(0) # make sure it's repeatable.

size = 1024

imgr = np.random.randint(0, 0xFF, (size, size, 3)).astype('uint8')
pimg = Image.fromarray(imgr)
pimg.save('noise.jpg')

шум

Тоді кілька баш, щоб зробити це:

./lepton noise.jpg noise.lep 2>\dev\null # vomits out a lot of technobabble
./lepton noise.lep noise-out.jpg 2>\dev\null

diff -qs noise.jpg noise-out.jpg

SIZE1=$(stat -f "%z" noise.jpg) # http://superuser.com/a/570920/18931
SIZE2=$(stat -f "%z" noise.lep)
RATIO=$(bc <<< "scale=4; $SIZE2/$SIZE1")
echo "$SIZE2/$SIZE1 = $RATIO"

# Files noise.jpg and noise-out.jpg are identical
# 538817/629769 = .8555
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.