Spherical relative-pose API

panorai.estimators is an isolated Experimental surface. It consumes panorama-frame bearings and does not import or call OpenCV, PyCOLMAP or Torch. See Spherical features and matching for the end-to-end feature workflow, coordinate convention and limitations.

Surface

Stability

Canonical import

Contract

Public components or entries

spherical-features-core

Stable

panorai.features

panorai-spherical-features/v1

DeduplicationResult, FaceSetSpec, FeatureExtractor, FeatureExtractorConfig, FeatureMatcher, FeatureMatcherConfig, FeatureProvenance, FaceDetectionDiagnostics, MatchProvenance, MultifaceDetectionDiagnostics, OpenCVFeatureBackend, SphericalBearingCorrespondences, SphericalFeature, SphericalFeatureMatches, SphericalFeaturePipeline, SphericalFeaturePipelineConfig, SphericalFeatureSet, available_presets, deduplicate_spherical_keypoints, extract_opencv_features, gnomonic_feature_mask, match_opencv_features, panorai.features.backends.OpenCVFeatureBackend

spherical-features-pycolmap

Experimental

panorai.features

panorai-spherical-features-pycolmap/v1

GnomonicRig, GnomonicRigCamera, PyCOLMAPExportResult

spherical-features-multiscale

Experimental

panorai.features

panorai-spherical-features-multiscale/v1

MultiscaleEmbeddingConfig, MultiscaleFeatureMatches, MultiscaleFeatureSet, MultiscaleSphericalFeaturePipeline, OpenCVContextEmbedding, VisualContextNode, VisualEmbeddingProvider

spherical-features-dog-sift

Experimental

panorai.features

panorai-spherical-dog-sift/v2

SphericalDoGSIFTConfig, SphericalDoGSIFTExtractor, SphericalDoGSIFTPipeline

spherical-features-dog-detector

Experimental

panorai.features

panorai-spherical-dog-detector/v2

SphericalDetectionDiagnostics, SphericalDoGDetector, SphericalDoGDetectorConfig, SphericalKeypoint, SphericalKeypointSet, SphericalOctaveDetectionDiagnostics, SphericalRefinedKeypoint

spherical-features-coarse-dog-detector

Experimental

panorai.features

panorai-spherical-coarse-dog-detector/v1

SphericalCoarseDoGDetector, SphericalCoarseDoGDetectorConfig

spherical-features-tangent-patches

Experimental

panorai.features

panorai-tangent-patches/v1

OpenCVTangentDescriptor, OpenCVTangentDescriptorConfig, TangentDescriptorSet, TangentPatch, TangentPatchGeometry, TangentPatchProvider, TangentPatchRequest, TangentPatchSet

spherical-feature-resolution-selection

Experimental

panorai.features

panorai-resolution-selection/v1

ResolutionLevelReport, ResolutionSelectionObservation, ResolutionSelectionPolicy, ResolutionSelectionReport, ResolutionTransitionReport, select_feature_resolution

spherical-features-tangent-descriptor-v2

Experimental

panorai.features

panorai-tangent-opencv-descriptor/v2

OpenCVTangentDescriptorV2, OpenCVTangentDescriptorV2Config, TangentDescriptorHypothesisSet

spherical-relative-pose-pipeline

Experimental

panorai.features

panorai-spherical-relative-pose-pipeline/v1-experimental

ExtractSphericalFeaturePair, MatchSphericalFeatures, SphericalFeaturePair, SphericalImagePair, ToBearingCorrespondences

spherical-deep-learning-depth

Experimental

panorai.experimental.deep_learning

panorai-spherical-metric-depth/v1-experimental

SphericalMetric3D, acquire_metric3d_convnext_large_v1, acquire_metric3d_convnext_tiny_v1, load_spherical_metric3d_convnext_large_v1, load_spherical_metric3d_convnext_tiny_v1, panorai.depth.DepthAdapterUnavailableError, panorai.depth.ModelRegistry, panorai.depth.load_dav2_model, panorai.depth.load_dust3r_model, panorai.depth.load_m3dv2_model, panorai.depth.load_zoe_model, panorai.depth.zoe.load_zoe_model, panorai.experimental.deep_learning.depth.SPHERICAL_METRIC_DEPTH_INTERFACE, panorai.experimental.deep_learning.depth.METRIC3D_CHECKPOINT_REVISION, panorai.experimental.deep_learning.depth.METRIC3D_CONVNEXT_LARGE_V1, panorai.experimental.deep_learning.depth.METRIC3D_CONVNEXT_TINY_V1, panorai.experimental.deep_learning.depth.METRIC3D_SOURCE, panorai.experimental.deep_learning.depth.METRIC3D_SOURCE_COMMIT, panorai.experimental.deep_learning.depth.ExternalArtifactRecord, panorai.experimental.deep_learning.depth.ExternalArtifactSpec, panorai.experimental.deep_learning.depth.LoadedSphericalDepthModel, panorai.experimental.deep_learning.depth.Metric3DAssets, panorai.experimental.deep_learning.depth.SphericalMetric3D, panorai.experimental.deep_learning.depth.UpstreamTermsNotAcceptedError, panorai.experimental.deep_learning.depth.acquire_metric3d_convnext_large_v1, panorai.experimental.deep_learning.depth.acquire_metric3d_convnext_tiny_v1, panorai.experimental.deep_learning.depth.load_spherical_metric3d_convnext_large_v1, panorai.experimental.deep_learning.depth.load_spherical_metric3d_convnext_tiny_v1

