Skip to content

Commit 26fadd2

Browse files
committed
update testpypi workflow; update table css in docs; add contributing to docs;
1 parent 5ce084a commit 26fadd2

8 files changed

Lines changed: 148 additions & 64 deletions

File tree

.github/workflows/publish.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,16 @@ jobs:
3131
path: dist/
3232

3333
publish-to-testpypi:
34-
needs: build
34+
name: Publish Python 🐍 distribution 📦 to TestPyPI
35+
needs:
36+
- build
3537
runs-on: ubuntu-latest
3638
environment:
3739
name: testpypi
3840
url: https://test.pypi.org/p/vismatch
3941
permissions:
4042
id-token: write # IMPORTANT: mandatory for trusted publishing
43+
4144
steps:
4245
- name: Download all the dists
4346
uses: actions/download-artifact@v6

CONTRIBUTING.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ git submodule update --remote vismatch/third_party/[submodule_name]
3535
```
3636

3737
## Optional: add docs
38-
You can create the file `docs/new_matcher.md` to explain how the model is used. This is especially useful if the model has multiple hyperparameters.
38+
You can create the file `docs/source/model_specific/new_matcher.md` to explain how the model is used. This is especially useful if the model has multiple hyperparameters.
3939

4040
## Optional: adding model weights to the Hugging Face Hub
4141

@@ -71,10 +71,10 @@ api = HfApi()
7171
api.upload_file(
7272
path_or_fileobj="eloftr_outdoors.safetensors",
7373
path_in_repo="eloftr_outdoors.safetensors ",
74-
repo_id="ariG23498/eloftr", # personal repository
74+
repo_id="{your_personal_repo}/eloftr", # personal repository
7575
)
7676
```
7777

78-
You can access the weights here: https://huggingface.co/ariG23498/eloftr
78+
You can access the weights here: https://huggingface.co/{your_personal_repo}/eloftr
7979

