Skip to content

ds_msp.stereo

Stereo depth directly on raw fisheye rays — sphere-sweep with no rectification step, using only the camera's project/unproject.

ds_msp.stereo

Stereo depth on wide-FOV cameras (Tier-1). Sphere-sweep runs straight on calibrated fisheye views — no rectification — using only the camera's project/unproject.

inverse_depth_samples

inverse_depth_samples(near: float, far: float, n: int) -> np.ndarray

n depth candidates evenly spaced in inverse depth over [near, far].

Source code in ds_msp/stereo/sphere_sweep.py
def inverse_depth_samples(near: float, far: float, n: int) -> np.ndarray:
    """``n`` depth candidates evenly spaced in **inverse** depth over ``[near, far]``."""
    return 1.0 / np.linspace(1.0 / far, 1.0 / near, n)

rectify_image

rectify_image(cam, img: ndarray, R_rect: ndarray, chart) -> np.ndarray

Resample img into the rectified equirectangular chart.

Source code in ds_msp/stereo/rectify.py
def rectify_image(cam, img: np.ndarray, R_rect: np.ndarray, chart) -> np.ndarray:
    """Resample ``img`` into the rectified equirectangular ``chart``."""
    mapx, mapy, _ = rectify_maps(cam, R_rect, chart)
    return cv2.remap(img, mapx, mapy, cv2.INTER_LINEAR, borderMode=cv2.BORDER_CONSTANT)

rectify_maps

rectify_maps(cam, R_rect: ndarray, chart) -> Tuple[np.ndarray, np.ndarray, np.ndarray]

cv2.remap lookups that resample cam into chart after applying R_rect.

For each chart pixel: chart.pixel_to_ray (rectified frame) → R_rectᵀ → camera frame → cam.project. valid marks imageable pixels (their map entries are -1 otherwise).

Source code in ds_msp/stereo/rectify.py
def rectify_maps(cam, R_rect: np.ndarray, chart) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
    """``cv2.remap`` lookups that resample ``cam`` into ``chart`` after applying ``R_rect``.

    For each chart pixel: ``chart.pixel_to_ray`` (rectified frame) → ``R_rectᵀ`` → camera frame →
    ``cam.project``. ``valid`` marks imageable pixels (their map entries are ``-1`` otherwise).
    """
    R_rect = np.asarray(R_rect, float)
    h, w = chart.shape
    u, v = np.meshgrid(np.arange(w, dtype=np.float64), np.arange(h, dtype=np.float64))
    rays = chart.pixel_to_ray(u, v).reshape(-1, 3) @ R_rect      # rect → camera frame
    pts, ok = cam.project(rays)
    valid = ok.reshape(h, w)
    mapx = pts[:, 0].reshape(h, w).astype(np.float32)
    mapy = pts[:, 1].reshape(h, w).astype(np.float32)
    mapx[~valid] = -1
    mapy[~valid] = -1
    return mapx, mapy, valid

rectifying_rotation

rectifying_rotation(baseline_dir: ndarray) -> np.ndarray

Rotation R mapping the (unit) baseline direction onto the equirectangular pole.

After rectifying both cameras by R, the baseline lies along the pole, so epipolar great circles become vertical meridians.

Source code in ds_msp/stereo/rectify.py
def rectifying_rotation(baseline_dir: np.ndarray) -> np.ndarray:
    """Rotation ``R`` mapping the (unit) baseline direction onto the equirectangular pole.

    After rectifying both cameras by ``R``, the baseline lies along the pole, so epipolar great
    circles become vertical meridians.
    """
    b = np.asarray(baseline_dir, float)
    b = b / np.linalg.norm(b)
    v = np.cross(b, _POLE)
    s = np.linalg.norm(v)
    c = float(b @ _POLE)
    if s < 1e-12:                            # already (anti)parallel to the pole
        return np.eye(3) if c > 0 else np.diag([1.0, -1.0, -1.0])
    K = np.array([[0, -v[2], v[1]], [v[2], 0, -v[0]], [-v[1], v[0], 0]])
    return np.eye(3) + K + K @ K * ((1 - c) / (s * s))

sweep_to_points

sweep_to_points(ref_cam, depth_map: ndarray, valid: Optional[ndarray] = None) -> np.ndarray

Back-project a depth map to a 3D point cloud in the reference frame, (M, 3).

Source code in ds_msp/stereo/sphere_sweep.py
def sweep_to_points(ref_cam, depth_map: np.ndarray, valid: Optional[np.ndarray] = None
                    ) -> np.ndarray:
    """Back-project a depth map to a 3D point cloud in the reference frame, ``(M, 3)``."""
    h, w = depth_map.shape
    u, v = np.meshgrid(np.arange(w, dtype=np.float64), np.arange(h, dtype=np.float64))
    rays, _ = ref_cam.unproject(np.stack([u, v], axis=-1).reshape(-1, 2))
    pts = (depth_map.reshape(-1, 1) * rays)
    if valid is not None:
        pts = pts[valid.reshape(-1)]
    return pts