tangent-da3-metric-depth

Experimental

panorai.experimental.deep_learning

panorai-depth-anything-3-metric-tangent/v1-experimental

DA3MetricTangent, acquire_da3metric_large, load_da3metric_large, panorai.experimental.deep_learning.da3.DA3Assets, panorai.experimental.deep_learning.da3.DA3MetricTangent, panorai.experimental.deep_learning.da3.DA3TermsNotAcceptedError, panorai.experimental.deep_learning.da3.DA3_CANONICAL_FOCAL_PX, panorai.experimental.deep_learning.da3.DA3_CHECKPOINT_REVISION, panorai.experimental.deep_learning.da3.DA3_MODEL_ID, panorai.experimental.deep_learning.da3.DA3_PATCH_SIZE, panorai.experimental.deep_learning.da3.DA3_SOURCE, panorai.experimental.deep_learning.da3.DA3_SOURCE_COMMIT, panorai.experimental.deep_learning.da3.DA3METRIC_LARGE, panorai.experimental.deep_learning.da3.LoadedDA3MetricModel, panorai.experimental.deep_learning.da3.SPHERICAL_DA3_METRIC_DEPTH_INTERFACE, panorai.experimental.deep_learning.da3.acquire_da3metric_large, panorai.experimental.deep_learning.da3.load_da3metric_large

spherical-semantic-segmentation

Experimental

panorai.experimental.deep_learning.segmentation

panorai-spherical-semantic-segmentation/v1

SPHERICAL_MASK_PROPOSALS_INTERFACE, SPHERICAL_PROXY_SEGMENTATION_INTERFACE, SPHERICAL_SEMANTIC_SEGMENTATION_INTERFACE, SAM21_HIERA_LARGE_LICENSE, SAM21_HIERA_LARGE_REPOSITORY, SAM21_HIERA_LARGE_REVISION, IMAGENET_PROXY_VOCABULARY, DenseSemanticEvidence, Sam21Assets, Sam21FileRecord, Sam21HieraLargeSegmenter, Sam21TermsNotAcceptedError, SamMultimaskOutput, SegmentPrompt, SemanticProxyConcept, SphericalBinaryMask, SphericalProxySegmenter, SphericalMaskProposal, SphericalMaskProposalSet, SphericalSeed, SphericalSegment, SphericalSegmentationConfig, SphericalSegmentationResult, SphericalSemanticSegmenter, acquire_sam21_hiera_large, advance_chart, backproject_face_mask_sets, angular_distance_degrees, backproject_face_masks, concept_display_names, concept_evidence_from_imagenet, concept_proxy_names, connected_component_at, consensus_frontiers, extract_mask_face, extract_rgb_face, face_point_direction, fibonacci_coverage_seeds, load_sam21_hiera_large, majority_and_envelope, mask_stability_score, maximum_pairwise_iou, merge_proposals, non_maximum_suppression, partition_proposals_by_origin, pairwise_mask_iou, prompt_from_mask, prompt_grid, proposal_is_accepted, resolve_panoptic_map, select_semantic_seeds, semantic_support_for_mask, solid_angle_weights, weighted_containment, weighted_intersection_over_union

spherical-relative-pose

Experimental

panorai.estimators

panorai-spherical-relative-pose/v1

CalibrationEvaluation, DecoupledPoseReport, EstimateRelativePose, FivePointSample, FivePointSampler, FivePointSamplingDiagnostics, ModelCompetitionReport, ModelEvidence, PoseStabilityReport, RelativePoseAcceptancePolicy, RelativePoseConfidenceCalibrator, RelativePoseOptions, RelativePoseQualityReport, RelativePoseResult, TranslationOrientationReport, SpatiallyWeightedFivePointSampler, SphericalRelativePoseEstimator, UniformFivePointSampler, estimate_relative_pose, native_kernels_available, solve_five_point_essential, spherical_tangent_sampson_error

semantic-object-localization

Experimental

panorai.object_localization

panorai-object-localization/v1

