Vincentqyw commited on
Commit
49a0323
1 Parent(s): 733c569

update: rord

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitignore +4 -0
  2. app.py +6 -3
  3. common/utils.py +10 -1
  4. hloc/extract_features.py +12 -0
  5. hloc/extractors/alike.py +0 -1
  6. hloc/extractors/d2net.py +0 -1
  7. hloc/extractors/darkfeat.py +1 -4
  8. hloc/extractors/dedode.py +1 -3
  9. hloc/extractors/example.py +1 -3
  10. hloc/extractors/fire_local.py +1 -2
  11. hloc/extractors/netvlad.py +1 -3
  12. hloc/extractors/rord.py +75 -0
  13. hloc/matchers/aspanformer.py +4 -3
  14. hloc/matchers/dkm.py +1 -3
  15. hloc/matchers/gluestick.py +1 -3
  16. hloc/matchers/lightglue.py +1 -2
  17. hloc/matchers/roma.py +1 -3
  18. hloc/matchers/sgmnet.py +1 -2
  19. hloc/matchers/sold2.py +14 -7
  20. hloc/utils/__init__.py +2 -2
  21. third_party/RoRD/LICENSE +251 -0
  22. third_party/RoRD/assets/register_ortho.jpg +3 -0
  23. third_party/RoRD/assets/register_persp.jpg +3 -0
  24. third_party/RoRD/assets/register_pointcloud.jpg +3 -0
  25. third_party/RoRD/assets/rord_evalRT.jpg +3 -0
  26. third_party/RoRD/assets/rord_extract.jpg +3 -0
  27. third_party/RoRD/assets/sift_extract.jpg +3 -0
  28. third_party/RoRD/assets/teaser2.jpg +3 -0
  29. third_party/RoRD/configs/camera.txt +3 -0
  30. third_party/RoRD/configs/train_scenes.txt +7 -0
  31. third_party/RoRD/configs/train_scenes_small.txt +1 -0
  32. third_party/RoRD/demo/__init__.py +0 -0
  33. third_party/RoRD/demo/depth/depth1_1.png +3 -0
  34. third_party/RoRD/demo/depth/depth1_2.png +3 -0
  35. third_party/RoRD/demo/depth/depth2_1.png +3 -0
  36. third_party/RoRD/demo/depth/depth2_2.png +3 -0
  37. third_party/RoRD/demo/depth/depth3_1.png +3 -0
  38. third_party/RoRD/demo/depth/depth3_2.png +3 -0
  39. third_party/RoRD/demo/register.py +265 -0
  40. third_party/RoRD/demo/rgb/rgb1_1.jpg +3 -0
  41. third_party/RoRD/demo/rgb/rgb1_1.npy +3 -0
  42. third_party/RoRD/demo/rgb/rgb1_2.jpg +3 -0
  43. third_party/RoRD/demo/rgb/rgb1_2.npy +3 -0
  44. third_party/RoRD/demo/rgb/rgb2_1.jpg +3 -0
  45. third_party/RoRD/demo/rgb/rgb2_1.npy +3 -0
  46. third_party/RoRD/demo/rgb/rgb2_2.jpg +3 -0
  47. third_party/RoRD/demo/rgb/rgb2_2.npy +3 -0
  48. third_party/RoRD/demo/rgb/rgb3_1.jpg +3 -0
  49. third_party/RoRD/demo/rgb/rgb3_1.npy +3 -0
  50. third_party/RoRD/demo/rgb/rgb3_2.jpg +3 -0
.gitignore CHANGED
@@ -17,3 +17,7 @@ third_party/REKD
17
  Dockerfile
18
  hloc/matchers/dedode.py
19
  gradio_cached_examples
 
 
 
 
 
17
  Dockerfile
18
  hloc/matchers/dedode.py
19
  gradio_cached_examples
20
+
21
+ hloc/matchers/quadtree.py
22
+ third_party/QuadTreeAttention
23
+ desktop.ini
app.py CHANGED
@@ -14,6 +14,9 @@ This Space demonstrates [Image Matching WebUI](https://github.com/Vincentqyw/ima
14
 
15
  🔎 For more details about supported local features and matchers, please refer to https://github.com/Vincentqyw/image-matching-webui
16
 
 
 
 
17
  """
18
 
19
 
@@ -102,9 +105,9 @@ def run(config):
102
  )
103
 
104
  with gr.Row():
105
- button_reset = gr.Button(label="Reset", value="Reset")
106
  button_run = gr.Button(
107
- label="Run Match", value="Run Match", variant="primary"
108
  )
109
 
110
  with gr.Accordion("Advanced Setting", open=False):
@@ -242,7 +245,7 @@ def run(config):
242
  )
243
  with gr.Accordion("Open for More: Geometry info", open=False):
244
  geometry_result = gr.JSON(label="Reconstructed Geometry")
245
-
246
  # callbacks
247
  match_image_src.change(
248
  fn=ui_change_imagebox,
 
14
 
15
  🔎 For more details about supported local features and matchers, please refer to https://github.com/Vincentqyw/image-matching-webui
16
 
17
+ 🚀 All algorithms run on CPU for inference on HF, causing slow speeds and high latency. For faster inference, please download the [source code](https://github.com/Vincentqyw/image-matching-webui) for local deployment or check [openxlab space](https://github.com/Vincentqyw/image-matching-webui) and [direct URL](https://g-app-center-083997-7409-n9elr1.openxlab.space)
18
+
19
+ 🐛 Your feedback is valuable to me. Please do not hesitate to report any bugs [here](https://github.com/Vincentqyw/image-matching-webui/issues).
20
  """
21
 
22
 
 
105
  )
106
 
107
  with gr.Row():
108
+ button_reset = gr.Button(value="Reset")
109
  button_run = gr.Button(
110
+ value="Run Match", variant="primary"
111
  )
112
 
113
  with gr.Accordion("Advanced Setting", open=False):
 
245
  )
246
  with gr.Accordion("Open for More: Geometry info", open=False):
247
  geometry_result = gr.JSON(label="Reconstructed Geometry")
248
+
249
  # callbacks
