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 plus

View on GitHub (pinned to 4685618388)

Solutions

  1. Use solve_two_board_extrinsics (wall + floor, the ADR-152 S2.1.3 procedure) instead of the single-board solve
  2. Check len(room_points) == len(image_points) and that ordering matches findChessboardCorners (cols varies fastest)
  3. Verify board_object_points used the correct cols, rows, and square_size in meters
  4. 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

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


AI-assisted analysis of ruvnet/RuView@4685618388 (2026-08-16). Data as JSON: /api/errors/e9fe9fc7c6b47710. Report an issue: GitHub.