JOINT_MATCH_CLUSTERS_INTERFACE, JointMatchCluster, JointMatchClusterConfig, JointMatchClusterResult, MULTIVIEW_OBJECT_HYPOTHESES_INTERFACE, BearingTrackTriangulation, DirectionalRegionTransfer, HypothesisAffinity, HypothesisAffinityConfig, HypothesisGnomonicRegion, HypothesisPairCues, HypothesisReductionCandidate, HypothesisReductionResult, HypothesisRegionEvaluation, HypothesisTransferEvaluation, HypothesisViewConsistency, HypothesisViewEmbedding, HypothesisViewPairEvaluation, MultiviewObjectHypothesis, MultiviewObjectHypothesisResult, MultiviewSpatialRegion, OBJECT_LOCALIZATION_INTERFACE, OBJECT_LOCALIZATION_STABILITY, ObjectHypothesis, ObjectLocalizationConfig, ObjectLocalizationPipeline, ObjectLocalizationResult, PairObjectLocalizationInput, RegionAssociation, ReducedHypothesisRecord, RegisteredSemanticEvidence, RegisteredBearingObservation, RegisteredBearingTrack, RegisteredPoseInconsistencyError, RegisteredRadialDepth, SEMANTIC_MATCH_PRIOR_INTERFACE, SEMANTIC_REGION_PROPOSALS_INTERFACE, SPHERICAL_ANCHOR_FUSION_INTERFACE, SemanticMatchPrior, SemanticMatchPriorConfig, SemanticQuery, SemanticConcept, SemanticRegionProposalConfig, SemanticRegionProposalResult, SemanticRegionObservation, SemanticTrackObservation, SphericalObjectHypothesisConfig, SphericalObjectHypothesisGenerator, SphericalObjectHypothesisMethod, SphericalObjectHypothesisMethodConfig, SphericalObjectHypothesisMethodResult, SphericalAnchorAffinity, SphericalAnchorCluster, SphericalAnchorClusterDecision, SphericalAnchorDecision, SphericalAnchorFusionConfig, SphericalAnchorFusionResult, SphericalAnchorPairCues, SphericalFOVAnchor, SphericalRegionMetrics, SpatialLocationHypothesis, SymmetricRegionTransfer, assign_region_associations, build_semantic_match_prior, cluster_region_association_matches, evaluate_spherical_region, fuse_registered_spherical_anchors, generate_spherical_fov_anchors, hypothesis_pair_affinity, hypothesis_view_consistency, triangulate_registered_bearing_track, localize_region_association, object_hypothesis_id, propose_region_associations, reduce_object_hypotheses, semantic_region_from_map, semantic_regions_from_map, spherical_region_mask, spherical_anchor_pair_affinity, spherical_solid_angle_weights, symmetric_spherical_region_transfer, transfer_spherical_region

spherical-reconstruction

Experimental

panorai.reconstruction

panorai-spherical-reconstruction/v1

BuildRegisteredReferenceSets, ColorizeSurface, DenseReconstructionWorkspace, EstimateMultiViewRanges, ExtractSurface, FuseTSDF, MultiViewRangeMap, MultiViewRangeSet, RegisteredReferenceSets, RegisteredSphericalScene, RegisteredSphericalView, SphericalBaselinePrior, SphericalCameraPose, SphericalDenseReconstructionResult, SphericalGlobalMapper, SphericalGlobalMapperOptions, SphericalPairwisePoseEdge, SphericalRangePrior, SphericalReconstructionDiagnostics, SphericalReconstructionResult, SphericalTrack, SphericalTrackObservation, SurfaceMesh, TSDFSpec, TSDFVolume, ValidateDenseReconstruction, colorize_surface, extract_surface, fuse_tsdf

metric-spherical-landmark-ba

Experimental

panorai.reconstruction.metric_landmark_ba

panorai-metric-spherical-landmark-ba/v1-experimental

METRIC_SPHERICAL_LANDMARK_BA_INTERFACE, MetricBearingObservation, MetricLandmarkBAOptions, MetricLandmarkBAReport, MetricLandmarkBAResult, MetricRadialRangePrior, MetricScaleGauge, MetricSphericalCamera, MetricSphericalLandmark, refine_metric_spherical_landmarks

spherical-dense-stereo

Experimental

panorai.stereo

panorai-spherical-dense-stereo/v1-experimental

SphericalDenseStereo, SphericalStereoOptions, SphericalStereoResult, classical, panoramic, colorize_spherical_range, estimate_spherical_range, render_spherical_stereo_result

classical-rectified-stereo

Experimental

panorai.stereo.classical

panorai-classical-dense-stereo/v1-experimental

ADCensusConfig, ADCensusCost, AbsoluteDifferenceCost, BirchfieldTomasiCost, BoxCostAggregation, BuildStereoCost, CensusCost, CensusMGMConfig, ClassicalStereoResult, CrossBasedCostAggregation, ELASConfig, ELASSupportPrior, MoreGlobalMatching, OpenCVStereoMatcher, PatchMatchConfig, PatchMatchStereo, RectifiedStereoGeometry, RectifiedStereoPair, RefineStereoDisparity, SelectStereoDisparity, SemiGlobalMatching, StereoBMConfig, StereoCostVolume, StereoDisparityCandidate, StereoSGBMConfig, StereoValidationConfig, TransformStereoCost, ad_census_pipeline, census_mgm_pipeline, disparity_labels, elas_pipeline, patchmatch_pipeline, stereo_bm_pipeline, stereo_sgbm_pipeline

registered-full-sphere-stereo-core

Experimental

panorai.stereo.panoramic

panorai-registered-full-sphere-stereo/v1-experimental

FullSphereMultiViewStereo, FullSphereStereoOptions, FullSphereStereoResult, OverlappingCubemapPlanner, PanoramicStereoPose, RegisteredPanoramaSet, StereoSourceView

panoramic-dense-stereo-workflow

Experimental

panorai.stereo.panoramic

panorai-panoramic-dense-stereo/v1-experimental

