limap.visualize package

Note

Everything here needs matplotlib, seaborn or open3d, which are installed with the viz extra: python -m pip install "limap[viz]".

2D visualization

limap.visualize.draw_2d_points(image: ndarray, points: ndarray, color: tuple[float, float, float] | None = None, thickness=1) ndarray
limap.visualize.draw_2d_lines(image: ndarray, lines: list[ndarray] | list[Line2d], color: tuple[float, float, float] | None = None, thickness: int = 1, endpoints: bool = True) ndarray
limap.visualize.draw_2d_vpresult(img: ndarray, lines: list[Line2d], vpres: VPResult, vp_id: float = -1, show_original: bool = False, endpoints: bool = False) ndarray
limap.visualize.make_big_image(imgs: list[ndarray], pad=20) ndarray

make a big image with 2d image collections all images should have the same size

3D visualization

limap.visualize.open3d_get_3d_points(points: ndarray, color: tuple[float, float, float] | None = None, ranges: tuple[ndarray, ndarray] | None = None) PointCloud
limap.visualize.open3d_get_3d_lines(lines: list[Line3d], color: tuple[float, float, float] | None = None, ranges: tuple[ndarray, ndarray] | None = None) LineSet
limap.visualize.open3d_get_camera_frustums(recon: Reconstruction, color: tuple[float, float, float] | None = None, ranges: tuple[ndarray, ndarray] | None = None, scale_cam_geometry: float = 1.0) LineSet
limap.visualize.open3d_visualize_3d_lines(lines: list[Line3d], ranges: tuple[ndarray, ndarray] | None = None) None

Visualize a 3D line map with Open3D

Parameters:
limap.visualize.open3d_get_plane_mesh(plane_params: list[float], points: ndarray, color: tuple[float, float, float] | None = None, padding: float = 0.4, alpha: float = 0.5, manhattan_directions: ndarray | None = None, atlanta_gravity: ndarray | None = None) PlaneMesh | None

Create a plane rectangle mesh from plane parameters and associated points.

Parameters:
  • plane_params – [a, b, c, d] where ax + by + cz + d = 0

  • points – Nx3 array of 3D points associated with the plane

  • color – RGB color tuple

  • padding – Relative padding around the bounding box (0.5 = 50% padding)

  • alpha – Transparency value (0.0 = fully transparent, 1.0 = opaque). Used with o3d.visualization.draw() API which supports transparency.

  • manhattan_directions – Optional Kx3 array of Manhattan world directions (e.g. VP directions). When provided, the plane bbox edges align with the two directions most orthogonal to the plane normal, and an axis-aligned bbox is used instead of an oriented bbox.

  • atlanta_gravity – Optional 3-vector for Atlanta world gravity direction. When provided, vertical planes (normal orthogonal to gravity) get their bbox aligned with gravity as one axis.

Returns:

PlaneMesh containing the mesh, color, and alpha, or None if insufficient points

limap.visualize.open3d_get_sphere_mesh(sphere_params: list[float], color: tuple[float, float, float] | None = None, alpha: float = 0.5, resolution: int = 20) SphereMesh | None

Create a sphere mesh from sphere parameters.

Parameters:
  • sphere_params – [cx, cy, cz, log_r] where (cx, cy, cz) is the center and r = exp(log_r) is the radius

  • color – RGB color tuple

  • alpha – Transparency value (0.0 = fully transparent, 1.0 = opaque)

  • resolution – Number of subdivisions for the sphere

Returns:

SphereMesh or None if invalid parameters

limap.visualize.open3d_get_cylinder_mesh(cylinder_params: list[float], associated_points: ndarray, color: tuple[float, float, float] | None = None, alpha: float = 0.5, resolution: int = 20) CylinderMesh | None

Create a cylinder mesh from cylinder parameters and associated points.

The cylinder is parameterized using MinimalInfiniteLine3d + log-radius: [qx, qy, qz, qw, wvec0, wvec1, log_r] where the quaternion is in Eigen storage order (x, y, z, w).

The axis is recovered as a Plucker line (d, m) where: - d = R[:, 0] (direction = first column of rotation matrix) - m = (wvec1 / wvec0) * R[:, 1] (moment vector)

Parameters:
  • cylinder_params – [qx, qy, qz, qw, wvec0, wvec1, log_r]

  • associated_points – Nx3 array of 3D points for height estimation

  • color – RGB color tuple

  • alpha – Transparency value (0.0 = fully transparent, 1.0 = opaque)

  • resolution – Number of subdivisions for the cylinder

Returns:

CylinderMesh or None if invalid parameters or insufficient points

class limap.visualize.PlaneMesh(mesh: TriangleMesh, color: tuple[float, float, float], alpha: float)

Wrapper for plane mesh with transparency info.

__init__(mesh: TriangleMesh, color: tuple[float, float, float], alpha: float) None
alpha: float
color: tuple[float, float, float]
mesh: TriangleMesh
class limap.visualize.SphereMesh(mesh: TriangleMesh, color: tuple[float, float, float], alpha: float)

