Skip to content

Latest commit

 

History

4 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

image-matching-lab

Classical vs learned local features, measured on the same images with the same keypoint budget: SIFT · ORB · AKAZE against XFeat · DISK · ALIKED, on the Oxford-VGG affine sequences and HPatches.

Companion code for a three-part series on condados.ai.

Layout

image-matching-lab/
├── pyproject.toml              # uv package + [project.scripts] + ruff
├── src/image_matching_lab/
│   ├── config.py               # paths (project-root-aware) + dataset + RANSAC constants
│   ├── core/
│   │   ├── datasets.py         # Oxford-VGG + HPatches download, Pair enumeration
│   │   ├── backends.py         # Features dataclass + OpenCV backends + registry
│   │   ├── deep_backends.py    # kornia backends (XFeat, DISK, ALIKED)
│   │   ├── matching.py         # NN / mutual-NN / Lowe ratio + MAGSAC++ homography
│   │   ├── metrics.py          # corner error, AUC, precision against ground truth
│   │   └── viz.py              # keypoint + match drawing, GIF writing
│   └── cli/                    # one click command per file
│       ├── download.py extract.py match.py
└── output/                     # generated artifacts (dir kept, contents gitignored)

Setup

uv sync

Pipeline

# 1. Datasets. Oxford-VGG is ~40 MB total; HPatches is 1.19 GiB, so it is opt-in.
uv run iml-download                          # Oxford-VGG, all 8 sequences
uv run iml-download --sequences graf,bark    # just the ones you need
uv run iml-download --hpatches               # adds HPatches (slow)

# 2. Detect and describe. Writes a keypoint overlay to output/.
uv run iml-extract --backend sift --image data/oxford-affine/graf/img1.ppm

# 3. Match a ground-truth pair and score it against the known homography.
uv run iml-match --backend sift --sequence graf --difficulty 4
uv run iml-match --backend disk --sequence graf --difficulty 4            # auto-picks LightGlue
uv run iml-match --backend disk --sequence graf --difficulty 4 --matcher nn  # the wrong protocol

Two traps this code defends against

The ratio threshold is not transferable. Learned descriptors are L2-normalised, so their first/second-nearest ratios cluster near 1.0; SIFT's are unnormalised with a wide spread. Applying SIFT's classic 0.8 to DISK keeps zero matches on graf 1-4. Defaults are per-descriptor-family (config.DEFAULT_RATIOS) and the threshold used is always logged.

DISK and ALIKED need LightGlue. Same keypoints, only the matcher changes:

method NN + ratio 0.95 + LightGlue
DISK precision 0.08, corner error 366 px precision 0.67, corner error 4.16 px
ALIKED precision 0.10, corner error 6.59 px precision 0.70, corner error 3.11 px

--matcher auto (the default) gives each backend the matcher it was designed for. Exception: XFeat is 64-D and kornia 0.8.3's LightGlue configs expect 128-D/256-D, so XFeat runs on nearest neighbour — upstream pairs it with LighterGlue, which kornia does not expose. Any XFeat number here was produced without its own matcher.

OpenCV 5 notes

This project runs on OpenCV 5 and depends on opencv-contrib-python, not opencv-python. OpenCV 5 folded features2d into a new Features module and moved several classical detectors out to opencv_contrib:

main module cv2.* contrib cv2.xfeatures2d.*
kept / moved SIFT, ORB, FAST, GFTT, MSER, AffineFeature AKAZE, KAZE, BRISK, AGAST, SURF, DAISY, FREAK, BRIEF, LATCH, VGG, BEBLID, TEBLID, …
new in 5.0 ALIKED_create, DISK_create, LightGlueMatcher_create, ANNIndex_create (Annoy)

So pip install opencv-python on 5.x gives you no AKAZE at all. backends._create_akaze checks the main module first and falls back to contrib, so OpenCV 4 keeps working; on 4.14.0.94 and 5.0.0.93 AKAZE returns identical results here (273 matches, 62 inliers, 3.29 px corner error on graf 1-4).

Use the _create factories. cv2.xfeatures2d.AKAZE() — the bare constructor of the abstract class — segfaults the interpreter on 5.0.0.

Every command writes its artifacts to output/ and logs what it did with loguru. Nothing is cached silently: re-running overwrites.

Datasets

Dataset Content Ground truth Source
Oxford-VGG affine 8 scenes × 6 images (blur, viewpoint, zoom+rotation, lighting, JPEG) homographies 1→2..6 robots.ox.ac.uk
HPatches sequences 116 scenes × 6 images (illumination / viewpoint) homographies 1→2..6 HF mirror

Note: the HPatches URL printed in the paper and in most downstream repos (icvl.ee.ic.ac.uk) is dead — the hostname has no DNS record. The dataset lives on the Hugging Face mirror linked from the official repo, which is what iml-download --hpatches uses.

Neither page states an explicit licence. Images are downloaded at run time and are not redistributed in this repo.

Citation

  • K. Mikolajczyk et al. A comparison of affine region detectors. IJCV 65(1/2):43–72, 2005.
  • V. Balntas, K. Lenc, A. Vedaldi, K. Mikolajczyk. HPatches: A benchmark and evaluation of handcrafted and learned local descriptors. CVPR 2017. https://arxiv.org/abs/1704.05939
  • G. Potje, F. Cadar, A. Araujo, R. Martins, E. R. Nascimento. XFeat: Accelerated Features for Lightweight Image Matching. CVPR 2024. https://arxiv.org/abs/2404.19174

License

The code in this repository is licensed under the Apache License 2.0.

That covers this code and nothing else. Everything the pipeline downloads at run time carries its own terms, and some of them are more restrictive:

what where it comes from terms
XFeat weights verlab/accelerated_features Apache-2.0
DISK weights cvlab-epfl/disk Apache-2.0
ALIKED weights Shiaoming/ALIKED BSD-3-Clause
LightGlue weights fetched by kornia see kornia and upstream
Oxford VGG affine sequences robots.ox.ac.uk no licence stated on the source page
HPatches sequences Hugging Face mirror no licence stated on the source page

Neither dataset page declares an explicit licence, so treat both as academic-use images: this repository links to them and downloads them at run time rather than redistributing them. Check the terms yourself before any commercial use, and cite the papers listed in the README.

About

Classical vs learned local features measured on the same images: SIFT, ORB, AKAZE against XFeat, DISK and ALIKED with LightGlue, on the Oxford VGG affine sequences and HPatches. Companion code for the condados.ai articles.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages