Skip to main content

Image symmetry detection and measurement toolkit

Project description

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 imagesimgsym.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 shapesimgsym.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.

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

imgsym-0.1.0.tar.gz (70.7 kB view details)

Uploaded Source

Built Distribution

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

imgsym-0.1.0-py3-none-any.whl (71.0 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: imgsym-0.1.0.tar.gz
  • Upload date:
  • Size: 70.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.13

File hashes

Hashes for imgsym-0.1.0.tar.gz
Algorithm Hash digest
SHA256 569c8a8a4dabf474618258dbf8143df30ccc1e964446bb6b0fb50ec3be4d7ff1
MD5 9e65b02122c491387b4aa901eae62234
BLAKE2b-256 8feda45261c3528f6dd6826cc7c861a84875b4789ee5fb7a22d00a2f55a06125

See more details on using hashes here.

File details

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

File metadata

  • Download URL: imgsym-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 71.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.13

File hashes

Hashes for imgsym-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 f98194596a6729e2876635d2b1a612054b69c28fb2713375cef85c67e73f27fb
MD5 df4b0e0d1804705d98912bda66a4ca5d
BLAKE2b-256 4908f28f41dec8a9fc70e3af49157196f299ea41d780cc3aee464e6af3a0c8c1

See more details on using hashes here.

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