250
  match_image_src.change(
251
  fn=ui_change_imagebox,
common/utils.py CHANGED
@@ -48,6 +48,7 @@ def gen_examples():
48
  pairs = list(combinations(imgs_list, 2))
49
  selected = random.sample(range(len(pairs)), count)
50
  return [pairs[i] for i in selected]
 
51
  # image pair path
52
  path = "datasets/sacre_coeur/mapping"
53
  pairs = gen_images_pairs(path, len(example_matchers))
@@ -176,7 +177,10 @@ def compute_geom(
176
  if H is not None:
177
  geo_info["Homography"] = H.tolist()
178
  _, H1, H2 = cv2.stereoRectifyUncalibrated(
179
- mkpts0.reshape(-1, 2), mkpts1.reshape(-1, 2), F, imgSize=(w1, h1)
 
 
 
180
  )
181
  geo_info["H1"] = H1.tolist()
182
  geo_info["H2"] = H2.tolist()
@@ -504,6 +508,11 @@ matcher_zoo = {
504
  "config_feature": extract_features.confs["d2net-ss"],
505
  "dense": False,
506
  },
 
 
 
 
 
507
  # "d2net-ms": {
508
  # "config": match_features.confs["NN-mutual"],
509
  # "config_feature": extract_features.confs["d2net-ms"],
 
48
  pairs = list(combinations(imgs_list, 2))
49
  selected = random.sample(range(len(pairs)), count)
50
  return [pairs[i] for i in selected]
51
+
52
  # image pair path
53
  path = "datasets/sacre_coeur/mapping"
54
  pairs = gen_images_pairs(path, len(example_matchers))
 
177
  if H is not None:
178
  geo_info["Homography"] = H.tolist()
179
  _, H1, H2 = cv2.stereoRectifyUncalibrated(
180
+ mkpts0.reshape(-1, 2),
181
+ mkpts1.reshape(-1, 2),
182
+ F,
183
+ imgSize=(w1, h1),
184
  )
185
  geo_info["H1"] = H1.tolist()
186
  geo_info["H2"] = H2.tolist()
 
508
  "config_feature": extract_features.confs["d2net-ss"],
509
  "dense": False,
510
  },
511
+ "rord": {
512
+ "config": match_features.confs["NN-mutual"],
513
+ "config_feature": extract_features.confs["rord"],
514
+ "dense": False,
515
+ },
516
  # "d2net-ms": {
517
  # "config": match_features.confs["NN-mutual"],
518
  # "config_feature": extract_features.confs["d2net-ms"],
hloc/extract_features.py CHANGED
@@ -115,6 +115,18 @@ confs = {
115
  "resize_max": 1600,
116
  },
117
  },
 
 
 
 
 
 
 
 
 
 
 
 
118
  "rootsift": {
119
  "output": "feats-rootsift-n5000-r1600",
120
  "model": {
 
115
  "resize_max": 1600,
116
  },
117
  },