BackProjectStereoRange, DenseStereoPerPair, FuseStereoRange, PanoramicStereoInput, PanoramicStereoResult, PlanRectifiedStereoViews, ProjectStereoViewPairs, RectifiedStereoViewPlanner, RectifiedStereoViewSpec, ResolveStereoPose, ResolveStereoScale, SelectStereoViewPairs, SphereNativeStereo, SphericalStereoViewPairer, StereoPairDiagnostic, StereoViewDescriptor, StereoViewPairScore, StereoViewSelectionDiagnostic, StereoViewPlan, ValidatePanoramicStereo, spec_from_axes

spherical-slam

Experimental

panorai.slam

panorai-spherical-slam/v1

EquidistantFisheyeCamera, FisheyeRayProjection, SphericalImageFrame, SphericalIncrementalSLAM, SphericalIncrementalSLAMDiagnostics, SphericalIncrementalSLAMOptions, SphericalIncrementalSLAMResult, SphericalKeyframeSummary, SphericalLocalBAReport, SphericalMapObservation, SphericalMapPoint, SphericalSLAMDiagnostics, SphericalSLAMFrameSummary, SphericalSLAMOptions, SphericalSLAMPose, SphericalSLAMResult, SphericalTrackingResult, SphericalVisualSLAM

rotation-pair-calibration

Experimental

panorai.calibration

panorai-rotation-pair-calibration/v1-experimental

RotationCalibrationOptions, RotationCalibrationResult, calibrate_rotation_pair

robust-model-fitting

Experimental

panorai.model_fitting

panorai-robust-model-fitting/v1-experimental

HomographyModel, ModelFamily, RobustFitOptions, RobustFitResult, RotationModel, fit_homography, fit_rotation, robust_fit

spherical-estimators-auto-experimental

Experimental

panorai.estimators

panorai-estimator/auto-experimental

—

EstimateRelativePose is the typed Pipeline adapter around the same SphericalRelativePoseEstimator implementation. It accepts spherical matches or bearing correspondences and returns RelativePoseResult or None; it is an estimator Stage, not a differentiable Torch layer.

Use the estimators and policies catalog to compare the direct estimator, Stage adapter, samplers and the distinct capture and post-estimation policies.

Experimental geometric estimators owned by PanorAi.

The package is intentionally independent from feature extraction backends. Its relative-pose estimator consumes spherical bearings and does not import OpenCV, PyCOLMAP, or Torch.

class panorai.estimators.CalibrationEvaluation(count: 'int', brier_score: 'float', expected_calibration_error: 'float', accuracy_at_half: 'float')
count
brier_score
expected_calibration_error
accuracy_at_half
to_dict()
class panorai.estimators.DecoupledPoseReport(attempted, applied, rotation_inliers, rotation_inlier_ratio, translation_pool_size, translation_consensus_size, translation_score_margin, rotation_refit_steps, translation_refit_steps, reason)

Evidence from the Experimental rotation/translation split.

attempted
applied
rotation_inliers
rotation_inlier_ratio
translation_pool_size
translation_consensus_size
translation_score_margin
rotation_refit_steps
translation_refit_steps
reason
to_dict()
class panorai.estimators.EstimateRelativePose(options=<factory>, sampler=<factory>, quality_policy=<factory>)

Estimate Essential, rotation, and unit translation direction.

This is a sparse robust-estimation Stage, not a Torch layer. It delegates every numerical decision to SphericalRelativePoseEstimator.

options
sampler
quality_policy
execute(value)
input_kind = ('bearing_correspondences', 'spherical_matches')
interface = 'panorai-spherical-relative-pose-pipeline/v1-experimental'
output_kind = 'relative_pose'
stability = 'experimental'
class panorai.estimators.FivePointSample(indices, strategy, relaxation_level, min_separation_a_deg, min_separation_b_deg, unique_cells_a, unique_cells_b, design_condition_number)

One minimal-set proposal and its geometric diagnostics.

indices
strategy
relaxation_level
min_separation_a_deg
min_separation_b_deg
unique_cells_a
unique_cells_b
design_condition_number
class panorai.estimators.FivePointSampler(*args, **kwargs)

Protocol for injectable five-point proposal components.

describe()
prepare(bearings_a, bearings_b, active_indices, sampling_weights=None)
name
supports_uniform_trial_bound
class panorai.estimators.FivePointSamplingDiagnostics(sampler_name, sampler_configuration, samples_drawn, strict_spatial_samples, relaxed_spatial_samples, uniform_samples, failed_draws, median_min_separation_a_deg, median_min_separation_b_deg, median_design_condition_number, adaptive_uniform_trial_bound_enabled)

Aggregate provenance for the minimal sets proposed during RANSAC.

sampler_name
sampler_configuration
samples_drawn
strict_spatial_samples
relaxed_spatial_samples
uniform_samples
failed_draws
median_min_separation_a_deg
median_min_separation_b_deg
median_design_condition_number
adaptive_uniform_trial_bound_enabled
to_dict()
class panorai.estimators.ModelCompetitionReport(essential, rotation_only, spherical_homography, preferred_model, essential_score_margin)

Evidence for Essential, rotation-only and spherical homography models.

