copy_move op• Datenarten: image2d → table
• Aufruf: import fullseye as fs; fs.ledger.copy_move_regions(image, method: 'str' = 'keypoint', min_matches: 'int' = 4, min_offset: 'float' = 16.0, offset_tol: 'float' = 2.0, ratio: 'float' = 0.6, patch: 'int' = 11, block: 'int' = 8, step: 'int' = 1, n_dct: 'int' = 10, min_variance: 'float' = 0.0001, max_feature_dist: 'float' = 0.02, neighbours: 'int' = 2, ransac_thresh: 'float' = 3.0, ransac_iters: 'int' = 300, seed: 'int' = 0) -> 'list' (die Implementierung direkt: import imgforensics; imgforensics.copy_move_regions(image, method: 'str' = 'keypoint', min_matches: 'int' = 4, min_offset: 'float' = 16.0, offset_tol: 'float' = 2.0, ratio: 'float' = 0.6, patch: 'int' = 11, block: 'int' = 8, step: 'int' = 1, n_dct: 'int' = 10, min_variance: 'float' = 0.0001, max_feature_dist: 'float' = 0.02, neighbours: 'int' = 2, ransac_thresh: 'float' = 3.0, ransac_iters: 'int' = 300, seed: 'int' = 0) -> 'list'; aus dem Register: opsimgforensics.get("copy_move_regions"))
Paare von Copy-Move-(selbstduplizierten)Regionen innerhalb eines Bildes. table.
method="keypoint" (Default)
nimmt Ecken mit features.harris_corners,
erzeugt normierte Patch-Deskriptoren mit features.describe_patches
und bildet Korrespondenzen über den nächsten Nachbarn mindestens min_offset px von sich selbst entfernt und Lowes Ratio-Test
(_self_match). Die Korrespondenzen werden nach Verschiebungsvektor gebündelt, und für jede Gruppe
wird die geometrische Konsistenz mit mosaic.proj_match_points_ransac geprüft.
Eine Ähnlichkeitstransformation wird mit fit_transform.vector_to_similarity (Umeyama) angepasst und
in similarity abgelegt.
method="block"
Fridrich, Soukal & Lukáš 2003. Überlappende block-Quadrat-Blöcke werden im Abstand von step px
genommen (Default step=1 —— das ist keine Dekoration; siehe "Schrittweite" unten),
die tieffrequenten n_dct DCT-Koeffizienten jedes Blocks dienen als Merkmal und werden lexikografisch sortiert,
bis zu neighbours lexikografisch nahe Einträge werden Kandidaten, und nur jene mit Merkmalsabstand
höchstens max_feature_dist werden nach Verschiebungsvektor gezählt.
Es wirkt nicht gegen Drehung oder Skalierung, findet aber bei eckenarmen Bildern mehr als das keypoint-Verfahren.
Blöcke mit Varianz unter min_variance werden verworfen (gleichmäßiger Himmel auf Himmel kopiert ergibt dieselben Merkmale = Hauptursache der falsch positiven Treffer, die der Detektor zwangsläufig erzeugt).
Warum die Schrittweite (step) 1 ist (per Messung entschieden): Das Blockverfahren kann "dieselben Merkmale" nur finden, wenn Quelle und Ziel der Kopie auf demselben Raster liegen. Mit step=4 stimmt eine Kopie, deren Verschiebung kein Vielfaches von 4 ist (z. B. (110, 128)), prinzipiell nie überein. In Messungen lieferte step=4 nicht einmal 1 wahre Verschiebung, sondern stattdessen 60 falsche Gruppen. Mit step=1 kommt die wahre Verschiebung als Gruppe 1. Bei großen, schweren Bildern darf man step erhöhen, aber nur in dem Wissen, dass dann nur noch Verschiebungen gefunden werden, die Vielfache der erhöhten Schrittweite sind.
Die Rückgabe ist eine list von Bereichspaaren (absteigend nach Korrespondenzzahl). Jedes Element:
offset Verschiebung (dy, dx) (row, col). Die Richtung ist nach Position normiert
(die lexikografisch positive Richtung) —— per Index entschieden wäre dieselbe Kopie
sowohl (110, 128) als auch (-110, -128) (gemessen und behoben)
n_matches Korrespondenzzahl dieser Gruppe
n_inliers Anzahl der RANSAC-Inlier (bei method="block" gleich n_matches)
inlier_ratio Inlier-Anteil src_bbox / dst_bbox (r0, c0, r1, c1) src_points / dst_points (row, col) der Form (N, 2)
similarity per Umeyama angepasste 3x3 (nur method="keypoint", sonst None)
method das verwendete Verfahren
caveats was dieses Ergebnis nicht aussagen kann
Da die Lösung bekannt ist, ist das Treffen in Zahlen fixiert (tests/test_imgforensics.py::test_copy_move_finds_the_known_offset, ein 64x64-Stück bei (40, 32) eines 256x256-Texturbildes nach (150, 160) kopiert = wahre Verschiebung (110, 128)):
============ ================= ============ ========= ==============
method Offset Gruppe 1 n_matches Gruppen Fehler
============ ================= ============ ========= ==============
keypoint (110.0, 128.0) 15 1 0 px
block (110.0, 128.0) 3249 1 0 px
============ ================= ============ ========= ==============
Auch falsch positive Treffer sind gemessen: Bei 3 nicht manipulierten Bildern derselben Art liefern keypoint- wie block-Verfahren 0 Gruppen (seeds 4/5/6).
Was es nicht aussagen kann (alles im selben Test gemessen):
• Gleichmäßige Bereiche (Himmel, Wände) haben auch ohne Kopie dieselben Merkmale. Bei einem (nicht manipulierten) Bild, dessen obere Hälfte ein gleichmäßiger "Himmel" ist, ergeben min_variance=1e-4 und 1e-6 beide 0 Gruppen, aber mit min_variance=0 erscheint 1 falsche Gruppe mit 264 Paaren (Verschiebung (1, -247) = beliebige Korrespondenzen im Himmel).
• method="keypoint" nutzt normierte Patch-Deskriptoren und wirkt daher nicht gegen Drehung. Dreht man die Kopie vor dem Einfügen, ist die Gruppenzahl bei 0 Grad 1 → 5 Grad 0 → 15 Grad 0 → 30 Grad 0. Dass similarity mit einer Drehung zurückkommt, passiert praktisch nicht.
• Auch method="block" wirkt überhaupt nicht gegen Drehung (0 bei 5 Grad).
• Null Detektionen heißt nicht, dass keine Kopie existiert. Bei einer Kopie mit zwischengeschalteter Rekompression wächst der Merkmalsabstand und überschreitet max_feature_dist. Gemessen (dasselbe kopierte Bild vor der Detektion durch JPEG geschickt):
========== ============================ ==========================
Qualität keypoint Gruppe 1 n_matches block Gruppe 1 n_matches
========== ============================ ==========================
Unkompr. 15 3249
95 10 138
85 7 10
75 7 0 (keine Gruppe)
========== ============================ ==========================
Die Verschiebung bleibt bei jeder Qualität korrekt bei (110.0, 128.0). Was kaputtgeht, ist "ob es gefunden wird", nicht die Antwort, wenn es gefunden wird.
• 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.
• image_forensics_audit — py -3.11 examples/image_forensics_audit.py
• poc_forensics_roc — py -3.11 examples/poc_forensics_roc.py
table als Eingabe)copy_move)—
*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.