romav2 2.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- romav2-2.0.0/PKG-INFO +161 -0
- romav2-2.0.0/README.md +134 -0
- romav2-2.0.0/pyproject.toml +38 -0
- romav2-2.0.0/src/romav2/__init__.py +8 -0
- romav2-2.0.0/src/romav2/benchmarks/__init__.py +4 -0
- romav2-2.0.0/src/romav2/benchmarks/mega1500.py +115 -0
- romav2-2.0.0/src/romav2/benchmarks/satast.py +463 -0
- romav2-2.0.0/src/romav2/benchmarks/scannet1500.py +125 -0
- romav2-2.0.0/src/romav2/benchmarks/wxbs.py +104 -0
- romav2-2.0.0/src/romav2/device.py +9 -0
- romav2-2.0.0/src/romav2/dpt.py +516 -0
- romav2-2.0.0/src/romav2/features.py +191 -0
- romav2-2.0.0/src/romav2/geometry.py +261 -0
- romav2-2.0.0/src/romav2/io.py +24 -0
- romav2-2.0.0/src/romav2/local_correlation.py +152 -0
- romav2-2.0.0/src/romav2/logging.py +97 -0
- romav2-2.0.0/src/romav2/matcher.py +207 -0
- romav2-2.0.0/src/romav2/normalizers.py +17 -0
- romav2-2.0.0/src/romav2/refiner.py +277 -0
- romav2-2.0.0/src/romav2/romav2.py +531 -0
- romav2-2.0.0/src/romav2/types.py +75 -0
- romav2-2.0.0/src/romav2/vis.py +36 -0
- romav2-2.0.0/src/romav2/vit/__init__.py +304 -0
- romav2-2.0.0/src/romav2/vit/attention.py +181 -0
- romav2-2.0.0/src/romav2/vit/block.py +293 -0
- romav2-2.0.0/src/romav2/vit/ffn_layers.py +83 -0
- romav2-2.0.0/src/romav2/vit/layer_scale.py +29 -0
- romav2-2.0.0/src/romav2/vit/patch_embed.py +94 -0
- romav2-2.0.0/src/romav2/vit/rms_norm.py +24 -0
- romav2-2.0.0/src/romav2/vit/rope.py +133 -0
- romav2-2.0.0/src/romav2/vit/rope_mixed.py +111 -0
- romav2-2.0.0/src/romav2/vit/utils.py +48 -0
romav2-2.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: romav2
|
|
3
|
+
Version: 2.0.0
|
|
4
|
+
Summary: RoMa v2: Harder Better Faster Denser Feature Matching
|
|
5
|
+
Author: Johan Edstedt
|
|
6
|
+
Author-email: Johan Edstedt <johan.edstedt@liu.se>
|
|
7
|
+
Requires-Dist: dataclasses>=0.8
|
|
8
|
+
Requires-Dist: einops>=0.8.1
|
|
9
|
+
Requires-Dist: pillow>=12.0.0
|
|
10
|
+
Requires-Dist: rich>=14.2.0
|
|
11
|
+
Requires-Dist: torch
|
|
12
|
+
Requires-Dist: torchvision>=0.23.0
|
|
13
|
+
Requires-Dist: tqdm>=4.67.1
|
|
14
|
+
Requires-Dist: slurm-util>=0.2.7 ; extra == 'dev'
|
|
15
|
+
Requires-Dist: ruff>=0.14.5 ; extra == 'dev'
|
|
16
|
+
Requires-Dist: kornia>=0.8.2 ; extra == 'eval'
|
|
17
|
+
Requires-Dist: matplotlib>=3.10.7 ; extra == 'eval'
|
|
18
|
+
Requires-Dist: opencv-python>=4.12.0.88 ; extra == 'eval'
|
|
19
|
+
Requires-Dist: wandb>=0.23.0 ; extra == 'eval'
|
|
20
|
+
Requires-Dist: wxbs-benchmark>=0.0.4 ; extra == 'eval'
|
|
21
|
+
Requires-Dist: fused-local-corr ; sys_platform == 'linux' and extra == 'fused-local-corr'
|
|
22
|
+
Requires-Python: >=3.10
|
|
23
|
+
Provides-Extra: dev
|
|
24
|
+
Provides-Extra: eval
|
|
25
|
+
Provides-Extra: fused-local-corr
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
|
|
28
|
+
<p align="center">
|
|
29
|
+
<h1 align="center"> <ins>RoMa v2</ins> 馃: Harder Better Faster Denser Feature Matching
|
|
30
|
+
<h2 align="center">
|
|
31
|
+
<a href="https://scholar.google.com/citations?user=Ul-vMR0AAAAJ">Johan Edstedt</a>
|
|
32
|
+
路
|
|
33
|
+
<a href="https://scholar.google.com/citations?user=-vJPE04AAAAJ">David Nordstr枚m</a>
|
|
34
|
+
路
|
|
35
|
+
<a href="https://scholar.google.com/citations?user=mvY4rdIAAAAJ">Yushan Zhang</a>
|
|
36
|
+
路
|
|
37
|
+
<a href="https://scholar.google.com/citations?user=FUE3Wd0AAAAJ">Georg B枚kman</a>
|
|
38
|
+
路
|
|
39
|
+
<a href="https://scholar.google.com/citations?user=dsEPAvUAAAAJ">Jonathan Astermark</a>
|
|
40
|
+
路
|
|
41
|
+
<a href="https://scholar.google.com/citations?user=vHeD0TYAAAAJ">Viktor Larsson</a>
|
|
42
|
+
路
|
|
43
|
+
<a href="https://scholar.google.com/citations?user=9j-6i_oAAAAJ&hl">Anders Heyden</a>
|
|
44
|
+
路
|
|
45
|
+
<a href="https://scholar.google.com/citations?user=P_w6UgMAAAAJ&hl">Fredrik Kahl</a>
|
|
46
|
+
路
|
|
47
|
+
<a href="https://scholar.google.com/citations?user=6WRQpCQAAAAJ">M氓rten Wadenb盲ck</a>
|
|
48
|
+
路
|
|
49
|
+
<a href="https://scholar.google.com/citations?user=lkWfR08AAAAJ">Michael Felsberg</a>
|
|
50
|
+
</p>
|
|
51
|
+
<h2 align="center"><p>
|
|
52
|
+
<a href="https://arxiv.org/abs/2511.15706" align="center">Paper</a> |
|
|
53
|
+
<a href="TBD" align="center">Project Page</a>
|
|
54
|
+
</p></h2>
|
|
55
|
+
<div align="center"></div>
|
|
56
|
+
</p>
|
|
57
|
+
<br/>
|
|
58
|
+
<p align="center">
|
|
59
|
+
<img src="assets/qualitative.png" alt="example" width=80%>
|
|
60
|
+
</p>
|
|
61
|
+
|
|
62
|
+
## How to Use
|
|
63
|
+
```python
|
|
64
|
+
from romav2 import RoMaV2
|
|
65
|
+
|
|
66
|
+
# load pretrained model
|
|
67
|
+
model = RoMaV2()
|
|
68
|
+
# Match densely for any image-like pair of inputs
|
|
69
|
+
preds = model.match(img_A_path, img_B_path)
|
|
70
|
+
|
|
71
|
+
# you can also run the forward method directly as
|
|
72
|
+
# preds = model(img_A, img_B)
|
|
73
|
+
|
|
74
|
+
# Sample 5000 matches for estimation
|
|
75
|
+
matches, overlaps, precision_AB, precision_BA = model.sample(preds, 5000)
|
|
76
|
+
|
|
77
|
+
# Convert to pixel coordinates (RoMaV2 produces matches in [-1,1]x[-1,1])
|
|
78
|
+
kptsA, kptsB = model.to_pixel_coordinates(matches, H_A, W_A, H_B, W_B)
|
|
79
|
+
|
|
80
|
+
# Find a fundamental matrix (or anything else of interest)
|
|
81
|
+
F, mask = cv2.findFundamentalMat(
|
|
82
|
+
kptsA.cpu().numpy(), kptsB.cpu().numpy(), ransacReprojThreshold=0.2, method=cv2.USAC_MAGSAC, confidence=0.999999, maxIters=10000
|
|
83
|
+
)
|
|
84
|
+
```
|
|
85
|
+
We additionally provide two demos in the [demos folder](demo), which might help in understanding.
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
## Setup/Install
|
|
89
|
+
In your python environment (tested on Linux python 3.12), run:
|
|
90
|
+
```bash
|
|
91
|
+
uv pip install -e .
|
|
92
|
+
```
|
|
93
|
+
or
|
|
94
|
+
```bash
|
|
95
|
+
uv sync
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Benchmarks
|
|
99
|
+
If you do not already have MegaDepth and ScanNet, you can the following to download them:
|
|
100
|
+
```bash
|
|
101
|
+
source scripts/eval_prep.sh
|
|
102
|
+
```
|
|
103
|
+
### Mega-1500
|
|
104
|
+
```bash
|
|
105
|
+
uv run tests/test_mega1500.py
|
|
106
|
+
```
|
|
107
|
+
### ScanNet-1500
|
|
108
|
+
```bash
|
|
109
|
+
uv run tests/test_scannet1500.py
|
|
110
|
+
```
|
|
111
|
+
### Expected Results
|
|
112
|
+
Experiments on ScanNet-1500 and MegaDepth-1500 are provided in the [tests folder](tests).
|
|
113
|
+
Running these gave me `ScanNet-1500: [34.0, 56.5, 73.9]`, and `Mega-1500: [62.8, 76,8, 86.5]`, which are similar to the results of the paper.
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
## Fused local correlation kernel
|
|
117
|
+
Include the `--extra fused-local-corr` flag as:
|
|
118
|
+
```bash
|
|
119
|
+
uv sync --extra fused-local-corr
|
|
120
|
+
```
|
|
121
|
+
or
|
|
122
|
+
```bash
|
|
123
|
+
uv pip install romav2[fused-local-corr]
|
|
124
|
+
```
|
|
125
|
+
or
|
|
126
|
+
```bash
|
|
127
|
+
uv add romav2[fused-local-corr]
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Settings
|
|
131
|
+
By twiddling with some different settings you may reach better results on your task of interest.
|
|
132
|
+
Some important ones, which we enable setting to some reasonable defaults through `model.apply_setting`, are:
|
|
133
|
+
|
|
134
|
+
`model.H_lr, model.W_lr`: height and width for the image pair.
|
|
135
|
+
|
|
136
|
+
`model.H_hr, model.W_hr`: height and width for a high resolution version of the image pair (used for upsampling as in RoMa)
|
|
137
|
+
|
|
138
|
+
`model.bidirectional`: Useful for getting more diverse matches, and for estimating the covariance matrix in both directions.
|
|
139
|
+
|
|
140
|
+
`model.threshold`: Value between [0,1]. Used to set overlap prediction above it to 1. Useful for Mega1500.
|
|
141
|
+
|
|
142
|
+
`model.balanced_sampling`: Diverse sampling, same as RoMa. Typically helps to get better RANSAC estimates.
|
|
143
|
+
|
|
144
|
+
## License
|
|
145
|
+
All our code except DINOv3 is MIT license.
|
|
146
|
+
DINOv3 has a custom license, see [DINOv3](https://github.com/facebookresearch/dinov3/tree/main?tab=License-1-ov-file#readme).
|
|
147
|
+
|
|
148
|
+
## Acknowledgement
|
|
149
|
+
Our codebase builds mainly on the code in [RoMa](https://github.com/Parskatt/RoMa).
|
|
150
|
+
We were additionally inspired by [UFM](https://github.com/UniFlowMatch/UFM) and [MapAnything](https://github.com/facebookresearch/map-anything), particularly for the datasets used to train the models.
|
|
151
|
+
|
|
152
|
+
## BibTeX
|
|
153
|
+
If you find our models useful, please consider citing our paper!
|
|
154
|
+
```
|
|
155
|
+
@article{edstedt2025romav2,
|
|
156
|
+
title={{RoMa v2: Harder Better Faster Denser Feature Matching}},
|
|
157
|
+
author={Johan Edstedt, David Nordstr枚m, Yushan Zhang, Georg B枚kman, Jonathan Astermark, Viktor Larsson, Anders Heyden, Fredrik Kahl, M氓rten Wadenb盲ck, Michael Felsberg},
|
|
158
|
+
journal={arXiv preprint arXiv:2511.15706},
|
|
159
|
+
year={2025}
|
|
160
|
+
}
|
|
161
|
+
```
|
romav2-2.0.0/README.md
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<h1 align="center"> <ins>RoMa v2</ins> 馃: Harder Better Faster Denser Feature Matching
|
|
3
|
+
<h2 align="center">
|
|
4
|
+
<a href="https://scholar.google.com/citations?user=Ul-vMR0AAAAJ">Johan Edstedt</a>
|
|
5
|
+
路
|
|
6
|
+
<a href="https://scholar.google.com/citations?user=-vJPE04AAAAJ">David Nordstr枚m</a>
|
|
7
|
+
路
|
|
8
|
+
<a href="https://scholar.google.com/citations?user=mvY4rdIAAAAJ">Yushan Zhang</a>
|
|
9
|
+
路
|
|
10
|
+
<a href="https://scholar.google.com/citations?user=FUE3Wd0AAAAJ">Georg B枚kman</a>
|
|
11
|
+
路
|
|
12
|
+
<a href="https://scholar.google.com/citations?user=dsEPAvUAAAAJ">Jonathan Astermark</a>
|
|
13
|
+
路
|
|
14
|
+
<a href="https://scholar.google.com/citations?user=vHeD0TYAAAAJ">Viktor Larsson</a>
|
|
15
|
+
路
|
|
16
|
+
<a href="https://scholar.google.com/citations?user=9j-6i_oAAAAJ&hl">Anders Heyden</a>
|
|
17
|
+
路
|
|
18
|
+
<a href="https://scholar.google.com/citations?user=P_w6UgMAAAAJ&hl">Fredrik Kahl</a>
|
|
19
|
+
路
|
|
20
|
+
<a href="https://scholar.google.com/citations?user=6WRQpCQAAAAJ">M氓rten Wadenb盲ck</a>
|
|
21
|
+
路
|
|
22
|
+
<a href="https://scholar.google.com/citations?user=lkWfR08AAAAJ">Michael Felsberg</a>
|
|
23
|
+
</p>
|
|
24
|
+
<h2 align="center"><p>
|
|
25
|
+
<a href="https://arxiv.org/abs/2511.15706" align="center">Paper</a> |
|
|
26
|
+
<a href="TBD" align="center">Project Page</a>
|
|
27
|
+
</p></h2>
|
|
28
|
+
<div align="center"></div>
|
|
29
|
+
</p>
|
|
30
|
+
<br/>
|
|
31
|
+
<p align="center">
|
|
32
|
+
<img src="assets/qualitative.png" alt="example" width=80%>
|
|
33
|
+
</p>
|
|
34
|
+
|
|
35
|
+
## How to Use
|
|
36
|
+
```python
|
|
37
|
+
from romav2 import RoMaV2
|
|
38
|
+
|
|
39
|
+
# load pretrained model
|
|
40
|
+
model = RoMaV2()
|
|
41
|
+
# Match densely for any image-like pair of inputs
|
|
42
|
+
preds = model.match(img_A_path, img_B_path)
|
|
43
|
+
|
|
44
|
+
# you can also run the forward method directly as
|
|
45
|
+
# preds = model(img_A, img_B)
|
|
46
|
+
|
|
47
|
+
# Sample 5000 matches for estimation
|
|
48
|
+
matches, overlaps, precision_AB, precision_BA = model.sample(preds, 5000)
|
|
49
|
+
|
|
50
|
+
# Convert to pixel coordinates (RoMaV2 produces matches in [-1,1]x[-1,1])
|
|
51
|
+
kptsA, kptsB = model.to_pixel_coordinates(matches, H_A, W_A, H_B, W_B)
|
|
52
|
+
|
|
53
|
+
# Find a fundamental matrix (or anything else of interest)
|
|
54
|
+
F, mask = cv2.findFundamentalMat(
|
|
55
|
+
kptsA.cpu().numpy(), kptsB.cpu().numpy(), ransacReprojThreshold=0.2, method=cv2.USAC_MAGSAC, confidence=0.999999, maxIters=10000
|
|
56
|
+
)
|
|
57
|
+
```
|
|
58
|
+
We additionally provide two demos in the [demos folder](demo), which might help in understanding.
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
## Setup/Install
|
|
62
|
+
In your python environment (tested on Linux python 3.12), run:
|
|
63
|
+
```bash
|
|
64
|
+
uv pip install -e .
|
|
65
|
+
```
|
|
66
|
+
or
|
|
67
|
+
```bash
|
|
68
|
+
uv sync
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Benchmarks
|
|
72
|
+
If you do not already have MegaDepth and ScanNet, you can the following to download them:
|
|
73
|
+
```bash
|
|
74
|
+
source scripts/eval_prep.sh
|
|
75
|
+
```
|
|
76
|
+
### Mega-1500
|
|
77
|
+
```bash
|
|
78
|
+
uv run tests/test_mega1500.py
|
|
79
|
+
```
|
|
80
|
+
### ScanNet-1500
|
|
81
|
+
```bash
|
|
82
|
+
uv run tests/test_scannet1500.py
|
|
83
|
+
```
|
|
84
|
+
### Expected Results
|
|
85
|
+
Experiments on ScanNet-1500 and MegaDepth-1500 are provided in the [tests folder](tests).
|
|
86
|
+
Running these gave me `ScanNet-1500: [34.0, 56.5, 73.9]`, and `Mega-1500: [62.8, 76,8, 86.5]`, which are similar to the results of the paper.
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
## Fused local correlation kernel
|
|
90
|
+
Include the `--extra fused-local-corr` flag as:
|
|
91
|
+
```bash
|
|
92
|
+
uv sync --extra fused-local-corr
|
|
93
|
+
```
|
|
94
|
+
or
|
|
95
|
+
```bash
|
|
96
|
+
uv pip install romav2[fused-local-corr]
|
|
97
|
+
```
|
|
98
|
+
or
|
|
99
|
+
```bash
|
|
100
|
+
uv add romav2[fused-local-corr]
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Settings
|
|
104
|
+
By twiddling with some different settings you may reach better results on your task of interest.
|
|
105
|
+
Some important ones, which we enable setting to some reasonable defaults through `model.apply_setting`, are:
|
|
106
|
+
|
|
107
|
+
`model.H_lr, model.W_lr`: height and width for the image pair.
|
|
108
|
+
|
|
109
|
+
`model.H_hr, model.W_hr`: height and width for a high resolution version of the image pair (used for upsampling as in RoMa)
|
|
110
|
+
|
|
111
|
+
`model.bidirectional`: Useful for getting more diverse matches, and for estimating the covariance matrix in both directions.
|
|
112
|
+
|
|
113
|
+
`model.threshold`: Value between [0,1]. Used to set overlap prediction above it to 1. Useful for Mega1500.
|
|
114
|
+
|
|
115
|
+
`model.balanced_sampling`: Diverse sampling, same as RoMa. Typically helps to get better RANSAC estimates.
|
|
116
|
+
|
|
117
|
+
## License
|
|
118
|
+
All our code except DINOv3 is MIT license.
|
|
119
|
+
DINOv3 has a custom license, see [DINOv3](https://github.com/facebookresearch/dinov3/tree/main?tab=License-1-ov-file#readme).
|
|
120
|
+
|
|
121
|
+
## Acknowledgement
|
|
122
|
+
Our codebase builds mainly on the code in [RoMa](https://github.com/Parskatt/RoMa).
|
|
123
|
+
We were additionally inspired by [UFM](https://github.com/UniFlowMatch/UFM) and [MapAnything](https://github.com/facebookresearch/map-anything), particularly for the datasets used to train the models.
|
|
124
|
+
|
|
125
|
+
## BibTeX
|
|
126
|
+
If you find our models useful, please consider citing our paper!
|
|
127
|
+
```
|
|
128
|
+
@article{edstedt2025romav2,
|
|
129
|
+
title={{RoMa v2: Harder Better Faster Denser Feature Matching}},
|
|
130
|
+
author={Johan Edstedt, David Nordstr枚m, Yushan Zhang, Georg B枚kman, Jonathan Astermark, Viktor Larsson, Anders Heyden, Fredrik Kahl, M氓rten Wadenb盲ck, Michael Felsberg},
|
|
131
|
+
journal={arXiv preprint arXiv:2511.15706},
|
|
132
|
+
year={2025}
|
|
133
|
+
}
|
|
134
|
+
```
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "romav2"
|
|
3
|
+
version = "2.0.0"
|
|
4
|
+
description = "RoMa v2: Harder Better Faster Denser Feature Matching"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
authors = [
|
|
7
|
+
{ name = "Johan Edstedt", email = "johan.edstedt@liu.se" }
|
|
8
|
+
]
|
|
9
|
+
requires-python = ">=3.10"
|
|
10
|
+
dependencies = [
|
|
11
|
+
"dataclasses>=0.8",
|
|
12
|
+
"einops>=0.8.1",
|
|
13
|
+
"pillow>=12.0.0",
|
|
14
|
+
"rich>=14.2.0",
|
|
15
|
+
"torch",
|
|
16
|
+
"torchvision>=0.23.0",
|
|
17
|
+
"tqdm>=4.67.1",
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
[build-system]
|
|
21
|
+
requires = ["uv_build>=0.8.15,<0.9.0"]
|
|
22
|
+
build-backend = "uv_build"
|
|
23
|
+
|
|
24
|
+
[project.optional-dependencies]
|
|
25
|
+
fused-local-corr = [
|
|
26
|
+
"fused-local-corr ; sys_platform == 'linux'",
|
|
27
|
+
]
|
|
28
|
+
eval = [
|
|
29
|
+
"kornia>=0.8.2",
|
|
30
|
+
"matplotlib>=3.10.7",
|
|
31
|
+
"opencv-python>=4.12.0.88",
|
|
32
|
+
"wandb>=0.23.0",
|
|
33
|
+
"wxbs-benchmark>=0.0.4",
|
|
34
|
+
]
|
|
35
|
+
dev = [
|
|
36
|
+
"slurm-util>=0.2.7",
|
|
37
|
+
"ruff>=0.14.5",
|
|
38
|
+
]
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import logging as _logging
|
|
2
|
+
from .logging import configure_logger as configure_logger
|
|
3
|
+
from .logging import logger as _logger
|
|
4
|
+
|
|
5
|
+
if not any(not isinstance(h, _logging.NullHandler) for h in _logger.handlers):
|
|
6
|
+
configure_logger()
|
|
7
|
+
|
|
8
|
+
from .romav2 import RoMaV2 as RoMaV2
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import logging
|
|
3
|
+
from romav2.geometry import (
|
|
4
|
+
compute_pose_error,
|
|
5
|
+
pose_auc,
|
|
6
|
+
estimate_pose_cv2_ransac,
|
|
7
|
+
compute_relative_pose,
|
|
8
|
+
)
|
|
9
|
+
from PIL import Image
|
|
10
|
+
from tqdm import tqdm
|
|
11
|
+
|
|
12
|
+
logger = logging.getLogger(__name__)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class Mega1500:
|
|
16
|
+
def __init__(self, data_root="data/megadepth") -> None:
|
|
17
|
+
self.scene_names = [
|
|
18
|
+
"0015_0.1_0.3.npz",
|
|
19
|
+
"0015_0.3_0.5.npz",
|
|
20
|
+
"0022_0.1_0.3.npz",
|
|
21
|
+
"0022_0.3_0.5.npz",
|
|
22
|
+
"0022_0.5_0.7.npz",
|
|
23
|
+
]
|
|
24
|
+
self.scenes = [
|
|
25
|
+
np.load(f"{data_root}/{scene}", allow_pickle=True)
|
|
26
|
+
for scene in self.scene_names
|
|
27
|
+
]
|
|
28
|
+
self.data_root = data_root
|
|
29
|
+
|
|
30
|
+
def benchmark(self, model, model_name=None):
|
|
31
|
+
data_root = self.data_root
|
|
32
|
+
tot_e_t, tot_e_R, tot_e_pose = [], [], []
|
|
33
|
+
thresholds = [5, 10, 20]
|
|
34
|
+
for scene_ind in range(len(self.scenes)):
|
|
35
|
+
scene = self.scenes[scene_ind]
|
|
36
|
+
pairs = scene["pair_infos"]
|
|
37
|
+
intrinsics = scene["intrinsics"]
|
|
38
|
+
poses = scene["poses"]
|
|
39
|
+
im_paths = scene["image_paths"]
|
|
40
|
+
pair_inds = range(len(pairs))
|
|
41
|
+
for pairind in (pbar := tqdm(pair_inds, desc="Mega1500 eval")):
|
|
42
|
+
idx1, idx2 = pairs[pairind][0]
|
|
43
|
+
K1 = intrinsics[idx1].copy()
|
|
44
|
+
T1 = poses[idx1].copy()
|
|
45
|
+
R1, t1 = T1[:3, :3], T1[:3, 3]
|
|
46
|
+
K2 = intrinsics[idx2].copy()
|
|
47
|
+
T2 = poses[idx2].copy()
|
|
48
|
+
R2, t2 = T2[:3, :3], T2[:3, 3]
|
|
49
|
+
R, t = compute_relative_pose(R1, t1, R2, t2)
|
|
50
|
+
im_A_path = f"{data_root}/{im_paths[idx1]}"
|
|
51
|
+
im_B_path = f"{data_root}/{im_paths[idx2]}"
|
|
52
|
+
preds = model.match(im_A_path, im_B_path)
|
|
53
|
+
im_A = Image.open(im_A_path)
|
|
54
|
+
w1, h1 = im_A.size
|
|
55
|
+
im_B = Image.open(im_B_path)
|
|
56
|
+
w2, h2 = im_B.size
|
|
57
|
+
if True: # Note: we keep this true as it was used in DKM/RoMa papers. There is very little difference compared to setting to False.
|
|
58
|
+
scale1 = 1200 / max(w1, h1)
|
|
59
|
+
scale2 = 1200 / max(w2, h2)
|
|
60
|
+
w1, h1 = scale1 * w1, scale1 * h1
|
|
61
|
+
w2, h2 = scale2 * w2, scale2 * h2
|
|
62
|
+
K1, K2 = K1.copy(), K2.copy()
|
|
63
|
+
K1[:2] = K1[:2] * scale1
|
|
64
|
+
K2[:2] = K2[:2] * scale2
|
|
65
|
+
for _ in range(5):
|
|
66
|
+
matches, _, _, _ = model.sample(preds, 5_000)
|
|
67
|
+
kpts1, kpts2 = model.to_pixel_coordinates(matches, h1, w1, h2, w2)
|
|
68
|
+
kpts1, kpts2 = kpts1.cpu().numpy(), kpts2.cpu().numpy()
|
|
69
|
+
shuffling = np.random.permutation(np.arange(len(kpts1)))
|
|
70
|
+
kpts1 = kpts1[shuffling]
|
|
71
|
+
kpts2 = kpts2[shuffling]
|
|
72
|
+
try:
|
|
73
|
+
threshold = 0.5
|
|
74
|
+
norm_threshold = threshold / (
|
|
75
|
+
np.mean(np.abs(K1[:2, :2])) + np.mean(np.abs(K2[:2, :2]))
|
|
76
|
+
)
|
|
77
|
+
R_est, t_est, _ = estimate_pose_cv2_ransac(
|
|
78
|
+
kpts1,
|
|
79
|
+
kpts2,
|
|
80
|
+
K1,
|
|
81
|
+
K2,
|
|
82
|
+
norm_threshold,
|
|
83
|
+
conf=0.99999,
|
|
84
|
+
)
|
|
85
|
+
e_t, e_R = compute_pose_error(R_est, t_est[:, 0], R, t)
|
|
86
|
+
e_pose = max(e_t, e_R)
|
|
87
|
+
except Exception as e:
|
|
88
|
+
logger.debug(f"Pose estimation error: {e}")
|
|
89
|
+
e_t, e_R = 90, 90
|
|
90
|
+
e_pose = max(e_t, e_R)
|
|
91
|
+
tot_e_t.append(e_t)
|
|
92
|
+
tot_e_R.append(e_R)
|
|
93
|
+
tot_e_pose.append(e_pose)
|
|
94
|
+
pbar.set_postfix(
|
|
95
|
+
auc=f"{[f'{a.item():.3f}' for a in pose_auc(tot_e_pose, thresholds)]}"
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
tot_e_pose = np.array(tot_e_pose)
|
|
99
|
+
auc = pose_auc(tot_e_pose, thresholds)
|
|
100
|
+
acc_5 = (tot_e_pose < 5).mean()
|
|
101
|
+
acc_10 = (tot_e_pose < 10).mean()
|
|
102
|
+
acc_15 = (tot_e_pose < 15).mean()
|
|
103
|
+
acc_20 = (tot_e_pose < 20).mean()
|
|
104
|
+
map_5 = acc_5
|
|
105
|
+
map_10 = np.mean([acc_5, acc_10])
|
|
106
|
+
map_20 = np.mean([acc_5, acc_10, acc_15, acc_20])
|
|
107
|
+
logger.info("%s auc: %s", model_name, auc)
|
|
108
|
+
return {
|
|
109
|
+
"auc_5": auc[0],
|
|
110
|
+
"auc_10": auc[1],
|
|
111
|
+
"auc_20": auc[2],
|
|
112
|
+
"map_5": map_5,
|
|
113
|
+
"map_10": map_10,
|
|
114
|
+
"map_20": map_20,
|
|
115
|
+
}
|