Skip to content

Commit 3bdf785

Browse files
committed
1 parent 65042cc commit 3bdf785

File tree

2 files changed

+99
-39
lines changed

2 files changed

+99
-39
lines changed

examples/datasets/colmap.py

Lines changed: 96 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,31 @@
1+
# 先頭付近に追記(ファイル先頭でもOK)
2+
# import logging, unicodedata, os, difflib
3+
# logger = logging.getLogger("colmap_debug")
4+
# if not logger.handlers:
5+
# h = logging.FileHandler("colmap_debug.txt", encoding="utf-8")
6+
# fmt = logging.Formatter("%(asctime)s %(levelname)s: %(message)s")
7+
# h.setFormatter(fmt)
8+
# logger.addHandler(h)
9+
# logger.setLevel(logging.DEBUG)
10+
11+
# def _norm_key(s: str) -> str:
12+
# # キーの正規化: 区切り・先頭 ./ ・大文字小文字・Unicode などを吸収
13+
# s = unicodedata.normalize("NFC", s.strip())
14+
# s = s.replace("\\", "/")
15+
# if s.startswith("./"):
16+
# s = s[2:]
17+
# return s.lower()
18+
19+
# def _peek(head, n=5):
20+
# head = list(head)
21+
# return head[:n]
22+
23+
# def _summarize_list(name, arr, n=5):
24+
# logger.debug("%s: count=%d, sample=%s", name, len(arr), _peek(arr, n))
25+
# -----debug
26+
# 既に import 済みなら重複不要
27+
28+
from collections import defaultdict
129
import json
230
import os
331
from typing import Any, Dict, List, Optional
@@ -6,8 +34,9 @@
634
import imageio.v2 as imageio
735
import numpy as np
836
import torch
37+
938
from PIL import Image
10-
from pycolmap import SceneManager
39+
from pycolmap import Reconstruction, CameraModelId
1140
from tqdm import tqdm
1241
from typing_extensions import assert_never
1342

@@ -18,6 +47,17 @@
1847
transform_points,
1948
)
2049

50+
# path patch
51+
import unicodedata
52+
def _norm_key(s: str) -> str:
53+
# 区切り/先頭.//大文字小文字/Unicode揺れを吸収
54+
s = unicodedata.normalize("NFC", s.strip())
55+
s = s.replace("\\", "/")
56+
if s.startswith("./"):
57+
s = s[2:]
58+
return s.lower()
59+
# -----
60+
2161

2262
def _get_rel_paths(path_dir: str) -> List[str]:
2363
"""Recursively get relative paths of files in a directory."""
@@ -75,25 +115,28 @@ def __init__(
75115
colmap_dir
76116
), f"COLMAP directory {colmap_dir} does not exist."
77117

78-
manager = SceneManager(colmap_dir)
79-
manager.load_cameras()
80-
manager.load_images()
81-
manager.load_points3D()
118+
manager = Reconstruction(colmap_dir)
119+
120+
# point_id -> point3D_id_contiguous
121+
point3D_id_contiguous = dict()
122+
for i, point_id in enumerate(manager.points3D.keys()):
123+
point3D_id_contiguous[point_id] = i
82124

83125
# Extract extrinsic matrices in world-to-camera format.
84126
imdata = manager.images
85127
w2c_mats = []
86128
camera_ids = []
87129
Ks_dict = dict()
130+
point_indices = defaultdict(list) # image_name -> [point_idx]
88131
params_dict = dict()
89132
imsize_dict = dict() # width, height
90133
mask_dict = dict()
91134
bottom = np.array([0, 0, 0, 1]).reshape(1, 4)
92135
for k in imdata:
93136
im = imdata[k]
94-
rot = im.R()
95-
trans = im.tvec.reshape(3, 1)
96-
w2c = np.concatenate([np.concatenate([rot, trans], 1), bottom], axis=0)
137+
w2c = im.cam_from_world().matrix()
138+
w2c = np.concatenate([w2c, bottom], axis=0)
139+
97140
w2c_mats.append(w2c)
98141

