[](https://www.python.org/)
| Sr | Scene | **Block matching** | SIFT + similarity | ORB + similarity | SIFT + translation | SIFT blobs (no verify) |
|---|---|---|---|---|---|---|
| 1 | penguin on pebbles · every stone resembles every stone | **1.000** | 0.855 | 0.854 | 0.851 | 0.748 |
| 2 | fighter jet · man-made straight edges | **1.000** | 0.873 | 0.868 | 0.860 | 0.789 |
| 3 | elephant herd · genuinely repeated objects | **1.000** | 0.861 | 0.845 | 0.848 | 0.836 |
| 4 | tortoise on rock · broken rock texture | **1.000** | 0.843 | 0.661 | 0.842 | 0.798 |
`mermaid flowchart LR A[Clean photo] --> B["Copy a TEXTURED patch
rotate / rescale it
paste it elsewhere"] B --> C[Exact mask of BOTH copies] B --> D1[Block matching] B --> D2[SIFT / ORB self-match] D2 --> E{Verify what
hypothesis?} E -->|nothing| F1[Paint blobs] E -->|a shift| F2[Translation verify] E -->|shift + rotate + scale| F3[Similarity verify] D1 & F1 & F2 & F3 --> G[Score vs BOTH copies] C --> G A2[UNTAMPERED photos] --> D1 & F1 & F2 & F3 D1 & F1 & F2 & F3 --> H[False alarms:
what does it accuse
a clean photo of?]
style C fill:#fef3c7,stroke:#d97706 style E fill:#dbeafe,stroke:#2563eb style H fill:#fee2e2,stroke:#dc2626 `
Two design choices carry the whole project:
The truth mask marks both copies (amber). After the paste, the source and the destination are *identical* — same content, same noise, same compression. Nothing in the image says which one came first. A detector that finds a duplicated pair has done its job; deciding which half is the forgery needs information the pixels do not contain (lighting direction, perspective, a second photograph). Scoring against the pasted region alone caps precision at about 0.5 for every method and measures that ambiguity instead of the detector.
Untampered images are scored too (red). A detector that marks part of every photograph you feed it is not a detector. On a clean image IoU, precision and recall are all undefined — the truth is empty — so the only honest number is the fraction of pixels flagged, and it should be zero. This is where the rotation-robust methods stop looking free.
---





Code and full results on GitHub (code private)
Every number is read from the file the run produced. github.com/hammasbuilds · kaggle.com/muhammadhammas13