Refactor triangulation stages and camera model

This commit is contained in:
2026-03-11 23:42:07 +08:00
parent 24f74c87f1
commit 103aeb5887
10 changed files with 1268 additions and 232 deletions
+30 -1
View File
@@ -3,7 +3,23 @@ from __future__ import annotations
from collections.abc import Sequence
from typing import TYPE_CHECKING
from ._core import Camera, triangulate_poses
from ._core import (
Camera,
CameraModel,
CoreProposalDebug,
FullProposalDebug,
GroupingDebug,
MergeDebug,
PairCandidate,
PreviousPoseFilterDebug,
PreviousPoseMatch,
ProposalGroupDebug,
TriangulationTrace,
build_pair_candidates,
filter_pairs_with_previous_poses,
triangulate_debug,
triangulate_poses,
)
if TYPE_CHECKING:
import numpy as np
@@ -28,7 +44,20 @@ def pack_poses_2d(
__all__ = [
"Camera",
"CameraModel",
"CoreProposalDebug",
"FullProposalDebug",
"GroupingDebug",
"MergeDebug",
"PairCandidate",
"PreviousPoseFilterDebug",
"PreviousPoseMatch",
"ProposalGroupDebug",
"TriangulationTrace",
"build_pair_candidates",
"convert_cameras",
"filter_pairs_with_previous_poses",
"pack_poses_2d",
"triangulate_debug",
"triangulate_poses",
]
+33 -5
View File
@@ -1,12 +1,12 @@
from __future__ import annotations
from collections.abc import Sequence
from typing import TypeAlias, TypedDict
from typing import Literal, TypeAlias, TypedDict
import numpy as np
import numpy.typing as npt
from ._core import Camera
from ._core import Camera, CameraModel
Matrix3x3Like: TypeAlias = Sequence[Sequence[float]]
VectorLike: TypeAlias = Sequence[float]
@@ -21,12 +21,39 @@ class CameraDict(TypedDict, total=False):
T: Sequence[Sequence[float]]
width: int
height: int
type: str
type: Literal["pinhole", "fisheye"]
model: Literal["pinhole", "fisheye"] | CameraModel
CameraModelLike: TypeAlias = CameraModel | Literal["pinhole", "fisheye"]
CameraLike = Camera | CameraDict
def _coerce_camera_model(model: CameraModelLike) -> CameraModel:
if isinstance(model, CameraModel):
return model
if model == "pinhole":
return CameraModel.PINHOLE
if model == "fisheye":
return CameraModel.FISHEYE
raise ValueError(f"Unsupported camera model: {model}")
def _coerce_distortion(distortion: VectorLike, camera_model: CameraModel) -> tuple[float, float, float, float, float]:
values = tuple(float(value) for value in distortion)
expected = 4 if camera_model is CameraModel.FISHEYE else 5
if len(values) not in {expected, 5}:
raise ValueError(
f"{camera_model.name.lower()} cameras require {expected} distortion coefficients"
+ (" (or 5 with a trailing zero)." if camera_model is CameraModel.FISHEYE else ".")
)
if camera_model is CameraModel.FISHEYE and len(values) == 4:
values = values + (0.0,)
if len(values) != 5:
raise ValueError("Distortion coefficients must normalize to exactly 5 values.")
return values
def convert_cameras(cameras: Sequence[CameraLike]) -> list[Camera]:
"""Normalize mappings or existing Camera objects into bound Camera instances."""
@@ -39,12 +66,13 @@ def convert_cameras(cameras: Sequence[CameraLike]) -> list[Camera]:
camera = Camera()
camera.name = str(cam["name"])
camera.K = cam["K"]
camera.DC = cam["DC"]
camera_model = _coerce_camera_model(cam.get("model", cam.get("type", "pinhole")))
camera.DC = _coerce_distortion(cam["DC"], camera_model)
camera.R = cam["R"]
camera.T = cam["T"]
camera.width = int(cam["width"])
camera.height = int(cam["height"])
camera.type = str(cam.get("type", "pinhole"))
camera.model = camera_model
converted.append(camera)
return converted