This commit is contained in:
Afloat authored and GitHub committed 2026-11-09 02:07:22 +00:00
commit b583f6f8cc
2 files changed
+56 -17

No files matched your search

+21 -17
View File
@@ -104,35 +104,39 @@ def cameras2nerfds(
cameras = json.loads(f.read())
camera_ids = list(cameras.keys())
if len(camera_ids) > 1:
raise ValueError("Only one camera is supported")
if len(camera_ids) != 1:
raise ValueError("Expected exactly one ODM camera")
camera_id = camera_ids[0]
camera = cameras[camera_id]
data = {}
if camera["projection_type"] in ["brown", "perspective"]:
projection_type = camera["projection_type"]
if projection_type in ["brown", "perspective"]:
data["camera_model"] = CAMERA_MODELS["perspective"].value
elif camera["projection_type"] in ["fisheye", "fisheye_opencv"]:
elif projection_type in ["fisheye", "fisheye_opencv"]:
data["camera_model"] = CAMERA_MODELS["fisheye"].value
elif camera["projection_type"] in ["spherical", "equirectangular"]:
elif projection_type in ["spherical", "equirectangular"]:
data["camera_model"] = CAMERA_MODELS["equirectangular"].value
else:
raise ValueError("Unsupported ODM camera model: " + data["camera_model"])
raise ValueError("Unsupported ODM camera model: " + projection_type)
sensor_dict = {}
s = {"w": int(camera["width"]), "h": int(camera["height"])}
s: Dict[str, float] = {"w": int(camera["width"]), "h": int(camera["height"])}
s["fl_x"] = camera.get("focal_x", camera.get("focal")) * max(s["w"], s["h"])
s["fl_y"] = camera.get("focal_y", camera.get("focal")) * max(s["w"], s["h"])
if projection_type in ["spherical", "equirectangular"]:
s["fl_x"] = s["w"] / 2.0
s["fl_y"] = s["h"]
s["cx"] = s["w"] / 2.0
s["cy"] = s["h"] / 2.0
else:
scale = max(s["w"], s["h"])
s["fl_x"] = camera.get("focal_x", camera.get("focal")) * scale
s["fl_y"] = camera.get("focal_y", camera.get("focal")) * scale
s["cx"] = camera.get("c_x", 0.0) * scale + (s["w"] - 1.0) / 2.0
s["cy"] = camera.get("c_y", 0.0) * scale + (s["h"] - 1.0) / 2.0
s["cx"] = camera["c_x"] + (s["w"] - 1.0) / 2.0
s["cy"] = camera["c_y"] + (s["h"] - 1.0) / 2.0
for p in ["k1", "k2", "p1", "p2", "k3"]:
for p in ["k1", "k2", "p1", "p2", "k3", "k4"]:
if p in camera:
s[p] = camera[p]
sensor_dict[camera_id] = s
shots_dict = {}
reconstruction = None
@@ -182,7 +186,7 @@ def cameras2nerfds(
frame = {}
frame["file_path"] = image_filename_map[fname].as_posix()
frame.update(sensor_dict[camera_id])
frame.update(s)
frame["transform_matrix"] = transform.tolist()
frames.append(frame)
+35
View File
@@ -0,0 +1,35 @@
"""Regression tests for OpenSfM camera intrinsics in ODM conversions."""
import json
from pathlib import Path
import pytest
from nerfstudio.process_data.odm_utils import cameras2nerfds
@pytest.mark.parametrize(
"camera, expected",
[
({"projection_type": "perspective", "focal": 0.5}, {"fl_x": 400, "cx": 399.5, "cy": 299.5}),
({"projection_type": "brown", "focal": 0.5, "c_x": 0.1, "c_y": -0.05}, {"cx": 479.5, "cy": 259.5}),
(
{"projection_type": "brown", "width": 600, "height": 800, "focal": 0.5, "c_x": 0.1, "c_y": -0.05},
{"fl_x": 400, "fl_y": 400, "cx": 379.5, "cy": 359.5},
),
({"projection_type": "fisheye_opencv", "focal": 0.5, "k4": 0.004}, {"k4": 0.004}),
({"projection_type": "spherical"}, {"fl_x": 400, "fl_y": 600, "cx": 400, "cy": 300}),
],
)
def test_odm_intrinsics(tmp_path, camera, expected):
cameras_path = tmp_path / "cameras.json"
cameras_path.write_text(json.dumps({"camera": {"width": 800, "height": 600, **camera}}))
reconstruction_path = tmp_path / "reconstruction.json"
shot = {"rotation": [0, 0, 0], "translation": [0, 0, 0]}
reconstruction_path.write_text(json.dumps([{"shots": {"sample.jpg": shot}}]))
cameras2nerfds(
{"sample": Path("sample.jpg")}, cameras_path, tmp_path / "shots.geojson", reconstruction_path, tmp_path
)
frame = json.loads((tmp_path / "transforms.json").read_text())["frames"][0]
for key, value in expected.items():
assert frame[key] == pytest.approx(value)