Verhindern Sie die Lepton-Komprimierung


17

Dropbox hat kürzlich Lepton ( GitHub ) veröffentlicht, eine Methode, die JPEG-Bilder verlustfrei komprimiert und dabei durchschnittlich 22% einspart.

Aufgrund des Pigeonhole-Prinzips kann nicht garantiert werden , dass ein allgemeiner Komprimierungsalgorithmus zu einer kleineren Datei führt ( allgemein, da er nicht für Eingaben gilt, die auf ein bestimmtes Format beschränkt sind). Lepton nutzt die allgemeinen Eigenschaften von JPEGs aus, die, wenn sie unterwandert werden, in eine Schublade gesteckt werden können, um eine Datei zu erstellen, die größer als die Quelle ist.

Bedarf

Schreiben Sie ein Programm, das Folgendes generiert:

  • Ein gültiges JPEG / JFIF-Bild,
  • mit einer Größe zwischen 0,5 MB und 1 MB,
  • nicht kleiner als 256 × 256 px,
  • nicht größer als 4096 × 4096 px,
  • erkennbar an Lepton (es kann erfolgreich zu einem .lepBild "komprimiert" werden) und
  • dekomprimiert auf eine identische .jpg (als Eingabe).
  • APPx, COMUnd andere Metadaten, nicht-grafische Markierungsabschnitte sind in den JPEG (Injizieren beliebigen Mengen von Zufallsbytes in das Bild asymptotisch nähern . 1: 1 - Komprimierung lahm) eingeschränkt
    • Ein APP0JFIF-Marker ist zulässig, aber keine Miniaturansicht (sollte genau 16 Byte groß sein).
    • tl; dr Wenn Sie Metadaten nicht absichtlich in ein EXIF-Segment verschieben und eine beliebige Art von Miniaturbild deaktivieren, das Ihre Sprachbibliothek in das Bild einfügen möchte, sollte dies in Ordnung sein.

Posten Sie den Code und das Bild.

Wenn Sie ein Programm schreiben möchten, das ein Lepton- Bild erzeugt, das bei der Konvertierung ein JPEG ergibt, das die Kriterien erfüllt, ist das in Ordnung. Es muss über beliebig viele JPEG → Lepton → JPEG → ... Zyklen hinweg identisch bleiben.

Wertung

Die Bytegröße des Lepton-Bildes geteilt durch das JPEG-Quellbild. Höhere (schlechtere Lepton-Komprimierung) ist besser. Führen Sie Lepton mit Standardflags und -schaltern aus.


Lepton bekommen

Ein 5-Sekunden-Crashkurs zum Bau von Lepton:

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

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

Dann ./lepton --helpsollten Sie Dinge erzählen.


Ich denke, dies könnte zu einer Code-Golf-Herausforderung umgerüstet werden, bei der Sie Code schreiben, der ein Bild erzeugt, bei dem die Komprimierung um mindestens eine Konstante fehlschlägt. Eigentlich reicht es vielleicht aus, nur eine Obergrenze für die Codegröße zu setzen, die viel kleiner ist als die Größe, um das JPEG fest zu codieren, aber groß genug für ein vernünftiges Programm.
Xnor

3
Gibt es einen Grund zu der Annahme, dass gleichmäßig zufällige Pixel nicht die beste Antwort sind?
Feersum

@feersum meinst du genau wie mein beispiel?
Nick T

1
Da JPEG ein verlustbehaftetes Format ist, gibt es auch viele, viele Möglichkeiten (z. B. "Qualität" unter anderem), ein bestimmtes Bild zu komprimieren. Jede JPEG-Datei enthält einige Tabellen, die festlegen, wie der Rest des Bildes dekodiert wird. Diese Tabellen können grundsätzlich beliebig sein. Wenn Sie ein BMP-Image in verschiedenen Programmen speichern, ist es wahrscheinlich identisch. Wenn Sie eine JPG-Datei in verschiedenen Programmen speichern, sofern diese nicht dieselbe Back-End-Bibliothek verwenden, ist dies wahrscheinlich nicht der Fall.
Nick T

2
Die gleichmäßig zufällige Eingabe von @feersum in einen JPEG-Kompressor führt nicht zu einer gleichmäßig zufälligen Ausgabe, und diese Ausgabe wird von Lepton verarbeitet. Wenn Sie einen Eingang finden können, der bewirkt, dass ein JPEG-Kompressor eine gleichmäßig zufällige Ausgabe erzeugt, wäre dies wahrscheinlich hier und anderswo nützlich.
Sparr

Antworten:


4

Python 3 + Mozjpeg + / dev / urandom, 720 × 720: Durchschn. Ergebnis 102%

Abhängig vom mozjpegPaket geht der Code davon aus, dass es installiert ist /usr/local/opt/mozjpeg. (Unter OS X ist es einfach zu installieren, einfach ausführen brew install mozjpeg)

Es hängt auch von einer /dev/urandomspeziellen Datei ab, die zur Erzeugung von Zufallsdaten verwendet wird.

Der Code speist einfach zufällige Daten in den mozjpegKompressor ein (im TGA-Format, da CJPEG dies versteht und einen sehr einfachen Header hat) und ermöglicht es ihm, eine optimierte JPEG-Datei zu erstellen. Die Qualität ist auf das Maximum eingestellt, da DCT-Koeffizienten am wenigsten komprimierbar sind und es keine Rolle spielt, welcher Algorithmus zum Komprimieren nicht komprimierbarer Daten verwendet wird.

Ich habe überprüft, ob der JPEG-> LEPTON-> JPEG-Zyklus verlustfrei ist - das stimmt.

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()

Code wird offensichtlich nicht gespielt.

Beispielbild:

Unterhaltsame Tatsache: Die generierte JPEG-Datei ist größer als das unkomprimierte TGA-Quellbild, obwohl JPEG eine verlustbehaftete Komprimierung verwendet.

Unterhaltsame Tatsache 2: Imgur (das Standard-Image-Hosting für SO) leistet bei dieser Datei sehr schlechte Arbeit - aus irgendeinem Grund wird sie auf eine niedrigere Qualität komprimiert, obwohl sie weniger als 1 MB groß ist. Also habe ich Github verwendet, um das Beispielbild hochzuladen.

Unterhaltsame Tatsache 3: Im Allgemeinen ist Mozjpeg in der Tat besser für die JPEG-Komprimierung geeignet, während es mit vorhandenen JPEG-Decodern kompatibel bleibt. Und es hat auch ein Tool, um JPEG-Dateien verlustfrei zu optimieren - jpegtran.


Ich könnte ein plattformübergreifendes RNG (z. B. SystemRandom-Klasse) verwenden, war aber zu faul. Es ist trivial und sollte ähnliche Ergebnisse liefern.
Sarge Borsch

1

Naives Rauschen, 1024 × 1024: Ergebnis 85.55%

Ein konformes Beispiel in Python, um den Ball ins Rollen zu bringen. In keiner Weise optimiert; wahrscheinliche Mängel:

  • Keine Ahnung, wie die Standardqualitätseinstellung lautet.
  • Jeder 8x8-Block hat praktisch den gleichen Durchschnittswert (~ 50%) wie der benachbarte: Lepton gibt an, diese Informationen zu verwenden, um Platz zu sparen.
  • Völlig standardmäßige Quantisierung und Huffman-Tabellen (unabhängig davon, welche Bibliothek sie verwendet).

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')

Lärm

Dann ein paar Schläge, um das Ding zu machen:

./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
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.