Wrapper for sphere mesh with transparency info.

__init__(mesh: TriangleMesh, color: tuple[float, float, float], alpha: float) None
alpha: float
color: tuple[float, float, float]
mesh: TriangleMesh
class limap.visualize.CylinderMesh(mesh: TriangleMesh, color: tuple[float, float, float], alpha: float)

Wrapper for cylinder mesh with transparency info.

__init__(mesh: TriangleMesh, color: tuple[float, float, float], alpha: float) None
alpha: float
color: tuple[float, float, float]
mesh: TriangleMesh

Textured meshes

Meshes carrying the image texture of the group they were fitted to.

limap.visualize.create_textured_plane_mesh(group3d_id: int, group, associated_points: ndarray, hrecon: HolisticReconstruction, start_ids: dict, group_workspace: Path, image_dir: Path, mesh_resolution: int = 50, padding: float = 0.2, use_all_masks: bool = False) TriangleMesh | None

Create a textured plane mesh with vertex colors from images.

Reuses the local (u, v) frame from open3d_get_plane_mesh but creates a dense grid mesh instead of 2 triangles.

Parameters:
  • group3d_id – 3D group identifier

  • group – Group3d object with plane params

  • associated_points – (N, 3) 3D points on the plane

  • hrecon – HolisticReconstruction

  • start_ids – Mask offset dict

  • group_workspace – Path to group_description/ directory

  • image_dir – Undistorted images directory

  • mesh_resolution – Grid density (mesh_resolution x mesh_resolution)

  • padding – Relative padding around bounding box

  • use_all_masks – If True, scan all images with masks instead of track

Returns:

Vertex-colored TriangleMesh, or None if insufficient data

limap.visualize.create_textured_sphere_mesh(group3d_id: int, group, hrecon: HolisticReconstruction, start_ids: dict, group_workspace: Path, image_dir: Path, mesh_resolution: int = 50, use_all_masks: bool = False) TriangleMesh | None

Create a textured sphere mesh with vertex colors from images.

Parameters:
  • group3d_id – 3D group identifier

  • group – Group3d object with sphere params

  • hrecon – HolisticReconstruction

  • start_ids – Mask offset dict

  • group_workspace – Path to group_description/ directory

  • image_dir – Undistorted images directory

  • mesh_resolution – Sphere subdivision resolution

  • use_all_masks – If True, scan all images with masks instead of track

Returns:

Vertex-colored TriangleMesh, or None if insufficient data

limap.visualize.create_textured_cylinder_mesh(group3d_id: int, group, associated_points: ndarray, hrecon: HolisticReconstruction, start_ids: dict, group_workspace: Path, image_dir: Path, mesh_resolution: int = 50, use_all_masks: bool = False) TriangleMesh | None

Create a textured cylinder mesh with vertex colors from images.

Reuses axis recovery from open3d_get_cylinder_mesh.

Parameters:
  • group3d_id – 3D group identifier

  • group – Group3d object with cylinder params

  • associated_points – (N, 3) 3D points for height estimation

  • hrecon – HolisticReconstruction

  • start_ids – Mask offset dict

  • group_workspace – Path to group_description/ directory

  • image_dir – Undistorted images directory

  • mesh_resolution – Cylinder angular resolution

  • use_all_masks – If True, scan all images with masks instead of track

Returns:

Vertex-colored TriangleMesh, or None if insufficient data

limap.visualize.get_group_binary_mask(group3d_id: int, image_id: int, structure_recon, start_ids: dict, group_workspace: Path) ndarray | None

Get binary mask for a group3D in a specific image.

Resolves group3D -> track -> group2D_idx -> mask_label -> binary.

Parameters:
  • group3d_id – 3D group identifier

  • image_id – Image to look up the mask in

  • structure_recon – StructureReconstruction instance

  • start_ids – Dict mapping {TYPE_NAME: {image_id: offset}}

  • group_workspace – Path to group_description/ directory

Returns:

(H, W) bool array, or None if the group is not visible in image

limap.visualize.project_points_to_image(points_3d: ndarray, image: Image, camera: Camera) tuple[ndarray, ndarray]

Project 3D points to 2D pixel coordinates.

Parameters:
  • points_3d – (N, 3) array of 3D world points

  • image – pycolmap.Image with pose

  • camera – pycolmap.Camera with intrinsics

Returns:

(N, 2) pixel coordinates valid: (N,) bool mask (in front of camera and within image bounds)

Return type:

uv

Ranges

The visualizers clip to a range, which is best computed robustly from the reconstruction rather than from its extremes.

limap.visualize.compute_robust_range_points(points: ndarray, range_robust: tuple[float, float] | None = None, k_stretch: float = 2.0) tuple[ndarray, ndarray]
limap.visualize.compute_robust_range_lines(lines: list[Line3d], range_robust: tuple[float, float] | None = None, k_stretch: float = 2.0) tuple[ndarray, ndarray]