Plane segmentation with RANSAC-LP+ for Open3D point clouds
Project description
ransaclpplus
In this repository you can find the code related to the RANSACLPPLUS algorithm.
Table of Contents
- Installation
- Docker
- Publishing
- Basic usage
- Repository Structure
- Reproducible Experiments
- Method
- Current Research Status
- CUDA backend
- CUDA benchmark
- Documentation with Sphinx
- Tests
- Visual Step-by-Step Test (Open3D)
- Run The Devcontainer From CLI (JSON-Equivalent)
Installation
Install the CPU-portable package from PyPI:
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install ransaclpplus
For repository development:
git clone https://github.com/jmartinezot/lp4-plus.git
cd lp4-plus
python -m pip install -e .
PyPI installations use CPU execution by default. To enable native CUDA on a machine with the NVIDIA CUDA toolkit and CMake:
ransaclpplus-build-cuda --cuda-architectures "61;75;86;89;90"
See the installation guide for complete installation, CUDA, devcontainer, and troubleshooting instructions.
Docker
Build and run the CPU image:
docker build -f docker/Dockerfile.cpu -t ransaclpplus:cpu .
docker run --rm -it ransaclpplus:cpu
Build and run the native CUDA image:
docker build -f docker/Dockerfile.cuda -t ransaclpplus:cuda .
docker run --rm -it --gpus=all ransaclpplus:cuda
See the Docker guide for architecture selection, dataset mounts, and Open3D display notes.
Publishing
Package releases are published to PyPI from GitHub Releases using trusted publishing. See the PyPI release guide for the one-time PyPI setup, local validation commands, and release procedure.
Basic usage
An example of use:
import ransaclpplus
import open3d as o3d
office_dataset = o3d.data.OfficePointClouds()
office_filename = office_dataset.paths[0]
ransaclpplus_iterations = 200
threshold = 0.02
seed = 42
percentage_chosen_lines = 0.2
percentage_chosen_planes = 0.05
pcd = o3d.io.read_point_cloud(office_filename)
plane_model, inliers = ransaclpplus.segment_plane(pcd, distance_threshold=threshold, num_iterations=ransaclpplus_iterations,
percentage_chosen_lines = percentage_chosen_lines,
percentage_chosen_planes = percentage_chosen_planes, seed = seed)
number_inliers = len(inliers)
inlier_cloud = pcd.select_by_index(inliers)
inlier_cloud.paint_uniform_color([1, 0, 0])
o3d.visualization.draw_geometries([pcd, inlier_cloud], window_name="RANSACLPPLUS Inliers: " + str(number_inliers))
You can use native C++ CUDA-accelerated line fitting by setting use_cuda=True:
plane_model, inliers = ransaclpplus.segment_plane(pcd, distance_threshold=threshold, num_iterations=ransaclpplus_iterations,
percentage_chosen_lines = percentage_chosen_lines, use_cuda = True,
percentage_chosen_planes = percentage_chosen_planes, seed = seed)
Adaptive line selection (optional) can replace fixed percentage_chosen_lines:
plane_model, inliers = ransaclpplus.segment_plane(
pcd,
distance_threshold=threshold,
num_iterations=ransaclpplus_iterations,
percentage_chosen_lines=0.2,
percentage_chosen_planes=percentage_chosen_planes,
line_selection_mode="adaptive_poisson_mixture",
adaptive_tau=0.5,
adaptive_em_max_iter=100,
adaptive_em_tol=1e-6,
adaptive_min_lines=2,
adaptive_allow_empty=False,
seed=seed,
)
Compatibility-filtered pairing (optional) can be enabled for pair generation:
plane_model, inliers = ransaclpplus.segment_plane(
pcd,
distance_threshold=threshold,
num_iterations=ransaclpplus_iterations,
percentage_chosen_lines=0.2,
percentage_chosen_planes=percentage_chosen_planes,
line_selection_mode="adaptive_poisson_mixture",
adaptive_tau=0.5,
pairing_filter_enabled=True,
pairing_min_angle_deg=10.0,
pairing_max_angle_deg=170.0,
pairing_max_centroid_distance=0.6,
seed=seed,
)
Repository Structure
Experiment artifacts are organized with a canonical snapshot and a separate exploratory area:
- Canonical fixed-vs-adaptive Open3D experiment:
results/open3d_fixed_vs_adaptive_alpha/
- Canonical pairing-ablation snapshots:
results/open3d_pairing_ablation_06/results/open3d_pairing_ablation_pairing_max_centroid_20/results/open3d_pairing_ablation_pairing_max_centroid_30/
- Exploratory sweeps and follow-up tuning runs:
results/exploratory/
- S3DIS validation outputs:
results/s3dis_pilot_validation/results/s3dis_validation/
Experiment code and run guide:
- Script:
experiments/run_open3d_fixed_vs_adaptive_alpha.py - Script (pairing ablation):
experiments/run_open3d_pairing_ablation.py - Script (angle-only ablation):
experiments/run_open3d_angle_only_ablation.py - Script (pairing-ablation post-analysis):
experiments/analyze_pairing_ablation_results.py - Script (S3DIS pilot validation):
experiments/run_s3dis_pilot_validation.py - Script (S3DIS full validation):
experiments/run_s3dis_validation.py - Helper (S3DIS dataset discovery):
experiments/s3dis_dataset.py - Usage guide:
experiments/README_open3d_fixed_vs_adaptive_alpha.md - Usage guide (angle-only ablation):
experiments/README_open3d_angle_only_ablation.md - Reproducibility overview:
docs/reproducibility.md
Reproducible Experiments
The canonical Open3D fixed-vs-adaptive-alpha snapshot is preserved in:
results/open3d_fixed_vs_adaptive_alpha/
This directory includes:
- configuration (
experiment_config.json) - environment and git metadata (
environment.json) - exact dataset file manifest (
dataset_files.txt) - raw run-level outputs (
raw_runs.csv) - aggregated outputs (
aggregated_per_file.csv,aggregated_global.csv)
Canonical pairing-ablation snapshots are stored separately by pairing_max_centroid_distance:
results/open3d_pairing_ablation_06/results/open3d_pairing_ablation_pairing_max_centroid_20/results/open3d_pairing_ablation_pairing_max_centroid_30/
For each snapshot, derived post-analysis artifacts are generated in-place:
analysis/*.csvandanalysis/*.mdsummariesplots/*.pngpaper-oriented figures (runtime-vs-inliers, boxplots, pair-filter and rejection breakdowns, per-scene deltas)
Exploratory tuning runs remain intentionally separated in results/exploratory/ and are not the primary paper snapshots.
Pairing-ablation post-analysis command (single snapshot):
python experiments/analyze_pairing_ablation_results.py \
--results-dir results/open3d_pairing_ablation_06 \
--plot-format png \
--title-suffix "(pairing_max_centroid_distance=0.6)"
Manual multi-snapshot analysis sequence:
python experiments/analyze_pairing_ablation_results.py --results-dir results/open3d_pairing_ablation_06 --plot-format png --title-suffix "(pairing_max_centroid_distance=0.6)"
python experiments/analyze_pairing_ablation_results.py --results-dir results/open3d_pairing_ablation_pairing_max_centroid_20 --plot-format png --title-suffix "(pairing_max_centroid_distance=2.0)"
python experiments/analyze_pairing_ablation_results.py --results-dir results/open3d_pairing_ablation_pairing_max_centroid_30 --plot-format png --title-suffix "(pairing_max_centroid_distance=3.0)"
Completed follow-up snapshot:
results/open3d_angle_only_ablation/
Angle-only rerun command:
python experiments/run_open3d_angle_only_ablation.py \
--output-dir results/open3d_angle_only_ablation \
--num-runs 10 \
--n-line-iterations 250 \
--threshold 0.03 \
--beta 0.05 \
--fixed-alpha 0.2 \
--adaptive-tau 0.5 \
--pairing-min-angle-deg 10 \
--pairing-max-angle-deg 170 \
--pairing-max-centroid-distance 3.0 \
--use-cuda
S3DIS validation workflow:
- S3DIS is expected to be mounted read-only at
/datasets/S3DIS. - If
S3DIS_DATA_ROOTis set, the S3DIS scripts use it by default; otherwise they fall back to/datasets/S3DIS. - Run the pilot first on
Area_1, review outputs, then launch the full validation later if approved. - Search is performed on a reduced point set for efficiency:
- optional voxelized cloud
- optional deterministic search subset from that voxelized cloud
- Final support is re-evaluated on the full raw point cloud for reviewer-facing reporting.
- For S3DIS validation, the top-level reported final support metric is intended to be the raw-cloud support.
S3DIS pilot command:
python experiments/run_s3dis_pilot_validation.py \
--output-dir results/s3dis_pilot_validation \
--num-runs 10 \
--n-line-iterations 250 \
--threshold 0.03 \
--beta 0.05 \
--fixed-alpha 0.2 \
--adaptive-tau 0.5 \
--pairing-min-angle-deg 10 \
--pairing-max-angle-deg 170 \
--voxel-size 0.02 \
--search-subset-size 30000 \
--search-subset-seed 0 \
--use-cuda
S3DIS full validation command:
python experiments/run_s3dis_validation.py \
--output-dir results/s3dis_validation \
--num-runs 10 \
--n-line-iterations 250 \
--threshold 0.03 \
--beta 0.05 \
--fixed-alpha 0.2 \
--adaptive-tau 0.5 \
--pairing-min-angle-deg 10 \
--pairing-max-angle-deg 170 \
--voxel-size 0.02 \
--search-subset-size 30000 \
--search-subset-seed 0 \
--use-cuda
S3DIS post-analysis command:
python experiments/analyze_pairing_ablation_results.py \
--results-dir results/s3dis_pilot_validation \
--plot-format png \
--title-suffix "(S3DIS pilot validation)"
Key conservative findings from the canonical snapshot:
- Adaptive alpha has higher mean best-plane inliers than fixed alpha (
128071.33vs127446.12). - Adaptive alpha has higher mean runtime than fixed alpha (
260.54 msvs232.97 ms). - Per-file mean inlier comparison: adaptive better on
103/110, equal on3/110, worse on4/110. - Per-file mean runtime comparison: adaptive slower on
105/110, faster on5/110.
All values above are derived from:
results/open3d_fixed_vs_adaptive_alpha/aggregated_global.csvresults/open3d_fixed_vs_adaptive_alpha/per_file_win_loss_summary.csv
Method
RANSAC-LP4 is a plane-detection method that reduces expensive full point-to-plane evaluations while keeping robustness to outliers.
Instead of sampling planes directly from three points, it first samples lines (two-point hypotheses), then constructs plane candidates from pairs of promising lines.
The method has three stages:
- Candidate line generation:
sample
nlines, score each line by inlier count with thresholdt, keepN_l = floor(alpha * n)best lines. - Candidate plane generation from line pairs:
generate all unique pairs of retained lines, fit one plane per pair, rank by local fit quality (SSE), keep
N_pi = floor(beta * N_lambda)whereN_lambda = N_l * (N_l - 1) / 2. - Final plane evaluation: evaluate only retained candidate planes on the full point cloud and select the plane with highest inlier support.
Parameters:
- Shared with classical RANSAC:
n,t - Specific to RANSAC-LP4:
alpha,beta
Adaptive line-selection option:
- Fixed mode (
line_selection_mode="fixed_alpha"): keeps the topalphafraction by line support. - Adaptive mode (
line_selection_mode="adaptive_poisson_mixture"): fits a 2-component Poisson mixture to line supports and keeps lines with posteriorP(good | support) >= tau. taucontrols strictness: highertaukeeps fewer lines.- The effective retained fraction is
alpha_adapt = kept_lines / n. - Adaptive mode exposes
rho_hat = sqrt(w), wherewis the estimated mixture weight of the “good-line” component.
Limitations:
- The adaptive selector assumes line supports are reasonably modeled by a 2-component Poisson mixture.
- If supports are nearly constant or EM is unstable, the implementation falls back to deterministic top-support retention with minimum-line safeguards.
Repository implementation notes:
- Planes from two lines are fit with a four-point least-squares (SVD) fit.
- Step-2 quality uses four-point SSE.
- Final scoring uses standard inlier counting against threshold
t.
Current Research Status
Completed:
- baseline LP4 implementation
- adaptive alpha line selection
- reproducible Open3D fixed-vs-adaptive canonical experiment
Interpretation from completed evidence:
- Adaptive alpha improves best-plane quality in most files.
- Adaptive alpha usually increases runtime, consistent with keeping more lines and therefore increasing line-pair combinations.
Current pairing focus:
- compatibility-filtered pairing with angle and support-centroid distance gates
- four-way Open3D ablation:
- fixed alpha
- adaptive alpha
- fixed alpha + compatibility-filtered pairing
- adaptive alpha + compatibility-filtered pairing
- completed angle-gate isolation ablation:
adaptive_alphaadaptive_alpha_cf_pairing_angle_onlyadaptive_alpha_cf_pairing_angle_plus_distance(pairing_max_centroid_distance=3.0)
Prepared artifacts:
- script:
experiments/run_open3d_pairing_ablation.py - script:
experiments/run_open3d_angle_only_ablation.py - script:
experiments/analyze_pairing_ablation_results.py - canonical snapshot folders:
results/open3d_pairing_ablation_06/results/open3d_pairing_ablation_pairing_max_centroid_20/results/open3d_pairing_ablation_pairing_max_centroid_30/
- method note:
docs/open3d_pairing_ablation.md - research report:
docs/research_report.md
Next validation target:
- minimal S3DIS validation with:
fixed_alphaadaptive_alphaadaptive_alpha_cf_pairing_angle_only
- pilot-first execution on
Area_1 - full-dataset execution only after pilot review
CUDA backend
The project uses a native C++ CUDA shared library for CUDA execution. Numba is not required.
Native backend coverage includes:
- single plane inlier counting
- batched plane inlier counting
- single line inlier counting
- plane inlier index collection
Runtime behavior:
ransaclpplus.ransaccudapreserves the existing Python helper names while routing all CUDA work throughransaclpplus.nativecuda.use_cuda=Truerequires the native shared library. A clear runtime error is raised when it is unavailable.
Building the native CUDA backend
Build from ransaclpplus/native/cuda:
cmake -S . -B build
cmake --build build -j
The Python loader checks:
RANSACLPPLUS_CUDA_LIB(if set)ransaclpplus/native/cuda/build/libransaclpplus_cuda.so(Linux)ransaclpplus/native/cuda/build/libransaclpplus_cuda.dylib(macOS)ransaclpplus/native/cuda/build/Release/ransaclpplus_cuda.dll(Windows)
Quick verification:
python -c "from ransaclpplus.nativecuda import native_backend_available; print(native_backend_available())"
CUDA benchmark
Benchmark native CUDA kernels and persistent-context cache behavior with:
python -m ransaclpplus.benchmark_cuda_backends --points 200000 --planes 64 --warmup 2 --repetitions 10
Optional JSON output:
python -m ransaclpplus.benchmark_cuda_backends --json-out benchmark_results.json
Historical migration measurements comparing native CUDA with the former Numba backend are preserved in:
docs/reports/cuda_vs_numba_report.mddocs/reports/cuda_numba_analysis.jsondocs/reports/cuda_numba_analysis_after_async_pinned.json(latest optimized baseline)docs/reports/cuda_numba_analysis_after_plane_cache.json(latest plane-cache run)docs/reports/cuda_optimization_comparison.md(cross-version comparison)docs/reports/optimization_backups/(source snapshots by optimization stage)
Backup and artifact policy:
- Keep historical benchmark JSON files; append new versioned artifacts instead of overwriting old ones.
- Keep snapshot copies of changed optimization source files in
docs/reports/optimization_backups/before major tuning changes. - Prefer explicit version/date suffixes in artifact names for reproducible cross-version comparisons.
Historical optimized baseline summary (native over former Numba backend, plane-cache run):
- Small (
4096points,12planes): plane15.42x, line14.83x, batched32.42x - Medium (
50000points,32planes): plane16.19x, line15.39x, batched7.29x - Large (
200000points,64planes): plane9.68x, line10.22x, batched2.27x
If the package is installed with scripts, the equivalent command is:
ransaclpplus-benchmark-cuda --points 200000 --planes 64
Campaigns
The repository now includes paper-oriented LP4 campaign families for Open3D and S3DIS. The broader campaign roots remain reusable for reruns, and the compact minimum paper-oriented subset has already been executed in versioned result roots.
Reusable campaign roots:
results/open3d_core_robustness/results/s3dis_core_robustness/results/open3d_adaptive_tau_sweep/results/s3dis_adaptive_tau_sweep/results/open3d_budget_sweep/results/s3dis_budget_sweep/results/s3dis_preprocessing_stability/results/open3d_vs_open3d_ransac/results/s3dis_vs_open3d_ransac/results/open3d_vs_open3d_ransac_lo/results/s3dis_vs_open3d_ransac_lo/
Campaign entrypoints:
experiments/run_open3d_core_robustness.pyexperiments/run_s3dis_core_robustness.pyexperiments/run_open3d_adaptive_tau_sweep.pyexperiments/run_s3dis_adaptive_tau_sweep.pyexperiments/run_open3d_budget_sweep.pyexperiments/run_s3dis_budget_sweep.pyexperiments/run_s3dis_preprocessing_stability.pyexperiments/run_open3d_vs_open3d_ransac.pyexperiments/run_s3dis_vs_open3d_ransac.pyexperiments/run_open3d_vs_open3d_ransac_lo.pyexperiments/run_s3dis_vs_open3d_ransac_lo.py
Unified post-analysis entrypoint:
experiments/lp4_campaign_analysis.py
Primary metrics:
- Open3D:
best_plane_inliers/best_plane_inlier_ratio - S3DIS: raw-cloud final support via
best_plane_inliers_raw, also mapped to top-levelbest_plane_inliers
External baseline policy:
- Plain external baseline: Open3D
segment_plane - LO-style external baseline: Open3D
segment_planeplus local inlier refit rounds open3d_segment_plane_lois a local-optimization proxy baseline, not a formal true LO-RANSAC implementation- Hypothesis generation runs on the designated search-stage point set
- Final support is evaluated with the same final metric convention as the corresponding LP4 campaign
- For S3DIS, raw-cloud final support remains the primary reported metric
- Baseline parameters are written explicitly to
experiment_config.jsonandraw_runs.csv
Manual run commands:
python experiments/run_open3d_core_robustness.py --output-dir results/open3d_core_robustness --num-runs 30 --n-line-iterations 250 --threshold 0.03 --beta 0.05 --fixed-alpha 0.2 --adaptive-tau 0.5 --pairing-min-angle-deg 10 --pairing-max-angle-deg 170 --use-cuda
python experiments/run_s3dis_core_robustness.py --output-dir results/s3dis_core_robustness --num-runs 30 --n-line-iterations 250 --threshold 0.03 --beta 0.05 --fixed-alpha 0.2 --adaptive-tau 0.5 --pairing-min-angle-deg 10 --pairing-max-angle-deg 170 --voxel-size 0.02 --search-subset-size 30000 --search-subset-seed 0 --use-cuda
python experiments/run_open3d_adaptive_tau_sweep.py --output-dir results/open3d_adaptive_tau_sweep --num-runs 10 --n-line-iterations 250 --threshold 0.03 --beta 0.05 --fixed-alpha 0.2 --pairing-min-angle-deg 10 --pairing-max-angle-deg 170 --use-cuda
python experiments/run_s3dis_adaptive_tau_sweep.py --output-dir results/s3dis_adaptive_tau_sweep --num-runs 10 --n-line-iterations 250 --threshold 0.03 --beta 0.05 --fixed-alpha 0.2 --pairing-min-angle-deg 10 --pairing-max-angle-deg 170 --voxel-size 0.02 --search-subset-size 30000 --search-subset-seed 0 --use-cuda
python experiments/run_open3d_budget_sweep.py --output-dir results/open3d_budget_sweep --num-runs 10 --threshold 0.03 --beta 0.05 --fixed-alpha 0.2 --adaptive-tau 0.5 --pairing-min-angle-deg 10 --pairing-max-angle-deg 170 --use-cuda
python experiments/run_s3dis_budget_sweep.py --output-dir results/s3dis_budget_sweep --num-runs 10 --threshold 0.03 --beta 0.05 --fixed-alpha 0.2 --adaptive-tau 0.5 --pairing-min-angle-deg 10 --pairing-max-angle-deg 170 --voxel-size 0.02 --search-subset-size 30000 --search-subset-seed 0 --use-cuda
python experiments/run_s3dis_preprocessing_stability.py --output-dir results/s3dis_preprocessing_stability --num-runs 10 --n-line-iterations 250 --threshold 0.03 --beta 0.05 --fixed-alpha 0.2 --adaptive-tau 0.5 --pairing-min-angle-deg 10 --pairing-max-angle-deg 170 --voxel-size 0.02 --search-subset-size 30000 --search-subset-seed 0 --use-cuda
External-baseline run commands:
python experiments/run_open3d_vs_open3d_ransac.py --output-dir results/open3d_vs_open3d_ransac --num-runs 10 --n-line-iterations 250 --threshold 0.03 --beta 0.05 --fixed-alpha 0.2 --adaptive-tau 0.5 --pairing-min-angle-deg 10 --pairing-max-angle-deg 170 --baseline-ransac-n 3 --baseline-lo-refit-max-rounds 2 --use-cuda
python experiments/run_s3dis_vs_open3d_ransac.py --output-dir results/s3dis_vs_open3d_ransac --num-runs 10 --n-line-iterations 250 --threshold 0.03 --beta 0.05 --fixed-alpha 0.2 --adaptive-tau 0.5 --pairing-min-angle-deg 10 --pairing-max-angle-deg 170 --voxel-size 0.02 --search-subset-size 30000 --search-subset-seed 0 --baseline-ransac-n 3 --baseline-lo-refit-max-rounds 2 --use-cuda
python experiments/run_open3d_vs_open3d_ransac_lo.py --output-dir results/open3d_vs_open3d_ransac_lo --num-runs 10 --n-line-iterations 250 --threshold 0.03 --beta 0.05 --fixed-alpha 0.2 --adaptive-tau 0.5 --pairing-min-angle-deg 10 --pairing-max-angle-deg 170 --baseline-ransac-n 3 --baseline-lo-refit-max-rounds 2 --use-cuda
python experiments/run_s3dis_vs_open3d_ransac_lo.py --output-dir results/s3dis_vs_open3d_ransac_lo --num-runs 10 --n-line-iterations 250 --threshold 0.03 --beta 0.05 --fixed-alpha 0.2 --adaptive-tau 0.5 --pairing-min-angle-deg 10 --pairing-max-angle-deg 170 --voxel-size 0.02 --search-subset-size 30000 --search-subset-seed 0 --baseline-ransac-n 3 --baseline-lo-refit-max-rounds 2 --use-cuda
Analysis commands:
python experiments/lp4_campaign_analysis.py --results-dir results/open3d_core_robustness --plot-format png
python experiments/lp4_campaign_analysis.py --results-dir results/s3dis_core_robustness --plot-format png
python experiments/lp4_campaign_analysis.py --results-dir results/open3d_adaptive_tau_sweep --plot-format png
python experiments/lp4_campaign_analysis.py --results-dir results/s3dis_adaptive_tau_sweep --plot-format png
python experiments/lp4_campaign_analysis.py --results-dir results/open3d_budget_sweep --plot-format png
python experiments/lp4_campaign_analysis.py --results-dir results/s3dis_budget_sweep --plot-format png
python experiments/lp4_campaign_analysis.py --results-dir results/s3dis_preprocessing_stability --plot-format png
python experiments/lp4_campaign_analysis.py --results-dir results/open3d_vs_open3d_ransac --plot-format png
python experiments/lp4_campaign_analysis.py --results-dir results/s3dis_vs_open3d_ransac --plot-format png
python experiments/lp4_campaign_analysis.py --results-dir results/open3d_vs_open3d_ransac_lo --plot-format png
python experiments/lp4_campaign_analysis.py --results-dir results/s3dis_vs_open3d_ransac_lo --plot-format png
Command-printer helpers:
scripts/print_open3d_core_commands.shscripts/print_s3dis_core_commands.shscripts/print_sweep_commands.sh
Executed minimum paper-oriented result roots:
results/synthetic_lp4_benchmark_paper_minimum_20260313/results/open3d_budget_sweep_paper_minimum_20260313/results/open3d_lp4_proposal_lo_paper_minimum_20260313/
Documentation with Sphinx
This repository includes a Sphinx configuration under docs/ for the package
reference and the main project guides.
Install documentation dependencies:
pip install -e ".[docs]"
Build HTML docs:
make -C docs html
The generated site will be available at docs/_build/html/index.html.
It includes:
- repository overview and navigation page
- API reference for the package modules
- method overview
- research report
- reproducibility guide
- benchmark and report pages under
docs/reports/
The repository also includes Read the Docs deployment configuration. See the Read the Docs deployment guide for the one-time project import and build settings.
Documentation expectations for ongoing development:
- new public functionality should be documented with Sphinx-compatible docstrings
- new user-visible workflows or features should be reflected in the relevant
page under
docs/
Tests
The repository uses pytest for automated tests.
Run the full suite:
pytest -q
Run a focused test file:
pytest -q tests/test_ransaclpplus_api.py
Current baseline status in this environment:
- broad suite:
91 passed, 5 skipped
Testing expectations for ongoing development:
- behavior changes should include updated or new automated tests
- new public additions and user-visible workflows should ship with both tests and Sphinx documentation in the same change
Visual Step-by-Step Test (Open3D)
A manual visual test is available at tests/test_ransaclpplus_visual_steps.py.
It opens Open3D windows for:
- Step 1: sampled lines retained after line scoring
- Step 2: candidate planes generated from retained line pairs
- Step 3: final inliers of the best-scoring plane
Run it with:
RANSACLPPLUS_VISUAL_TEST=1 pytest -m visual -s
Or use the helper script:
./scripts/run_visual_test.sh
Close each Open3D window to continue to the next stage.
If you run inside the devcontainer, X11 forwarding must be enabled on your host.
Run The Devcontainer From CLI (JSON-Equivalent)
The .devcontainer/devcontainer.json configuration can be reproduced from the command line with the following commands.
Exact devcontainer.json parity (including features) via Dev Container CLI:
devcontainer up --workspace-folder .
Plain Docker workflow approximating the build, run, and post-create settings:
Build the image from the same Dockerfile/context:
docker build -f .devcontainer/Dockerfile -t ransaclpplus-dev .
Run the container with the same GPU, env vars, X11, and workspace mount behavior:
REPOSITORY_ROOT="$(pwd)"
WORKSPACE_NAME="$(basename "${REPOSITORY_ROOT}")"
HOST_S3DIS_DATA_ROOT="${S3DIS_DATA_ROOT:-${HOME}/S3DIS/Stanford3dDataset_v1.2}"
docker run --rm -it \
--gpus=all \
--user vscode \
--env DISPLAY="${DISPLAY}" \
--env NVIDIA_VISIBLE_DEVICES=all \
--env NVIDIA_DRIVER_CAPABILITIES=compute,utility \
--env QT_X11_NO_MITSHM=1 \
--env RANSACLPPLUS_CUDA_ARCH=61 \
--env OPEN3D_DATA_ROOT=/home/vscode/open3d_data \
--env S3DIS_DATA_ROOT=/datasets/S3DIS \
--volume /tmp/.X11-unix:/tmp/.X11-unix:rw \
--mount "type=bind,source=${REPOSITORY_ROOT},target=/workspaces/${WORKSPACE_NAME}" \
--mount "type=bind,source=${HOST_S3DIS_DATA_ROOT},target=/datasets/S3DIS,readonly" \
--workdir "/workspaces/${WORKSPACE_NAME}" \
--name ransaclpplus-dev \
ransaclpplus-dev \
bash
Run the same post-create setup command defined in devcontainer.json:
docker exec -u vscode -it ransaclpplus-dev bash -lc \
'pip install -e . && cmake -S ransaclpplus/native/cuda -B ransaclpplus/native/cuda/build -DCMAKE_CUDA_ARCHITECTURES=${RANSACLPPLUS_CUDA_ARCH} && cmake --build ransaclpplus/native/cuda/build -j'
Notes:
- Run the plain Docker commands from the repository root. Set
S3DIS_DATA_ROOTon the host when the dataset is not stored at the default path shown above. - The plain Docker workflow mirrors the core
runArgs,containerEnv,workspaceMount,workspaceFolder,remoteUser, andpostCreateCommandsettings. Only the Dev Container CLI command appliesfeaturesand provides exactdevcontainer.jsonbehavior. - For Open3D windows from inside the container, host X11 access is required (for example,
xhost +local:dockeron Linux before running, and revert later withxhost -local:docker).
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ransaclpplus-0.1.0.tar.gz.
File metadata
- Download URL: ransaclpplus-0.1.0.tar.gz
- Upload date:
- Size: 71.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bcf07d3bd844cef27a84a19ef19b31f9f230ae30b7eaa0a58345aca6c68cf6ab
|
|
| MD5 |
0d5496b9d37960223b540e867e86a5fc
|
|
| BLAKE2b-256 |
506f751a5feb08d26b97f00fd5685dda9ebd55f292298a48d4c4ab7f8ee66f3a
|
Provenance
The following attestation bundles were made for ransaclpplus-0.1.0.tar.gz:
Publisher:
publish-pypi.yml on jmartinezot/lp4-plus
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ransaclpplus-0.1.0.tar.gz -
Subject digest:
bcf07d3bd844cef27a84a19ef19b31f9f230ae30b7eaa0a58345aca6c68cf6ab - Sigstore transparency entry: 1765660584
- Sigstore integration time:
-
Permalink:
jmartinezot/lp4-plus@9ad5de79389cc4c00f030a7601addf95a52bc7ae -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/jmartinezot
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@9ad5de79389cc4c00f030a7601addf95a52bc7ae -
Trigger Event:
release
-
Statement type:
File details
Details for the file ransaclpplus-0.1.0-py3-none-any.whl.
File metadata
- Download URL: ransaclpplus-0.1.0-py3-none-any.whl
- Upload date:
- Size: 71.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e40bc35c673c43c64e69b475b75a7c8d097f4eca892ae322ec472b9b671b6d9e
|
|
| MD5 |
3d9cd20b914ed0a48798ada907f7ab32
|
|
| BLAKE2b-256 |
bf8288c90b2a3ffd64001747fb8a717b79044a176c254fa029f1d73661c96e3f
|
Provenance
The following attestation bundles were made for ransaclpplus-0.1.0-py3-none-any.whl:
Publisher:
publish-pypi.yml on jmartinezot/lp4-plus
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ransaclpplus-0.1.0-py3-none-any.whl -
Subject digest:
e40bc35c673c43c64e69b475b75a7c8d097f4eca892ae322ec472b9b671b6d9e - Sigstore transparency entry: 1765660692
- Sigstore integration time:
-
Permalink:
jmartinezot/lp4-plus@9ad5de79389cc4c00f030a7601addf95a52bc7ae -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/jmartinezot
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@9ad5de79389cc4c00f030a7601addf95a52bc7ae -
Trigger Event:
release
-
Statement type: