Enterprise-Grade Visual Anomaly Detection Toolkit with 120+ registry models and 80+ operations
Project description
Production-oriented visual anomaly detection for industrial inspection.
Image-level + Pixel-level · 120+ Models · Train → Deploy in one pipeline
Installation • Quickstart • Model Zoo • API • Benchmarking • Docs • Citation
Why pyimgano?
Most anomaly detection libraries target either research (maximizing paper metrics) or tabular data (PyOD-style). pyimgano bridges the gap for teams that need to go from algorithm selection to production deployment on real industrial images:
| Research libs | Tabular AD (PyOD…) | pyimgano | |
|---|---|---|---|
| Image-level scoring | ✓ | ✓ | ✓ |
| Pixel-level anomaly maps | ✓ | — | ✓ |
| Industrial IO (numpy, tiling, formats) | — | — | ✓ |
| Deploy bundles (ONNX / OpenVINO) | partial | — | ✓ |
| Reproducible CLI + audit trail | — | — | ✓ |
| 120+ unified model registry | — | ✓ | ✓ |
| Synthetic anomaly generation | — | — | ✓ |
✨ Key Features
|
🧠 Unified Model Registry
|
🔍 Image + Pixel Anomaly Detection
|
|
⚡ Production CLI Pipeline
|
🚀 Deploy-ready Inference
|
🏗️ Architecture
Pipeline flow (Mermaid)
graph LR
A[📁 Images / NumPy] --> B[Preprocessing]
B --> C[Feature Extraction]
C --> D[Model Zoo<br/>120+ Detectors]
D --> E[Calibration]
E --> F{Output}
F --> G[🎯 Anomaly Score]
F --> H[🗺️ Pixel Map]
F --> I[🔲 Defect Regions]
F --> J[📄 JSONL Report]
style A fill:#1e293b,stroke:#38bdf8,color:#e2e8f0
style B fill:#1e293b,stroke:#38bdf8,color:#e2e8f0
style C fill:#1e293b,stroke:#818cf8,color:#e2e8f0
style D fill:#1e293b,stroke:#f472b6,color:#e2e8f0
style E fill:#1e293b,stroke:#fb923c,color:#e2e8f0
style F fill:#0f172a,stroke:#34d399,color:#e2e8f0
style G fill:#1e293b,stroke:#34d399,color:#e2e8f0
style H fill:#1e293b,stroke:#34d399,color:#e2e8f0
style I fill:#1e293b,stroke:#34d399,color:#e2e8f0
style J fill:#1e293b,stroke:#34d399,color:#e2e8f0
📦 Installation
pip install pyimgano
Install from source (latest dev)
git clone https://github.com/skygazer42/pyimgano.git
cd pyimgano
pip install -e ".[dev]"
Optional extras
pip install "pyimgano[torch]" # PyTorch deep backends + TorchScript export
pip install "pyimgano[onnx]" # ONNX runtime
pip install "pyimgano[openvino]" # OpenVINO runtime
pip install "pyimgano[skimage]" # scikit-image baselines (SSIM/HOG/LBP/Gabor…)
pip install "pyimgano[numba]" # Numba-accelerated baselines
pip install "pyimgano[viz]" # matplotlib / seaborn plots
pip install "pyimgano[diffusion]" # Diffusion-based methods
pip install "pyimgano[clip]" # OpenCLIP backends
pip install "pyimgano[faiss]" # Faster kNN for memory-bank methods
pip install "pyimgano[anomalib]" # Anomalib checkpoint wrappers
pip install "pyimgano[backends]" # clip + faiss + anomalib
pip install "pyimgano[all]" # Everything
See docs/OPTIONAL_DEPENDENCIES.md for the full extras map.
🚀 Quickstart
Python API — 5 lines to detect
from pyimgano.models import create_model
detector = create_model("vision_patchcore", device="cuda")
detector.fit(train_paths) # normal/reference images
scores = detector.decision_function(test_paths) # anomaly scores
Classical baseline (CPU, no pixel maps)
from pyimgano.models import create_model
from pyimgano.utils import ImagePreprocessor
extractor = ImagePreprocessor(resize=(224, 224), output_tensor=False)
detector = create_model("vision_ecod", feature_extractor=extractor, contamination=0.1, n_jobs=-1)
detector.fit(train_paths)
scores = detector.decision_function(test_paths)
labels, confidence = detector.predict(test_paths, return_confidence=True)
NumPy-first industrial inference
import numpy as np
from pyimgano.inference import calibrate_threshold, infer
from pyimgano.inputs import ImageFormat
train_frames = [np.zeros((64, 64, 3), dtype=np.uint8) for _ in range(8)]
detector.fit(train_frames)
calibrate_threshold(detector, train_frames, input_format=ImageFormat.RGB_U8_HWC, quantile=0.995)
results = infer(detector, test_frames, input_format=ImageFormat.RGB_U8_HWC, include_maps=True)
print(results[0].score, results[0].label)
CLI — End-to-end pipeline
# 1. Quick demo (creates dataset + runs suite + exports tables)
pyimgano-demo
# 2. Environment check
pyimgano-doctor --suite industrial-v4
# 3. Train → export infer config
pyimgano-train \
--config examples/configs/industrial_adapt_defects_fp40.json \
--export-infer-config
# 4. Inference → JSONL + defect masks
pyimgano-infer \
--infer-config /path/to/run_dir/artifacts/infer_config.json \
--input /path/to/images \
--defects \
--save-masks /tmp/pyimgano_masks \
--save-jsonl /tmp/pyimgano_results.jsonl
The JSONL output carries stable deployment metadata for downstream systems, including
decision_summary on each success record; Python best-effort batch integrations also
receive a triage_summary aggregate from run_continue_on_error_inference(...).
One-off inference (no workbench)
pyimgano-infer \
--model vision_patchcore \
--preset industrial-balanced \
--device cuda \
--train-dir /path/to/normal/train_images \
--calibration-quantile 0.995 \
--input /path/to/images \
--include-maps
Pass extra kwargs via --model-kwargs '{"backbone":"wide_resnet50","coreset_sampling_ratio":0.1}'.
Model discovery
pyimgano --list models
pyimgano list models
pyimgano -- list models --json
pyimgano --list models --family patchcore
pyimgano --list preprocessing --deployable-only
pyim --list models
pyim --list models --family patchcore
pyim --list models --year 2021 --type deep-vision
pyim --list models --type flow-based
pyim --list preprocessing --deployable-only
pyimgano is now the umbrella CLI. pyimgano list ... and pyimgano -- list ...
map to the same discovery flow as pyimgano --list .... pyim remains the
shorter discovery alias.
Shortest audited operator path
If you want the shortest “train -> validate -> gate” path for production-style handoff, the root CLI now exposes it directly:
pyimgano --help
pyimgano -- list preprocessing --deployable-only
pyimgano train --config examples/configs/industrial_adapt_audited.json --export-infer-config --export-deploy-bundle
pyimgano validate-infer-config runs/<run_dir>/deploy_bundle/infer_config.json
pyimgano runs quality runs/<run_dir> --require-status audited --json
pyimgano runs acceptance runs/<run_dir> --require-status audited --check-bundle-hashes --json
pyimgano weights audit-bundle runs/<run_dir>/deploy_bundle --check-hashes --json
That flow uses the checked-in
industrial_adapt_audited.json
example and is described in more detail in
docs/INDUSTRIAL_FASTPATH.md.
For reproducible benchmark reporting, pair that operator loop with the built-in official preset discovery and publication gate:
pyimgano benchmark --list-official-configs
pyimgano benchmark --official-config-info official_mvtec_industrial_v4_cpu_offline.json --json
pyimgano runs acceptance /path/to/suite_export --json
pyimgano runs publication /path/to/suite_export --json
That keeps the shortest industrial fast-path and the publication path visible from the same umbrella CLI entrypoint.
If your deploy bundle carries model_card.json and weights_manifest.json,
pyimgano weights audit-bundle ... gives you a single delivery gate for both.
If you want one aggregated release check instead of calling the low-level
validators individually, use pyimgano runs acceptance ...; it now auto-routes
run directories and suite publication exports through the matching gate.
For suite exports, the publication gate now also enforces benchmark provenance
(benchmark_config.source + sha256), evaluation_contract, and citation
instead of trusting a manually stamped publication_ready=true.
It also expects audit refs back to report.json, config.json, and
environment.json, plus matching sha256 digests for those files, so exported
leaderboards remain traceable to the saved run. The exported leaderboard tables
themselves now carry recorded sha256 digests too, so leaderboard.csv,
best_by_baseline.csv, skipped.csv (and markdown variants when exported)
are verified before a suite export is treated as publication-ready.
🧠 Model Zoo
pyimgano ships 120+ registered model entry points spanning classical statistics to modern vision-language models.
Algorithm Capability Matrix
Recommended Baselines
| Goal | Model | Tags | Notes |
|---|---|---|---|
| 🎯 Strong pixel localization | vision_patchcore |
numpy,pixel_map |
Best default for MVTec/VisA-style data |
| 🛡️ Robust to noisy normals | vision_softpatch |
numpy,pixel_map |
Filters outlier patches in memory bank |
| 🪶 Lightweight pixel baseline | vision_padim / vision_spade |
numpy,pixel_map |
Simpler, easier to tune |
| 📸 Few-shot / small normal set | vision_anomalydino |
numpy,pixel_map |
DINOv2-based, downloads weights on first run |
| 💻 CPU-only / precomputed | vision_ecod / vision_copod |
classical |
Fast, parameter-free, score-only |
| 🔌 Anomalib integration | vision_*_anomalib |
deep |
Requires pyimgano[anomalib] |
Full algorithm taxonomy
| Category | Type | Algorithms | Count |
|---|---|---|---|
| Statistical | Density / Distribution | ECOD, COPOD, HBOS, KDE, GMM, MCD, QMCD | 24 |
| Proximity | Neighbor-based | KNN, LOF, COF, LDOF, ODIN, INNE, LoOP | 18 |
| Subspace | Projection | PCA, KPCA, SOD, ROD, LODA | 8 |
| Tree / Graph | Isolation | Isolation Forest, RRCF, HST, MST, R-Graph | 10 |
| Ensemble | Multi-detector | Feature Bagging, LSCP, SUOD, Score Ensemble | 6 |
| Memory Bank | Patch-based deep | PatchCore, PaDiM, SPADE, SoftPatch, MemSeg | 12 |
| Student-Teacher | Knowledge distill | STFPM, Reverse Distillation, EfficientAD, AST | 8 |
| Flow-based | Normalizing flows | FastFlow, CFlow, CS-Flow | 6 |
| Reconstruction | AE / VAE | AE, VAE, VQ-VAE, DRAEM, DFM | 10 |
| VLM / Zero-shot | Vision-Language | WinCLIP, AnomalyDINO, PromptAD | 6 |
| Template | Pixel statistics | SSIM, NCC, Phase correlation, Pixel Gaussian | 8 |
| Industrial | Pipeline wrappers | ResNet18, ONNX, TorchScript pipelines | 14+ |
📖 See
docs/ALGORITHM_SELECTION_GUIDE.mdfor a detailed decision flowchart.
📋 API Cheatsheet
from pyimgano.models import create_model, list_models
# ╭──────────────────────────────────────────────╮
# │ Discovery │
# ╰──────────────────────────────────────────────╯
list_models() # all registered names
list_models(tags=["vision", "pixel_map"]) # filter by tags
# ╭──────────────────────────────────────────────╮
# │ Core detector API │
# ╰──────────────────────────────────────────────╯
detector = create_model("vision_patchcore", device="cuda", contamination=0.1)
detector.fit(X_train) # train on normal images
scores = detector.decision_function(X) # → np.ndarray of anomaly scores
labels = detector.predict(X) # → 0 (normal) / 1 (anomaly)
labels, conf = detector.predict(X, return_confidence=True)
# ╭──────────────────────────────────────────────╮
# │ Pixel-level (models with pixel_map tag) │
# ╰──────────────────────────────────────────────╯
anomaly_map = detector.predict_anomaly_map(image) # → H×W float array
# ╭──────────────────────────────────────────────╮
# │ Industrial inference │
# ╰──────────────────────────────────────────────╯
from pyimgano.inference import infer, calibrate_threshold
from pyimgano.inputs import ImageFormat
calibrate_threshold(detector, X_train, input_format=ImageFormat.RGB_U8_HWC, quantile=0.995)
results = infer(detector, X_test, input_format=ImageFormat.RGB_U8_HWC, include_maps=True)
# results[i].score, results[i].label, results[i].anomaly_map
# ╭──────────────────────────────────────────────╮
# │ Evaluation │
# ╰──────────────────────────────────────────────╯
from pyimgano import evaluate_detector, compute_auroc
metrics = evaluate_detector(detector, X_test, y_test) # full report
auroc = compute_auroc(y_true, scores) # single metric
📊 Benchmarking
Run curated baseline suites with a single command and get aggregated leaderboard tables:
# Discover suites
pyimgano-benchmark --list-suites
pyimgano-benchmark --suite-info industrial-v4 --json
# Run a suite
pyimgano-benchmark \
--dataset mvtec --root /path/to/mvtec_ad --category bottle \
--suite industrial-v4 --device cpu --no-pretrained \
--suite-export both --output-dir /tmp/suite_run
# Optional: small grid search
pyimgano-benchmark \
--dataset mvtec --root /path/to/mvtec_ad --category bottle \
--suite industrial-v4 --suite-sweep industrial-template-small \
--suite-sweep-max-variants 1 --suite-export csv \
--output-dir /tmp/suite_sweep
Run comparison
pyimgano-runs list --root runs
pyimgano-runs list --root runs --kind robustness --same-robustness-protocol-as runs/run_a --json
pyimgano-runs compare runs/run_a runs/run_b --json
pyimgano-runs compare runs/run_a runs/run_b --baseline runs/run_a --require-same-split --json
pyimgano-runs compare runs/run_a runs/run_b --baseline runs/run_a --require-same-robustness-protocol --json
pyimgano-runs acceptance /path/to/suite_export --json
pyimgano-runs publication /path/to/suite_export --json
Some suite entries are optional and are skipped if extras are missing (with hints like
pip install 'pyimgano[torch]'). For reproducible publications, use built-in official presets via--config official_mvtec_industrial_v4_cpu_offline.json.
🎨 Synthetic Anomaly Generation
When real defects are scarce, generate controlled synthetic anomalies for smoke tests, robustness checks, and pixel-mask pipelines:
pyimgano-synthesize \
--in-dir /path/to/normal_images \
--out-root ./out_synth_dataset \
--category synthetic_demo \
--presets scratch stain tape edge_wear \
--roi-mask /path/to/roi_mask.png \
--blend alpha --alpha 0.9 \
--n-train 50 --n-test-normal 20 --n-test-anomaly 20 \
--seed 0
Supported presets: scratch · stain · tape · edge_wear · Perlin noise · CutPaste · custom
📖 Guide:
docs/SYNTHETIC_ANOMALY_GENERATION.md
🏭 Industrial Outputs (Defects)
When --defects is enabled, pyimgano-infer derives structured defect information from the anomaly map:
graph LR
A[Anomaly Map] --> B[Threshold]
B --> C[Binary Mask]
C --> D[Morphology<br/>open / close / fill]
D --> E[Connected Components]
E --> F[Defect Regions]
F --> G["area · bbox · score"]
F --> H[ROI Gating]
style A fill:#1e293b,stroke:#f472b6,color:#e2e8f0
style C fill:#1e293b,stroke:#818cf8,color:#e2e8f0
style F fill:#1e293b,stroke:#34d399,color:#e2e8f0
- Binary defect mask — optional artifact output
- Connected-component regions — area, bbox, per-region score
- ROI gating — only flag defects inside the region of interest
- Morphology — open/close/fill holes to reduce noise
- Stable triage metadata — per-record
decision_summaryfor review routing and low-confidence rejection handling
📖 Guides:
docs/INDUSTRIAL_INFERENCE.md·docs/FALSE_POSITIVE_DEBUGGING.md
🔧 CLI Reference
| Command | Purpose |
|---|---|
pyimgano |
Top-level umbrella CLI (pyimgano --help, pyimgano list models) |
pyimgano-demo |
Quick end-to-end demo |
pyimgano-doctor |
Environment & dependency check |
pyimgano-train |
Train + export infer_config.json |
pyimgano-infer |
Inference → JSONL + masks |
pyimgano-benchmark |
Suite / sweep benchmarking |
pyimgano-synthesize |
Synthetic anomaly generation |
pyimgano-runs |
Run listing & comparison |
pyimgano-weights |
Weight manifest & model cards |
pyimgano-features |
Feature extraction utilities |
pyimgano-datasets |
Dataset management |
pyimgano-defects |
Defect post-processing |
pyim |
Unified discovery (pyim --list models) |
📖 Full reference:
docs/CLI_REFERENCE.md
pyimgano-runs quality, pyimgano-runs acceptance, and pyimgano-runs publication now expose structured
trust metadata as well:
trust_summaryfor saved run artifactstrust_signalsfor suite publication bundles
This makes it easier to gate CI/release automation on auditable machine-readable signals instead of parsing free-form warnings.
⚖️ Weights & Cache Policy
pyimganodoes not ship model weights inside the wheel.- Weights are cached by upstream libraries (torchvision / OpenCLIP / HuggingFace).
- Set cache env vars on servers:
TORCH_HOME,HF_HOME,XDG_CACHE_HOME
# Auditable weight management
pyimgano-weights template manifest > ./weights_manifest.json
pyimgano-weights validate ./weights_manifest.json --check-files --json
📚 Documentation
|
Getting Started |
Industrial / Production |
Reference |
🤝 Contributing
We welcome contributions! Please see:
CONTRIBUTING.md— development workflowCODE_OF_CONDUCT.mdSECURITY.md
📄 License
📝 Citation
GitHub citation metadata is provided via CITATION.cff.
@software{pyimgano2026,
author = {PyImgAno Contributors},
title = {pyimgano: Production-oriented Visual Anomaly Detection},
year = {2026},
url = {https://github.com/skygazer42/pyimgano}
}
Made with care for industrial inspection teams.
⭐ Star us on GitHub
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pyimgano-0.7.1.tar.gz.
File metadata
- Download URL: pyimgano-0.7.1.tar.gz
- Upload date:
- Size: 1.8 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.9.25
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
62207573fd0a5b3ce0af40704c8d11eb2763674100bd69abf97899996ff8f141
|
|
| MD5 |
8a027f2f80efa6d3ce8d2afddd0448d5
|
|
| BLAKE2b-256 |
0998b0ffdbba5b2ddd1aa755eaa9a94701ca789f4e0830bea0de502b1b2cdc62
|
File details
Details for the file pyimgano-0.7.1-py3-none-any.whl.
File metadata
- Download URL: pyimgano-0.7.1-py3-none-any.whl
- Upload date:
- Size: 1.2 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.9.25
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f6ed1a1d2a80f24a562d6d0e252bb3a5683166b6fd9ab6996e743634387789d9
|
|
| MD5 |
19add474df4b926cbb171fb31a03017d
|
|
| BLAKE2b-256 |
838d21e77faf89cbbc1cd575d9d3b36125c8c36c89bae7fc21bd09de679a57e6
|