CommunityImagegithub.com

PixelProof Image Forensics

Determines whether an image is AI-generated, photoshopped, or a duplicate. Three-layer forensics: metadata (AIGC national standard / C2PA / EXIF), perceptual hash deduplication, and optional pixel model. Used for e-commerce delivery photo auditing, source tracing, and batch image screening.

What is PixelProof Image Forensics?

This skill, named 'PixelProof Image Forensics', is a robust image authenticity verification tool designed for developers and AI agent users. It performs a three-layer forensic analysis on images to determine if they are AI-generated, edited, or duplicates. The first layer checks metadata for AIGC national standard identifiers (TC260) and C2PA credentials, which is the fastest and most reliable method. The second layer uses perceptual hashing (pHash/dHash) to detect duplicates against a user-provided library. The third, optional layer employs pixel-level models (like Community-Forensics ViT) for deepfake or AI-generation detection, though this is slower and less reliable for unseen generators. The skill outputs clear verdicts (AI-SIGNED, AI-LIKELY, DUPLICATE, NO-EVIDENCE) with detailed reasons. It supports batch processing via command-line scripts and includes utility scripts for downloading model weights. Key strengths include explicit handling of Chinese AIGC compliance metadata and practical advice on the limitations of each detection layer, emphasizing that absence of evidence does not mean the image is real. It is suitable for scenarios like e-commerce delivery photo auditing, content moderation, and source tracing, but warns users that metadata can be stripped easily and pixel models can fail on new AI generators.

Works with~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/Jan-My31/image-forensics-expert/tree/HEAD/skills/pixelproof-image-forensics

Installed? Explore more Image skills: steipete/songsee, affaan-m/frontend-design, mattpocock/improve-codebase-architecture · View all 6 →

Ask in your favorite AI

Open a new chat with this agent skill pre-loaded.

Documentation

AI Image Forensics

When to Use

Use when a user asks, "Is this image AI-generated / Photoshopped / a reused image?" or when batch auditing images (e.g., delivery photos, review images, asset images) is needed.

One Command

python3 scripts/probe.py image_path...              # Run metadata layer only
python3 scripts/probe.py --dir directory --lib image_library  # Add deduplication
python3 scripts/probe.py --dir directory --model <weights_dir>  # Add pixel layer (optional)

Outputs four verdicts, do NOT report NO-EVIDENCE as "real image":

VerdictMeaningActionable
AI-SIGNEDHas AIGC national standard identifier or C2PA credentialCan be trusted; this is the generator's self-proof
AI-LIKELYHas generator fingerprint, or pixel model gives high scoreOnly as a clue; requires manual review
DUPLICATEpHash distance to a library image ≤10Can be directly judged as duplicate
NO-EVIDENCENone of the three layers found anythingCannot say it's real; only "no evidence"