118
+ "rord": {
119
+ "output": "feats-rord-ss-n5000-r1600",
120
+ "model": {
121
+ "name": "rord",
122
+ "multiscale": False,
123
+ "max_keypoints": 5000,
124
+ },
125
+ "preprocessing": {
126
+ "grayscale": False,
127
+ "resize_max": 1600,
128
+ },
129
+ },
130
  "rootsift": {
131
  "output": "feats-rootsift-n5000-r1600",
132
  "model": {
hloc/extractors/alike.py CHANGED
@@ -1,6 +1,5 @@
1
  import sys
2
  from pathlib import Path
3
- import subprocess
4
  import torch
5
 
6
  from ..utils.base_model import BaseModel
 
1
  import sys
2
  from pathlib import Path
 
3
  import torch
4
 
5
  from ..utils.base_model import BaseModel
hloc/extractors/d2net.py CHANGED
@@ -10,7 +10,6 @@ sys.path.append(str(d2net_path))
10
  from lib.model_test import D2Net as _D2Net
11
  from lib.pyramid import process_multiscale
12
 
13
-
14
  class D2Net(BaseModel):
15
  default_conf = {
16
  "model_name": "d2_tf.pth",
 
10
  from lib.model_test import D2Net as _D2Net
11
  from lib.pyramid import process_multiscale
12
 
 
13
  class D2Net(BaseModel):
14
  default_conf = {
15
  "model_name": "d2_tf.pth",
hloc/extractors/darkfeat.py CHANGED
@@ -1,11 +1,8 @@
1
  import sys
2
  from pathlib import Path
3
  import subprocess
4
- import logging
5
-
6
  from ..utils.base_model import BaseModel
7
-
8
- logger = logging.getLogger(__name__)
9
 
10
  darkfeat_path = Path(__file__).parent / "../../third_party/DarkFeat"
11
  sys.path.append(str(darkfeat_path))
 
1
  import sys
2
  from pathlib import Path
3
  import subprocess
 
 
4
  from ..utils.base_model import BaseModel
5
+ from .. import logger
 
6
 
7
  darkfeat_path = Path(__file__).parent / "../../third_party/DarkFeat"
8
  sys.path.append(str(darkfeat_path))
hloc/extractors/dedode.py CHANGED
@@ -1,10 +1,10 @@
1
  import sys
2
  from pathlib import Path
3
  import subprocess
4
- import logging
5
  import torch
6
  from PIL import Image
7
  from ..utils.base_model import BaseModel
 
8
  import torchvision.transforms as transforms
9
 
10
  dedode_path = Path(__file__).parent / "../../third_party/DeDoDe"
@@ -14,8 +14,6 @@ from DeDoDe import dedode_detector_L, dedode_descriptor_B
14
  from DeDoDe.utils import to_pixel_coords
15
 
16
  device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
17
- logger = logging.getLogger(__name__)
18
-
19
 
20
  class DeDoDe(BaseModel):
21
  default_conf = {
 
1
  import sys
2
  from pathlib import Path
3
  import subprocess
 
4
  import torch
5
  from PIL import Image
6
  from ..utils.base_model import BaseModel
7
+ from .. import logger
8
  import torchvision.transforms as transforms
9
 
10
  dedode_path = Path(__file__).parent / "../../third_party/DeDoDe"
 
14
  from DeDoDe.utils import to_pixel_coords
15
 
16
  device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
 
 
17
 
18
  class DeDoDe(BaseModel):
19
  default_conf = {
hloc/extractors/example.py CHANGED
@@ -2,7 +2,7 @@ import sys
2
  from pathlib import Path
3
  import subprocess
4
  import torch
5
- import logging
6
 
7
  from ..utils.base_model import BaseModel
8
 
@@ -12,8 +12,6 @@ sys.path.append(str(example_path))
12
  # import some modules here
13
 
14
  device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
15
- logger = logging.getLogger(__name__)
16
-
17
 
18
  class Example(BaseModel):
19
  # change to your default configs
 
2
  from pathlib import Path
3
  import subprocess
4
  import torch
5
+ from .. import logger
6
 
7
  from ..utils.base_model import BaseModel
8
 
 
12
  # import some modules here
13
 
14
  device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
 
 
15
 
16
  class Example(BaseModel):
17
  # change to your default configs
hloc/extractors/fire_local.py CHANGED
@@ -1,13 +1,12 @@
1
  from pathlib import Path
2
  import subprocess
3
- import logging
4
  import sys
5
  import torch
6
  import torchvision.transforms as tvf
7
 
8
  from ..utils.base_model import BaseModel
 
9
 
10
- logger = logging.getLogger(__name__)
11
  fire_path = Path(__file__).parent / "../../third_party/fire"
12
 
13
  sys.path.append(str(fire_path))
 
1
  from pathlib import Path
2
  import subprocess
 
3
  import sys
4
  import torch
5
  import torchvision.transforms as tvf
6
 
7
  from ..utils.base_model import BaseModel
8
+ from .. import logger
9
 
 
10
  fire_path = Path(__file__).parent / "../../third_party/fire"
11
 
12
  sys.path.append(str(fire_path))
hloc/extractors/netvlad.py CHANGED
@@ -1,6 +1,5 @@
1
  from pathlib import Path
2
  import subprocess
3
- import logging
4
  import numpy as np
5
  import torch
6
  import torch.nn as nn
@@ -9,8 +8,7 @@ import torchvision.models as models
9
  from scipy.io import loadmat
10
 
11
  from ..utils.base_model import BaseModel
12
-
13
- logger = logging.getLogger(__name__)
14
 
15
  EPS = 1e-6
16
 
 
1
  from pathlib import Path
2
  import subprocess
 
3
  import numpy as np
4
  import torch
5
  import torch.nn as nn
 
8
  from scipy.io import loadmat
9
 
10
  from ..utils.base_model import BaseModel
11
+ from .. import logger
 
12
 
13
  EPS = 1e-6
14
 
hloc/extractors/rord.py ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import sys
2
+ from pathlib import Path
3
+ import subprocess
4
+ import torch
5
+
6
+ from ..utils.base_model import BaseModel
7
+ from .. import logger
8
+
9
+ rord_path = Path(__file__).parent / "../../third_party/RoRD"
10
+ sys.path.append(str(rord_path))
11
+ from lib.model_test import D2Net as _RoRD
12
+ from lib.pyramid import process_multiscale
13
+
14
+ class RoRD(BaseModel):
15
+ default_conf = {
16
+ "model_name": "rord.pth",
17
+ "checkpoint_dir": rord_path / "models",
18
+ "use_relu": True,
19
+ "multiscale": False,
20
+ "max_keypoints": 1024,
21
+ }
22
+ required_inputs = ["image"]
23
+ weight_urls = {
24
+ "rord.pth": "https://drive.google.com/uc?id=12414ZGKwgPAjNTGtNrlB4VV9l7W76B2o&confirm=t",
25
+ }
26
+ proxy = "http://localhost:1080"
27
+
28
+ def _init(self, conf):
29
+ model_path = conf["checkpoint_dir"] / conf["model_name"]
30
+ link = self.weight_urls[conf["model_name"]]
31
+ if not model_path.exists():
32
+ model_path.parent.mkdir(exist_ok=True)
33
+ cmd_wo_proxy = ["gdown", link, "-O", str(model_path)]
34
+ cmd = ["gdown", link, "-O", str(model_path), "--proxy", self.proxy]
35
+ logger.info(
36
+ f"Downloading the RoRD model with `{cmd_wo_proxy}`."
37
+ )
38
+ try:
39
+ subprocess.run(cmd_wo_proxy, check=True)
40
+ except subprocess.CalledProcessError as e:
41
+ logger.info(f"Downloading the RoRD model with `{cmd}`.")
42
+ try:
43
+ subprocess.run(cmd, check=True)
44
+ except subprocess.CalledProcessError as e:
45
+ logger.error(f"Failed to download the RoRD model.")
46
+ raise e
47
+ logger.info("RoRD model loaded.")
48
+ self.net = _RoRD(
49
+ model_file=model_path, use_relu=conf["use_relu"], use_cuda=False
50
+ )
51
+
52
+ def _forward(self, data):
53
+ image = data["image"]
54
+ image = image.flip(1) # RGB -> BGR
55
+ norm = image.new_tensor([103.939, 116.779, 123.68])
56
+ image = image * 255 - norm.view(1, 3, 1, 1) # caffe normalization
57
+
58
+ if self.conf["multiscale"]:
59
+ keypoints, scores, descriptors = process_multiscale(image, self.net)
60
+ else:
61
+ keypoints, scores, descriptors = process_multiscale(
62
+ image, self.net, scales=[1]
63
+ )
64
+ keypoints = keypoints[:, [1, 0]] # (x, y) and remove the scale
65
+
66
+ idxs = scores.argsort()[-self.conf["max_keypoints"] or None :]
67
+ keypoints = keypoints[idxs, :2]
68
+ descriptors = descriptors[idxs]
69
+ scores = scores[idxs]
70
+
71
+ return {
72
+ "keypoints": torch.from_numpy(keypoints)[None],
73
+ "scores": torch.from_numpy(scores)[None],
74
+ "descriptors": torch.from_numpy(descriptors.T)[None],
75
+ }
hloc/matchers/aspanformer.py CHANGED
@@ -4,9 +4,8 @@ from ..utils.base_model import BaseModel
4
  from ..utils import do_system
5
  from pathlib import Path
6
  import subprocess
7
- import logging
8
 
9
- logger = logging.getLogger(__name__)
10
 
11
  sys.path.append(str(Path(__file__).parent / "../../third_party"))
12
  from ASpanFormer.src.ASpanFormer.aspanformer import ASpanFormer as _ASpanFormer
@@ -77,7 +76,9 @@ class ASpanFormer(BaseModel):
77
 
78
  # update: match threshold
79
  _config["aspan"]["match_coarse"]["thr"] = conf["match_threshold"]
80
- _config["aspan"]["match_coarse"]["skh_iters"] = conf["sinkhorn_iterations"]
 
 
81
 
82
  self.net = _ASpanFormer(config=_config["aspan"])
83
  weight_path = model_path
 
4
  from ..utils import do_system
5
  from pathlib import Path
6
  import subprocess
 
7
 
8
+ from .. import logger
9
 
10
  sys.path.append(str(Path(__file__).parent / "../../third_party"))
11
  from ASpanFormer.src.ASpanFormer.aspanformer import ASpanFormer as _ASpanFormer
 
76
 
77
  # update: match threshold
78
  _config["aspan"]["match_coarse"]["thr"] = conf["match_threshold"]
79
+ _config["aspan"]["match_coarse"]["skh_iters"] = conf[
80
+ "sinkhorn_iterations"
81
+ ]
82
 
83
  self.net = _ASpanFormer(config=_config["aspan"])
84
  weight_path = model_path
hloc/matchers/dkm.py CHANGED
@@ -3,16 +3,14 @@ from pathlib import Path
3
  import torch
4
  from PIL import Image
5
  import subprocess
6
- import logging
7
  from ..utils.base_model import BaseModel
 
8
 
9
  sys.path.append(str(Path(__file__).parent / "../../third_party"))
10
  from DKM.dkm import DKMv3_outdoor
11
 
12
  dkm_path = Path(__file__).parent / "../../third_party/DKM"
13
  device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
14
- logger = logging.getLogger(__name__)
15
-
16
 
17
  class DKMv3(BaseModel):
18
  default_conf = {
 
3
  import torch
4
  from PIL import Image
5
  import subprocess
 
6
  from ..utils.base_model import BaseModel
7
+ from .. import logger
8
 
9
  sys.path.append(str(Path(__file__).parent / "../../third_party"))
10
  from DKM.dkm import DKMv3_outdoor
11
 
12
  dkm_path = Path(__file__).parent / "../../third_party/DKM"
13
  device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
 
 
14
 
15
  class DKMv3(BaseModel):
16
  default_conf = {
hloc/matchers/gluestick.py CHANGED
@@ -1,11 +1,9 @@
1
  import sys
2
  from pathlib import Path
3
  import subprocess
4
- import logging
5
  import torch
6
  from ..utils.base_model import BaseModel
7
-
8
- logger = logging.getLogger(__name__)
9
 
10
  gluestick_path = Path(__file__).parent / "../../third_party/GlueStick"
11
  sys.path.append(str(gluestick_path))
 
1
  import sys
2
  from pathlib import Path
3
  import subprocess
 
4
  import torch
5
  from ..utils.base_model import BaseModel
6
+ from .. import logger
 
7
 
8
  gluestick_path = Path(__file__).parent / "../../third_party/GlueStick"
9
  sys.path.append(str(gluestick_path))
hloc/matchers/lightglue.py CHANGED
@@ -1,9 +1,8 @@
1
  import sys
2
  from pathlib import Path
3
- import logging
4
  from ..utils.base_model import BaseModel
 
5
 
6
- logger = logging.getLogger(__name__)
7
  lightglue_path = Path(__file__).parent / "../../third_party/LightGlue"
8
  sys.path.append(str(lightglue_path))
9
  from lightglue import LightGlue as LG
 
1
  import sys
2
  from pathlib import Path
 
3
  from ..utils.base_model import BaseModel
4
+ from .. import logger
5
 
 
6
  lightglue_path = Path(__file__).parent / "../../third_party/LightGlue"
7
  sys.path.append(str(lightglue_path))
8
  from lightglue import LightGlue as LG
hloc/matchers/roma.py CHANGED
@@ -1,10 +1,10 @@
1
  import sys
2
  from pathlib import Path
3
  import subprocess
4
- import logging
5
  import torch
6
  from PIL import Image
7
  from ..utils.base_model import BaseModel
 
8
 
9
  roma_path = Path(__file__).parent / "../../third_party/Roma"
10
  sys.path.append(str(roma_path))
@@ -12,8 +12,6 @@ sys.path.append(str(roma_path))
12
  from roma.models.model_zoo.roma_models import roma_model
13
 
14
  device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
15
- logger = logging.getLogger(__name__)
16
-
17
 
18
  class Roma(BaseModel):
19
  default_conf = {
 
1
  import sys
2
  from pathlib import Path
3
  import subprocess
 
4
  import torch
5
  from PIL import Image
6
  from ..utils.base_model import BaseModel
7
+ from .. import logger
8
 
9
  roma_path = Path(__file__).parent / "../../third_party/Roma"
10
  sys.path.append(str(roma_path))
 
12
  from roma.models.model_zoo.roma_models import roma_model
13
 
14
  device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
 
 
15
 
16
  class Roma(BaseModel):
17
  default_conf = {
hloc/matchers/sgmnet.py CHANGED
@@ -1,12 +1,12 @@
1
  import sys
2
  from pathlib import Path
3
  import subprocess
4
- import logging
5
  import torch
6
  from PIL import Image
7
  from collections import OrderedDict, namedtuple
8
  from ..utils.base_model import BaseModel
9
  from ..utils import do_system
 
10
 
11
  sgmnet_path = Path(__file__).parent / "../../third_party/SGMNet"
12
  sys.path.append(str(sgmnet_path))
@@ -14,7 +14,6 @@ sys.path.append(str(sgmnet_path))
14
  from sgmnet import matcher as SGM_Model
15
 
16
  device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
17
- logger = logging.getLogger(__name__)
18
 
19
 
20
  class SGMNet(BaseModel):
 
1
  import sys
2
  from pathlib import Path
3
  import subprocess
 
4
  import torch
5
  from PIL import Image
6
  from collections import OrderedDict, namedtuple
7
  from ..utils.base_model import BaseModel
8
  from ..utils import do_system
9
+ from .. import logger
10
 
11
  sgmnet_path = Path(__file__).parent / "../../third_party/SGMNet"
12
  sys.path.append(str(sgmnet_path))
 
14
  from sgmnet import matcher as SGM_Model
15
 
16
  device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
 
17
 
18
 
19
  class SGMNet(BaseModel):
hloc/matchers/sold2.py CHANGED
@@ -4,18 +4,13 @@ from ..utils.base_model import BaseModel
4
  import torch
5
 
6
  from ..utils.base_model import BaseModel
 
 
7
 
8
  sold2_path = Path(__file__).parent / "../../third_party/SOLD2"
9
  sys.path.append(str(sold2_path))
10
 
11
  from sold2.model.line_matcher import LineMatcher
12
- from sold2.misc.visualize_util import (
13
- plot_images,
14
- plot_lines,
15
- plot_line_matches,
16
- plot_color_line_matches,
17
- plot_keypoints,
18
- )
19
 
20
  device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
21
 
@@ -36,9 +31,21 @@ class SOLD2(BaseModel):
36
  "image1",
37
  ]
38
 
 
 
 
39
  # Initialize the line matcher
40
  def _init(self, conf):
41
  checkpoint_path = conf["checkpoint_dir"] / conf["weights"]
 
 
 
 
 
 
 
 
 
42
  mode = "dynamic" # 'dynamic' or 'static'
43
  match_config = {
44
  "model_cfg": {
 
4
  import torch
5
 
6
  from ..utils.base_model import BaseModel
7
+ from .. import logger
8
+ import subprocess
9
 
10
  sold2_path = Path(__file__).parent / "../../third_party/SOLD2"
11
  sys.path.append(str(sold2_path))
12
 
13
  from sold2.model.line_matcher import LineMatcher
 
 
 
 
 
 
 
14
 
15
  device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
16
 
 
31
  "image1",
32
  ]
33
 
34
+ weight_urls = {
35
+ "sold2_wireframe.tar": "https://www.polybox.ethz.ch/index.php/s/blOrW89gqSLoHOk/download",
36
+ }
37
  # Initialize the line matcher
38
  def _init(self, conf):
39
  checkpoint_path = conf["checkpoint_dir"] / conf["weights"]
40
+
41
+ # Download the model.
42
+ if not checkpoint_path.exists():
43
+ checkpoint_path.parent.mkdir(exist_ok=True)
44
+ link = self.weight_urls[conf["weights"]]
45
+ cmd = ["wget", link, "-O", str(checkpoint_path)]
46
+ logger.info(f"Downloading the SOLD2 model with `{cmd}`.")
47
+ subprocess.run(cmd, check=True)
48
+
49
  mode = "dynamic" # 'dynamic' or 'static'
50
  match_config = {
51
  "model_cfg": {
hloc/utils/__init__.py CHANGED
@@ -1,7 +1,7 @@
1
  import os
2
  import logging
3
-
4
- logger = logging.getLogger(__name__)
5
 
6
 
7
  def do_system(cmd, verbose=False):
 
1
  import os
2
  import logging
3
+ import sys
4
+ from .. import logger
5
 
6
 
7
  def do_system(cmd, verbose=False):
third_party/RoRD/LICENSE ADDED
@@ -0,0 +1,251 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International Public License
2
+
3
+ By exercising the Licensed Rights (defined below), You accept and agree to be
4
+ bound by the terms and conditions of this Creative Commons
5
+ Attribution-NonCommercial-NoDerivatives 4.0 International Public License
6
+ ("Public License"). To the extent this Public License may be interpreted as a
7
+ contract, You are granted the Licensed Rights in consideration of Your
8
+ acceptance of these terms and conditions, and the Licensor grants You such
9
+ rights in consideration of benefits the Licensor receives from making the
10
+ Licensed Material available under these terms and conditions.
11
+
12
+ Section 1 – Definitions.
13
+
14
+ a. Adapted Material means material subject to Copyright and Similar Rights
15
+ that is derived from or based upon the Licensed Material and in which
16
+ the Licensed Material is translated, altered, arranged, transformed, or
17
+ otherwise modified in a manner requiring permission under the Copyright
18
+ and Similar Rights held by the Licensor. For purposes of this Public
19
+ License, where the Licensed Material is a musical work, performance, or
20
+ sound recording, Adapted Material is always produced where the Licensed
21
+ Material is synched in timed relation with a moving image.
22
+ b. Copyright and Similar Rights means copyright and/or similar rights
23
+ closely related to copyright including, without limitation,
24
+ performance, broadcast, sound recording, and Sui Generis Database
25
+ Rights, without regard to how the rights are labeled or categorized.
26
+ For purposes of this Public License, the rights specified in Section
27
+ 2(b)(1)-(2) are not Copyright and Similar Rights.
28
+ c. Effective Technological Measures means those measures that, in the
29
+ absence of proper authority, may not be circumvented under laws
30
+ fulfilling obligations under Article 11 of the WIPO Copyright Treaty
31
+ adopted on December 20, 1996, and/or similar international agreements.
32
+ d. Exceptions and Limitations means fair use, fair dealing, and/or any
33
+ other exception or limitation to Copyright and Similar Rights that
34
+ applies to Your use of the Licensed Material.
35
+ e. Licensed Material means the artistic or literary work, database, or
36
+ other material to which the Licensor applied this Public License.
37
+ f. Licensed Rights means the rights granted to You subject to the terms
38
+ and conditions of this Public License, which are limited to all
39
+ Copyright and Similar Rights that apply to Your use of the Licensed
40
+ Material and that the Licensor has authority to license.
41
+ g. Licensor means the individual(s) or entity(ies) granting rights under
42
+ this Public License.
43
+ h. NonCommercial means not primarily intended for or directed towards
44
+ commercial advantage or monetary compensation. For purposes of this
45
+ Public License, the exchange of the Licensed Material for other
46
+ material subject to Copyright and Similar Rights by digital
47
+ file-sharing or similar means is NonCommercial provided there is no
48
+ payment of monetary compensation in connection with the exchange.
49
+ i. Share means to provide material to the public by any means or process
50
+ that requires permission under the Licensed Rights, such as
51
+ reproduction, public display, public performance, distribution,
52
+ dissemination, communication, or importation, and to make material
53
+ available to the public including in ways that members of the public
54
+ may access the material from a place and at a time individually chosen
55
+ by them.
56
+ j. Sui Generis Database Rights means rights other than copyright resulting
57
+ from Directive 96/9/EC of the European Parliament and of the Council of
58
+ 11 March 1996 on the legal protection of databases, as amended and/or
59
+ succeeded, as well as other essentially equivalent rights anywhere in
60
+ the world.
61
+ k. You means the individual or entity exercising the Licensed Rights under
62
+ this Public License. Your has a corresponding meaning.
63
+
64
+ Section 2 – Scope.
65
+
66
+ a. License grant.
67
+ 1. Subject to the terms and conditions of this Public License, the
68
+ Licensor hereby grants You a worldwide, royalty-free,
69
+ non-sublicensable, non-exclusive, irrevocable license to exercise
70
+ the Licensed Rights in the Licensed Material to:
71
+ A. reproduce and Share the Licensed Material, in whole or in part,
72
+ for NonCommercial purposes only; and
73
+ B. produce and reproduce, but not Share, Adapted Material for
74
+ NonCommercial purposes only.
75
+ 2. Exceptions and Limitations. For the avoidance of doubt, where
76
+ Exceptions and Limitations apply to Your use, this Public License
77
+ does not apply, and You do not need to comply with its terms and
78
+ conditions.
79
+ 3. Term. The term of this Public License is specified in Section 6(a).
80
+ 4. Media and formats; technical modifications allowed. The Licensor
81
+ authorizes You to exercise the Licensed Rights in all media and
82
+ formats whether now known or hereafter created, and to make
83
+ technical modifications necessary to do so. The Licensor waives
84
+ and/or agrees not to assert any right or authority to forbid You
85
+ from making technical modifications necessary to exercise the
86
+ Licensed Rights, including technical modifications necessary to
87
+ circumvent Effective Technological Measures. For purposes of this
88
+ Public License, simply making modifications authorized by this
89
+ Section 2(a)(4) never produces Adapted Material.
90
+ 5. Downstream recipients.
91
+ A. Offer from the Licensor – Licensed Material. Every recipient of
92
+ the Licensed Material automatically receives an offer from the
93
+ Licensor to exercise the Licensed Rights under the terms and
94
+ conditions of this Public License.
95
+ B. No downstream restrictions. You may not offer or impose any
96
+ additional or different terms or conditions on, or apply any
97
+ Effective Technological Measures to, the Licensed Material if
98
+ doing so restricts exercise of the Licensed Rights by any
99
+ recipient of the Licensed Material.
100
+ 6. No endorsement. Nothing in this Public License constitutes or may
101
+ be construed as permission to assert or imply that You are, or that
102
+ Your use of the Licensed Material is, connected with, or sponsored,
103
+ endorsed, or granted official status by, the Licensor or others
104
+ designated to receive attribution as provided in Section
105
+ 3(a)(1)(A)(i).
106
+
107
+ b. Other rights.
108
+ 1. Moral rights, such as the right of integrity, are not licensed
109
+ under this Public License, nor are publicity, privacy, and/or other
110
+ similar personality rights; however, to the extent possible, the
111
+ Licensor waives and/or agrees not to assert any such rights held by
112
+ the Licensor to the limited extent necessary to allow You to
113
+ exercise the Licensed Rights, but not otherwise.
114
+ 2. Patent and trademark rights are not licensed under this Public
115
+ License.
116
+ 3. To the extent possible, the Licensor waives any right to collect
117
+ royalties from You for the exercise of the Licensed Rights, whether
118
+ directly or through a collecting society under any voluntary or
119
+ waivable statutory or compulsory licensing scheme. In all other
120
+ cases the Licensor expressly reserves any right to collect such
121
+ royalties, including when the Licensed Material is used other than
122
+ for NonCommercial purposes.
123
+
124
+ Section 3 – License Conditions.
125
+
126
+ Your exercise of the Licensed Rights is expressly made subject to the following conditions.
127
+
128
+ a. Attribution.
129
+
130
+ 1. If You Share the Licensed Material, You must:
131
+ A. retain the following if it is supplied by the Licensor with the
132
+ Licensed Material:
133
+ i. identification of the creator(s) of the Licensed Material
134
+ and any others designated to receive attribution, in any
135
+ reasonable manner requested by the Licensor (including by
136
+ pseudonym if designated);
137
+ ii. a copyright notice;
138
+ iii. a notice that refers to this Public License;
139
+ iv. a notice that refers to the disclaimer of warranties;
140
+ v. a URI or hyperlink to the Licensed Material to the extent
141
+ reasonably practicable;
142
+ B. indicate if You modified the Licensed Material and retain an
143
+ indication of any previous modifications; and
144
+ C. indicate the Licensed Material is licensed under this Public
145
+ License, and include the text of, or the URI or hyperlink to,
146
+ this Public License.
147
+
148
+ For the avoidance of doubt, You do not have permission under this
149
+ Public License to Share Adapted Material.
150
+
151
+ 2. You may satisfy the conditions in Section 3(a)(1) in any reasonable
152
+ manner based on the medium, means, and context in which You Share
153
+ the Licensed Material. For example, it may be reasonable to satisfy
154
+ the conditions by providing a URI or hyperlink to a resource that
155
+ includes the required information.
156
+ 3. If requested by the Licensor, You must remove any of the
157
+ information required by Section 3(a)(1)(A) to the extent reasonably
158
+ practicable.
159
+
160
+ Section 4 – Sui Generis Database Rights.
161
+
162
+ Where the Licensed Rights include Sui Generis Database Rights that apply to
163
+ Your use of the Licensed Material:
164
+
165
+ a. for the avoidance of doubt, Section 2(a)(1) grants You the right to
166
+ extract, reuse, reproduce, and Share all or a substantial portion of
167
+ the contents of the database for NonCommercial purposes only and
168
+ provided You do not Share Adapted Material;
169
+ b. if You include all or a substantial portion of the database contents in
170
+ a database in which You have Sui Generis Database Rights, then the
171
+ database in which You have Sui Generis Database Rights (but not its
172
+ individual contents) is Adapted Material; and
173
+ c. You must comply with the conditions in Section 3(a) if You Share all or
174
+ a substantial portion of the contents of the database.
175
+
176
+ For the avoidance of doubt, this Section 4 supplements and does not replace
177
+ Your obligations under this Public License where the Licensed Rights include
178
+ other Copyright and Similar Rights.
179
+
180
+ Section 5 – Disclaimer of Warranties and Limitation of Liability.
181
+
182
+ a. Unless otherwise separately undertaken by the Licensor, to the extent
183
+ possible, the Licensor offers the Licensed Material as-is and
184
+ as-available, and makes no representations or warranties of any kind
185
+ concerning the Licensed Material, whether express, implied, statutory,
186
+ or other. This includes, without limitation, warranties of title,
187
+ merchantability, fitness for a particular purpose, non-infringement,
188
+ absence of latent or other defects, accuracy, or the presence or
189
+ absence of errors, whether or not known or discoverable. Where
190
+ disclaimers of warranties are not allowed in full or in part, this
191
+ disclaimer may not apply to You.
192
+ b. To the extent possible, in no event will the Licensor be liable to You
193
+ on any legal theory (including, without limitation, negligence) or
194
+ otherwise for any direct, special, indirect, incidental, consequential,
195
+ punitive, exemplary, or other losses, costs, expenses, or damages
196
+ arising out of this Public License or use of the Licensed Material,
197
+ even if the Licensor has been advised of the possibility of such
198
+ losses, costs, expenses, or damages. Where a limitation of liability is
199
+ not allowed in full or in part, this limitation may not apply to You.
200
+ c. The disclaimer of warranties and limitation of liability provided above
201
+ shall be interpreted in a manner that, to the extent possible, most
202
+ closely approximates an absolute disclaimer and waiver of all
203
+ liability.
204
+
205
+ Section 6 – Term and Termination.
206
+
207
+ a. This Public License applies for the term of the Copyright and Similar
208
+ Rights licensed here. However, if You fail to comply with this Public
209
+ License, then Your rights under this Public License terminate
210
+ automatically.
211
+ b. Where Your right to use the Licensed Material has terminated under
212
+ Section 6(a), it reinstates:
213
+ 1. automatically as of the date the violation is cured, provided it is
214
+ cured within 30 days of Your discovery of the violation; or
215
+ 2. upon express reinstatement by the Licensor.
216
+
217
+ For the avoidance of doubt, this Section 6(b) does not affect any right
218
+ the Licensor may have to seek remedies for Your violations of this
219
+ Public License.
220
+
221
+ c. For the avoidance of doubt, the Licensor may also offer the Licensed
222
+ Material under separate terms or conditions or stop distributing the
223
+ Licensed Material at any time; however, doing so will not terminate
224
+ this Public License.
225
+ d. Sections 1, 5, 6, 7, and 8 survive termination of this Public License.
226
+
227
+ Section 7 – Other Terms and Conditions.
228
+
229
+ a. The Licensor shall not be bound by any additional or different terms or
230
+ conditions communicated by You unless expressly agreed.
231
+ b. Any arrangements, understandings, or agreements regarding the Licensed
232
+ Material not stated herein are separate from and independent of the
233
+ terms and conditions of this Public License.
234
+
235
+ Section 8 – Interpretation.
236
+
237
+ a. For the avoidance of doubt, this Public License does not, and shall not
238
+ be interpreted to, reduce, limit, restrict, or impose conditions on any
239
+ use of the Licensed Material that could lawfully be made without
240
+ permission under this Public License.
241
+ b. To the extent possible, if any provision of this Public License is
242
+ deemed unenforceable, it shall be automatically reformed to the minimum
243
+ extent necessary to make it enforceable. If the provision cannot be
244
+ reformed, it shall be severed from this Public License without
245
+ affecting the enforceability of the remaining terms and conditions.
246
+ c. No term or condition of this Public License will be waived and no
247
+ failure to comply consented to unless expressly agreed to by the Licensor.
248
+ d. Nothing in this Public License constitutes or may be interpreted as a
249
+ limitation upon, or waiver of, any privileges and immunities that apply
250
+ to the Licensor or You, including from the legal processes of any
251
+ jurisdiction or authority.
third_party/RoRD/assets/register_ortho.jpg ADDED

Git LFS Details

  • SHA256: 9ae058933d1602e685c225a2593554a406f921cbda1f9a9a5a9292d30fe71c6e
  • Pointer size: 130 Bytes
  • Size of remote file: 76.7 kB
third_party/RoRD/assets/register_persp.jpg ADDED

Git LFS Details

  • SHA256: a76f0ca084e821269944e3ae1ace05ef8324393dfcc2c9193a67cd0f80391c9a
  • Pointer size: 131 Bytes
  • Size of remote file: 127 kB
third_party/RoRD/assets/register_pointcloud.jpg ADDED

Git LFS Details

  • SHA256: 5b726bf5a13ae292597b7c8b94fc3d1c7356fd6dfcceeb17b93bff74f65b3d19
  • Pointer size: 131 Bytes
  • Size of remote file: 234 kB
third_party/RoRD/assets/rord_evalRT.jpg ADDED

Git LFS Details

  • SHA256: 8b9055e5fc89083a0966a73de15539db38b62732cdff7846abe9ed68ca589ac3
  • Pointer size: 130 Bytes
  • Size of remote file: 92.9 kB
third_party/RoRD/assets/rord_extract.jpg ADDED

Git LFS Details

  • SHA256: cedae008701ea04b4cf14ed15ace850a7b284df3103beceb4c45851725754d3f
  • Pointer size: 131 Bytes
  • Size of remote file: 113 kB
third_party/RoRD/assets/sift_extract.jpg ADDED

Git LFS Details

  • SHA256: d9121c9d4e507232b3eb60f949194b48fcad6ac7c8f51f0f6ddeaf8d8269064b
  • Pointer size: 130 Bytes
  • Size of remote file: 78.6 kB
third_party/RoRD/assets/teaser2.jpg ADDED

Git LFS Details

  • SHA256: 5c76bf17da04332b8bdd1449d5896bfbcc277a73e7f937ede316a97d41624c3e
  • Pointer size: 131 Bytes
  • Size of remote file: 976 kB
third_party/RoRD/configs/camera.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ 382.1996765136719 381.8395690917969 312.7102355957031 247.72047424316406 1000.0
2
+
3
+
third_party/RoRD/configs/train_scenes.txt ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ temple_nara_japan
2
+ brandenburg_gate
3
+ taj_mahal
4
+ buckingham_palace
5
+ grand_place_brussels
6
+ hagia_sophia_interior
7
+ westminster_abbey
third_party/RoRD/configs/train_scenes_small.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ brandenburg_gate
third_party/RoRD/demo/__init__.py ADDED
File without changes
third_party/RoRD/demo/depth/depth1_1.png ADDED

Git LFS Details

  • SHA256: 3b99487f8fd54fd5fc15e84d24f15287972f98eaf24a44b3daf1c6374e51b6cc
  • Pointer size: 131 Bytes
  • Size of remote file: 171 kB
third_party/RoRD/demo/depth/depth1_2.png ADDED

Git LFS Details

  • SHA256: 006b4531f1c204d846dda996a3cca93fcf81c74e01aad68183a5382531564659
  • Pointer size: 131 Bytes
  • Size of remote file: 193 kB
third_party/RoRD/demo/depth/depth2_1.png ADDED

Git LFS Details

  • SHA256: fd153d4d09f95b25361088c315dbcc92d6e97b329e27af35b2f4dde10433a743
  • Pointer size: 131 Bytes
  • Size of remote file: 199 kB
third_party/RoRD/demo/depth/depth2_2.png ADDED

Git LFS Details

  • SHA256: bd35728a0e7a507e5b8ed8c9725925c0d78a756663dd3e87622e6970afdc64b8
  • Pointer size: 131 Bytes
  • Size of remote file: 198 kB
third_party/RoRD/demo/depth/depth3_1.png ADDED

Git LFS Details

  • SHA256: 80870cd890fdddf6307924f702653a9797cd0e3dc8775a0750253e58967b0993
  • Pointer size: 131 Bytes
  • Size of remote file: 239 kB
third_party/RoRD/demo/depth/depth3_2.png ADDED

Git LFS Details

  • SHA256: 1b2bb7f780db03e1a0898bfa16bf5466dc04f8d9e755d59ce9151425b80fce13
  • Pointer size: 131 Bytes
  • Size of remote file: 279 kB
third_party/RoRD/demo/register.py ADDED
@@ -0,0 +1,265 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ import copy
3
+ import argparse
4
+ import os, sys
5
+ import open3d as o3d
6
+ from sys import argv
7
+ from PIL import Image
8
+ import math
9
+ import cv2
10
+ import torch
11
+
12
+ sys.path.append("../")
13
+ from lib.extractMatchTop import getPerspKeypoints, getPerspKeypointsEnsemble, siftMatching
14
+ from lib.model_test import D2Net
15
+
16
+ #### Cuda ####
17
+ use_cuda = torch.cuda.is_available()
18
+ device = torch.device('cuda:0' if use_cuda else 'cpu')
19
+
20
+ #### Argument Parsing ####
21
+ parser = argparse.ArgumentParser(description='RoRD ICP evaluation')
22
+
23
+ parser.add_argument(
24
+ '--rgb1', type=str, default = 'rgb/rgb2_1.jpg',
25
+ help='path to the rgb image1'
26
+ )
27
+ parser.add_argument(
28
+ '--rgb2', type=str, default = 'rgb/rgb2_2.jpg',
29
+ help='path to the rgb image2'
30
+ )
31
+
32
+ parser.add_argument(
33
+ '--depth1', type=str, default = 'depth/depth2_1.png',
34
+ help='path to the depth image1'
35
+ )
36
+
37
+ parser.add_argument(
38
+ '--depth2', type=str, default = 'depth/depth2_2.png',
39
+ help='path to the depth image2'
40
+ )
41
+
42
+ parser.add_argument(
43
+ '--model_rord', type=str, default = '../models/rord.pth',
44
+ help='path to the RoRD model for evaluation'
45
+ )
46
+
47
+ parser.add_argument(
48
+ '--model_d2', type=str,
49
+ help='path to the vanilla D2-Net model for evaluation'
50
+ )
51
+
52
+ parser.add_argument(
53
+ '--model_ens', action='store_true',
54
+ help='ensemble model of RoRD + D2-Net'
55
+ )
56
+
57
+ parser.add_argument(
58
+ '--sift', action='store_true',
59
+ help='Sift'
60
+ )
61
+
62
+ parser.add_argument(
63
+ '--camera_file', type=str, default='../configs/camera.txt',
64
+ help='path to the camera intrinsics file. In order: focal_x, focal_y, center_x, center_y, scaling_factor.'
65
+ )
66
+
67
+ parser.add_argument(
68
+ '--viz3d', action='store_true',
69
+ help='visualize the pointcloud registrations'
70
+ )
71
+
72
+ args = parser.parse_args()
73
+
74
+ if args.model_ens: # Change default paths accordingly for ensemble
75
+ model1_ens = '../../models/rord.pth'
76
+ model2_ens = '../../models/d2net.pth'
77
+
78
+ def draw_registration_result(source, target, transformation):
79
+ source_temp = copy.deepcopy(source)
80
+ target_temp = copy.deepcopy(target)
81
+ source_temp.transform(transformation)
82
+
83
+ target_temp += source_temp
84
+ # print("Saved registered PointCloud.")
85
+ # o3d.io.write_point_cloud("registered.pcd", target_temp)
86
+
87
+ trgSph.append(source_temp); trgSph.append(target_temp)
88
+ axis1 = o3d.geometry.TriangleMesh.create_coordinate_frame(size=0.5, origin=[0, 0, 0])
89
+ axis2 = o3d.geometry.TriangleMesh.create_coordinate_frame(size=0.5, origin=[0, 0, 0])
90
+ axis2.transform(transformation)
91
+ trgSph.append(axis1); trgSph.append(axis2)
92
+ print("Showing registered PointCloud.")
93
+ o3d.visualization.draw_geometries(trgSph)
94
+
95
+
96
+ def readDepth(depthFile):
97
+ depth = Image.open(depthFile)
98
+ if depth.mode != "I":
99
+ raise Exception("Depth image is not in intensity format")
100
+
101
+ return np.asarray(depth)
102
+
103
+ def readCamera(camera):
104
+ with open (camera, "rt") as file:
105
+ contents = file.read().split()
106
+
107
+ focalX = float(contents[0])
108
+ focalY = float(contents[1])
109
+ centerX = float(contents[2])
110
+ centerY = float(contents[3])
111
+ scalingFactor = float(contents[4])
112
+
113
+ return focalX, focalY, centerX, centerY, scalingFactor
114
+
115
+ def getPointCloud(rgbFile, depthFile, pts):
116
+ thresh = 15.0
117
+
118
+ depth = readDepth(depthFile)
119
+ rgb = Image.open(rgbFile)
120
+
121
+ points = []
122
+ colors = []
123
+
124
+ corIdx = [-1]*len(pts)
125
+ corPts = [None]*len(pts)
126
+ ptIdx = 0
127
+
128
+ for v in range(depth.shape[0]):
129
+ for u in range(depth.shape[1]):
130
+ Z = depth[v, u] / scalingFactor
131
+ if Z==0: continue
132
+ if (Z > thresh): continue
133
+
134
+ X = (u - centerX) * Z / focalX
135
+ Y = (v - centerY) * Z / focalY
136
+
137
+ points.append((X, Y, Z))
138
+ colors.append(rgb.getpixel((u, v)))
139
+
140
+ if((u, v) in pts):
141
+ # print("Point found.")
142
+ index = pts.index((u, v))
143
+ corIdx[index] = ptIdx
144
+ corPts[index] = (X, Y, Z)
145
+
146
+ ptIdx = ptIdx+1
147
+
148
+ points = np.asarray(points)
149
+ colors = np.asarray(colors)
150
+
151
+ pcd = o3d.geometry.PointCloud()
152
+ pcd.points = o3d.utility.Vector3dVector(points)
153
+ pcd.colors = o3d.utility.Vector3dVector(colors/255)
154
+
155
+ return pcd, corIdx, corPts
156
+
157
+
158
+ def convertPts(A):
159
+ X = A[0]; Y = A[1]
160
+
161
+ x = []; y = []
162
+
163
+ for i in range(len(X)):
164
+ x.append(int(float(X[i])))
165
+
166
+ for i in range(len(Y)):
167
+ y.append(int(float(Y[i])))
168
+
169
+ pts = []
170
+ for i in range(len(x)):
171
+ pts.append((x[i], y[i]))
172
+
173
+ return pts
174
+
175
+
176
+ def getSphere(pts):
177
+ sphs = []
178
+
179
+ for ele in pts:
180
+ if(ele is not None):
181
+ sphere = o3d.geometry.TriangleMesh.create_sphere(radius=0.03)
182
+ sphere.paint_uniform_color([0.9, 0.2, 0])
183
+
184
+ trans = np.identity(4)
185
+ trans[0, 3] = ele[0]
186
+ trans[1, 3] = ele[1]
187
+ trans[2, 3] = ele[2]
188
+
189
+ sphere.transform(trans)
190
+ sphs.append(sphere)
191
+
192
+ return sphs
193
+
194
+
195
+ def get3dCor(src, trg):
196
+ corr = []
197
+
198
+ for sId, tId in zip(src, trg):
199
+ if(sId != -1 and tId != -1):
200
+ corr.append((sId, tId))
201
+
202
+ corr = np.asarray(corr)
203
+
204
+ return corr
205
+
206
+ if __name__ == "__main__":
207
+
208
+ focalX, focalY, centerX, centerY, scalingFactor = readCamera(args.camera_file)
209
+
210
+ rgb_name_src = os.path.basename(args.rgb1)
211
+ H_name_src = os.path.splitext(rgb_name_src)[0] + '.npy'
212
+ srcH = os.path.join(os.path.dirname(args.rgb1), H_name_src)
213
+ rgb_name_trg = os.path.basename(args.rgb2)
214
+ H_name_trg = os.path.splitext(rgb_name_trg)[0] + '.npy'
215
+ trgH = os.path.join(os.path.dirname(args.rgb2), H_name_trg)
216
+
217
+ use_cuda = torch.cuda.is_available()
218
+ device = torch.device('cuda:0' if use_cuda else 'cpu')
219
+ model1 = D2Net(model_file=args.model_d2)
220
+ model1 = model1.to(device)
221
+ model2 = D2Net(model_file=args.model_rord)
222
+ model2 = model2.to(device)
223
+
224
+ if args.model_rord:
225
+ srcPts, trgPts, matchImg, matchImgOrtho = getPerspKeypoints(args.rgb1, args.rgb2, srcH, trgH, model2, device)
226
+ elif args.model_d2:
227
+ srcPts, trgPts, matchImg, matchImgOrtho = getPerspKeypoints(args.rgb1, args.rgb2, srcH, trgH, model1, device)
228
+ elif args.model_ens:
229
+ model1 = D2Net(model_file=model1_ens)
230
+ model1 = model1.to(device)
231
+ model2 = D2Net(model_file=model2_ens)
232
+ model2 = model2.to(device)
233
+ srcPts, trgPts, matchImg, matchImgOrtho = getPerspKeypointsEnsemble(model1, model2, args.rgb1, args.rgb2, srcH, trgH, device)
234
+ elif args.sift:
235
+ srcPts, trgPts, matchImg, matchImgOrtho = siftMatching(args.rgb1, args.rgb2, srcH, trgH, device)
236
+
237
+ #### Visualization ####
238
+ print("\nShowing matches in perspective and orthographic view. Press q\n")
239
+ cv2.imshow('Orthographic view', matchImgOrtho)
240
+ cv2.imshow('Perspective view', matchImg)
241
+ cv2.waitKey()
242
+
243
+ srcPts = convertPts(srcPts)
244
+ trgPts = convertPts(trgPts)
245
+
246
+ srcCld, srcIdx, srcCor = getPointCloud(args.rgb1, args.depth1, srcPts)
247
+ trgCld, trgIdx, trgCor = getPointCloud(args.rgb2, args.depth2, trgPts)
248
+
249
+ srcSph = getSphere(srcCor)
250
+ trgSph = getSphere(trgCor)
251
+ axis = o3d.geometry.TriangleMesh.create_coordinate_frame(size=0.5, origin=[0, 0, 0])
252
+ srcSph.append(srcCld); srcSph.append(axis)
253
+ trgSph.append(trgCld); trgSph.append(axis)
254
+
255
+ corr = get3dCor(srcIdx, trgIdx)
256
+
257
+ p2p = o3d.registration.TransformationEstimationPointToPoint()
258
+ trans_init = p2p.compute_transformation(srcCld, trgCld, o3d.utility.Vector2iVector(corr))
259
+ print("Transformation matrix: \n", trans_init)
260
+
261
+ if args.viz3d:
262
+ # o3d.visualization.draw_geometries(srcSph)
263
+ # o3d.visualization.draw_geometries(trgSph)
264
+
265
+ draw_registration_result(srcCld, trgCld, trans_init)
third_party/RoRD/demo/rgb/rgb1_1.jpg ADDED

Git LFS Details

  • SHA256: 1b1d39690370373d343f7b5346d0680be4bf193db345116d6f2278239da4580b
  • Pointer size: 130 Bytes
  • Size of remote file: 76.7 kB
third_party/RoRD/demo/rgb/rgb1_1.npy ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:99396bb9e7c265b8bad5237806d37d8fd9d92a772e118f6de22668f1db011948
3
+ size 200
third_party/RoRD/demo/rgb/rgb1_2.jpg ADDED

Git LFS Details

  • SHA256: 8478af0cab017dfaf2c6d45831e67a0adfd882d02bb87379580c00098b1afa4a
  • Pointer size: 130 Bytes
  • Size of remote file: 76 kB
third_party/RoRD/demo/rgb/rgb1_2.npy ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:f29bb750adcb50b497192ecbd554cf3cd74c3f1c9809d41994c5acd1654179f2
3
+ size 200
third_party/RoRD/demo/rgb/rgb2_1.jpg ADDED

Git LFS Details

  • SHA256: 57a0652bcfbcf9cf6bb75768c9d0950705fb41fa75bb3c410ca13a046ec70c95
  • Pointer size: 131 Bytes
  • Size of remote file: 104 kB
third_party/RoRD/demo/rgb/rgb2_1.npy ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:0b911f2c3962789f99f31fc78313262ec3fa257b9dd8887d318f69fa7a303c04
3
+ size 200
third_party/RoRD/demo/rgb/rgb2_2.jpg ADDED

Git LFS Details

  • SHA256: d94b8cfc6f73be41d900a4600c35ac76b098e04375f57b3c32ccadb8f7d00660
  • Pointer size: 131 Bytes
  • Size of remote file: 111 kB
third_party/RoRD/demo/rgb/rgb2_2.npy ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:63b82950927db25768fe129af2138f535faf3da2789c87e7c98957c90d8423f2
3
+ size 200
third_party/RoRD/demo/rgb/rgb3_1.jpg ADDED

Git LFS Details

  • SHA256: b8e07ba17dfe649b98893a347596ec029e133b1696301b844c39c2c8fa54f994
  • Pointer size: 131 Bytes
  • Size of remote file: 105 kB
third_party/RoRD/demo/rgb/rgb3_1.npy ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:d3262c4ce815dad042112aed3f3a082806fc3dab62ee6bd02492ec94abbf6987
3
+ size 200
third_party/RoRD/demo/rgb/rgb3_2.jpg ADDED

Git LFS Details

  • SHA256: 0b18c61d052100474665df7de431ed9bc7ee11ff1df56998c85822087b6e2bee
  • Pointer size: 130 Bytes
  • Size of remote file: 97.5 kB