Skip to main content

imgsym

Detect symmetry axes in images and score mirror symmetry along them. imgsym implements multiple algorithms from symmetry research — 4 detectors and 13 scorers — behind one small API, and benchmarks them head-to-head.

Installation

pip install imgsym

This covers the classical scoring methods and the nxc / xfeatures / r_lip detectors. Some methods pull optional extras:

pip install "imgsym[deep]"      # alexnet, deep_features
pip install "imgsym[wavelets]"  # wavelets detector
pip install "imgsym[all]"       # everything (+ numba speedups)

Quick start

import cv2
import imgsym

# find symmetry axes: (angles, midpoints, lengths, strengths), strongest first
img = cv2.imread("assets/butterfly.jpg")
bf_axes = imgsym.detect_axes(img, detector="nxc")
vis1 = imgsym.visualize(img, bf_axes)

# score mirror symmetry along an axis; higher = more symmetric
axis = imgsym.get_axis(bf_axes, 0)                # strongest detected axis
imgsym.score_along_axis(img, axis, method="hog")  # 0.89

# binary shape masks have their own detector
mask = cv2.imread("assets/synthetic_star.png", cv2.IMREAD_GRAYSCALE)
star_axes = imgsym.detect_axes_from_mask(mask, detector="r_lip", mode="multi", threshold=0.9)
vis2 = imgsym.visualize(cv2.cvtColor(mask, cv2.COLOR_GRAY2BGR), star_axes)
Detected symmetry axis on a natural image r_lip: five mirror axes of a star mask
natural image — nxc binary shape mask — r_lip

demo.ipynb reproduces every figure on this page and has more to play with.

Choosing a method

Detectors

Natural images — imgsym.detect_axes(image, detector=...)

Detection accuracy is competition-protocol max-F (a detected axis counts if its angle is within 10° of ground truth and its center lies on the true segment), measured on three annotated benchmarks with scripts/eval_detection_competition.py:

detector symComp17 NYU symComp13 speed (s/img) source
nxc 0.67 0.81 0.80 ~7 Cicconet et al. (2017)
xfeatures 0.59 0.74 0.57 0.05–0.2 Loy & Eklundh (2006)
wavelets 0.46 0.53 0.49 ~0.15 Elawady et al. (2017)

nxc leads on every benchmark — use it when accuracy matters; xfeatures is ~25× faster and the solid middle ground; wavelets trails clearly.

Binary shapes — imgsym.detect_axes_from_mask(mask, detector=...)

A different input domain, so not comparable above:

detector speed (s/img) source
r_lip <0.1 Nguyen et al. (2022)

Scorers

Numbers, not guesswork: skill is single-axis discrimination skill (2·AUC−1; 1 = perfect, 0 = chance) averaged over the four datasets of our benchmark (see Benchmark); speed is the median scoring time per crop on CPU. Scores are comparable within a method, not across methods.

Three methods share the top and are statistically close — deep_features (0.83), alexnet (0.81), hog (0.80). hog runs at 0.45 ms, ~20× faster than alexnet and ~370× faster than deep_features, which makes it the default choice; reach for deep_features when accuracy matters more than speed. Below the top tier there is a clear gap to gabor and the remaining classical measures.

scoring method skill speed (ms) source
deep_features 0.83 169 Brachmann & Redies (2016), generalized to modern backbones
alexnet 0.81 9.9 Brachmann & Redies (2016)
hog 0.80 0.45 Renero-C. et al. (2017)
gabor 0.71 14.9 Shaker & Monadjemi (2015)
gradient 0.67 0.72 Gnutti, Guerrini & Leonardi (2021)
multi_scale_gradient 0.65 0.36 multi-scale extension of the gradient measure
local_global 0.65 7.8 Hogeweg et al. (2017), "PatchNN"
sliding_window 0.65 0.07 windowed variant of pixel correlation
pixel_correlation 0.64 0.06 Mayer & Landwehr (2018)
phog 0.63 0.85 Renero-C. et al. (2017)
dct 0.61 0.15 Gunlu & Bilge (2009)
weighted_binary 0.58 0.05 Bauerly & Liu (2006)
eros 0.27 1.1 Smith & Jenkinson (1999)

Full citations live in each method's docstring (imgsym/scoring/calculators.py).

Where is it symmetric? (PatchNN heatmap)

The local_global scoring method matches every patch to its best mirror-twin on the other side of the axis. calculate_heatmap returns the per-patch match quality as a map about the vertical center column (aligned below is the image rotated so the detected axis is that center column — see the notebook).

calc = imgsym.SymmetryCalculatorFactory.create("local_global")
score, heatmap = calc.calculate_heatmap(aligned)   # (H, W) map of mirror-match quality
PatchNN local-symmetry map

Blue = high local symmetry, red = low: the mirrored wing bands read blue, while the gravel background is genuinely asymmetric and reads warm. (Butterfly photo from Wikimedia Commons.)

Benchmark

The skill numbers above come from the symmetry-scoring benchmark that ships in scripts/: every method ranks true symmetry axes against perturbed negatives on four annotated datasets (~3900 axis units), with derived results (leaderboards, ablations, timings) tracked under results/. The raw per-image score JSONs are not tracked — they regenerate deterministically (fixed seeds) from the datasets, whose sources and expected directory layout are documented in data/README.md:

python scripts/run_discrimination.py                    # single-axis protocol
python scripts/run_discrimination.py --protocol multi   # multi-axis protocol

The full protocol and analysis are described in the accompanying paper.

License

MIT — see LICENSE.

Metadata

Release files for imgsym 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for imgsym 0.1.0
File Size Uploaded Provenance Actions
imgsym-0.1.0.tar.gz 70.7 kB Without provenance Details for imgsym-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for imgsym 0.1.0
File Interpreter ABI Platform Actions
imgsym-0.1.0-py3-none-any.whl Python 3 none any Details for imgsym-0.1.0-py3-none-any.whl

Total release size: 141.8 kB

Release files / imgsym-0.1.0.tar.gz

Download URL imgsym-0.1.0.tar.gz
Size 70.7 kB
Tags Source
SHA-256 checksum
How to use checksums
569c8a8a4dabf474618258dbf8143df30ccc1e964446bb6b0fb50ec3be4d7ff1
BLAKE2b-256 checksum
How to use checksums
8feda45261c3528f6dd6826cc7c861a84875b4789ee5fb7a22d00a2f55a06125
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.13

Release files / imgsym-0.1.0-py3-none-any.whl

Download URL imgsym-0.1.0-py3-none-any.whl
Size 71.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
f98194596a6729e2876635d2b1a612054b69c28fb2713375cef85c67e73f27fb
BLAKE2b-256 checksum
How to use checksums
4908f28f41dec8a9fc70e3af49157196f299ea41d780cc3aee464e6af3a0c8c1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.13

Security for imgsym 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page