From 83ca084945b9f2911937b66cca3f5ffa16b0db55 Mon Sep 17 00:00:00 2001 From: Martino Ferrari Date: Fri, 3 Jul 2026 14:04:24 +0200 Subject: [PATCH] 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 --- he11lib/fitting.py | 10 ++-------- he11lib/geometry.py | 5 +++++ tests/test_geometry.py | 9 +++++++++ 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/he11lib/fitting.py b/he11lib/fitting.py index e43c3fd..0c7b399 100644 --- a/he11lib/fitting.py +++ b/he11lib/fitting.py @@ -9,6 +9,7 @@ from scipy.optimize import least_squares from .data import MeasurementPlane, ReconstructionResult, validate_planes from .geometry import ( + CAMERA_FIELD_NAMES, CameraModel, CameraModelTolerance, GeometryCalibration, @@ -166,14 +167,7 @@ class ModalFitter: for i in range(len(planes)) ] - geometry: dict[str, float] = dict(zip( - ( - "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), - )) + geometry: dict[str, float] = dict(zip(CAMERA_FIELD_NAMES, camera_to_values(fitted_camera))) for i in range(len(planes)): geometry[f"z_{i}"] = z_values[i] diff --git a/he11lib/geometry.py b/he11lib/geometry.py index edd25b4..8f016a6 100644 --- a/he11lib/geometry.py +++ b/he11lib/geometry.py @@ -237,6 +237,11 @@ class GeometryCalibration: keystoned. """ 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) mid_row, mid_col = rows // 2, cols // 2 dx = abs(x[mid_row, mid_col + 1] - x[mid_row, mid_col]) diff --git a/tests/test_geometry.py b/tests/test_geometry.py index 6179841..0ec03b8 100644 --- a/tests/test_geometry.py +++ b/tests/test_geometry.py @@ -149,3 +149,12 @@ def test_effective_pixel_scale_matches_on_axis_focal_length(): scale = calib.effective_pixel_scale((41, 41), z) expected = (z - camera_z) / focal_length_px 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)