essential
rotation_only
spherical_homography
preferred_model
essential_score_margin
class panorai.estimators.ModelEvidence(model, num_inliers, inlier_ratio, normalized_robust_score, median_residual_deg)

Comparable evidence for one geometric explanation.

model
num_inliers
inlier_ratio
normalized_robust_score
median_residual_deg
class panorai.estimators.PoseStabilityReport(requested_trials, successful_trials, rotation_median_deg, rotation_p90_deg, translation_median_deg, translation_p90_deg)

Dispersion after independent deterministic consensus re-estimation.

requested_trials
successful_trials
rotation_median_deg
rotation_p90_deg
translation_median_deg
translation_p90_deg
class panorai.estimators.RelativePoseAcceptancePolicy(min_inliers=20, min_inlier_ratio=0.15, min_occupied_cells=4, min_coverage_entropy=0.25, max_median_residual_deg=0.5, min_median_parallax_deg=0.5, min_cheirality_ratio=0.6, min_translation_orientation_margin=0.05, max_stability_rotation_p90_deg=3.0, max_stability_translation_p90_deg=10.0, min_essential_score_margin=0.0, require_essential_preferred=True, require_stability=True, interface='panorai-relative-pose-acceptance/v1')

Conservative, explicit evidence gate for an already estimated pose.

This policy does not alter RANSAC or the returned pose. It turns measured evidence into an auditable accept/reject decision. Its output is not a calibrated probability.

min_inliers
min_inlier_ratio
min_occupied_cells
min_coverage_entropy
max_median_residual_deg
min_median_parallax_deg
min_cheirality_ratio
min_translation_orientation_margin
max_stability_rotation_p90_deg
max_stability_translation_p90_deg
min_essential_score_margin
require_essential_preferred
require_stability
interface
rejection_reasons(report)
to_dict()
class panorai.estimators.RelativePoseConfidenceCalibrator(score_upper_bounds, probabilities, calibration_sample_ids, interface='panorai-relative-pose-confidence-calibration/v1')

Isotonic post-hoc calibrator with mandatory sample-ID separation.

score_upper_bounds
probabilities
calibration_sample_ids
interface
evaluate(reports, successes, *, sample_ids, bins=5)
classmethod fit(reports, successes, *, sample_ids)
predict_proba(report)
to_dict()
class panorai.estimators.RelativePoseOptions(max_angular_error_deg=1.0, confidence=0.999, min_inlier_ratio=0.1, min_num_trials=32, max_num_trials=1000, dynamic_trials_multiplier=3.0, min_inliers=8, local_optimization_steps=3, minimal_solver_starts=16, minimal_solver_max_nfev=100, refinement_max_nfev=100, random_seed=0, min_median_parallax_deg=0.25, minimal_solver='polynomial', scale_marginal_levels=8, scale_marginal_min_fraction=0.2, robust_refinement_steps=2, quality_cell_count=20, stability_trials=6, stability_fraction=0.8, stability_ransac_trials=24, model_competition_trials=128, model_competition_tie_margin=0.01, translation_orientation_method='parallax-weighted', translation_orientation_parallax_scale_deg=1.0, compute_backend='auto', hypothesis_ranking='msac-first', nonminimal_refit_max_steps=100, pose_refinement_method='joint', decoupled_rotation_trials=512, decoupled_refit_max_steps=100, decoupled_translation_min_score_margin=0.15)

Configuration for estimate_relative_pose().

max_angular_error_deg thresholds the first-order spherical tangent Sampson residual. Its unit is degrees, not ERP or face pixels.

max_angular_error_deg
confidence
min_inlier_ratio
min_num_trials
max_num_trials
dynamic_trials_multiplier
min_inliers
local_optimization_steps
minimal_solver_starts
minimal_solver_max_nfev
refinement_max_nfev
random_seed
min_median_parallax_deg
minimal_solver
scale_marginal_levels
scale_marginal_min_fraction
robust_refinement_steps
quality_cell_count
stability_trials
stability_fraction
stability_ransac_trials
model_competition_trials
model_competition_tie_margin
translation_orientation_method
translation_orientation_parallax_scale_deg
compute_backend
hypothesis_ranking
nonminimal_refit_max_steps
pose_refinement_method
decoupled_rotation_trials
decoupled_refit_max_steps
decoupled_translation_min_score_margin
to_dict()
class panorai.estimators.RelativePoseQualityReport(num_correspondences, num_inliers, inlier_ratio, occupied_cells_a, occupied_cells_b, coverage_entropy_a, coverage_entropy_b, median_residual_deg, p90_residual_deg, median_parallax_deg, cheirality_ratio, translation_orientation, stability, model_competition, raw_quality_score, accepted, rejection_reasons, interface='panorai-relative-pose-quality/v1')

Inspectible pose evidence; raw_quality_score is not a probability.