8080
You can now see in this [PR](https://github.com/alexstoken/vismatch/pull/46) how we can move holistically to the Hub.

docs/source/_static/custom.css

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,13 @@ a.reference.external[href*="github.com"] {
22
color: #2b7a0b;
33
font-size: 0.85em;
44
margin-left: 0.5em;
5+
}
6+
7+
table td, table th {
8+
border: 1px solid #000 !important;
9+
padding: 6px 12px;
10+
}
11+
12+
table {
13+
border-collapse: collapse;
514
}

docs/source/contributing.md

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# Contributing
2+
3+
## Adding a New Method
4+
Let's for example add a matcher called new_matcher.
5+
1. Copy the template to create a new file: `cp vismatch/TEMPLATE.py vismatch/im_models/new_matcher.py`
6+
2. If the method requires external modules (for example the offical repository of new_matcher), use `git submodule add`: for example, I used this command to add the LightGlue module
7+
```bash
8+
git submodule add https://github.com/cvg/LightGlue vismatch/third_party/LightGlue
9+
```
10+
This command automatically modifies `.gitmodules` (you should not modify `.gitmodules` manually!), and when cloning the repository it will automatically clone also the LightGlue repo in `vismatch/third_party`.
11+
12+
3. In `vismatch/im_models/new_matcher.py` you only need to implement the method `_forward`, which takes two image tensors as input and returns 6 objects: `[mkpts0, mkpts1, kpts0, kpts1, desc0, desc1]`. The template has more details on how to implement the class.
13+
14+
4. Open `vismatch/__init__.py` and add the model name (all lowercase) to the `available_models` list. Add an `elif` case to instantiate the class, as for the other matchers.
15+
16+
5. If it requires additional dependencies, add them to `requirements.txt` or to the `[project.optional-dependencies]` of `pyproject.toml`.
17+
18+
6. Format the code with [ruff](https://github.com/astral-sh/ruff)
19+
```
20+
ruff format .
21+
ruff check --fix .
22+
```
23+
24+
7. Test your model. Make sure the model weights are downloaded automatically in the code, either with huggingface_hub (if on HF), gdown (if on GDrive), or py3_wget (any other platform or HTTP URL).
25+
```
26+
# Run this and have a look at the generated images in outputs_new_matcher
27+
python vismatch_match.py --matcher new_matcher --out_dir outputs_new_matcher
28+
# Run this and make sure it passes the test
29+
python vismatch_test.py --matcher new_matcher
30+
```
31+
Now submit a PR!
32+
33+
```{note}
34+
As authors update their model repos, consider updating the submodule reference here using the below:
35+
To update a submodule to the head of the remote, run
36+
```bash
37+
git submodule update --remote vismatch/third_party/[submodule_name]
38+
```
39+
40+
41+
## Optional: add docs
42+
You can create the file `docs/source/model_specific/new_matcher.md` to explain how the model is used. This is especially useful if the model has multiple hyperparameters.
43+
44+
## Optional: adding model weights to the Hugging Face Hub
45+
46+
Although not mandatory, we encourage authors to upload their models to the Hugging Face Hub, under the [image matching organization](https://huggingface.co/vismatch). This will increase model visibility and help track usage of each model.
47+
48+
Here are the steps that we took to add the ELoFTR model:
49+
50+
1. Dowloaded the model from Google Drive (any other storage)
51+
```py
52+
!pip install -q pytorch_lightning # Needed for the ELoFTR download
53+
from pathlib import Path
54+
from safetensors.torch import save_file
55+
from huggingface_hub import upload_file
56+
import gdown
57+
import torch
58+
59+
weights_src = "https://drive.google.com/file/d/1jFy2JbMKlIp82541TakhQPaoyB5qDeic/view"
60+
model_path = "eloftr_outdoor.ckpt"
61+
gdown.download(weights_src, output=model_path, fuzzy=True)
62+
```
63+
64+
2. Although weights can be uploaded as PyTorch file, safetensor is preferred. Save the state dict as a [safetensor](https://huggingface.co/docs/safetensors/en/index)
65+
```py
66+
state_dict = torch.load(model_path, map_location=torch.device("cpu"), weights_only=False)["state_dict"]
67+
save_file(state_dict, "eloftr_outdoors.safetensors")
68+
```
69+
70+
3. Upload the safetensor file to the Hub (you can upload it to your personal account and later transfer to the organization)
71+
```
72+
from huggingface_hub import HfApi
73+
74+
api = HfApi()
75+
api.upload_file(
76+
path_or_fileobj="eloftr_outdoors.safetensors",
77+
path_in_repo="eloftr_outdoors.safetensors ",
78+
repo_id="{your_personal_repo}/eloftr", # personal repository
79+
)
80+
```
81+
82+
You can access the weights here: https://huggingface.co/{your_personal_repo}/eloftr
83+
84+
You can now see in this [PR](https://github.com/alexstoken/vismatch/pull/46) how we can move holistically to the Hub.

docs/source/index.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ Vis(ion)Match(ers) is a unified API for 50+ image matching models with a consist
1919
installation
2020
quickstart
2121
model_details
22+
contributing
2223

2324
.. toctree::
2425
:maxdepth: 3
@@ -30,6 +31,12 @@ Vis(ion)Match(ers) is a unified API for 50+ image matching models with a consist
3031
api/vismatch.viz
3132
api/vismatch.im_models
3233

34+
.. toctree::
35+
:maxdepth: 2
36+
:caption: Model Specific Info
37+
38+
model_specific/matchanything
39+
3340
Indices and tables
3441
------------------
3542

docs/source/matchanything.md

Lines changed: 0 additions & 50 deletions
This file was deleted.

docs/source/model_details.md

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
## Model Details
2-
> [!IMPORTANT]
3-
> Check the `LICENSE` of each model/original code base before use in your application. Some are heavily restricted.
2+
```{important}
3+
Check the `LICENSE` of each model/original code base before use in your application. Some are heavily restricted.
4+
```
45

56
Most models can run on both CPU and GPU. If a runtime shows ❌, that model cannot run on that device. MPS (Apple Silicon) is not tested.
67

@@ -295,21 +296,22 @@ Most models can run on both CPU and GPU. If a runtime shows ❌, that model cann
295296
</table>
296297
<!--| SiLK (ICCV '23) | [Official](https://github.com/facebookresearch/silk) | [arxiv](https://arxiv.org/abs/2304.06194) | 0.694 | 3.733 | -->
297298

299+
300+
\
298301
Our implementation of Patch2Pix (+ Patch2PixSuperGlue), R2D2, and D2Net are based on the [Image Matching Toolbox](https://github.com/GrumpyZhou/image-matching-toolbox/tree/main) (IMT). LoFTR and DeDoDe-Lightglue are from [Kornia](https://github.com/kornia/kornia). Other models are based on the offical repos above.
299302

300303
Runtime benchmark is the average of 5 iterations over the 5 pairs of examples in the `assets/example_pairs` folder at image size 512x512. Benchmark is done using `vismatch_test.py` on an NVIDIA RTX A4000 GPU. Results rounded to the hundredths place.
301304

302-
\* `SphereGlue` requires `torch-geometric` and `torch-cluster`. Install with: `pip install .[all] -f https://data.pyg.org/whl/torch-2.5.0+cu124.html` (replace `cu124` with `cpu` for CPU). See [PyG installation docs](https://pytorch-geometric.readthedocs.io/en/latest/install/installation.html).
305+
* `SphereGlue` requires `torch-geometric` and `torch-cluster`. Install with: `pip install .[all] -f https://data.pyg.org/whl/torch-2.5.0+cu124.html` (replace `cu124` with `cpu` for CPU). See [PyG installation docs](https://pytorch-geometric.readthedocs.io/en/latest/install/installation.html).
303306

304-
\* `SphereGlue` model runtimes are listed in the order: `SIFT, SuperPoint`
307+
* `SphereGlue` model runtimes are listed in the order: `SIFT, SuperPoint`
305308

306-
\* `GIM` model runtimes are listed in the order: `LG, DKMv3`
309+
* `GIM` model runtimes are listed in the order: `LG, DKMv3`
307310

308-
\* `LightGlue` model runtimes are listed in the order: `SIFT, SuperPoint, Disk, ALIKED`
311+
* `LightGlue` model runtimes are listed in the order: `SIFT, SuperPoint, Disk, ALIKED`
309312

310-
\* `Keypt2Subpx` model runtimes are listed in the order: `superpoint-lightglue, aliked-lightglue, xfeat, dedode`
313+
* `Keypt2Subpx` model runtimes are listed in the order: `superpoint-lightglue, aliked-lightglue, xfeat, dedode`
311314

312-
\* `MINIMA` model runtimes are listed in the order: `superpoint-lightglue, LoFTR, RoMa (large), RoMa (tiny)`
315+
* `MINIMA` model runtimes are listed in the order: `superpoint-lightglue, LoFTR, RoMa (large), RoMa (tiny)`
313316

314-
\* `RDD` model runtimes are listed in the order: `sparse, star (semi-dense), lightglue, aliked`
315-
##
317+
* `RDD` model runtimes are listed in the order: `sparse, star (semi-dense), lightglue, aliked`
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# MatchAnything (ELoFTR / RoMa)
2+
3+
The `matchanything-eloftr` and `matchanything-roma` wrappers use the upstream MatchAnything repo (HF Space: https://huggingface.co/spaces/LittleFrog/MatchAnything), included here as a git submodule at `vismatch/third_party/MatchAnything`.
4+
5+
## Submodule setup
6+
7+
If you cloned without submodules:
8+
9+
```bash
10+
git submodule update --init --recursive vismatch/third_party/MatchAnything
11+
```
12+
13+
## Use
14+
15+
Run either variant via:
16+
```bash
17+
# ELoFTR backbone (defaults to 832px NPE size)
18+
python vismatch_match.py --matcher matchanything-eloftr --device cuda --img-size 832 --out-dir outputs_matchanything-eloftr
19+
20+
# RoMa backbone (AMP disabled on CPU automatically)
21+
python vismatch_match.py --matcher matchanything-roma --device cuda --img-size 832 --out-dir outputs_matchanything-roma
22+
```
23+
Weights download automatically on first MatchAnything use and are cached in the HF Cache.
24+
25+
## Weights cache location
26+
27+
Checkpoints are cached in the HF_CACHE, usually `~/.cache/huggingface/hub`:
28+
29+
The wrapper will also reuse checkpoints previously downloaded to the legacy location under the MatchAnything submodule.

0 commit comments

Comments
 (0)