Update h5_to_db.py
Browse files- h5_to_db.py +29 -18
h5_to_db.py
CHANGED
|
@@ -82,13 +82,14 @@ def add_keypoints(db, h5_path, image_path, img_ext, camera_model, single_camera=
|
|
| 82 |
camera_id = None
|
| 83 |
fname_to_id = {}
|
| 84 |
|
|
|
|
| 85 |
all_images = {}
|
| 86 |
for ext in ['.jpg', '.jpeg', '.png', '.JPG', '.JPEG', '.PNG']:
|
| 87 |
for img_file in glob.glob(os.path.join(image_path, f'*{ext}')):
|
| 88 |
base_name = os.path.splitext(os.path.basename(img_file))[0]
|
| 89 |
all_images[base_name] = img_file
|
| 90 |
|
| 91 |
-
# ★★★
|
| 92 |
camera_model_ids = {
|
| 93 |
'SIMPLE_PINHOLE': 0,
|
| 94 |
'PINHOLE': 1,
|
|
@@ -111,34 +112,35 @@ def add_keypoints(db, h5_path, image_path, img_ext, camera_model, single_camera=
|
|
| 111 |
path = all_images[filename]
|
| 112 |
fname_with_ext = os.path.basename(path)
|
| 113 |
|
| 114 |
-
#
|
| 115 |
if camera_id is None:
|
| 116 |
img = Image.open(path)
|
| 117 |
width, height = img.size
|
| 118 |
|
|
|
|
| 119 |
focal_length = float(max(width, height))
|
| 120 |
cx = float(width / 2.0)
|
| 121 |
cy = float(height / 2.0)
|
| 122 |
|
| 123 |
-
# ★★★
|
| 124 |
if camera_model == 'PINHOLE':
|
| 125 |
# PINHOLE: [fx, fy, cx, cy]
|
| 126 |
params = np.array([focal_length, focal_length, cx, cy], dtype=np.float64)
|
| 127 |
-
print(f"
|
| 128 |
elif camera_model == 'SIMPLE_PINHOLE':
|
| 129 |
# SIMPLE_PINHOLE: [f, cx, cy]
|
| 130 |
params = np.array([focal_length, cx, cy], dtype=np.float64)
|
| 131 |
-
print(f"
|
| 132 |
elif camera_model == 'SIMPLE_RADIAL':
|
| 133 |
# SIMPLE_RADIAL: [f, cx, cy, k]
|
| 134 |
-
k = 0.0
|
| 135 |
params = np.array([focal_length, cx, cy, k], dtype=np.float64)
|
| 136 |
-
print(f"
|
| 137 |
else:
|
| 138 |
raise ValueError(f"Unsupported camera model: {camera_model}")
|
| 139 |
|
| 140 |
camera_id = db.add_camera(
|
| 141 |
-
model=model_id, #
|
| 142 |
width=width,
|
| 143 |
height=height,
|
| 144 |
params=params
|
|
@@ -154,22 +156,28 @@ def add_keypoints(db, h5_path, image_path, img_ext, camera_model, single_camera=
|
|
| 154 |
|
| 155 |
def add_matches(db, h5_path, fname_to_id):
|
| 156 |
"""
|
| 157 |
-
matches.h5
|
| 158 |
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 159 |
match_file = h5py.File(os.path.join(h5_path, 'matches.h5'), 'r')
|
| 160 |
|
| 161 |
-
|
| 162 |
n_keys = len(match_file.keys())
|
| 163 |
|
| 164 |
-
with tqdm(total=n_keys, desc="
|
| 165 |
for pair_key in match_file.keys():
|
|
|
|
| 166 |
parts = pair_key.split('_')
|
| 167 |
mid = len(parts) // 2
|
| 168 |
key_1 = '_'.join(parts[:mid])
|
| 169 |
key_2 = '_'.join(parts[mid:])
|
| 170 |
|
| 171 |
if key_1 not in fname_to_id or key_2 not in fname_to_id:
|
| 172 |
-
print(f"Warning: {key_1} or {key_2}
|
| 173 |
pbar.update(1)
|
| 174 |
continue
|
| 175 |
|
|
@@ -177,32 +185,35 @@ def add_matches(db, h5_path, fname_to_id):
|
|
| 177 |
id_2 = fname_to_id[key_2]
|
| 178 |
pair_id = image_ids_to_pair_id(id_1, id_2)
|
| 179 |
|
| 180 |
-
if
|
|
|
|
| 181 |
pbar.update(1)
|
| 182 |
continue
|
| 183 |
|
| 184 |
matches = match_file[pair_key][()]
|
| 185 |
|
| 186 |
-
#
|
| 187 |
if len(matches) == 0:
|
| 188 |
pbar.update(1)
|
| 189 |
continue
|
| 190 |
|
| 191 |
-
# COLMAP
|
| 192 |
matches = matches.astype(np.uint32)
|
| 193 |
|
| 194 |
-
#
|
| 195 |
db.add_matches(id_1, id_2, matches)
|
| 196 |
|
| 197 |
-
#
|
|
|
|
| 198 |
db.add_two_view_geometry(id_1, id_2, matches)
|
| 199 |
|
| 200 |
-
|
| 201 |
pbar.update(1)
|
| 202 |
|
| 203 |
match_file.close()
|
| 204 |
|
| 205 |
|
|
|
|
| 206 |
def import_into_colmap(img_dir,
|
| 207 |
feature_dir ='.featureout',
|
| 208 |
database_path = 'colmap.db',
|
|
|
|
| 82 |
camera_id = None
|
| 83 |
fname_to_id = {}
|
| 84 |
|
| 85 |
+
# Map filenames to their full paths
|
| 86 |
all_images = {}
|
| 87 |
for ext in ['.jpg', '.jpeg', '.png', '.JPG', '.JPEG', '.PNG']:
|
| 88 |
for img_file in glob.glob(os.path.join(image_path, f'*{ext}')):
|
| 89 |
base_name = os.path.splitext(os.path.basename(img_file))[0]
|
| 90 |
all_images[base_name] = img_file
|
| 91 |
|
| 92 |
+
# ★★★ Camera Model Mapping ★★★
|
| 93 |
camera_model_ids = {
|
| 94 |
'SIMPLE_PINHOLE': 0,
|
| 95 |
'PINHOLE': 1,
|
|
|
|
| 112 |
path = all_images[filename]
|
| 113 |
fname_with_ext = os.path.basename(path)
|
| 114 |
|
| 115 |
+
# Initialize camera once (if single_camera=True)
|
| 116 |
if camera_id is None:
|
| 117 |
img = Image.open(path)
|
| 118 |
width, height = img.size
|
| 119 |
|
| 120 |
+
# Use the max dimension as a heuristic for initial focal length
|
| 121 |
focal_length = float(max(width, height))
|
| 122 |
cx = float(width / 2.0)
|
| 123 |
cy = float(height / 2.0)
|
| 124 |
|
| 125 |
+
# ★★★ Set parameters based on the chosen camera model ★★★
|
| 126 |
if camera_model == 'PINHOLE':
|
| 127 |
# PINHOLE: [fx, fy, cx, cy]
|
| 128 |
params = np.array([focal_length, focal_length, cx, cy], dtype=np.float64)
|
| 129 |
+
print(f"Camera created: PINHOLE, f={focal_length}, cx={cx}, cy={cy}")
|
| 130 |
elif camera_model == 'SIMPLE_PINHOLE':
|
| 131 |
# SIMPLE_PINHOLE: [f, cx, cy]
|
| 132 |
params = np.array([focal_length, cx, cy], dtype=np.float64)
|
| 133 |
+
print(f"Camera created: SIMPLE_PINHOLE, f={focal_length}, cx={cx}, cy={cy}")
|
| 134 |
elif camera_model == 'SIMPLE_RADIAL':
|
| 135 |
# SIMPLE_RADIAL: [f, cx, cy, k]
|
| 136 |
+
k = 0.0 # Initial radial distortion coefficient
|
| 137 |
params = np.array([focal_length, cx, cy, k], dtype=np.float64)
|
| 138 |
+
print(f"Camera created: SIMPLE_RADIAL, f={focal_length}, cx={cx}, cy={cy}, k={k}")
|
| 139 |
else:
|
| 140 |
raise ValueError(f"Unsupported camera model: {camera_model}")
|
| 141 |
|
| 142 |
camera_id = db.add_camera(
|
| 143 |
+
model=model_id, # Set based on argument
|
| 144 |
width=width,
|
| 145 |
height=height,
|
| 146 |
params=params
|
|
|
|
| 156 |
|
| 157 |
def add_matches(db, h5_path, fname_to_id):
|
| 158 |
"""
|
| 159 |
+
Directly add matches from matches.h5 (compatible with COLMAP format).
|
| 160 |
"""
|
| 161 |
+
import h5py
|
| 162 |
+
import numpy as np
|
| 163 |
+
import os
|
| 164 |
+
from tqdm import tqdm
|
| 165 |
+
|
| 166 |
match_file = h5py.File(os.path.join(h5_path, 'matches.h5'), 'r')
|
| 167 |
|
| 168 |
+
added_pairs = set()
|
| 169 |
n_keys = len(match_file.keys())
|
| 170 |
|
| 171 |
+
with tqdm(total=n_keys, desc="Importing matches to database") as pbar:
|
| 172 |
for pair_key in match_file.keys():
|
| 173 |
+
# Parse the pair key to extract individual image filenames
|
| 174 |
parts = pair_key.split('_')
|
| 175 |
mid = len(parts) // 2
|
| 176 |
key_1 = '_'.join(parts[:mid])
|
| 177 |
key_2 = '_'.join(parts[mid:])
|
| 178 |
|
| 179 |
if key_1 not in fname_to_id or key_2 not in fname_to_id:
|
| 180 |
+
print(f"Warning: Filename lookup failed for {key_1} or {key_2}")
|
| 181 |
pbar.update(1)
|
| 182 |
continue
|
| 183 |
|
|
|
|
| 185 |
id_2 = fname_to_id[key_2]
|
| 186 |
pair_id = image_ids_to_pair_id(id_1, id_2)
|
| 187 |
|
| 188 |
+
# Skip if this pair has already been processed
|
| 189 |
+
if pair_id in added_pairs:
|
| 190 |
pbar.update(1)
|
| 191 |
continue
|
| 192 |
|
| 193 |
matches = match_file[pair_key][()]
|
| 194 |
|
| 195 |
+
# Ensure the match array is not empty
|
| 196 |
if len(matches) == 0:
|
| 197 |
pbar.update(1)
|
| 198 |
continue
|
| 199 |
|
| 200 |
+
# COLMAP requirement: uint32 array with shape (N, 2)
|
| 201 |
matches = matches.astype(np.uint32)
|
| 202 |
|
| 203 |
+
# Add raw matches to the database
|
| 204 |
db.add_matches(id_1, id_2, matches)
|
| 205 |
|
| 206 |
+
# Add two-view geometry (required by COLMAP for reconstruction)
|
| 207 |
+
# This step typically marks matches as "verified"
|
| 208 |
db.add_two_view_geometry(id_1, id_2, matches)
|
| 209 |
|
| 210 |
+
added_pairs.add(pair_id)
|
| 211 |
pbar.update(1)
|
| 212 |
|
| 213 |
match_file.close()
|
| 214 |
|
| 215 |
|
| 216 |
+
|
| 217 |
def import_into_colmap(img_dir,
|
| 218 |
feature_dir ='.featureout',
|
| 219 |
database_path = 'colmap.db',
|