num_correspondences
num_inliers
inlier_ratio
occupied_cells_a
occupied_cells_b
coverage_entropy_a
coverage_entropy_b
median_residual_deg
p90_residual_deg
median_parallax_deg
cheirality_ratio
translation_orientation
stability
model_competition
raw_quality_score
accepted
rejection_reasons
interface
to_dict()
with_decision(policy)
class panorai.estimators.RelativePoseResult(rotation, translation_direction, essential_matrix, inlier_mask, residuals_rad, num_inliers, num_trials, median_parallax_deg, cheirality_ratio, degenerate, degeneracy_reasons, sampling_diagnostics, quality_report, acceptance_policy, options, compute_backend='numpy', interface='panorai-spherical-relative-pose/v1', minimal_solver='panorai-polynomial-action-matrix-v1+numerical-chart-fallback', robust_estimator='panorai-scale-marginal-lo-ransac-v1', consensus_refit_steps=0, decoupled_pose_report=None)

One panorama-2-from-panorama-1 relative-pose estimate.

Translation has unit norm. Its metric magnitude is unobservable from two calibrated central views and is therefore intentionally absent.

rotation
translation_direction
essential_matrix
inlier_mask
residuals_rad
num_inliers
num_trials
median_parallax_deg
cheirality_ratio
degenerate
degeneracy_reasons
sampling_diagnostics
quality_report
acceptance_policy
options
compute_backend
interface
minimal_solver
robust_estimator
consensus_refit_steps
decoupled_pose_report
property R

Alias for the panorama-2-from-panorama-1 rotation.

describe()
property t

Alias for the unit translation direction in panorama-2 coordinates.

class panorai.estimators.TranslationOrientationReport(hypothesis_count, provisional_correspondence_count, best_positive_depth_count, alternative_positive_depth_count, positive_depth_fraction, cheirality_margin, median_triangulation_angle_deg, ambiguous, selection_method='positive-depth-count', parallax_weight_scale_deg=0.0, best_weighted_positive_depth_support=0.0, alternative_weighted_positive_depth_support=0.0, weighted_cheirality_margin=0.0, raw_cheirality_margin=0.0, effective_correspondence_weight=0.0, reliable_correspondence_count=0)

Cheirality evidence distinguishing the four Essential decompositions.

hypothesis_count
provisional_correspondence_count
best_positive_depth_count
alternative_positive_depth_count
positive_depth_fraction
cheirality_margin
median_triangulation_angle_deg
ambiguous
selection_method
parallax_weight_scale_deg
best_weighted_positive_depth_support
alternative_weighted_positive_depth_support
weighted_cheirality_margin
raw_cheirality_margin
effective_correspondence_weight
reliable_correspondence_count
class panorai.estimators.SpatiallyWeightedFivePointSampler(min_angular_separation_deg=8.0, min_unique_cells=4, spherical_cell_count=20, density_radius_deg=10.0, density_power=0.0, diversity_power=0.5, uniform_trial_probability=0.2, max_design_condition_number=1000000.0, attempts_per_level=24, name='spatially-weighted-five-point-v1', supports_uniform_trial_bound=False)

Propose diverse, well-conditioned five-point minimal sets.

Input weights define the initial proposal mass. Optional inverse-density weighting can be enabled explicitly. Each subsequent draw is additionally weighted by angular distance from the points already selected in both panoramas. Strict separation and cell diversity are relaxed progressively; uniform sampling is used only as the final fallback when no spatial proposal satisfies the conditioning gate.

Every explicitly valid correspondence retains positive proposal mass. Robust scoring and refinement remain the responsibility of RANSAC and use the complete valid correspondence set.

min_angular_separation_deg
min_unique_cells
spherical_cell_count
density_radius_deg
density_power
diversity_power
uniform_trial_probability
max_design_condition_number
attempts_per_level
name
supports_uniform_trial_bound
describe()
prepare(bearings_a, bearings_b, active_indices, sampling_weights=None)
class panorai.estimators.SphericalRelativePoseEstimator(options=None, *, sampler=None, quality_policy=None)

Reusable façade for the Experimental PanorAi relative-pose estimator.

estimate(bearings_a, bearings_b=None, *, valid=None, sampling_weights=None)
class panorai.estimators.UniformFivePointSampler(name='uniform-five-point-v1', supports_uniform_trial_bound=True)

Classic uniform sampling without correspondence prefiltering.

name
supports_uniform_trial_bound
describe()
prepare(bearings_a, bearings_b, active_indices, sampling_weights=None)
panorai.estimators.estimate_relative_pose(bearings_a, bearings_b=None, *, valid=None, sampling_weights=None, options=None, sampler=None, quality_policy=None)

Estimate one central relative pose from paired spherical bearings.

Parameters:
  • bearings_a – Arrays with shape (N, 3). Alternatively, bearings_a may be a PanorAi correspondence object exposing bearings_a, bearings_b and valid, in which case bearings_b is omitted. Finite non-zero rows are normalized on private copies, so inputs are never modified.

  • bearings_b – Arrays with shape (N, 3). Alternatively, bearings_a may be a PanorAi correspondence object exposing bearings_a, bearings_b and valid, in which case bearings_b is omitted. Finite non-zero rows are normalized on private copies, so inputs are never modified.

  • valid – Optional explicit boolean mask. Invalid rows are excluded and remain false in the returned inlier mask; validity is never inferred from a bearing’s numeric value beyond mandatory finite/non-zero validation.

  • sampling_weights – Optional non-negative proposal weights with shape (N,). They only influence selection of five-point minimal sets; all explicitly valid correspondences remain in hypothesis scoring and refinement. A correspondence object’s weights field is used when present unless this argument overrides it.

  • options – Robust-estimation and numerical-solver configuration.

  • sampler – Injectable minimal-set proposal component. The default spatial sampler chooses only the five correspondences used to generate each hypothesis; it never prefilters the full scoring, inlier or refinement set. Use UniformFivePointSampler for classic uniform proposals.