99142
# support different camera intrinsics
@@ -102,30 +145,40 @@ def __init__(
102145

103146
# camera intrinsics
104147
cam = manager.cameras[camera_id]
105-
fx, fy, cx, cy = cam.fx, cam.fy, cam.cx, cam.cy
106-
K = np.array([[fx, 0, cx], [0, fy, cy], [0, 0, 1]])
148+
149+
K = cam.calibration_matrix()
107150
K[:2, :] /= factor
108151
Ks_dict[camera_id] = K
109152

153+
# get image_name -> [point_idx] dict
154+
for obs_point2d in im.get_observation_points2D():
155+
point_indices[im.name].append(point3D_id_contiguous[obs_point2d.point3D_id])
156+
110157
# Get distortion parameters.
111-
type_ = cam.camera_type
112-
if type_ == 0 or type_ == "SIMPLE_PINHOLE":
158+
type_ = cam.model
159+
# SIMPLE_PINHOLE: f, cx, cy
160+
if type_ == CameraModelId.SIMPLE_PINHOLE:
113161
params = np.empty(0, dtype=np.float32)
114162
camtype = "perspective"
115-
elif type_ == 1 or type_ == "PINHOLE":
163+
# PINHOLE: fx, fy, cx, cy
164+
elif type_ == CameraModelId.PINHOLE:
116165
params = np.empty(0, dtype=np.float32)
117166
camtype = "perspective"
118-
if type_ == 2 or type_ == "SIMPLE_RADIAL":
119-
params = np.array([cam.k1, 0.0, 0.0, 0.0], dtype=np.float32)
167+
# SIMPLE_RADIAL: f, cx, cy, k
168+
if type_ == CameraModelId.SIMPLE_RADIAL:
169+
params = np.array([cam.params[3], 0.0, 0.0, 0.0], dtype=np.float32)
120170
camtype = "perspective"
121-
elif type_ == 3 or type_ == "RADIAL":
122-
params = np.array([cam.k1, cam.k2, 0.0, 0.0], dtype=np.float32)
171+
# RADIAL: f, cx, cy, k1, k2
172+
elif type_ == CameraModelId.RADIAL:
173+
params = np.array([cam.params[3], cam.params[4], 0.0, 0.0], dtype=np.float32)
123174
camtype = "perspective"
124-
elif type_ == 4 or type_ == "OPENCV":
125-
params = np.array([cam.k1, cam.k2, cam.p1, cam.p2], dtype=np.float32)
175+
# OPENCV: fx, fy, cx, cy, k1, k2, p1, p2
176+
elif type_ == CameraModelId.OPENCV:
177+
params = np.array([cam.params[4], cam.params[5], cam.params[6], cam.params[7]], dtype=np.float32)
126178
camtype = "perspective"
127-
elif type_ == 5 or type_ == "OPENCV_FISHEYE":
128-
params = np.array([cam.k1, cam.k2, cam.k3, cam.k4], dtype=np.float32)
179+
# OPENCV_FISHEYE: fx, fy, cx, cy, k1, k2, k3, k4
180+
elif type_ == CameraModelId.OPENCV_FISHEYE:
181+
params = np.array([cam.params[4], cam.params[5], cam.params[6], cam.params[7]], dtype=np.float32)
129182
camtype = "fisheye"
130183
assert (
131184
camtype == "perspective" or camtype == "fisheye"
@@ -140,7 +193,7 @@ def __init__(
140193

141194
if len(imdata) == 0:
142195
raise ValueError("No images found in COLMAP.")
143-
if not (type_ == 0 or type_ == 1):
196+
if not (type_ == CameraModelId.PINHOLE or type_ == CameraModelId.SIMPLE_PINHOLE):
144197
print("Warning: COLMAP Camera is not PINHOLE. Images have distortion.")
145198

146199
w2c_mats = np.stack(w2c_mats, axis=0)
@@ -195,21 +248,27 @@ def __init__(
195248
colmap_image_dir, image_dir + "_png", factor=factor
196249
)
197250
image_files = sorted(_get_rel_paths(image_dir))
198-
colmap_to_image = dict(zip(colmap_files, image_files))
199-
image_paths = [os.path.join(image_dir, colmap_to_image[f]) for f in image_names]
200-
201-
# 3D points and {image_name -> [point_idx]}
202-
points = manager.points3D.astype(np.float32)
203-
points_err = manager.point3D_errors.astype(np.float32)
204-
points_rgb = manager.point3D_colors.astype(np.uint8)
205-
point_indices = dict()
206-
207-
image_id_to_name = {v: k for k, v in manager.name_to_image_id.items()}
208-
for point_id, data in manager.point3D_id_to_images.items():
209-
for image_id, _ in data:
210-
image_name = image_id_to_name[image_id]
211-
point_idx = manager.point3D_id_to_point3D_idx[point_id]
212-
point_indices.setdefault(image_name, []).append(point_idx)
251+
252+
# --- fix ---
253+
# colmap_to_image = dict(zip(colmap_files, image_files))
254+
# image_paths = [os.path.join(image_dir, colmap_to_image[f]) for f in image_names]
255+
256+
# キーは“正規化した colmap_files”、値はディスク上の相対パス(そのまま)
257+
colmap_to_image = { _norm_key(k): v for k, v in zip(colmap_files, image_files) }
258+
259+
# 参照側(COLMAP名)も正規化して引く。最後に normpath でOS向けに整形。
260+
image_paths = [
261+
os.path.normpath(os.path.join(image_dir, colmap_to_image[_norm_key(f)]))
262+
for f in image_names
263+
# --- fix
264+
]
265+
266+
# 3D points
267+
points3D = manager.points3D.values()
268+
points_err = np.array([p.error for p in points3D], dtype=np.float32)
269+
points_rgb = np.array([p.color for p in points3D], dtype=np.uint8)
270+
points = np.array([p.xyz for p in points3D], dtype=np.float32)
271+
213272
point_indices = {
214273
k: np.array(v).astype(np.int32) for k, v in point_indices.items()
215274
}

examples/requirements.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
# assume torch is already installed
22

33
# pycolmap for data parsing
4-
git+https://github.com/rmbrualla/pycolmap@cc7ea4b7301720ac29287dbe450952511b32125e
4+
# git+https://github.com/rmbrualla/pycolmap@cc7ea4b7301720ac29287dbe450952511b32125e
5+
pycolmap
56
# (optional) nerfacc for torch version rasterization
67
# git+https://github.com/nerfstudio-project/nerfacc
78

@@ -20,5 +21,5 @@ tensorly
2021
pyyaml
2122
matplotlib
2223
git+https://github.com/rahul-goel/fused-ssim@328dc9836f513d00c4b5bc38fe30478b4435cbb5
23-
git+https://github.com/harry7557558/fused-bilagrid@90f9788e57d3545e3a033c1038bb9986549632fe
24+
#git+https://github.com/harry7557558/fused-bilagrid@90f9788e57d3545e3a033c1038bb9986549632fe
2425
splines

0 commit comments

Comments
 (0)