imret
imret is a C++ image retrieval library. Given a query image, it finds the closest matching image from a previously ingested collection. It uses ORB binary feature descriptors and a FAISS inverted-file index (IVF) for approximate nearest-neighbour search, with a two-tier search strategy and per-keypoint voting to produce a confidence score.
How it works
- Feature extraction — ORB extracts up to
max_featureskeypoints per image, each producing a 256-bit (32-byte) binary descriptor. - Indexing —
build()runs k-means on all accumulated descriptors to partition them into Voronoi cells (IndexBinaryIVF). The number of cells scales with the total feature count. - Search — A query image is described with ORB. Each descriptor votes for the image it matches (filtered by Hamming distance). Tier 1 searches
fast_cellscells; if the top vote fraction falls belowconfidence_threshold, Tier 2 searchesdeep_cellscells. - Result — The image with the most votes wins, returning its label and a confidence value in
[0, 1].
Dependencies
- CMake >= 3.15
- C++17 compiler
- OpenCV 4.x
- FAISS
- OpenMP (macOS:
brew install libomp)
Building (C++)
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build --parallel
This produces build/imret_cli and build/libimret_core.a.
Running the tests
C++ tests:
ctest --test-dir build --output-on-failure
Python binding tests (requires imret installed and pytest):
pip install pytest
python -m pytest bindings/python/tests/ -v
C++ API
Include vault.hpp and link against libimret_core.a and its dependencies (OpenCV, faiss, omp).
OrbConfig
#include "imret.hpp"
OrbConfig cfg;
cfg.max_features = 500; // ORB keypoints per image
cfg.resize_dim = 0; // 0 = no resize; >0 = resize to (N x N) before extraction
cfg.fast_cells = 8; // IVF cells probed in tier-1 search
cfg.deep_cells = 64; // IVF cells probed in tier-2 fallback
cfg.max_hamming_distance = 45; // maximum Hamming distance for a keypoint to count as a match
cfg.confidence_threshold = 0.15f; // confidence below this triggers the tier-2 fallback
Ingest, build, search
#include "vault.hpp"
OrbConfig cfg;
Vault vault(cfg);
// Ingest images (grayscale cv::Mat)
vault.add(image_a, "label_a");
vault.add(image_b, "label_b");
// Bulk ingest with OpenMP parallelism — preferred for large collections
vault.add_batch({image_a, image_b, image_c}, {"label_a", "label_b", "label_c"});
// Build the index — required before searching
vault.build();
// Query
MatchResult result = vault.search(query_image);
// result.label — label of the best match, or "Unknown"
// result.confidence — fraction of keypoints that voted for the winner [0, 1]
// result.fallback_used — true if the tier-2 search was triggered
add() and add_batch() can be called after build(). Call build() again afterwards to retrain the index over all accumulated data.
Stats
Vault::Stats s = vault.stats();
// s.n_images — number of unique images in the vault
// s.n_features — total feature vectors accumulated
// s.nlist — number of IVF clusters (0 if not yet built)
// s.is_built — whether the index has been trained
All fields are O(1) reads from in-memory structures.
Persistence
vault.save("/path/to/prefix"); // writes prefix.faiss and prefix.meta
vault.load("/path/to/prefix"); // restores the index and label map; no rebuild needed
The .meta file stores the OrbConfig alongside the label map, so a loaded vault always uses the config it was originally built with.
Python
Install
pip install imret
Pre-built binary wheels are available for Linux x86_64 and macOS arm64, covering Python 3.9–3.13. Google Colab is supported without any additional setup.
The Linux wheel needs an x86-64-v2 CPU (SSE4.2 + POPCNT, any x86 CPU from roughly 2009 on). Its bundled FAISS is built with runtime SIMD dispatch, so AVX2/AVX-512 are used when present. 0.1.1's Linux wheel shipped a generic FAISS without hardware popcount, which made search ~20x slower; upgrade to 0.1.4 or later.
Usage
import cv2
import imret
cfg = imret.OrbConfig()
cfg.max_features = 500
cfg.resize_dim = 800 # resize images to 800x800 before extraction
cfg.fast_cells = 8
cfg.deep_cells = 64
cfg.max_hamming_distance = 45
cfg.confidence_threshold = 0.15
vault = imret.Vault(cfg)
# Ingest — images must be grayscale uint8 numpy arrays
gray = cv2.imread("painting.jpg", cv2.IMREAD_GRAYSCALE)
vault.add(gray, "my_label")
# Bulk ingest (parallel via OpenMP)
vault.add_batch([gray_a, gray_b, gray_c], ["label_a", "label_b", "label_c"])
# Build the index
vault.build()
# Search
result = vault.search(query_gray)
print(result.label, result.confidence, result.fallback_used)
# Vault stats (all O(1))
s = vault.stats()
print(s["n_images"]) # images in the vault
print(s["n_features"]) # total ORB descriptor vectors stored
print(s["nlist"]) # IVF Voronoi clusters (0 before build)
print(s["is_built"]) # whether the index has been trained
# Save and load
vault.save("/tmp/my_vault")
vault2 = imret.Vault.load_from_disk("/tmp/my_vault", cfg)
add() expects a 2-D numpy.ndarray with dtype uint8. If resize_dim > 0, resizing is applied internally before extraction.
Building from source
Requirements: Python >= 3.9, pybind11, scikit-build-core, OpenCV, FAISS, OpenMP.
On macOS, install OpenMP first:
brew install libomp
Then build and install the Python package:
cd bindings/python
pip install scikit-build-core pybind11
pip install .
The CMakeLists detects the Homebrew libomp prefix automatically.
CLI
./build/imret_cli <vault_prefix> <path_to_image>
Loads the vault at <vault_prefix>.faiss / <vault_prefix>.meta, searches with the given image, and prints the matched label to stdout. Exits with code 1 and prints UNKNOWN if confidence is below confidence_threshold.
OrbConfig reference
| Field | Default | Description |
|---|---|---|
max_features |
500 | Maximum ORB keypoints extracted per image |
resize_dim |
0 | If > 0, resize each image to resize_dim x resize_dim before extraction |
fast_cells |
8 | IVF cells probed during tier-1 search |
deep_cells |
64 | IVF cells probed during tier-2 fallback |
max_hamming_distance |
45 | Keypoints with Hamming distance above this threshold are excluded from voting |
confidence_threshold |
0.15 | Vote fraction below this triggers the tier-2 fallback |
Benchmarks
Generated by benchmark.py on macOS arm64, max_features=500, 20 queries per size.
imret and imret-batch differ only at ingest: the batch variant uses add_batch() which extracts ORB features in parallel via OpenMP, reducing build time by up to 37% at large N. Search latency is identical.
Speed comparison — synthetic images, no transform
All methods score 100% accuracy on structurally distinct synthetic images, so this measures speed only.
Search latency p50 (ms)
| N | imret | imret-batch | bfmatcher | imagehash |
|---|---|---|---|---|
| 100 | 3.19 | 3.11 | 8.60 | 0.20 |
| 500 | 3.26 | 3.27 | 39.97 | 0.52 |
| 1,000 | 3.30 | 3.33 | 85.14 | 0.90 |
| 2,000 | 3.36 | 3.33 | 166.58 | 1.67 |
Build time (s)
| N | imret | imret-batch | bfmatcher | imagehash |
|---|---|---|---|---|
| 100 | 1.11 | 0.98 | 0.11 | 0.44 |
| 500 | 15.64 | 15.12 | 0.56 | 0.07 |
| 1,000 | 31.19 | 30.18 | 1.11 | 0.17 |
| 2,000 | 62.20 | 60.27 | 2.25 | 0.33 |
imret search latency is nearly flat (3.19ms → 3.36ms across 20× more images). BFMatcher grows linearly. Build time is higher because imret trains a FAISS IVF index upfront — a one-time cost at index time.
Accuracy comparison — WikiArt paintings, wall-photo transform
The wall transform adds a grey background border and light Gaussian blur, simulating a gallery photo. This is where the methods diverge. Perceptual hashing (imagehash) is designed for near-duplicate detection; adding a border shifts the global DCT hash enough to confuse it with unrelated paintings. imret's ORB keypoints are local to the painting interior and are unaffected.
Accuracy (%)
| N | imret | imret-batch | bfmatcher | imagehash |
|---|---|---|---|---|
| 100 | 100.0 | 100.0 | 100.0 | 15.0 |
| 500 | 100.0 | 100.0 | 100.0 | 15.0 |
| 1,000 | 100.0 | 100.0 | 100.0 | 10.0 |
Search latency p50 (ms)
| N | imret | imret-batch | bfmatcher | imagehash |
|---|---|---|---|---|
| 100 | 21.64 | 21.54 | 29.74 | 1.69 |
| 500 | 22.53 | 22.27 | 71.64 | 2.07 |
| 1,000 | 22.21 | 22.33 | 130.68 | 2.42 |
imagehash is fast but effectively random on real images under this transform (10–15% ≈ 1-in-10 chance). imret maintains 100% accuracy. BFMatcher matches imret accuracy but latency grows linearly.
To reproduce:
python benchmark.py --dataset wikiart --transform wall --sizes 100,500,1000 --plot
python benchmark.py --sizes 100,500,1000,2000 --plot # synthetic speed comparison
Publishing a release
Wheels for Linux x86_64 and macOS arm64 are built automatically via GitHub Actions using cibuildwheel. To publish a new version to PyPI:
- Update
versioninpyproject.toml. - Push a version tag:
git tag v0.1.0 git push origin v0.1.0
- The workflow builds wheels for all supported platforms and Python versions, then uploads to PyPI using trusted publishing (no API token required — configure the PyPI project to trust this repository's Actions environment named
pypi).
Metadata
Release files for imret 0.1.4
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distributions (wheels)
Total release size: 280.6 MB
Release files / imret-0.1.4-cp313-cp313-manylinux_2_39_x86_64.whl
| Download URL | imret-0.1.4-cp313-cp313-manylinux_2_39_x86_64.whl |
|---|---|
| Size | 42.9 MB |
| Tags | CPython 3.13 Linux glibc 2.39+ x86-64 |
|
SHA-256 checksum How to use checksums |
8beb5a74338ee44c6d6f3525917ac25db853efc414bfa47a2f133d7fa161e827
|
|
BLAKE2b-256 checksum How to use checksums |
1299e942bf91ee355759f2019df928e5b87cfa5605d1482472fb1ce33ee54853
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 14, 2026.
Transparency logRelease files / imret-0.1.4-cp313-cp313-macosx_15_0_arm64.whl
| Download URL | imret-0.1.4-cp313-cp313-macosx_15_0_arm64.whl |
|---|---|
| Size | 13.2 MB |
| Tags | CPython 3.13 macOS 15.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
f512a6d2a416272306e1392ca209923ac904a080701c20f8235ce55f4772ce8c
|
|
BLAKE2b-256 checksum How to use checksums |
a35a614e6ca5b6ccdc407c689a78c43633d6bc16ac6babc0b9908eb674cd27ae
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 14, 2026.
Transparency logRelease files / imret-0.1.4-cp312-cp312-manylinux_2_39_x86_64.whl
| Download URL | imret-0.1.4-cp312-cp312-manylinux_2_39_x86_64.whl |
|---|---|
| Size | 42.9 MB |
| Tags | CPython 3.12 Linux glibc 2.39+ x86-64 |
|
SHA-256 checksum How to use checksums |
3288c49a8db3d4449fe0aa1e9a69cc1765fff3bb5a7f0d3f02efc57a551bd18b
|
|
BLAKE2b-256 checksum How to use checksums |
054a7b1274e45fb5cc64c3bfd4d8ab2c13789a23b2ad0070adc4db2bc1ea7172
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 14, 2026.
Transparency logRelease files / imret-0.1.4-cp312-cp312-macosx_15_0_arm64.whl
| Download URL | imret-0.1.4-cp312-cp312-macosx_15_0_arm64.whl |
|---|---|
| Size | 13.2 MB |
| Tags | CPython 3.12 macOS 15.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
85aefeab915a450530d4001fe042819e608360b19006c9684fcbfc1e05dc1f45
|
|
BLAKE2b-256 checksum How to use checksums |
557956afb4882ec2c1618f755ee586c8fe5bf9fd22a9d6c4dd853a2d9c6b28b1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 14, 2026.
Transparency logRelease files / imret-0.1.4-cp311-cp311-manylinux_2_39_x86_64.whl
| Download URL | imret-0.1.4-cp311-cp311-manylinux_2_39_x86_64.whl |
|---|---|
| Size | 42.9 MB |
| Tags | CPython 3.11 Linux glibc 2.39+ x86-64 |
|
SHA-256 checksum How to use checksums |
2db21ba63e194f09f04e3af6d7cb622ff7c7a6844a3f8820fac7808ae189ca33
|
|
BLAKE2b-256 checksum How to use checksums |
26e69314c3f04a8aaacaffdcbc72f26cfbbdb20e7da42ee39d96f5e6894a43b6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 14, 2026.
Transparency logRelease files / imret-0.1.4-cp311-cp311-macosx_15_0_arm64.whl
| Download URL | imret-0.1.4-cp311-cp311-macosx_15_0_arm64.whl |
|---|---|
| Size | 13.2 MB |
| Tags | CPython 3.11 macOS 15.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
0c9a2780912f6136a5d9e558e134f82c5e5645ef4f3b5ccb7e2a5c7d359ef261
|
|
BLAKE2b-256 checksum How to use checksums |
67c66498a6953ad1d617925ee46b6fa90134a7a39982c7de6ebdb3340dd0ecb1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 14, 2026.
Transparency logRelease files / imret-0.1.4-cp310-cp310-manylinux_2_39_x86_64.whl
| Download URL | imret-0.1.4-cp310-cp310-manylinux_2_39_x86_64.whl |
|---|---|
| Size | 42.9 MB |
| Tags | CPython 3.10 Linux glibc 2.39+ x86-64 |
|
SHA-256 checksum How to use checksums |
496d3c8a2143e6d143c63f21276e09d3d30b43934dc2adbbe3040c8f23920682
|
|
BLAKE2b-256 checksum How to use checksums |
f47801336d6f27015391c8fdea2476beb01acebf306d9cdbac04cb2b77070fb3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 14, 2026.
Transparency logRelease files / imret-0.1.4-cp310-cp310-macosx_15_0_arm64.whl
| Download URL | imret-0.1.4-cp310-cp310-macosx_15_0_arm64.whl |
|---|---|
| Size | 13.2 MB |
| Tags | CPython 3.10 macOS 15.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
cd5d4ee9f7aa0f1e6c01cc4aaad2242a82c86a0781ad8d36d41739f9d9bf7b86
|
|
BLAKE2b-256 checksum How to use checksums |
e76763f6500c5863e0703d4ee5ff50aea3da34b776d0de6d5cffa8fde6eb485a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 14, 2026.
Transparency logRelease files / imret-0.1.4-cp39-cp39-manylinux_2_39_x86_64.whl
| Download URL | imret-0.1.4-cp39-cp39-manylinux_2_39_x86_64.whl |
|---|---|
| Size | 42.9 MB |
| Tags | CPython 3.9 Linux glibc 2.39+ x86-64 |
|
SHA-256 checksum How to use checksums |
e313ad25bb377b331594aa2ad78a25be9e0ace3ab77ace1a2ce2b4301728509e
|
|
BLAKE2b-256 checksum How to use checksums |
eb780fcfad00e01c4cc3bfae0d593efd38786685eaae67292b393a4c6b089024
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 14, 2026.
Transparency logRelease files / imret-0.1.4-cp39-cp39-macosx_15_0_arm64.whl
| Download URL | imret-0.1.4-cp39-cp39-macosx_15_0_arm64.whl |
|---|---|
| Size | 13.2 MB |
| Tags | CPython 3.9 macOS 15.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
e8cba8afae93d0a493792b0256e13d7b4eaf6c42776cde4efb6ea4425a86f1c0
|
|
BLAKE2b-256 checksum How to use checksums |
8c455e1f06ccc57778a958bf3cd4b4d2a7b4babfd29fcae19fb11b5fbe34f0b9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 14, 2026.
Transparency logSecurity for imret 0.1.4
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.
Full provenance
All 10 files in this release have been uploaded with provenance metadata.
Attestation for imret-0.1.4-cp313-cp313-manylinux_2_39_x86_64.whl
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 14, 2026.
Transparency logA 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.