Returns:

None when no hypothesis reaches min_inliers. A successful result contains R and only the direction of t.

Return type:

RelativePoseResult | None

panorai.estimators.native_kernels_available()

Return whether the optional first-party C++ kernels are importable.

panorai.estimators.solve_five_point_essential(bearings_a, bearings_b, *, max_epipolar_error=5e-06, max_constraint_error=5e-05, backend='auto')

Return real essential matrices satisfying five bearing correspondences.

The result is sign-deduplicated and normalized to Frobenius norm one. All four projective coefficient charts are attempted so solutions with a zero coordinate in one chart are not silently lost.

panorai.estimators.spherical_tangent_sampson_error(bearings_a, bearings_b, essential_matrix, *, squared=False, backend='auto')

Return intrinsic first-order epipolar errors for central-camera rays.

The constraint gradient is projected into each unit sphere’s tangent plane, giving an approximately angular residual. The returned unit is radians (or squared radians when squared=True).

Polynomial five-correspondence kernel

The PanorAi-owned solver parameterizes E in the four-dimensional nullspace of five epipolar equations, builds the ten calibrated cubic constraints, and uses a 10-by-10 action matrix to enumerate real solutions. All four projective coefficient charts are attempted and sign-equivalent roots are deduplicated. A separately identified deterministic numerical search remains a fallback for singular polynomial charts. This is PanorAi code and does not call OpenCV or COLMAP’s minimal solver.

Native compute kernels

The distribution can build a first-party C++17 extension for the repeated fixed-size polynomial construction and spherical tangent-Sampson residual kernels. This is an acceleration of the same PanorAi mathematics, not a call to OpenCV or COLMAP. RelativePoseOptions(compute_backend="auto") selects the native implementation when it is installed and otherwise uses the NumPy reference. The caller can force either route for reproducibility:

from panorai.estimators import (
    RelativePoseOptions,
    SphericalRelativePoseEstimator,
    native_kernels_available,
)

print(native_kernels_available())

reference = SphericalRelativePoseEstimator(
    RelativePoseOptions(compute_backend="numpy")
)
accelerated = SphericalRelativePoseEstimator(
    RelativePoseOptions(compute_backend="native")
)

Explicit native selection fails when the compiled extension is absent; it never silently falls back. Every successful pose records the resolved compute_backend in describe(). Because the global mapper and incremental SLAM both consume SphericalRelativePoseEstimator, they reuse this kernel automatically instead of carrying separate essential-matrix implementations.

The NumPy implementation remains the normative readable oracle. Native and NumPy paths are required to agree on essential solution sets, residuals, inlier masks, rotations, translation directions and acceptance decisions.

Minimal-set sampling inside RANSAC

The default SpatiallyWeightedFivePointSampler is a proposal component inside RANSAC. On each trial it chooses only the five correspondences used to generate a hypothesis. It never removes correspondences from full-set scoring, inlier classification, cheirality checks, or local refinement.

The proposal combines optional caller weights with angular diversity in both panoramas, spherical-cell coverage, and a conditioning check on the five epipolar equations. It first enforces the configured angular separation, then retries with half that separation, and finally falls back to a uniform five-point draw. A uniform-trial mixture, enabled by default, ensures that a localized but valid overlap region retains a direct proposal route.

The sampler is injectable:

from panorai.estimators import (
    SpatiallyWeightedFivePointSampler,
    SphericalRelativePoseEstimator,
    UniformFivePointSampler,
)

spatial = SpatiallyWeightedFivePointSampler(
    min_angular_separation_deg=8.0,
    min_unique_cells=4,
)
estimator = SphericalRelativePoseEstimator(sampler=spatial)

# Exact compatibility route for classic uniform proposals.
uniform_estimator = SphericalRelativePoseEstimator(
    sampler=UniformFivePointSampler()
)

The classic adaptive w**5 RANSAC trial bound is valid only for independent uniform minimal-set draws and is therefore used only by UniformFivePointSampler. The spatial sampler runs the configured conservative trial budget. The returned pose records proposal counts, relaxations, sample separation and conditioning in sampling_diagnostics.

Quality, stability and model competition

Every successful result includes quality_report. It records inlier count and ratio, spherical-cell occupancy and normalized entropy in both panoramas, residual quantiles, parallax, cheirality, independent re-estimation from subsets of the discovered consensus (scored against all observations), and competition among Essential, rotation-only, and spherical homography explanations. The default RelativePoseAcceptancePolicy turns that evidence into accepted and explicit rejection_reasons without hiding or replacing the estimated R and t:

pose = estimator.estimate(correspondences)
if pose is not None and pose.quality_report.accepted:
    use_pose(pose.R, pose.t)
elif pose is not None:
    inspect(pose.quality_report.rejection_reasons)

