CLI and Python package for bird photo detection, species classification, and XMP region tagging.
Project description
Detect birds in JPGs or common RAW formats (NEF/CR2/ARW/CR3/DNG), tag them with accurate species labels, and write MWG region metadata. Snipe is ready to use out of the box, runs fast locally, and is tuned for high classification accuracy.
Quick Start
pipx install "snipe-cli[cpu]"
# init will create config and download models.
snipe init
snipe ./path/to/photos
Install
Prerequisites:
- Python 3.12 or newer.
- ONNX models are downloaded on demand into the user model cache: Windows
%APPDATA%\.snipe\models, Linux/macOS~/.config/.snipe/models. - Labels, taxonomy, and GPS filter data remain packaged under
snipe/resources/.
Install from PyPI with pipx:
pipx install "snipe-cli[cpu]"
If pipx is not using Python 3.12+, select the interpreter explicitly:
pipx install --python python3.12 "snipe-cli[cpu]"
Install from PyPI with pip:
python -m pip install "snipe-cli[cpu]"
For the GPU runtime build, install snipe-cli[gpu] instead.
Install from source:
git clone https://github.com/woolen-sheep/snipe.git
cd snipe
uv sync --extra cpu
After syncing from source, activate the virtual environment or prefix runtime commands with uv run while working from the checkout.
For the GPU runtime build from source, install with:
uv sync --extra gpu
Snipe ships as a single package. The cpu extra installs onnxruntime, while the gpu extra installs onnxruntime-gpu.
Run snipe init once if you want to create the default config file and pre-download the managed detector/classifier models before the first processing run.
At runtime Snipe detects which ONNX Runtime package is installed and prefers CUDAExecutionProvider automatically when the GPU package and CUDA runtime dependencies are available. If CUDA cannot be initialized, Snipe falls back to CPUExecutionProvider.
The gpu extra does not bundle NVIDIA system libraries by itself. You still need a compatible local CUDA Toolkit and cuDNN installation for onnxruntime-gpu.
For the GPU extra on Windows, make sure the system runtime dependencies required by your onnxruntime-gpu build are installed and visible on PATH. The current setup was validated with CUDA 12 and cuDNN 9.
Config File
Most workflows do not require a config file. Run snipe init to create the default config file and download the managed models. Snipe reads its default config from:
- Windows:
%APPDATA%\.snipe\config.yaml - Linux/macOS:
~/.config/.snipe/config.yaml
Managed models are stored separately under:
- Windows:
%APPDATA%\.snipe\models - Linux/macOS:
~/.config/.snipe/models
For a full example configuration, see config.example.yaml.
You can also keep a config file anywhere and pass it explicitly:
snipe --config .\config.example.yaml .\photos
Detailed Usage
Core commands:
snipe <file-or-directory> [options]
snipe init
snipe clear <directory> [--workers N]
snipe preview <file-or-directory>
python -m snipe <file-or-directory> [options]
Output
- Adds classification labels to
XMP:SubjectandXMP:HierarchicalSubject. - Writes each bird crop as an
mwg-rs:RegionListentry with normalized rectangle coordinates.
Preview Mode
snipe preview <path>opens a pywebview window that shows one image at a time.- Uses arrow keys or on-screen buttons to move between images; scroll to zoom and drag to pan.
- Reads XMP MWG Region metadata and overlays boxes and labels on top of the image.
Clear Mode
snipe clear <directory>removes only the XMP fields managed by Snipe from supported images under that directory.- The clear command writes empty keyword and MWG region values through
exifmwgso the clear behavior can be validated against real files. - The command accepts a directory path only, supports
--workersfor parallel clears, and logs each clear normally.
Key Options
-o, --output-dircopy images there before tagging; omit to write in place.- Supports JPG plus RAW files such as
.nef,.cr2,.cr3,.arw,.orf,.rw2,.raf,.dng,.pef,.sr2. --confconfidence threshold for bird detection (default 0.35).--workersnumber of parallel threads.--detector-modelpath to a local YOLO ONNX detector model; omit it to use the managed model downloaded into the user cache.--detector-merge-overlap-thresholdoverlap ratio used by the detector post-processing merge heuristic (default 0.7).--detector-min-box-area-ratiominimum box area as a fraction of the largest detected box; smaller boxes are dropped (default 0.05).--gps-filter/--no-gps-filterenable or disable GPS-based species filtering (default enabled).--gps-filter-datapath to the JSON GPS filter data used for in-memory species filtering.--region-filterforce filtering by a specific region code such asCNorCN-11; this implies location filtering automatically.--languagecommon-name language enum; supported values areCNandUS(defaultCN).--classifier-modelpath to the ONNX classifier.--labelslabels file for classification.--taxonomypath to the merged common-name CSV withCOMMON_NAME_ZH_CNandCOMMON_NAME_UScolumns.initcreates the default config if missing and downloads the managed ONNX models if they are missing or fail checksum validation.--log-levellogging level; leave it unset or set it tonull/nonein process mode to use the cross-workertqdmprogress UI instead of log lines.--dry-runskip EXIF writes while running detection/classification.
Python API
Snipe also exposes an importable API for single-image inference. The public entrypoint returns a typed list[BirdDetection] and supports both region_code and language_code parameters.
from snipe import detect_birds
results = detect_birds(
r"D:\photos\bird.jpg",
region_code="CN",
language_code="CN",
)
for item in results:
print(item.bird_name, item.species_code, item.score, item.bbox.as_tuple())
API notes:
detect_birds(...)accepts a local file path, raw image bytes,io.BytesIOor another binary file-like object, aPIL.Image.Image, anumpy.ndarrayRGB image, or afile:///http(s)://URL.- Each
BirdDetectionitem containsbird_name,species_code,score,bbox,image_width, andimage_height. bboxis a typedBoundingBoxobject withleft,top,right,bottom,width,height, andas_tuple().- When
imageis a local file path orfile://URL andregion_codeis omitted, the API can use embedded GPS metadata for species filtering just like the CLI.
Developer Notes
Project Layout
- Runtime package code lives under
snipe/. - Packaged runtime support assets live under
snipe/resources/andsnipe/web/. - Repository-level
data/is kept as editable source/reference input for now. - Local ONNX model source files live under
local_models/and are published separately through GitHub Releases. - Developer helper scripts live under
tools/.
Runtime Notes
- Detector and classifier ONNX models are downloaded lazily from the dedicated model release tag into the user model cache when they are missing.
- ONNX Runtime provider selection is automatic:
snipe-cli[cpu]runs onCPUExecutionProvider, whilesnipe-cli[gpu]attemptsCUDAExecutionProviderfirst and falls back to CPU if the CUDA stack is unavailable. - GPS species filtering uses the packaged
snipe/resources/location_species_filter.jsonartifact and preloads the filter data into memory at startup. - The GPS filter performance and CLI cleanup proposal is documented in
docs/gps-filter-optimization-plan.md.
YOLO ONNX Export
If you need to convert local .pt YOLO weights into ONNX files, use the tool script with temporary export-time dependencies:
uv run --with ultralytics --with onnx python tools/export_yolo_onnx.py
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 snipe_cli-0.1.1a1.tar.gz.
File metadata
- Download URL: snipe_cli-0.1.1a1.tar.gz
- Upload date:
- Size: 637.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d72805898c681a605a68bb29841d962a7e06e037ad3c48178d25fe1eda085945
|
|
| MD5 |
c44df62c9d12b4c42b384fc9b4cfdd64
|
|
| BLAKE2b-256 |
dfe0b74e1198154f5a222ec981e6e91458c936896a74dbdb9ba4518bb19fe3ba
|
File details
Details for the file snipe_cli-0.1.1a1-py3-none-any.whl.
File metadata
- Download URL: snipe_cli-0.1.1a1-py3-none-any.whl
- Upload date:
- Size: 637.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cad6af9232a5879ce200f52ac87ff13b690d06ee25cb66384742d220840093a6
|
|
| MD5 |
8102097ae0ad16332ce3d26b8e7a040f
|
|
| BLAKE2b-256 |
0947016eb0859430ace6f5a7332bbdf79f8c0c1a64b1c53ba1e581b126d0ef82
|