ruvnet/RuView · error · RuntimeError
solvePnP failed
Error message
solvePnP failed
What it means
The single-board extrinsics wrapper calls cv2.solvePnP (via _solve_pnp); a None return means OpenCV could not fit a camera pose to the 3D room points and 2D pixel observations, and the wrapper raises RuntimeError. The docstring warns that one planar checkerboard is centrosymmetric — corner ordering from findChessboardCorners is ambiguous from a single board — so the two-board procedure (solve_two_board_extrinsics) is the supported path.
Source
Thrown at scripts/calibration_lib.py:224
def solve_extrinsics(
room_points: np.ndarray,
image_points: np.ndarray,
camera_matrix: np.ndarray,
dist_coeffs: np.ndarray,
) -> dict:
"""Solve the camera->room rigid transform from 3D room-frame points and
their 2D pixel observations.
NOTE: the corner grid of a single planar checkerboard is centrosymmetric,
so the corner ordering returned by findChessboardCorners (which may
enumerate from either board end) cannot be disambiguated from one board
alone -- the reversed ordering fits a ghost pose with identical
reprojection error. Use solve_two_board_extrinsics for the full
two-checkerboard procedure, where the joint point set breaks the symmetry.
"""
ext = _solve_pnp(room_points, image_points, camera_matrix, dist_coeffs)
if ext is None:
raise RuntimeError("solvePnP failed")
return ext
def solve_two_board_extrinsics(
wall_room: np.ndarray,
wall_image: np.ndarray,
floor_room: np.ndarray,
floor_image: np.ndarray,
camera_matrix: np.ndarray,
dist_coeffs: np.ndarray,
) -> dict:
"""Joint camera->room solve over both checkerboards (the ADR-152 S2.1.3
two-checkerboard method).
Tries all 4 per-board corner-ordering combinations: each board's ordering
is individually ambiguous (centrosymmetric grid), but the combined
wall+floor point set is not, so exactly one combination reaches minimal
reprojection error. Returns the solve_extrinsics dict plusView on GitHub (pinned to 4685618388)
Solutions
- Use solve_two_board_extrinsics (wall + floor, the ADR-152 S2.1.3 procedure) instead of the single-board solve
- Check len(room_points) == len(image_points) and that ordering matches findChessboardCorners (cols varies fastest)
- Verify board_object_points used the correct cols, rows, and square_size in meters
- Recapture sharper, evenly lit photos and confirm the intrinsics match the capture camera
Example fix
# before
ext = solve_board_extrinsics(room_points, image_points, K, D) # RuntimeError
# after
ext = solve_two_board_extrinsics(
wall_room, wall_image, floor_room, floor_image, K, D
) Defensive patterns
Strategy: try-catch
Validate before calling
assert len(room_points) == len(image_points) >= 6, \
"need matching 3D/2D point sets of at least 6 corners"
# single planar boards are ambiguous; prefer the two-board solve Try / catch
try:
ext = solve_board_extrinsics(room, image, K, D)
except RuntimeError:
# single-board failure/ambiguity — fall back to the two-board procedure
ext = solve_two_board_extrinsics(
wall_room, wall_image, floor_room, floor_image, K, D
) Prevention
- Default to the two-checkerboard ADR-152 procedure for extrinsics
- Verify point counts, ordering, and units (meters) before any PnP call
- Log reprojection RMSE per candidate to catch bad detections early
When it happens
Trigger: Calling the single-board solve with degenerate inputs: too few or collinear points, object points mismatched to the detected corners (wrong cols/rows/square_size), or intrinsics from a different camera/resolution.
Common situations: Blurry or glare-affected checkerboard photos; cols and rows swapped when generating board_object_points; square size entered in cm while room points are meters.
Related errors
- solvePnP failed for all corner-ordering combinations
- Intrinsics file {path} missing key {key!r}
- Calibration already in progress
- {path}: expected {{'nodes': [...]}} or a top-level list
- {path}: each node needs 'id' and 'position_m' [x,y,z]
AI-assisted analysis of ruvnet/RuView@4685618388 (2026-08-16).
Data as JSON: /api/errors/e9fe9fc7c6b47710.
Report an issue: GitHub.