How Sky Segmentation Filters Sky Points from a Point Cloud: The lingbot-map Implementation
Sky segmentation filters sky points by running an ONNX inference model to generate per-pixel probability masks, converting those masks into binary confidence filters, and element-wise multiplying them against the depth confidence tensor to zero out sky regions before point-cloud reconstruction.
The Robbyant/lingbot-map repository implements a dedicated sky segmentation pipeline that automatically removes sky pixels from RGB-D data to prevent artifacts in 3-D reconstructions. This system processes input frames through a pretrained neural network, caches the resulting masks, and applies them to confidence scores that drive point-cloud generation. Understanding how sky segmentation filters sky points from a point cloud requires examining the inference pipeline, the thresholding logic, and the integration points with the visualization system.
The Sky Segmentation Pipeline
The core implementation resides in lingbot_map/vis/sky_segmentation.py. The pipeline consists of four distinct stages: model inference, confidence conversion, disk caching, and application to the confidence tensor.
ONNX Model Inference
The system loads a pretrained segmentation model using onnxruntime.InferenceSession. In the run_skyseg function (line 46 of sky_segmentation.py), input images are converted from RGB to BGR format and resized to 320×320 before inference. The model outputs an 8-bit score map where higher values indicate sky regions and lower values represent non-sky areas such as buildings, vegetation, or ground planes.
The inference produces a raw score map that requires normalization to the [0, 255] range before further processing.
Confidence Map Conversion
Raw model outputs are transformed into usable confidence values by _result_map_to_non_sky_conf (line 92). This function inverts the probability scores to create a non-sky confidence map:
- Sky probability is normalized to [0, 1]
- Non-sky confidence is calculated as
1.0 - sky_score
This inversion ensures that subsequent multiplication operations suppress sky regions while preserving structural points. The resulting floating-point array represents the probability that each pixel belongs to the non-sky class.
Mask Caching Strategy
For batch processing efficiency, the system implements an aggressive caching mechanism via load_or_create_sky_masks (line 210) and _prepare_sky_mask_cache. When processing a dataset:
- The function checks for existing cached masks on disk
- If unavailable, it invokes
segment_sky_from_arrayorsegment_skyto generate masks - Results are written to the configured cache directory to avoid recomputation in subsequent runs
This caching proves essential when iterating on point-cloud parameters, as sky segmentation remains constant for static camera positions.
Applying the Sky Filter to Point Clouds
The critical filtering step occurs when the confidence tensor meets the sky mask. This happens in apply_sky_segmentation at line 73 of sky_segmentation.py.
Binary Mask Thresholding
The confidence tensor conf enters with shape (S, H, W), where S represents the number of frames. The system loads cached sky masks and resizes them to match (H, W) if dimensional mismatches exist. A soft threshold converts the continuous sky probability into a binary decision:
sky_mask_binary = (sky_mask_array > _SKYSEG_SOFT_THRESHOLD).astype(np.float32)
conf = conf * sky_mask_binary
The default _SKYSEG_SOFT_THRESHOLD of 0.1 provides a conservative filter that removes most sky pixels while preserving edge cases near horizon lines. Pixels exceeding this threshold receive a value of 0 in the confidence tensor, effectively filtering out sky points from any subsequent point-cloud reconstruction algorithms that rely on these confidence scores.
Integration with the Visualization Pipeline
The viser_wrapper module (lines 82-84) exposes this functionality to end users through the mask_sky parameter. When enabled, the wrapper:
- Loads the confidence map from depth estimation
- Invokes
apply_sky_segmentationwith the appropriate image folder and model path - Passes the filtered confidence to the point-cloud view generator
This integration ensures that sky points never enter the 3-D reconstruction buffer, improving visual quality and reducing noise in downstream processing tasks such as mesh extraction or semantic labeling.
Practical Implementation Examples
Filtering Confidence Scores Directly
To apply sky segmentation to existing confidence data:
import numpy as np
from lingbot_map.vis.sky_segmentation import apply_sky_segmentation
# `conf` – confidence scores from depth estimation, shape (S, H, W)
conf = np.random.rand(10, 480, 640).astype(np.float32)
# Apply sky segmentation using images stored in a folder
filtered_conf = apply_sky_segmentation(
conf,
image_folder="data/images", # folder with the RGB frames
skyseg_model_path="skyseg.onnx", # automatically downloaded if missing
sky_mask_dir="cache/sky_masks", # optional cache dir
sky_mask_visualization_dir="cache/visuals", # optional visualisation
)
# `filtered_conf` now has zeros where sky was detected
Generating Masks for Batch Processing
For scenarios requiring mask inspection before point-cloud generation:
from lingbot_map.vis.sky_segmentation import load_or_create_sky_masks
sky_masks = load_or_create_sky_masks(
image_folder="data/images",
skyseg_model_path="skyseg.onnx",
target_shape=(480, 640), # resize to match depth map resolution
)
# `sky_masks` shape → (num_frames, 480, 640) with values in [0, 1]
Summary
- ONNX Inference: The system uses
skyseg.onnxwith onnxruntime to generate per-pixel sky probabilities from 320×320 BGR inputs inrun_skyseg. - Confidence Inversion: The
_result_map_to_non_sky_conffunction converts sky scores to non-sky confidence via1.0 - sky_scorearithmetic. - Persistent Caching: Masks are cached to disk via
load_or_create_sky_masksto eliminate redundant inference on subsequent runs. - Threshold-Based Filtering:
apply_sky_segmentationuses a default threshold of 0.1 to create binary masks that zero out sky regions in the confidence tensor through element-wise multiplication. - Pipeline Integration: The
viser_wrapperenables sky masking through themask_skyflag, ensuring filtered confidence drives the final point-cloud view.
Frequently Asked Questions
What neural network architecture powers the sky segmentation?
The repository utilizes a pretrained ONNX model (skyseg.onnx) loaded through onnxruntime.InferenceSession. While the specific architecture (likely a lightweight CNN or segmentation transformer) is abstracted by the ONNX format, the model accepts 320×320 BGR inputs and outputs 8-bit segmentation maps where high values indicate sky regions.
How does the soft threshold affect point cloud quality?
The _SKYSEG_SOFT_THRESHOLD default of 0.1 balances aggressive sky removal with horizon preservation. Lower thresholds (e.g., 0.05) retain more sky edge pixels but may introduce noise, while higher thresholds (e.g., 0.2) risk clipping legitimate distant structures. The threshold applies in apply_sky_segmentation when converting the soft probability mask to the binary filter.
Can sky segmentation handle arbitrary image resolutions?
Yes. The load_or_create_sky_masks function accepts a target_shape parameter (H, W) that resizes cached masks to match your depth map resolution. The underlying ONNX model always processes 320×320 inputs, but the resulting masks are bilinearly resampled to match the confidence tensor dimensions before application.
Where does the system store cached sky masks?
The _prepare_sky_mask_cache function writes masks to the directory specified by sky_mask_dir (defaulting to a subdirectory of the image folder). These cached arrays persist as NumPy binary files, allowing load_or_create_sky_masks to skip ONNX inference on subsequent runs unless the source images change.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →