Cameras & Distortion Borders#

Note

Currently, only the OpenCV pinhole camera model is implemented. Contributions adding other camera model families are very welcome, including models for 360-degree imagery.

Cameras convert between pixel coordinates and camera rays. CameraOpenCVPerspective implements the OpenCV pinhole model with radial (k1-k4) and tangential (p1-p2) distortion.

For the full reference, see Camera Model.

Key properties#

  • param_dict / from_dict: serialize and rebuild cameras (used by metadata loaders and scene files).

  • focal_length_for_gsd_in_pixel: used to compute ground sampling distance during mapping.

  • principal_point(image_size): returns the pixel center for the current image dimensions.

  • origin: shift applied when converting between image pixels and calibration space (OpenCV origin is pixel center, so [0.5, 0.5]).

Distortion border#

The distortion border is the set of undistorted pixels that can be mapped back to valid distorted pixels inside the source image extent. Pixels outside this border are invalid for distortion-aware projection.

Implementation details (src/weitsicht/camera/base_perspective.py):

  • CameraBasePerspective.__init__(..., pts_distortion=5): default sampling density for border construction is pts_distortion = 5.

  • __post_init__(): automatically builds the border polygon after camera initialization.

  • _generate_distortion_border(points_between=5): samples the distorted image rectangle edges and transforms those samples to undistorted space.

  • distortion_border: stored as a Shapely Polygon for fast point-in-polygon checks.

  • undistorted_image_points_inside(...): tests whether undistorted pixels are within that valid border.

With points_between=5, each side is sampled at 6 positions (endpoint excluded), resulting in 24 sampled border points in total.

Where this is used in projection:

  • In perspective projection, undistorted candidate pixels are first checked with undistorted_image_points_inside(...).

  • Only valid pixels are forwarded to distortion mapping.

  • Invalid pixels stay masked and should not be used for ray-based mapping.

Practical checks#

from weitsicht import get_camera_from_dict

cam = get_camera_from_dict(camera_dict)
border = cam.distortion_border  # shapely Polygon

pts = cam.distorted_to_undistorted([[100, 200]], image_size=(4000, 3000))
inside = cam.undistorted_image_points_inside(pts, image_size=(4000, 3000))

# optional: map undistorted pixels back to distorted domain
pts_dist = cam.undistorted_to_distorted(pts, image_size=(4000, 3000))

Guidelines#

  • Keep calib_width / calib_height equal to the image size used for calibration; resampled images should adjust intrinsic values accordingly.

  • If distortion terms are unknown, set them to zero; this approximates an undistorted pinhole model and the valid border tends toward the image rectangle.

  • If you increase pts_distortion, the border approximation becomes denser (usually more robust near strong edge distortion) with slightly higher initialization cost.