error_level_map — IMGFORENSICS compression op

• Datenarten: image2d → image2d

• Aufruf: import fullseye as fs; fs.ledger.error_level_map(image, quality: 'int' = 90, normalize: 'bool' = True) -> 'np.ndarray' (die Implementierung direkt: import imgforensics; imgforensics.error_level_map(image, quality: 'int' = 90, normalize: 'bool' = True) -> 'np.ndarray'; aus dem Register: opsimgforensics.get("error_level_map"))

Verwendung

ELA (Error-Level-Analyse). Eine Karte der Differenz nach Neukomprimierung bei gegebener Qualität. image2d.

Krawetz 2007. JPEG quantisiert pro 8x8-Block, daher zeigt ein bereits einmal komprimierter Bereich bei Rekompression mit derselben Qualität wenig Fehler, während ein nachträglich eingefügter / gezeichneter Bereich einen großen Fehler behält; auf dieser Idee beruht es.

Mit normalize=True (Default) wird durch das Maximum auf [0, 1] geteilt (zum Ansehen). Mit False ist es der absolute Fehler in rohen 8-bit-Stufen (zum Zählen).

Ohne Pillow ImportError. Es fällt nicht auf eine Näherung zurück. Wer nur die DCT-Quantisierung in numpy nachahmt, erhält *etwas anderes*, bei dem Rundung des Encoders, Farbraumkonvertierung und Chroma-Unterabtastung fehlen. Das ELA zu nennen hieße, selbst das "plausibel Falsche" zu begehen, das diese Familie ausmerzen will.

Was diese Karte nicht aussagen kann (tests/test_imgforensics.py fixiert es in Zahlen; ein anderes Bild in die mittleren 64x64 eines 256x256-Bildes mit 1/f^1.6 eingefügt):

==================================== =============== =============== =========

Originalbild ELA Eingefügtes ELA Hintergrund Verh.

==================================== =============== =============== =========

Unkomprimiert (nie als JPEG) 0.1966 0.1793 1.096

Einmal durch JPEG Qualität 75 0.1966 0.0401 4.898

==================================== =============== =============== =========

• Bei unkomprimiertem PNG kann sie nichts aussagen. Das 1.096-Fache oben bedeutet "eingefügte und nicht eingefügte Stellen sind nicht unterscheidbar". ELA hat nur dann Aussagekraft, wenn "das Original ein JPEG ist", und erst dann ergibt sich ein Unterschied des 4.898-Fachen.

• Auch die verbreitete Behauptung "ELA verfolgt nur hohe Frequenzen" gilt für dieses Bild nicht —— die Korrelation zwischen ELA und Sobel-Gradientenstärke ist 0.003 (unkomprimiert) / 0.057 (bereits JPEG). ELA betrachtet das Quantisierungsresiduum der 8x8-Blöcke und misst daher etwas anderes als den Gradienten. Trotzdem trennt es, wie die Tabelle zeigt, ohne Kompression keine Manipulation. Es scheitert nicht, "weil es nur eine Umschreibung des Gradienten ist", sondern weil keine Quantisierungshistorie als Vergleichsbasis vorhanden ist.

• Flache Bereiche zeigen auch bei Kompression keinen Fehler und bleiben daher dunkel, selbst wenn sie manipuliert sind.

Referenzen (Beispieldaten, Literatur)

• Katalog der Beispieldaten (Download-URLs / Lizenzen) — 2-D nutzt skimage.data (BSD/Public Domain) plus synthetische Bilder, 3-D nennt Download-URLs echter Datenquellen (Stanford, PDS, …).

• Herkunft und Literatur der Operatoren — die Quellen der Forschung/Verfahren, auf denen diese Operatorfamilie beruht.

• Der kanonische Algorithmus (Autor, Jahr) und seine Anwendungen stehen im Familienleitfaden oben.

Ausführbare Beispiele (verifizierte Samples, die diesen Operator wirklich aufrufen)

• image_forensics_audit — py -3.11 examples/image_forensics_audit.py

• poc_forensics_roc — py -3.11 examples/poc_forensics_roc.py

Typkompatible Folge-Operatoren (nehmen image2d als Eingabe)

perceptual_hash · fingerprint_correlate · jpeg_quality_estimate · jpeg_ghost_map · noise_inconsistency_map · copy_move_regions · watermark_embed · watermark_extract

Gleiche Kategorie (compression)

jpeg_quality_estimate · jpeg_ghost_map · jpeg_ghost_quality


*Provenance: imgforensics.py — IMGFORENSICS Operator-Registry. Diese Notiz wird von tools/opdocs.py md erzeugt (nicht von Hand bearbeiten).*

© 2026 Kazufumi Furuse — Fullseye operator documentation. Licensed under Apache-2.0.