Migrating from PanorAi 3.0.19 to 3.1.0

PanorAi 3.1 keeps the public 3.0 imports for containers, projections, samplers, blenders, factories, depth, and point-cloud adapters. The new API is opt-in so existing code does not silently change coordinate conventions.

Use the canonical API in new code

from panorai.geometry import GnomonicProjector, GnomonicSpec

spec = GnomonicSpec(
    center_lat_deg=10,
    center_lon_deg=-35,
    hfov_deg=100,
    vfov_deg=60,
    roll_deg=5,
    output_shape_hw=(320, 640),
)
result = GnomonicProjector(spec).project(erp)
view, support = result.data, result.support_mask

The canonical frame is +X right, +Y up, +Z forward. ERP coordinates are pixel-center coordinates with a top-left origin, circular longitude in [-pi, pi), and latitude decreasing from north to south. Depth is radial range, not implicit z-depth.

Canonical specs validate eagerly: longitude and roll are normalized to [-180, 180), all angles must be finite real numbers, FOV values remain in (0, 180), and dimensions must be positive integers. Values that older internal helpers silently truncated, such as a floating image dimension, now raise an explicit error in the new canonical API.

Projector results compose directly:

view = projector.project(erp)
restored = projector.back_project(view, output_shape_hw=erp.shape[:2])

Extracting view.data first remains supported. The wheel is PEP 561 typed and keeps Torch optional at import time.

Container compatibility

Legacy calls remain valid:

face = image.to_gnomonic(lat=10, lon=-35, fov=90, x_points=640, y_points=320)

The resolution arguments now produce exactly (320, 640). The legacy inverse gnomonic calculation also defines its zero-radius sample analytically as the requested projection center. In 3.0.19 that sample was NaN before OpenCV remapping and could become a different pixel or border fill on different platforms. All other recorded legacy samples retain their 3.0 values.

To opt into the canonical convention through a container, pass only spec:

face = image.to_gnomonic(spec=spec)

spec cannot be combined with lat, lon, fov, or legacy projection keywords.

Interpolation and optional dependencies

  • Use bilinear for floating RGB, features, and continuous depth.

  • Use nearest for integer labels and masks. Bilinear integer input is an explicit error.

  • Bilinear defaults to invalid_policy="propagate", preserving strict IEEE NaN propagation. The opt-in renormalize mode requires an explicit boolean validity mask and min_valid_weight; it reports output validity and contributing weight separately from geometric support.

  • Core: pip install panorai

  • Torch: pip install "panorai[torch]"

  • Point clouds: pip install "panorai[pcd]"

  • Lightweight depth-adapter dependencies: pip install "panorai[depth]"

Neither Torch nor Open3D is imported by import panorai.

For sparse floating depth, for example:

projector = GnomonicProjector(
    spec,
    invalid_policy="renormalize",
    min_valid_weight=0.5,
)
view = projector.project(radial_range_m, validity_mask=depth_is_valid)
usable = view.support_mask & view.validity_mask

Choose the threshold from the measurement contract; PanorAi does not infer validity from zero or choose a universal threshold.

Depth distribution boundary

PanorAi 3.0 artifacts exposed deep copies of Depth Anything V2, DUSt3R/CroCo, Metric3D, legacy ZoeDepth, and research training/data helpers. Those trees are experimental/internal rather than stable PanorAi API and have been removed from the source tree and release artifacts. This prevents an MIT-only PanorAi distribution from silently redistributing code with additional terms, including DUSt3R/CroCo’s CC BY-NC-SA 4.0 license.

The supported 3.x compatibility surface remains:

  • panorai.depth.ModelRegistry;

  • load_dav2_model, load_m3dv2_model, load_dust3r_model, and load_zoe_model;

  • registry keys dav2, m3dv2, dust3r, and zoe;

  • panorai.pcd modules and container to_pcd methods.

Loaders now import separately installed upstream projects only when invoked. If an implementation is absent, they raise DepthAdapterUnavailableError with the upstream location and license instead of becoming None at import time. Installing panorai[depth] supplies common adapter dependencies; it does not install or license the upstream source or model weights. Code importing a deep path such as panorai.depth.Dust3r.*, panorai.depth.DepthAnythingV2.*, or panorai.depth.Metric3D.* must install and import the corresponding upstream project directly.

Root imports are lazy

The five public 3.0 root names remain available and unchanged:

from panorai import (
    ConfigManager,
    EquirectangularImage,
    GnomonicFace,
    GnomonicFaceSet,
    PanoraiFactory,
)

PanorAi 3.1 resolves these compatibility objects only when code accesses them. Consequently, import panorai.geometry no longer imports containers, factories, registries, OpenCV, Pillow, Pydantic, SciPy, scikit-image, or YAML. This changes import timing, not the identity or import path of any recorded public 3.0 root object. Import subpackages explicitly rather than relying on an undocumented module attribute created as a side effect of import panorai.

Blender masks and output shapes

Blender masks are now authoritative and independent of values. A valid black RGB pixel or zero-valued scalar participates when its mask is true; an unsupported non-zero value does not. Valid non-finite floating samples raise an error instead of silently becoming zero.

The supported fusion blenders (average, closest, feathering, gaussian, and huber) preserve the input image shape. HuberBlender therefore returns (H, W) for scalar inputs and (H, W, C) for channel inputs instead of always forcing three channels. Pass return_mask=True to any built-in blender to get (data, support_mask). GnomonicFaceSet.to_equirectangular now obtains real back-projection masks and stores the fused mask on the returned EquirectangularImage.support_mask.

The overlap count/standard-deviation blenders are diagnostic. The huber_no_confidence, huber_spatial, and bundle_adjustment strategies are experimental and are not part of the stable projection path.