Global spherical reconstruction¶
panorai.reconstruction contains separate Experimental sparse and dense
reconstruction surfaces for central panoramas. The sparse mapper can attach soft radial-range
priors to matched features and optional measured metric baselines. It refines
points while all camera poses remain frozen before any pose block is opened.
Its equations, policies and orchestration are PanorAi
NumPy/SciPy code, with optional first-party C++ acceleration for repeated
numerical kernels. OpenCV remains responsible for optional feature extraction
and matching, and this mapper does not call OpenCV, PyCOLMAP, COLMAP, or Torch
for geometry.
The high-level input is a sequence of
panorai.features.SphericalFeatureMatches objects. Pairwise poses may be
estimated internally with SphericalRelativePoseEstimator or computed once
and supplied as SphericalPairwisePoseEdge objects:
from panorai.reconstruction import SphericalGlobalMapper
mapper = SphericalGlobalMapper(relative_pose_estimator=relative_estimator)
result = mapper.reconstruct(matches=pairwise_matches)
# Equivalent route when pairwise estimation is intentionally reused.
edges = mapper.estimate_pairwise(pairwise_matches)
reused = mapper.reconstruct(edges=edges)
if result.success:
pose = result.pose("panorama-003")
R_world_to_panorama = pose.R
center_world = pose.center
points_world = result.points_xyz
else:
inspect(result.failure_reasons)
Exactly one of matches and edges is accepted. Invalid contracts raise
TypeError or ValueError. Insufficient geometry returns an unsuccessful
result with no fabricated partial poses or points.
The metric-prior route is explicit and opt-in:
from panorai.reconstruction import (
SphericalGlobalMapper,
SphericalGlobalMapperOptions,
SphericalBaselinePrior,
SphericalRangePrior,
)
mapper = SphericalGlobalMapper(options=SphericalGlobalMapperOptions())
priors = [
SphericalRangePrior("panorama-001", feature_index, radial_range_m)
for feature_index, radial_range_m in feature_ranges
]
baseline = SphericalBaselinePrior(
"panorama-001", "panorama-002", baseline_m=1.279521, sigma_m=0.01
)
result = mapper.reconstruct(
edges=accepted_edges,
range_priors=priors,
baseline_priors=(baseline,),
)
Only priors attached to admitted inlier tracks participate. At least
range_prior_min_count matched priors are required when any are supplied.
The result records matched and unused counts, the robust scale factor, and
range and baseline residuals before and after refinement. A metric baseline is
not inferred from two-view bearing geometry: it must come from a measurement,
registration, or a separately validated metric sensor/depth source. The
connected reconstruction must still contain at least three panoramas.
One measured baseline fixes the global scale gauge, but a tree with only two
pairwise directions may still leave another camera’s relative distance weakly
constrained. Prefer a closed three-view cycle, additional measured baselines,
or sufficiently many tracks observed in all three panoramas. The permissive
edge_admission="successful" option can retain an audited low-support loop
edge, but it is not enabled automatically and keeps the risk described below.
Frames and scale¶
The public pose convention is
where R_i is rotation_world_to_panorama and C_i is
center_world. A relative-pose edge follows
The reference panorama has identity rotation and zero center. Bearings alone
do not contain metric scale, so the ordinary result uses
result.scale == "arbitrary". With sufficient SphericalRangePrior
evidence, a robust log-range scale fit changes this to
"metric-range-prior". Range values remain soft evidence: a Huber IRLS
scale fit limits outliers, and the bundle objective retains their declared
sigma_log_range and confidence.
When a SphericalBaselinePrior is supplied, it is the preferred scale gauge
and the result reports "metric-baseline-prior" or
"metric-baseline-and-range-priors". This transfers the successful
pair-refinement setup into global mapping: the measured baseline fixes scale
while the depth map remains a soft range prior, and the whole connected
three-or-more-view component supplies global geometric support. A monocular
depth map may have severe absolute scale bias and should not silently replace a
measured baseline.
GlobalMapper-aligned stages¶
The mapper follows the current global-SfM decomposition without copying COLMAP code or claiming numerical identity:
admit pairwise poses with
quality_report.acceptedby default;retain the deterministic largest connected component;
initialize through a maximum-support spanning tree and robustly average rotations on \(SO(3)\);
filter rotation-inconsistent edges and resolve the surviving component;
build conflict-free tracks by unioning only components with disjoint panorama IDs;
solve a translation-independent linear camera/point initialization from track bearings using several deterministic positive-depth scale anchors; select first by the weakest per-camera cheirality support, then total support and scale-normalized robust residual;
compare every relative translation as an unsigned axis against those centers, resolve its sign jointly, and remove the worst direction-inconsistent edge before rebuilding tracks and re-estimating;
refine centers from the surviving, consistently oriented relative translations;
jointly position cameras and points using
\[X_k - C_i - s_{ik}R_i^T b_{ik} \simeq 0, \qquad s_{ik}>0;\]robustly establish scale from the measured baseline when available, otherwise from declared metric range priors;
when range priors are present, optimize only the 3D points while all \(R,t\) blocks remain frozen;
run fixed-rotation and joint spherical bundle adjustment;
filter angular reprojection outliers and weak triangulation, retriangulate, and perform a final joint refinement;
independently repeat the position solve using only tracks observed by at least three panoramas, then require its pairwise camera-center directions to agree with the primary reconstruction.
Bundle adjustment compares the measured bearing with
using a two-dimensional log-map residual in the tangent plane of the measured bearing. The BATA and bundle residuals are evaluated in vectorized batches; this is an execution change, not a different objective. Descriptor distance is not treated as a calibrated geometric weight.
Native bundle computation¶
SphericalGlobalMapperOptions(bundle_compute_backend="auto") uses the
optional first-party C++17 kernel when it is present and otherwise retains the
NumPy reference path. "numpy" forces the readable reference with SciPy’s
sparse finite-difference Jacobian; "native" requires the compiled kernel
and fails explicitly when it is unavailable.
The native kernel evaluates the same tangent-plane log-map residual and its
analytic local Jacobian blocks with respect to the rotation increment, camera
center and world point. Python still owns graph admission, gauges, robust loss,
SciPy optimization, filtering, provenance and result construction. The
resolved route is recorded as diagnostics.bundle_compute_backend. Native
and NumPy paths are required to agree against independent finite differences
and complete reconstruction fixtures; the native path is acceleration, not a
second reconstruction method.
Range- and baseline-prior bundle adjustment currently uses the NumPy/SciPy path
because the native kernel does not yet expose those residual blocks. This
fallback is explicit in diagnostics.bundle_compute_backend and does not
silently drop the priors.
Metric landmark-only support¶
refine_metric_spherical_landmarks is a separate Experimental entry point
for an already constructed sparse graph with a known metric baseline. It accepts
two or more cameras, multiply observed landmarks, unit bearings and optional
soft monocular radial-range priors. Passing every camera ID in
fixed_camera_ids refines only landmark positions; fixing only the reference
camera permits joint camera/landmark refinement.
The result explicitly reports support="supplied-landmarks-only". It never
interpolates, splats or otherwise converts sparse points into a depth image.
Sparse landmark metrics must not be presented as full-panorama accuracy, and
dense propagation is outside this API contract.
Admission and failure policy¶
edge_admission="accepted" is the default. The explicit
"successful" override admits every numerical pairwise result, including
one rejected by its quality policy. Relative-pose quality now records all four
Essential decompositions, the best and alternative positive-depth counts, and
their normalized cheirality margin. A small margin is reported as
ambiguous-translation-orientation.
The global mapper treats pairwise translation as an axis before assigning a
sign. translation_max_error_deg controls removal against the independent
track-bearing initialization; the default is 20 degrees. Inconsistent edges
are removed worst-first for at most translation_consistency_rounds solves,
rather than all at once. bearing_position_anchor_trials bounds the
deterministic scale-anchor candidates. Rejected edges,
rotation- and translation-filtered edges, sign flips, per-edge axis errors,
positive-depth coverage, final reprojection percentiles, excluded panoramas,
active-track counts per panorama, multiview-corroboration status and angular
disagreement, track conflicts, costs, gauges, and stage names remain in
SphericalReconstructionDiagnostics.
The default require_multiview_corroboration=True prevents a map supported
only by independent two-view tracks from being reported as trustworthy. The
independent solve uses tracks of length three or greater and rejects the
result if it fails or if the P90 disagreement between pairwise center
directions exceeds 15 degrees. These controls are exposed as
multiview_corroboration_min_track_length and
multiview_corroboration_max_position_error_deg. Disabling corroboration
is an explicit permissive override; it increases coverage but removes this
independent check against repeated-texture and weak-translation solutions.
The mapper requires at least three connected panoramas. Pure rotation,
insufficient tracks, low triangulation angle, disconnected reference cameras,
complete filtering, or a panorama with fewer than
min_active_tracks_per_panorama surviving tracks return success=False
and an explicit reason. A camera is therefore never reported as registered
solely because it survived graph connectivity while all of its observations
were rejected. Failed independent multiview corroboration likewise returns no
partial geometry and starts its reason list with
multiview-corroboration-failed.
A reference_id that does not identify any input panorama remains invalid
and raises ValueError. If it identifies an input panorama that is excluded
from the selected connected component, that is geometric insufficiency: the
mapper returns success=False with
reference-not-in-selected-component instead of raising during a batch.
Limitations¶
This first version assumes calibrated central panoramas and NumPy bearings. It does not select image pairs, discover loops, estimate metric scale, adjust intrinsics, or replace the existing PyCOLMAP database exporter. Promotion from Experimental requires independent real multiview consumers and broader degeneracy/performance evidence.
The current promotion decision is explicitly negative. In the metadata-blind 423-set census, the current conservative policy fully registered 131 sets (31.0%); all 131 complete results were strict-accurate, but coverage remained too low. A development-tuned group-held-out Matterport gate selected 18/22 successes (81.8%), but the threshold was not prospectively frozen and external Stanford evidence covered only three spatial groups. Use explicit failure/recapture handling and do not treat this surface as an unattended Stable mapper. The next evidence order is: independent real consumer, prospective broader-domain validation, degeneracy corpus, then scalability and bounded-failure measurements.
Registered dense surface reconstruction¶
RegisteredSphericalView binds an EquirectangularImage to a
SphericalCameraPose. RegisteredSphericalScene validates shared units,
unique camera IDs and at least two supplied central-camera poses. The candidate
reviewed application profile requires at least three views.
SphericalDenseReconstruction in panorai.applications exposes the
complete route. The reusable contracts and Stages live here:
The typed values are RegisteredSphericalView,
RegisteredSphericalScene, MultiViewRangeMap, MultiViewRangeSet,
TSDFSpec, TSDFVolume, SurfaceMesh and
SphericalDenseReconstructionResult. The public Stages are
BuildRegisteredReferenceSets, EstimateMultiViewRanges, FuseTSDF,
ExtractSurface, ColorizeSurface and
ValidateDenseReconstruction.
FuseTSDF accepts a MultiViewRangeSet directly, including one produced
by another range method. TSDFVolume.weight_zyx == 0 means unknown. Surface
extraction requires the configured view count and does not close unknown holes.
SurfaceMesh is canonical; panorai.pcd.surface_mesh_to_open3d is a lazy
optional adapter.
The candidate profile is not Stable. Promotion requires the prospectively frozen multi-corpus surface metrics, installed-wheel Python matrix, memory and runtime evidence, content/license audit and independent review described in the concept.
API¶
Experimental PanorAi-owned global spherical reconstruction.
The implementation consumes panorama-frame bearings and uses NumPy/SciPy. It does not call OpenCV, PyCOLMAP, COLMAP, or Torch for geometry.
- class panorai.reconstruction.BuildRegisteredReferenceSets(reference_ids=None)¶
Create one deterministic registered MVS set per reference view.
- reference_ids¶
- execute(value)¶
- input_kind = 'registered-spherical-scene'¶
- output_kind = 'dense-reconstruction-workspace'¶
- stability = 'experimental'¶
- class panorai.reconstruction.ColorizeSurface(enabled=True)¶
Fuse range-consistent ERP colors into surface vertices.
- enabled¶
- execute(value)¶
- input_kind = 'dense-reconstruction-workspace'¶
- output_kind = 'dense-reconstruction-workspace'¶
- stability = 'experimental'¶
- class panorai.reconstruction.DenseReconstructionWorkspace(*, scene, reference_sets=None, ranges=None, volume=None, surface=None, diagnostics=<factory>, rejection_reasons=())¶
Typed state passed between public dense-reconstruction stages.
- scene¶
- reference_sets¶
- ranges¶
- volume¶
- surface¶
- diagnostics¶
- rejection_reasons¶
- class panorai.reconstruction.EstimateMultiViewRanges(options=<factory>)¶
Run the existing full-sphere MVS engine for every reference.
- options¶
- execute(value)¶
- input_kind = 'dense-reconstruction-workspace'¶
- output_kind = 'dense-reconstruction-workspace'¶
- stability = 'experimental'¶
- class panorai.reconstruction.ExtractSurface¶
Extract a world-frame mesh from a sufficiently observed TSDF.
- execute(value)¶
- input_kind = ('dense-reconstruction-workspace', 'tsdf-volume')¶
- output_kind = ('dense-reconstruction-workspace', 'surface-mesh')¶
- stability = 'experimental'¶
- class panorai.reconstruction.FuseTSDF(spec)¶
Fuse a range set (or workspace range set) into a dense TSDF.
- spec¶
- execute(value)¶
- input_kind = ('dense-reconstruction-workspace', 'multi-view-range-set')¶
- output_kind = ('dense-reconstruction-workspace', 'tsdf-volume')¶
- stability = 'experimental'¶
- class panorai.reconstruction.MultiViewRangeMap(*, reference_id, pose, radial_range, validity, sampling_support, observable, confidence, observable_source_count, source_count, source_consensus_count, contribution_count, source_ids, diagnostics=<factory>, interface='panorai-spherical-dense-reconstruction/v1-experimental')¶
One reference ERP radial-range estimate with its complete evidence.
- reference_id¶
- pose¶
- radial_range¶
- validity¶
- sampling_support¶
- observable¶
- confidence¶
- observable_source_count¶
- source_count¶
- source_consensus_count¶
- contribution_count¶
- source_ids¶
- diagnostics¶
- interface¶
- classmethod from_stereo_result(*, reference_id, pose, result)¶
- class panorai.reconstruction.MultiViewRangeSet(*, scene, maps, diagnostics=<factory>, interface='panorai-spherical-dense-reconstruction/v1-experimental')¶
Per-camera radial ranges tied to their registered input scene.
- scene¶
- maps¶
- diagnostics¶
- interface¶
- by_reference(reference_id)¶
- class panorai.reconstruction.RegisteredReferenceSets(*, scene, sets)¶
Deterministic MVS inputs, one for every selected reference camera.
- scene¶
- sets¶
- class panorai.reconstruction.RegisteredSphericalScene(*, views, units, frame='world')¶
Metric central-camera ERPs registered in one named world frame.
- views¶
- units¶
- frame¶
- property panorama_ids¶
- registered_set(reference_id)¶
Build the exact source-from-reference relations consumed by MVS.
- view(panorama_id)¶
- class panorai.reconstruction.RegisteredSphericalView(*, image, pose, validity=None)¶
One central ERP and its metric camera pose in a shared world frame.
- image¶
- pose¶
- validity¶
- effective_validity()¶
Return explicit image validity intersected with geometric support.
- property panorama_id¶
- property shape_hw¶
- class panorai.reconstruction.SphericalBaselinePrior(panorama_id_a, panorama_id_b, baseline_m, sigma_m=0.01, confidence=1.0)¶
Soft metric distance evidence between two panorama centers.
- panorama_id_a¶
- panorama_id_b¶
- baseline_m¶
- sigma_m¶
- confidence¶
- property pair¶
- class panorai.reconstruction.SphericalCameraPose(panorama_id: 'str', rotation_world_to_panorama: 'np.ndarray', center_world: 'np.ndarray')¶
- panorama_id¶
- rotation_world_to_panorama¶
- center_world¶
- property R¶
- property center¶
- class panorai.reconstruction.SphericalDenseReconstructionResult(*, status, reasons, diagnostics, surface=None, ranges=None, volume=None, interface='panorai-spherical-dense-reconstruction/v1-experimental')¶
Auditable accepted or rejected dense-reconstruction outcome.
- status¶
- reasons¶
- diagnostics¶
- surface¶
- ranges¶
- volume¶
- interface¶
- property accepted¶
- require_success()¶
- class panorai.reconstruction.SphericalGlobalMapper(relative_pose_estimator=None, options=None)¶
PanorAi-owned Experimental global mapper for central panoramas.
- estimate_pairwise(matches)¶
Estimate one relative pose for every supplied match set.
Pairs for which the relative estimator returns
Noneare omitted. Rejected but numerically successful poses remain available for audit; normal global reconstruction admission filters them later.
- reconstruct(*, matches=None, edges=None, panorama_ids=None, reference_id=None, range_priors=(), baseline_priors=())¶
Reconstruct a panorama rig and sparse points.
Exactly one of
matchesandedgesis required. Invalid input is rejected. Soft feature-aligned radial ranges and measured baselines can establish metric scale before any camera pose is refined. Geometric insufficiency returns an unsuccessful result with explicit reasons and no partial geometry.
- class panorai.reconstruction.SphericalGlobalMapperOptions(edge_admission='accepted', min_panoramas=3, min_track_length=2, min_active_tracks_per_panorama=3, rotation_max_error_deg=10.0, rotation_robust_scale_deg=5.0, rotation_max_iterations=100, translation_max_error_deg=20.0, translation_consistency_rounds=4, translation_min_positive_depth_ratio=0.55, bearing_position_irls_steps=3, bearing_position_anchor_trials=8, require_multiview_corroboration=True, multiview_corroboration_min_track_length=3, multiview_corroboration_max_position_error_deg=15.0, max_reprojection_error_deg=2.0, min_triangulation_angle_deg=0.5, bundle_loss='cauchy', bundle_loss_scale_deg=1.0, bundle_max_nfev=100, max_refinement_rounds=3, initial_fixed_pose_refinement=True, range_prior_min_count=3, range_prior_huber_delta_log=0.1, bundle_compute_backend='auto')¶
Numerical and admission policy for
SphericalGlobalMapper.- edge_admission¶
- min_panoramas¶
- min_track_length¶
- min_active_tracks_per_panorama¶
- rotation_max_error_deg¶
- rotation_robust_scale_deg¶
- rotation_max_iterations¶
- translation_max_error_deg¶
- translation_consistency_rounds¶
- translation_min_positive_depth_ratio¶
- bearing_position_irls_steps¶
- bearing_position_anchor_trials¶
- require_multiview_corroboration¶
- multiview_corroboration_min_track_length¶
- multiview_corroboration_max_position_error_deg¶
- max_reprojection_error_deg¶
- min_triangulation_angle_deg¶
- bundle_loss¶
- bundle_loss_scale_deg¶
- bundle_max_nfev¶
- max_refinement_rounds¶
- initial_fixed_pose_refinement¶
- range_prior_min_count¶
- range_prior_huber_delta_log¶
- bundle_compute_backend¶
- to_dict()¶
- class panorai.reconstruction.SphericalPairwisePoseEdge(matches, pose)¶
A match set and its panorama-B-from-panorama-A pose estimate.
- matches¶
- pose¶
- property accepted¶
- property pair¶
- property panorama_id_a¶
- property panorama_id_b¶
- class panorai.reconstruction.SphericalRangePrior(panorama_id, feature_index, range_m, sigma_log_range=0.15, confidence=1.0)¶
Soft radial-range evidence attached to one panorama feature.
- panorama_id¶
- feature_index¶
- range_m¶
- sigma_log_range¶
- confidence¶
- class panorai.reconstruction.SphericalReconstructionDiagnostics(input_edge_count: 'int' = 0, successful_edge_count: 'int' = 0, admitted_edge_count: 'int' = 0, rejected_edge_pairs: 'tuple[tuple[str, str], ...]' = (), rotation_filtered_pairs: 'tuple[tuple[str, str], ...]' = (), translation_filtered_pairs: 'tuple[tuple[str, str], ...]' = (), translation_flipped_pairs: 'tuple[tuple[str, str], ...]' = (), translation_axis_errors_deg: 'tuple[tuple[tuple[str, str], float], ...]' = (), translation_positive_depth_ratio: 'float | None' = None, bearing_position_anchors_tested: 'int' = 0, bearing_position_min_camera_positive_depth_ratio: 'float | None' = None, excluded_panoramas: 'tuple[str, ...]' = (), candidate_match_count: 'int' = 0, track_count: 'int' = 0, track_conflict_count: 'int' = 0, filtered_observation_count: 'int' = 0, rotation_initial_cost: 'float | None' = None, rotation_final_cost: 'float | None' = None, position_initial_cost: 'float | None' = None, position_final_cost: 'float | None' = None, bundle_costs: 'tuple[tuple[str, float, float], ...]' = (), reprojection_median_deg: 'float | None' = None, reprojection_p90_deg: 'float | None' = None, reprojection_max_deg: 'float | None' = None, camera_max_reprojection_deg: 'tuple[tuple[str, float], ...]' = (), camera_active_track_counts: 'tuple[tuple[str, int], ...]' = (), multiview_corroboration_passed: 'bool | None' = None, multiview_corroboration_track_count: 'int' = 0, multiview_corroboration_position_p90_deg: 'float | None' = None, multiview_corroboration_failure_reasons: 'tuple[str, ...]' = (), range_prior_count: 'int' = 0, range_prior_unused_count: 'int' = 0, range_prior_scale_factor: 'float | None' = None, range_prior_median_abs_log_error_before: 'float | None' = None, range_prior_median_abs_log_error_after: 'float | None' = None, baseline_prior_count: 'int' = 0, baseline_prior_unused_count: 'int' = 0, baseline_prior_scale_factor: 'float | None' = None, baseline_prior_median_abs_log_error_after: 'float | None' = None, scale_anchor: 'str | None' = None, ba_scale_anchor: 'str | None' = None, stage_messages: 'tuple[str, ...]' = (), bundle_compute_backend: 'str' = 'numpy')¶
- input_edge_count¶
- successful_edge_count¶
- admitted_edge_count¶
- rejected_edge_pairs¶
- rotation_filtered_pairs¶
- translation_filtered_pairs¶
- translation_flipped_pairs¶
- translation_axis_errors_deg¶
- translation_positive_depth_ratio¶
- bearing_position_anchors_tested¶
- bearing_position_min_camera_positive_depth_ratio¶
- excluded_panoramas¶
- candidate_match_count¶
- track_count¶
- track_conflict_count¶
- filtered_observation_count¶
- rotation_initial_cost¶
- rotation_final_cost¶
- position_initial_cost¶
- position_final_cost¶
- bundle_costs¶
- reprojection_median_deg¶
- reprojection_p90_deg¶
- reprojection_max_deg¶
- camera_max_reprojection_deg¶
- camera_active_track_counts¶
- multiview_corroboration_passed¶
- multiview_corroboration_track_count¶
- multiview_corroboration_position_p90_deg¶
- multiview_corroboration_failure_reasons¶
- range_prior_count¶
- range_prior_unused_count¶
- range_prior_scale_factor¶
- range_prior_median_abs_log_error_before¶
- range_prior_median_abs_log_error_after¶
- baseline_prior_count¶
- baseline_prior_unused_count¶
- baseline_prior_scale_factor¶
- baseline_prior_median_abs_log_error_after¶
- scale_anchor¶
- ba_scale_anchor¶
- stage_messages¶
- bundle_compute_backend¶
- to_dict()¶
- class panorai.reconstruction.SphericalReconstructionResult(success: 'bool', failure_reasons: 'Sequence[str]', poses: 'Sequence[SphericalCameraPose]', tracks: 'Sequence[SphericalTrack]', pairwise_edges: 'Sequence[SphericalPairwisePoseEdge]', admitted_edge_indices: 'Sequence[int]', reference_panorama_id: 'str | None', diagnostics: 'SphericalReconstructionDiagnostics', options: 'SphericalGlobalMapperOptions', interface: 'str' = 'panorai-spherical-reconstruction/v1', scale: 'str' = 'arbitrary', _points_xyz: 'np.ndarray' = <factory>)¶
- success¶
- failure_reasons¶
- poses¶
- tracks¶
- pairwise_edges¶
- admitted_edge_indices¶
- reference_panorama_id¶
- diagnostics¶
- options¶
- interface¶
- scale¶
- describe()¶
- property points_xyz¶
- pose(panorama_id)¶
- require_success()¶
- class panorai.reconstruction.SphericalTrack(track_id: 'str', point_xyz: 'np.ndarray', observations: 'tuple[SphericalTrackObservation, ...]', valid: 'bool' = True)¶
- track_id¶
- point_xyz¶
- observations¶
- valid¶
- class panorai.reconstruction.SphericalTrackObservation(panorama_id: 'str', feature_index: 'int', bearing_xyz: 'np.ndarray', residual_rad: 'float', active: 'bool' = True, rejection_reason: 'str | None' = None)¶
- panorama_id¶
- feature_index¶
- bearing_xyz¶
- residual_rad¶
- active¶
- rejection_reason¶
- class panorai.reconstruction.SurfaceMesh(*, vertices_xyz, faces, normals_xyz, vertex_weight, vertex_view_count, colors_rgb=None, color_validity=None, color_contribution_count=None, units='m', frame='world', provenance=<factory>, interface='panorai-spherical-dense-reconstruction/v1-experimental')¶
World-frame triangle mesh with geometric and color evidence.
- vertices_xyz¶
- faces¶
- normals_xyz¶
- vertex_weight¶
- vertex_view_count¶
- colors_rgb¶
- color_validity¶
- color_contribution_count¶
- units¶
- frame¶
- provenance¶
- interface¶
- class panorai.reconstruction.TSDFSpec(*, voxel_size, bounds=None, truncation_distance=None, max_voxels=8000000, chunk_voxels=262144, min_surface_views=2, min_valid_weight=1.0, weighting='uniform')¶
Deterministic bounded dense-TSDF configuration.
- voxel_size¶
- bounds¶
- truncation_distance¶
- max_voxels¶
- chunk_voxels¶
- min_surface_views¶
- min_valid_weight¶
- weighting¶
- class panorai.reconstruction.TSDFVolume(*, tsdf_zyx, weight_zyx, view_count_zyx, origin_xyz, voxel_size, truncation_distance, units, frame, min_surface_views, diagnostics=<factory>, interface='panorai-spherical-dense-reconstruction/v1-experimental')¶
Dense ZYX TSDF grid in a named world frame.
- tsdf_zyx¶
- weight_zyx¶
- view_count_zyx¶
- origin_xyz¶
- voxel_size¶
- truncation_distance¶
- units¶
- frame¶
- min_surface_views¶
- diagnostics¶
- interface¶
- property bounds_xyz¶
- class panorai.reconstruction.ValidateDenseReconstruction(retain_intermediates='ranges')¶
Turn scientific acceptance or rejection into an auditable result.
- retain_intermediates¶
- execute(value)¶
- input_kind = 'dense-reconstruction-workspace'¶
- output_kind = 'spherical-dense-reconstruction-result'¶
- stability = 'experimental'¶
- panorai.reconstruction.colorize_surface(surface, range_set, *, truncation_distance)¶
Median-fuse range-consistent colors while preserving valid black.
- panorai.reconstruction.extract_surface(volume)¶
Extract a zero-level surface without inventing unknown-space geometry.
- panorai.reconstruction.fuse_tsdf(range_set, spec)¶
Fuse accepted radial ranges into a bounded dense world-frame TSDF.