Competing models within model_competition_tie_margin of the best normalized score are treated conservatively as an ambiguity, with rotation-only and then spherical homography taking precedence over Essential in a near-tie.

Hypotheses are ranked by inlier support and then a scale-marginal continuous residual score, rather than inlier count alone. Local refinement uses iterative weights marginalized over a declared range of angular noise scales. This is an independently named PanorAi scoring policy; it is not advertised as the MAGSAC++ implementation.

Experimental scoring and consensus-refit controls

RelativePoseOptions.hypothesis_ranking defaults to "msac-first". It minimizes sum(min((residual / threshold)**2, 1)) before applying the other tie breakers. "count-first" preserves the former maximum-consensus ordering, while "scale-marginal-first" promotes the existing multi-scale continuous score ahead of hard inlier count. These controls change model selection and remain Experimental.

nonminimal_refit_max_steps defaults to 100. A positive value enables an unweighted all-inlier linear Essential refit whenever at least eight current inliers are available. The implementation takes the last right singular vector of the spherical epipolar design matrix, projects its singular values to (s, s, 0), decomposes and globally rescores the pose, and repeats until the inlier mask stabilizes, cycles, becomes rank deficient, or reaches the explicit cap. It retains the best hypothesis observed under the selected ranking. RelativePoseResult.consensus_refit_steps reports the executed steps. No Hartley affine recentering is applied to calibrated unit bearings.

For real feature pairs with adequate support, the evidence-backed default is:

options = RelativePoseOptions()

The former compatibility route remains explicit:

options = RelativePoseOptions(
    hypothesis_ranking="count-first",
    nonminimal_refit_max_steps=0,
)

The limit is a cap; the loop normally stops on a stable or repeated inlier mask. A frozen 12-pair calibrated-fisheye phase reduced median oriented translation error from 12.93 to 5.93 degrees and increased strict successes from 4/12 to 6/12. Median rotation improved from 1.01 to 0.90 degrees, which did not meet the preregistered 25 percent reduction target. The estimator therefore remains Experimental despite this default selection. One 33-match pair produced no candidate, and near-zero translation remained unobservable; callers must retain the quality decision rather than assuming every returned or requested pose is trustworthy.

Experimental decoupled pose refinement

pose_refinement_method="decoupled" enables a two-stage estimator for far-background-dominated pairs. A three-ray Wahba RANSAC uses angular MSAC to estimate rotation. Correspondences rejected by that rotation-only model form the translation pool; pairs of their epipolar-plane normals propose translation axes, which are ranked by multiscale epipolar, cheirality and parallax support. Both consensus fits repeat to a bounded stable mask.

decoupled_rotation_trials controls the rotation proposal budget and decoupled_refit_max_steps bounds each stabilization loop. A translation candidate is accepted only when its relative margin over every direction more than ten degrees away reaches decoupled_translation_min_score_margin. The default margin is 0.15. Unobservable and ambiguous translation pools are explicit rejection reasons. RelativePoseResult.decoupled_pose_report exposes the decision evidence. The default pose_refinement_method="joint" preserves existing behavior.

Translation-orientation evidence

Every Essential hypothesis has four decompositions. The default translation_orientation_method="parallax-weighted" chooses among them by positive-depth support weighted by bounded triangulation strength:

options = RelativePoseOptions(
    translation_orientation_method="parallax-weighted",
    translation_orientation_parallax_scale_deg=1.0,
)

For triangulation angle theta and configured scale theta0, the weight is sin(theta)**2 / (sin(theta)**2 + sin(theta0)**2). Nearly parallel rays therefore cannot dominate the orientation merely because they are numerous. The compatibility experiment translation_orientation_method="positive-depth-count" reproduces the historical binary vote.

At least five rays must have weight greater than or equal to 0.5 before the weighted orientation is considered observable. Otherwise the result records selection_method="positive-depth-count-fallback" and a zero decision margin. The historical axis representative remains available for diagnostics, but the default quality policy rejects its oriented translation.

TranslationOrientationReport retains the raw positive-depth counts and raw margin alongside weighted supports, effective correspondence weight, weighted margin, method, and scale. cheirality_margin always denotes the margin used by the selected method, so the existing acceptance policy remains explicit. This changes only four-way decomposition and confidence evidence; it does not make translation scale observable and cannot rescue pure rotation or uniformly weak parallax.

Calibrated confidence

raw_quality_score is a bounded ranking score, not a probability. A probability is available only after fitting RelativePoseConfidenceCalibrator on labeled calibration examples. The calibrator uses isotonic regression and stores every calibration sample ID. Evaluation fails if any ID overlaps, making calibration/evaluation leakage an explicit error:

calibrator = RelativePoseConfidenceCalibrator.fit(
    calibration_reports,
    calibration_successes,
    sample_ids=calibration_ids,
)
probability = calibrator.predict_proba(new_pose.quality_report)
metrics = calibrator.evaluate(
    held_out_reports,
    held_out_successes,
    sample_ids=held_out_ids,
)

The default acceptance thresholds are deliberately conservative and remain Experimental; they are not a calibrated operating point. The 15-pair development fixture is not large enough to calibrate a production probability. A separately frozen and labeled set is required before confidence values can be interpreted statistically.