Skip to content

Commit 537499b

Browse files
authored
add: rdd sparse and dense matcher (#132)
1 parent 765373e commit 537499b

File tree

9 files changed

+165
-3
lines changed

9 files changed

+165
-3
lines changed

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,6 @@
7979
[submodule "imcui/third_party/LiftFeat"]
8080
path = imcui/third_party/LiftFeat
8181
url = https://github.com/agipro/LiftFeat.git
82+
[submodule "imcui/third_party/rdd"]
83+
path = imcui/third_party/rdd
84+
url = https://github.com/agipro/rdd.git

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,9 @@ The tool currently supports various popular image matching algorithms, namely:
3333

3434
| Algorithm | Supported | Conference/Journal | Year | GitHub Link |
3535
|------------------|-----------|--------------------|------|-------------|
36-
| DaD || ARXIV | 2025 | [Link](https://github.com/Parskatt/dad) |
36+
| RDD || CVPR | 2025 | [Link](https://github.com/xtcpete/rdd) |
3737
| LiftFeat || ICRA | 2025 | [Link](https://github.com/lyp-deeplearning/LiftFeat) |
38+
| DaD || ARXIV | 2025 | [Link](https://github.com/Parskatt/dad) |
3839
| MINIMA || ARXIV | 2024 | [Link](https://github.com/LSXI7/MINIMA) |
3940
| XoFTR || CVPR | 2024 | [Link](https://github.com/OnderT/XoFTR) |
4041
| EfficientLoFTR || CVPR | 2024 | [Link](https://github.com/zju3dv/EfficientLoFTR) |

config/config.yaml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,27 @@ matcher_zoo:
253253
paper: https://arxiv.org/abs/2505.0342
254254
project: null
255255
display: true
256+
rdd(sparse):
257+
matcher: NN-mutual
258+
feature: rdd
259+
dense: false
260+
info:
261+
name: RDD(sparse) #dispaly name
262+
source: "CVPR 2025"
263+
github: hhttps://github.com/xtcpete/rdd
264+
paper: https://arxiv.org/abs/2505.08013
265+
project: https://xtcpete.github.io/rdd
266+
display: true
267+
rdd(dense):
268+
matcher: rdd_dense
269+
dense: true
270+
info:
271+
name: RDD(dense) #dispaly name
272+
source: "CVPR 2025"
273+
github: hhttps://github.com/xtcpete/rdd
274+
paper: https://arxiv.org/abs/2505.08013
275+
project: https://xtcpete.github.io/rdd
276+
display: true
256277
dedode:
257278
matcher: Dual-Softmax
258279
feature: dedode

imcui/hloc/extract_features.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,17 @@
225225
"resize_max": 1600,
226226
},
227227
},
228+
"rdd": {
229+
"output": "feats-rdd-n5000-r1600",
230+
"model": {
231+
"name": "rdd",
232+
"max_keypoints": 5000,
233+
},
234+
"preprocessing": {
235+
"grayscale": False,
236+
"resize_max": 1600,
237+
},
238+
},
228239
"aliked-n16-rot": {
229240
"output": "feats-aliked-n16-rot",
230241
"model": {

imcui/hloc/extractors/liftfeat.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
from ..utils.base_model import BaseModel
44
from .. import logger, MODEL_REPO_ID
55

6-
fire_path = Path(__file__).parent / "../../third_party/LiftFeat"
7-
sys.path.append(str(fire_path))
6+
liftfeat_path = Path(__file__).parent / "../../third_party/LiftFeat"
7+
sys.path.append(str(liftfeat_path))
88

99
from models.liftfeat_wrapper import LiftFeat
1010

imcui/hloc/extractors/rdd.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import sys
2+
import yaml
3+
from pathlib import Path
4+
from ..utils.base_model import BaseModel
5+
from .. import logger, MODEL_REPO_ID, DEVICE
6+
7+
rdd_path = Path(__file__).parent / "../../third_party/rdd"
8+
sys.path.append(str(rdd_path))
9+
10+
from RDD.RDD import build as build_rdd
11+
12+
13+
class Rdd(BaseModel):
14+
default_conf = {
15+
"keypoint_threshold": 0.1,
16+
"max_keypoints": 4096,
17+
"model_name": "RDD-v2.pth",
18+
}
19+
20+
required_inputs = ["image"]
21+
22+
def _init(self, conf):
23+
logger.info("Loading RDD model...")
24+
model_path = self._download_model(
25+
repo_id=MODEL_REPO_ID,
26+
filename="{}/{}".format(Path(__file__).stem, self.conf["model_name"]),
27+
)
28+
config_path = rdd_path / "configs/default.yaml"
29+
with open(config_path, "r") as file:
30+
config = yaml.safe_load(file)
31+
config["top_k"] = conf["max_keypoints"]
32+
config["detection_threshold"] = conf["keypoint_threshold"]
33+
config["device"] = DEVICE
34+
self.net = build_rdd(config=config, weights=model_path)
35+
self.net.eval()
36+
logger.info("Loading RDD model done!")
37+
38+
def _forward(self, data):
39+
image = data["image"]
40+
pred = self.net.extract(image)[0]
41+
keypoints = pred["keypoints"]
42+
descriptors = pred["descriptors"]
43+
scores = pred["scores"]
44+
if self.conf["max_keypoints"] < len(keypoints):
45+
idxs = scores.argsort()[-self.conf["max_keypoints"] or None :]
46+
keypoints = keypoints[idxs, :2]
47+
descriptors = descriptors[idxs]
48+
scores = scores[idxs]
49+
50+
pred = {
51+
"keypoints": keypoints[None],
52+
"descriptors": descriptors[None].permute(0, 2, 1),
53+
"scores": scores[None],
54+
}
55+
return pred

imcui/hloc/match_dense.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,23 @@
320320
"dfactor": 8,
321321
},
322322
},
323+
"rdd_dense": {
324+
"output": "matches-rdd_dense",
325+
"model": {
326+
"name": "rdd_dense",
327+
"model_name": "RDD-v2.pth",
328+
"max_keypoints": 2000,
329+
"match_threshold": 0.2,
330+
},
331+
"preprocessing": {
332+
"grayscale": False,
333+
"force_resize": True,
334+
"resize_max": 1024,
335+
"width": 320,
336+
"height": 240,
337+
"dfactor": 8,
338+
},
339+
},
323340
"minima_roma": {
324341
"output": "matches-minima_roma",
325342
"model": {

imcui/hloc/matchers/rdd_dense.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import sys
2+
import yaml
3+
import torch
4+
from pathlib import Path
5+
from ..utils.base_model import BaseModel
6+
from .. import logger, MODEL_REPO_ID, DEVICE
7+
8+
rdd_path = Path(__file__).parent / "../../third_party/rdd"
9+
sys.path.append(str(rdd_path))
10+
11+
from RDD.RDD import build as build_rdd
12+
from RDD.RDD_helper import RDD_helper
13+
14+
15+
class RddDense(BaseModel):
16+
default_conf = {
17+
"keypoint_threshold": 0.1,
18+
"max_keypoints": 4096,
19+
"model_name": "RDD-v2.pth",
20+
"match_threshold": 0.1,
21+
}
22+
23+
required_inputs = ["image0", "image1"]
24+
25+
def _init(self, conf):
26+
logger.info("Loading RDD model...")
27+
model_path = self._download_model(
28+
repo_id=MODEL_REPO_ID,
29+
filename="{}/{}".format("rdd", self.conf["model_name"]),
30+
)
31+
config_path = rdd_path / "configs/default.yaml"
32+
with open(config_path, "r") as file:
33+
config = yaml.safe_load(file)
34+
config["top_k"] = conf["max_keypoints"]
35+
config["detection_threshold"] = conf["keypoint_threshold"]
36+
config["device"] = DEVICE
37+
rdd_net = build_rdd(config=config, weights=model_path)
38+
rdd_net.eval()
39+
self.net = RDD_helper(rdd_net)
40+
logger.info("Loading RDD model done!")
41+
42+
def _forward(self, data):
43+
img0 = data["image0"]
44+
img1 = data["image1"]
45+
mkpts_0, mkpts_1, conf = self.net.match_dense(
46+
img0, img1, thr=self.conf["match_threshold"]
47+
)
48+
pred = {
49+
"keypoints0": torch.from_numpy(mkpts_0),
50+
"keypoints1": torch.from_numpy(mkpts_1),
51+
"mconf": torch.from_numpy(conf),
52+
}
53+
return pred

imcui/third_party/rdd

Submodule rdd added at b9307a7

0 commit comments

Comments
 (0)