Metadata-Version: 2.4
Name: shopna-point
Version: 0.1.1
Summary: SHOPNA-Point: robust feature detection, description and homography estimation for restaurant menu-card images
Author: SHOPNA-Point contributors
License: MIT
Keywords: keypoint,matching,homography,opencv,numba,computer-vision,menu-card
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Topic :: Scientific/Engineering :: Image Recognition
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy<3,>=1.24
Requires-Dist: opencv-python-headless<5,>=4.8
Requires-Dist: numba>=0.61
Requires-Dist: tqdm>=4.60
Provides-Extra: gpu
Requires-Dist: numba-cuda>=0.2; extra == "gpu"
Provides-Extra: dev
Requires-Dist: pytest>=8; extra == "dev"
Dynamic: license-file

# SHOPNA-Point

Robust feature detection, description and homography estimation for
restaurant menu-card images. SHOPNA-Point is a NumPy/Numba/OpenCV algorithm
with GPU (CUDA) kernels available as an optional extra. It ships with three
ready-made presets (**accuracy**, **balanced**, **speed**) plus a
**device_performance** auto-tier mode, and supports arbitrary custom
overrides without recompiling anything.

The package is extracted line-by-line from the `experimental-shopna-point-gpu`
Kaggle notebook (see `tools/extract_notebook.py` for the provenance map), so
a plain run reproduces the pinned benchmark trace (120/120 images, zero
regressions vs the baseline; gate: `harness/diff_trace.py`).

## Install

```bash
pip install shopna-point            # CPU (Numba JIT)
pip install "shopna-point[gpu]"     # + CUDA kernels (numba-cuda)
```

## Quick start

Match one image pair:

```python
import cv2
from shopna_point import match

ref  = cv2.imread("menu_ref.jpg")
test = cv2.imread("menu_test.jpg")

res = match(ref, test, mode="balanced")   # accuracy | balanced | speed
if res["status"] == "success":
    H = res["H"]          # 3x3 homography
    print(res["inliers"], "inliers,", round(res["reproj"], 2), "px")
else:
    print("not matched:", res["status"])
```

Run the benchmark harnesses (identical to the notebook cells 8-11):

```python
from shopna_point import run_external_validation, run_main_validation

run_external_validation("path/to/dataset", num_samples=10, start=1, end=10)
run_main_validation(test_root="...", reference_root="...")
```

Command line:

```bash
shopna-point info
shopna-point match menu_ref.jpg menu_test.jpg --mode accuracy
shopna-point validate --dataset-dir path/to/dataset --num-samples 7790 --start 1 --end 2600
```

## Customization contract

* `set_mode("accuracy" | "balanced" | "speed" | "device_performance")` switches
  the active preset at runtime.
* `update_config({...})` merges arbitrary CONFIG keys on top of the active
  preset (partial override).
* `register_mode("myname", {...})` registers a new full preset usable by
  `set_mode`.
* `get_config()` returns the active merged config.
* `seed_all()` applies the reproducibility seeds (random + cv2 USAC; numpy is
  pinned at import like the notebook).

> New-API note: `match()` is the package convenience entry point. The
> byte-identical, gate-verified entry points are `run_external_validation`
> and `run_main_validation`. `match()` skips the ground-truth-driven FixA
> retry/rescue branches by design (no GT available per image).

## Determinism / reproduction

`run_external_validation(..., start=, end=)` supports chunked runs; chunks
are deterministic and disjoint, so a 7790-image run can be split into
sequential chunks. Use `SHOPNA_OUTPUT_DIR` (default: current directory) for
results and `SHOPNA_EXTERNAL_DATASET_DIR` for the dataset root. The CPU
pipeline is deterministic given the RNG discipline; GPU kernels are
numerically equivalent but CUDA reductions are not bit-exact, so use
`gpu_enabled()` to know which path ran.

## License

MIT — see `LICENSE`.
