Skip to main content

Detects AI-generated or AI-edited images using signal-processing artifact analysis — no ML model.

Project description

Minosse

Detects AI-generated or AI-edited images using three complementary, hand-crafted artifact signals — no ML model, just signal processing.

Minosse looks for tell-tale traces that diffusion models and neural upsamplers leave behind: ringing halos around text, noise in flat regions that shouldn't have any, and a synthetic signature in the high-frequency spectrum.

Signals

Signal What it catches How it works
ringing Diffusion VAE decoder halos Radial profile of band-pass energy vs. distance from strong edges. Real edges decay fast; ringing persists 10–40 px out.
noisy-flats AI "film grain" on solid panels RMS residual noise inside coarse-flat regions. Real screenshots are truly flat; JPEG smooths photo flats.
synthetic-noise Upsampled / generated noise Spectral energy at the Nyquist ring vs. mid frequencies. Real sensor noise stays hot at the highest frequencies; synthetic noise dies off.

An image is flagged if any signal fires; the fired signals are reported along with the raw feature values.

Quick start

python -m venv .venv
.venv/bin/pip install -r requirements.txt

# Analyse a single image
.venv/bin/python -m minosse path/to/image.png

# Analyse multiple images with visual proof sheets
.venv/bin/python -m minosse --proof results/ image1.png image2.jpg

--proof output

The --proof flag writes <name>_proof.png: a side-by-side sheet with the original image next to one panel per fired signal, with the artifact evidence burned in as a red heatmap.

Heat is scaled absolutely (calibrated to the detection thresholds), so clean images render dark — the glow itself is the proof. For ringing, the map only shows oscillation in regions that should be smooth (8–40 px from strong edges, locally flat at coarse scale), so legitimate texture doesn't light up.

Python API

from minosse import analyze, analyze_path, Result

# From a file path
r = analyze_path("image.png")
print(r.verdict)       # "likely AI-generated/edited" or "likely clean"
print(r.reasons)       # e.g. ["ringing", "synthetic-noise"]
print(r.decay)         # ringing feature value
print(r.vhf_mf)        # spectral ratio feature value
print(r.flat_noise)    # flat-region noise feature value
print(r.resid_std)     # overall residual noise

# From a PIL Image
from PIL import Image
img = Image.open("image.png")
r = analyze(img)

Result fields

Field Type Description
verdict str "likely AI-generated/edited" or "likely clean"
reasons list[str] Fired signal names: ringing, noisy-flats, synthetic-noise
score float Confidence score [0, 1] (0.75 per firing signal, capped at 1.0)
decay float Ringing persistence: mid-distance / near-edge band energy
halo_vs_bg float Mid-distance energy vs. image background
vhf_mf float Spectral ratio: Nyquist ring / mid frequencies
resid_std float Standard deviation of the noise residual
flat_noise float RMS residual inside coarse-flat regions

Visual proof from Python

from minosse import analyze, evidence
from PIL import Image

img = Image.open("image.png")
r = analyze(img)
sheet = evidence.render(img, r)
sheet.save("proof.png")

Project structure

minosse/
├── minosse/
│   ├── __init__.py      # Public API: analyze, analyze_path, Result
│   ├── __main__.py      # python -m minosse entry point
│   ├── cli.py           # Argument parsing and CLI loop
│   ├── detector.py      # Feature extraction + threshold logic
│   └── evidence.py      # Visual proof sheet renderer
├── results/             # Default --proof output directory
├── requirements.txt     # numpy, pillow, scipy
└── README.md

How it works (briefly)

  1. Preprocessing — the image is converted to RGB and downscaled if its longest edge exceeds 1600 px.
  2. Feature extraction (detector._features()) — three independent signal-processing pipelines compute scalar features from the grayscale luminance.
  3. Thresholding — each feature is compared against a tuned threshold; if it exceeds the threshold the corresponding signal is flagged.
  4. Verdict — if any signal fires, the image is marked likely AI-generated/edited; otherwise it's likely clean.

For a deeper explanation of each signal, see docs/signals.md.

Caveats

The thresholds are calibrated on a small set of examples and should be re-validated as more AI samples are added. See docs/tuning.md for instructions on re-tuning.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

minosse-0.1.0.tar.gz (11.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

minosse-0.1.0-py3-none-any.whl (10.0 kB view details)

Uploaded Python 3

File details

Details for the file minosse-0.1.0.tar.gz.

File metadata

  • Download URL: minosse-0.1.0.tar.gz
  • Upload date:
  • Size: 11.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for minosse-0.1.0.tar.gz
Algorithm Hash digest
SHA256 e734b5d47fc398b7c2372fc03960877db639a6af0a048fdea63657584592b6a1
MD5 18d64a9e860b5b0a39057165c3b4bb52
BLAKE2b-256 7fa4c2c1a30f1ca5fad117efcd4ce6217fb2f66d7c7003e2f51414e36af9d2b7

See more details on using hashes here.

Provenance

The following attestation bundles were made for minosse-0.1.0.tar.gz:

Publisher: publish.yml on cesp99/Minosse

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file minosse-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: minosse-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 10.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for minosse-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 d4530ed8dbb3b2771181b4447d23a511d6ed7d76577a7661b1327d63fdc9f371
MD5 a8fbf3094f087721877cf9aeb79021ba
BLAKE2b-256 5fe0f2e4f2af6512d44a755beb683fbd2e845b4398d095cf40696264425cbb1d

See more details on using hashes here.

Provenance

The following attestation bundles were made for minosse-0.1.0-py3-none-any.whl:

Publisher: publish.yml on cesp99/Minosse

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page