Fix final-review findings: pixel-scale size guard, DRY camera field names
effective_pixel_scale now raises a clear ValueError for image shapes too small for its finite-difference indexing, instead of an IndexError. ModalFitter.fit()'s geometry dict now reuses CAMERA_FIELD_NAMES from geometry.py instead of a duplicated hardcoded tuple. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
+2
-8
@@ -9,6 +9,7 @@ from scipy.optimize import least_squares
|
|||||||
|
|
||||||
from .data import MeasurementPlane, ReconstructionResult, validate_planes
|
from .data import MeasurementPlane, ReconstructionResult, validate_planes
|
||||||
from .geometry import (
|
from .geometry import (
|
||||||
|
CAMERA_FIELD_NAMES,
|
||||||
CameraModel,
|
CameraModel,
|
||||||
CameraModelTolerance,
|
CameraModelTolerance,
|
||||||
GeometryCalibration,
|
GeometryCalibration,
|
||||||
@@ -166,14 +167,7 @@ class ModalFitter:
|
|||||||
for i in range(len(planes))
|
for i in range(len(planes))
|
||||||
]
|
]
|
||||||
|
|
||||||
geometry: dict[str, float] = dict(zip(
|
geometry: dict[str, float] = dict(zip(CAMERA_FIELD_NAMES, camera_to_values(fitted_camera)))
|
||||||
(
|
|
||||||
"focal_length_px", "position_x", "position_y", "position_z",
|
|
||||||
"yaw_deg", "pitch_deg", "roll_deg",
|
|
||||||
"principal_point_x", "principal_point_y",
|
|
||||||
),
|
|
||||||
camera_to_values(fitted_camera),
|
|
||||||
))
|
|
||||||
for i in range(len(planes)):
|
for i in range(len(planes)):
|
||||||
geometry[f"z_{i}"] = z_values[i]
|
geometry[f"z_{i}"] = z_values[i]
|
||||||
|
|
||||||
|
|||||||
@@ -237,6 +237,11 @@ class GeometryCalibration:
|
|||||||
keystoned.
|
keystoned.
|
||||||
"""
|
"""
|
||||||
rows, cols = image_shape
|
rows, cols = image_shape
|
||||||
|
if rows < 2 or cols < 2:
|
||||||
|
raise ValueError(
|
||||||
|
f"image_shape must be at least 2x2 to compute a finite-difference "
|
||||||
|
f"pixel scale, got {image_shape}"
|
||||||
|
)
|
||||||
x, y = self.physical_coordinates(image_shape, z)
|
x, y = self.physical_coordinates(image_shape, z)
|
||||||
mid_row, mid_col = rows // 2, cols // 2
|
mid_row, mid_col = rows // 2, cols // 2
|
||||||
dx = abs(x[mid_row, mid_col + 1] - x[mid_row, mid_col])
|
dx = abs(x[mid_row, mid_col + 1] - x[mid_row, mid_col])
|
||||||
|
|||||||
@@ -149,3 +149,12 @@ def test_effective_pixel_scale_matches_on_axis_focal_length():
|
|||||||
scale = calib.effective_pixel_scale((41, 41), z)
|
scale = calib.effective_pixel_scale((41, 41), z)
|
||||||
expected = (z - camera_z) / focal_length_px
|
expected = (z - camera_z) / focal_length_px
|
||||||
assert scale == pytest.approx(expected, rel=1e-6)
|
assert scale == pytest.approx(expected, rel=1e-6)
|
||||||
|
|
||||||
|
|
||||||
|
def test_effective_pixel_scale_raises_for_image_too_small():
|
||||||
|
camera = make_on_axis_camera()
|
||||||
|
calib = GeometryCalibration(camera)
|
||||||
|
z = 0.5
|
||||||
|
|
||||||
|
with pytest.raises(ValueError, match="image_shape must be at least 2x2"):
|
||||||
|
calib.effective_pixel_scale((1, 1), z)
|
||||||
|
|||||||
Reference in New Issue
Block a user