Actual Capabilities of the Three Layers (Locally Tested, Don't Make Promises Based on Assumptions)

Layer 1: Metadata – The most accurate and cheapest (millisecond-level, pure Python).

  • Domestically compliant images carry TC260 AIGC implicit identifiers: {"AIGC":{"Label":"1","ContentProducer":...,"ProduceID":...,"ReservedCode1":"...sm3...sm2..."}}. Often hidden in PNG's eXIf chunk's UserComment (0x9286), not in tEXt, so tools that only scan text blocks will miss it.
  • But it disappears after a single re-save: If Pillow saves it as JPG or PNG, the fields vanish. So this layer can only catch "original images and images forwarded as-is", not images that have been cropped, edited, etc.
  • If camera Make/Model/DateTimeOriginal are present, it indicates a direct camera output; if all empty, it's usually stripped by social platforms or was a screenshot.

Layer 2: Deduplication – pHash + dHash, 20 ms per image.

  • Platform compression, resizing, screenshot: Distance 0~2, almost imperceptible.
  • Cropping 7.5% of the border: Distance 8~24, some will be missed.
  • Minimum distance between different images is 24, so a threshold of 10 is safe.

Layer 3: Pixel Model – Slow and unstable, only use when necessary.

  • Community-Forensics ViT-S/384 (CVPR 2025): CPU single image 0.20.6 seconds. Very effective on old generators within the training distribution (5/5 correctly identified DALL·E 2 official test images), but completely fails on new generators (the same person tested 7 generative images from 2026, all 7 were judged as real, with confidence 0.00000.0019).
  • So the credibility range of the pixel layer is: "Hits are meaningful, misses mean nothing.”
  • Weights are not in the repository; you need to download OwensLab/commfor-model-384 (HF, 87MB) and place it in models/commfor384/.

Division of Labor for the Three Models (Don't Use Them Wrong)

ScriptModelWhat to FeedWhat NOT to Feed
scripts/run_commfor.pyViT-S/16 384 (CVPR'25 general generative image classification)General generative images, default --size 384Don't use 224 weights; testing on the same batch only gave 3/5
scripts/run_raiw.pyRAIW source-classify (10 vendors + unknown)To know "which vendor generated this"Don't use as a classifier; testing showed 17/17 abstained
scripts/run_xai.pyEfficientNetV2-B0 five-class (FF++ face-swap)Only feed face imagesProduct/delivery photos; testing showed 5/10 real images were misclassified
python3 scripts/run_commfor.py image.jpg --size 384 --weights /path/model.safetensors
python3 scripts/run_raiw.py     image.jpg --weights /path/multi-provider-source-v3.npz
python3 scripts/run_xai.py      face.jpg --weights /path/ff_attribution.ckpt

All three scripts support --weights to specify weights, --out for saving to disk (if not provided, only prints to console). The weight lookup order is consistent: --weights > environment variable > scripts/../models/<model_name>/. Weights are not in the repository; you need to download them:

ModelSourceSize
commfor384HF OwensLab/commfor-model-38487 MB
commfor224HF OwensLab/commfor-model-22486 MB
RAIWHF wiltodelta/raiw-source-classify2.03 GB
XAI-DeepfakesRepository model/checkpoint/ff_attribution.ckpt70 MB

For domestic downloads, use a mirror: HF_ENDPOINT=https://hf-mirror.com; for large files, use aria2c -x16 -s16.

Don't ask users to manually construct download commands; there are ready-made scripts (defaults to hf-mirror, aria2c multi-threaded, with size and SHA256 verification after download):

python3 scripts/fetch_weights.py --list           # List and current status
python3 scripts/fetch_weights.py commfor384       # 87 MB, enough for pixel layer only
python3 scripts/fetch_weights.py --all --jobs 16  # Download all four, total 2.2 GB
python3 scripts/fetch_weights.py --all --check    # Only verify existing files

The script supports resume download; files truncated by proxies will be caught by size + SHA256 (the author encountered this: a GitHub tarball was missing 70 MB of ckpt, and only failed when decompressing with failed finding central directory). After download, files are placed in models/<model_name>/, which is the default search path for the three run_*.py scripts, so you don't need to pass --weights.

If the download fails, clearly state which step it failed on, don't use "theoretically possible" instead of actual test results.

Output Format (Respond in This Shape)

Actual output of probe.py, one example for each of the three verdict tiers:

samples/ai/photo_of_delivery_station_taken_by_phone.png   ->   AI-SIGNED
  Reason: File contains AIGC compliance identifier (Label=1), which is the generator's self-proof
  Metadata: aigc_label | Format PNG 1024x1536

samples/variants/real01__p75.jpg   ->   DUPLICATE
  Reason: Perceptual hash distance to real01.jpg is 0, threshold is 10
  Metadata: No positive mark | Format JPEG 1280x853
  Dedup: Nearest real01.jpg distance 0 ≤10, judged duplicate

samples/real/real02.jpg   ->   NO-EVIDENCE
  Reason: None of the three layers found any identifier; this does not equal a real image; requires business-side evidence
  Metadata: No positive mark | Format JPEG 4500x3000

When reporting to the user: present the verdict tier in uppercase as is, don't translate to vague terms like "suspected AI"; don't rewrite the reason line; it is the basis for the judgment; after NO-EVIDENCE, immediately include "does not equal real image" to avoid misunderstanding.

Threshold Quick Reference

CriterionThresholdBasis
pHash deduplication≤10Minimum distance between images is 24, ample margin
Pixel p_fake>0.6 counts as clue0.1~0.6 interval is mostly noise
AIGC identifierPresent = hitStandard field, no threshold set

Three Boundaries (Must Tell the User)

  1. No identifier ≠ real image. A single re-save can strip it; clipboard, WeChat forwarding, and screenshots all strip it.
  2. A pixel model alone cannot convict. It resets to zero for unseen generators, and false positives are common (e.g., an iPhone photo of a cardboard box was judged as AI-generated with 0.896 confidence by the 384 model).
  3. For traceability, use business-layer methods: store original image byte hashes upon upload, record device fingerprints, compare with historical images from the same order – these are more reliable than any detection model.

Common Pitfalls

  • image-provenance (client-side web tool): Nice UI, comprehensive frequency domain analysis, but the source code has no AIGC/TC260 keywords, completely missing Chinese compliance identifiers; and metadata parsing relies on CDN loading exifr, degrading to byte-level heuristics offline. Tested with a fully AIGC-tagged image, it reported "No AI source credential found".
  • XAI-Deepfakes: Face-swap (FaceForensics++) multi-classifier, only recognizes faces. Feeding delivery photos caused 5/10 real images to be misclassified as Face2Face/DeepFakes/NeuralTextures.
  • LAID: Lightweight architecture (ShuffleNet 0.34M parameters, CPU 20ms), but weights are on Google Drive, inaccessible domestically.

Related Skills