patchwork-plusplus

url-kaistBSD-2-Clause更新放缓

面向 3D 激光雷达点云的快速地面分割算法,能在复杂场景下稳健剔除地面点,为后续检测与建图提供干净的非地面点云。

Patchwork++: Fast and robust ground segmentation method for 3D LiDAR scans. @ IROS'22

v1.4.1发布于 2026-05-23 06:46 UTC1,132star163fork同步于 2026-11-07 07:30 UTC

怎么上手

由 README 提炼,执行前请确认
pip install pypatchworkpp
make cppinstall
硬件要求按 README 说明

README 未说明显存或 GPU 要求,算法本身在 CPU 上运行;测试环境为 Ubuntu 20.04/22.04/24.04 与 macOS 14+(Apple Silicon)

支持 Apple Silicon
下载:源码 zip·GitHub Releases(安装包)本站不镜像安装包

项目说明

由 README 自动翻译提炼

从 3D LiDAR 点云中快速稳健地分割地面,自带自适应阈值,适合做感知预处理

面向 3D 激光雷达点云的快速地面分割算法,能在复杂场景下稳健剔除地面点,为后续检测与建图提供干净的非地面点云。

核心能力

  • 用自适应高程与平坦度阈值自动调参
  • 用 RNR 去除基于强度的反射噪声
  • 用 RVPF 抑制垂直结构干扰
  • 用 TGR 按概率把误删的地面点恢复回来
  • 同时提供 C++、Python 绑定与 ROS2 节点

容易踩的坑

可视化 demo 需额外安装 Open3D(>0.17.0),可用 pip install 'pypatchworkpp[demo]' 或 make cppinstall_with_demo;从源码构建 Python 包需先装 libeigen3-dev、cmake 等依赖;ROS2 需在 colcon 工作空间中单独编译 patchworkpp 包

内容由模型根据 README 生成,可能不完整或不准确,以官方文档为准。看原文 README

最近发版

5 个版本v1.4.1
  1. v1.4.1v1.4.1 — Kill per-patch heap traffic in Patchwork++ (+14.8% Hz)最新正式版2026-05-23 · 2026-05-23 06:46 UTC

    Highlights

    Patch bump. pypatchworkpp.patchworkpp is now +14.8% Hz on KITTI seq 00 (97.5 → 111.9 Hz, median of 3 runs, i7-12700) thanks to killing short-lived heap allocations in R-VPF + R-GPF. Closes the alloc-driven part of #96.

    Perf — pypatchworkpp.patchworkpp

    KITTI seq 00, 2900 timed frames, median of 3 runs:

    Stagems/frameHzΔ Hz
    v1.4.0 baseline (JacobiSVD + per-call allocs)10.2697.5—
    eigh only9.94100.6+3.2%
    v1.4.1 (eigh + alloc-free)8.94111.9+14.8%

    The win comes from three changes inside PatchWorkpp::extract_piecewiseground and PatchWorkpp::estimate_plane:

    1. estimate_plane: drop Eigen::MatrixX3f eigen_ground, centered, and centered.adjoint() * centered heap allocations. Replace with a single-pass scalar accumulation of mean + 9 cross-products; build the 3×3 cov on the stack.
    2. extract_piecewiseground: promote src_wo_verticals and src_tmp to reused instance scratch members. vector::clear() keeps capacity, so per-patch malloc pressure on the glibc heap drops away after the first few patches.
    3. estimateGround main loop: auto& zone instead of auto zone for ConcentricZoneModel_[zone_idx]. Avoids a deep-copy of the full 3-level nested vector per outer iteration.

    Plus a smaller cleanup: JacobiSVD<Matrix3f> → SelfAdjointEigenSolver::computeDirect on the 3×3 PSD covariance in both cpp/common/src/plane_fit.cpp and the in-place PatchWorkpp::estimate_plane. singular_values_ is repacked descending so every consumer (linearity_, planarity_, ground_flatness, line_variable, flatness_thr index (2)) keeps the same convention bit-for-bit.

    Patchwork (classic)

    Unchanged: 4.29 ms / 232.9 Hz (within run-to-run noise of the v1.4.0 baseline). TBB parallel_for already amortises allocations across cores and SVD is sub-µs/patch.

    Numerical equivalence

    KITTI seq 00 (4541 frames), v1.4.0 → v1.4.1:

    Method (protocol)BeforeAfterΔ F1
    patchwork (pw)P 92.34, R 94.64, F1 93.41P 92.34, R 94.64, F1 93.410.00
    patchworkpp (pp)P 94.88, R 98.47, F1 96.62P 94.89, R 98.48, F1 96.63+0.01

    Algebraic identity of JacobiSVD vs eigh verified on 500 real KITTI patch covariances: normal_ (up to sign), singular_values_, linearity_, planarity_, ground_flatness, line_variable all match to FP precision.

    Refs

    • #100 — PR (perf: alloc-free + eigh)
    • #96 — Issue (R-VPF / R-GPF allocation profile)
  2. v1.4.0v1.4.0 — Shared common library + optional TBB on classic Patchwork (+1.73× Hz)2026-05-21 · 2026-05-21 08:26 UTC
    查看更新说明

    Highlights

    • Shared cpp/common/ library for PointXYZ, PCAFeature, PatchStatus, estimate_plane, xy2theta, xy2radius, point_z_cmp. Three previously-drifted copies of the plane-fit math (which had caused real bugs — see Fix 2 in #90) collapse to one canonical implementation.
    • pypatchworkpp.patchwork gains tbb::parallel_for. Measured 1.73× speedup on KITTI seq 00 (i7-12700, 24 logical cores): 8.31 ms → 4.81 ms median per frame, 120 → 208 Hz.
    • TBB is optional at build time. If libtbb-dev / brew install tbb / vcpkg install tbb is present, you get the speedup; otherwise the build falls back to a sequential loop with a CMake STATUS message. CI / wheels keep working without TBB installed.
    • pypatchworkpp.patchworkpp stays sequential — same TBB pattern was applied and benchmarked at 1 / 2 / 4 / 8 / 16 / 24 threads, every configuration was slower than single-thread (111 Hz → 93 Hz at 2 threads, → 69 Hz at 24 threads). Per-patch work is small (~14 µs avg) and dominated by short-lived allocations inside R-VPF + R-GPF; concurrent malloc serialises on the heap. See #96 for the full measurement and the conditions under which we'd revisit.
    • python/examples/bench_hz.py — per-frame timing harness reporting median / mean / p95 / p99 ms and Hz.

    Numerical equivalence

    KITTI 00–10 full sweep (23,201 frames), Patchwork++ paper protocol, v1.3.1 → v1.4.0:

    MethodF1 v1.3.1F1 v1.4.0Δ
    --method patchwork96.017296.01720 (byte-identical)
    --method patchworkpp96.291896.2919+0.0001 (float noise)

    Both within the ±0.05 F1 budget set in the refactor plan.

    References

    • #94 — PR: extract cpp/common/ library
    • #95 — PR: TBB on classic Patchwork
    • #96 — Issue: why Patchwork++ has no TBB
    • #97 — PR: this release

    See CHANGELOG.md for the full v1.4.0 entry.

  3. v1.3.1v1.3.1 — Fix ringwise_flatness leakage in TGR (#69)2026-05-21 · 2026-05-21 03:37 UTC
    查看更新说明

    Bug fix

    • #69 → #91: ringwise_flatness is now cleared at the end of every ring iteration in cpp/patchworkpp/src/patchworkpp.cpp, not only when the ring produced revert candidates. The previous placement leaked flatnesses from no-candidate rings into the next ring's temporal_ground_revert call, biasing the mean ± stdev decision threshold. Reported by @KennethBlomqvist.

    Numerical impact

    KITTI 00–10 full sweep (23,201 frames) under the Patchwork++ paper evaluation protocol:

    BuildPRF1
    v1.3.095.549497.164996.2886
    v1.3.195.549697.171096.2918

    ΔF1 = +0.003 (within run-to-run noise). The bug only triggers when a ring finishes with no revert candidates, which is uncommon on KITTI; macro-average impact is negligible but the fix is correctness.

    See CHANGELOG.md.

  4. v1.3.0v1.3.0 — Performance enhancement for pypatchworkpp.patchwork2026-05-21 · 2026-05-21 03:20 UTC
    查看更新说明

    Highlights

    • +2.29 F1 on KITTI 00–10 for pypatchworkpp.patchwork (classic Patchwork). Three deviations from the original url-kaist/patchwork were identified and fixed; numbers now match the Patchwork++ paper Table I within run-to-run variance (96.02 vs. 95.88 F1).
    • pypatchworkpp.patchworkpp (the real Patchwork++) is unaffected — all three fixes were in cpp/patchwork/, not cpp/patchworkpp/. Patchwork++ continues to match the paper.
    • New USAGE.md explains the two SemanticKITTI evaluation protocols (Patchwork vs Patchwork++ paper), the parameter-tuning order, and a copy-pasteable command to reproduce paper Table I.
    • New python/examples/evaluate_semantickitti.py — paper-faithful KITTI evaluation driver with --method {patchwork, patchworkpp} and --eval_protocol {patchwork, patchworkpp}.

    Results — SemanticKITTI 00–10, 23,201 frames, paper-matched params

    ConfigurationEval protocolPRF1
    pypatchworkpp.patchwork, v1.2.0Patchwork-paper86.9496.7591.37
    pypatchworkpp.patchwork, v1.2.0Patchwork++ paper89.7098.4993.73
    pypatchworkpp.patchwork, v1.3.0Patchwork-paper92.7793.6693.08
    pypatchworkpp.patchwork, v1.3.0Patchwork++ paper94.6497.5896.02
    url-kaist/patchwork original ROS 2 (reference)Patchwork++ paper94.3897.9096.05
    Patchwork++ paper Table I, Patchwork [1]Patchwork++ paper94.2397.6295.88

    The three fixes

    1. elevation_thr is converted to the sensor frame by subtracting sensor_height. The YAML thresholds in the original repo are documented as ground-frame; the reimpl was using the raw value, so the elevation gate effectively never fired for normal ground.
    2. Plane-distance comparison uses uncentred normal · p against th_dist_d_ = th_dist − d_. The previous centred form shifted the cutoff by an extra −d_ (~ 1.6 m on KITTI), absorbing far-from-plane points into ground.
    3. Tier index is the GLOBAL ring index across all zones, so each of the first elevation_thr.size() rings gets its own threshold. The previous (zone==0) ? ring : zone collapse destroyed the per-ring tuning.

    References

    • #87 — How to reproduce the performance on the paper?
    • #88 — Explanation about the evaluation protocol
    • #89 — Performance enhancement step-by-step ablation report (with subset and full-sweep tables)
    • #90 — PR landing the fixes

    See CHANGELOG.md for the full changelog.

  5. v1.2.0v1.2.0 — Crash fix for partial (non-360°) point clouds2026-05-10 · 2026-05-10 01:12 UTC
    查看更新说明

    What's new

    Bug-fix release. Fixes a startup crash reported in #62 when processing partial (non-360°) point clouds — for example OS1 128 Ouster scans that don't begin at azimuth 0.

    Changes since 1.1.0

    • #81 (#62, supersedes #66 #72) — Switch `normal_`, `singular_values_`, and `pc_mean_` from `Eigen::VectorXf` (dynamic) to `Eigen::Vector3f` (fixed-size). The dynamic vectors were being indexed before being sized, which was safe with full 360° clouds but crashed on partial inputs. Thanks @MatteGombia for the original fix; @enricocovili for diagnosing the root cause in #62.

    Compatibility

    • API unchanged. No migration needed.
    • Wheels for CPython 3.8 – 3.13 on Linux x86_64 (manylinux2014, musllinux), Windows 32/64-bit, macOS 14 (arm64).

用户点评

登录用户的真实使用记录,可按版本和硬件筛选
共 0 条

    还没有人点评。第一个说出真实体验的人最有价值。

    README 原文

    未翻译

    Patchwork++, an extension of Patchwork, is a fast, robust, and self-adaptive ground segmentation algorithm on 3D point cloud.

    :open_file_folder: What's in this repo

    • C++ source code of Patchwork++ (patchworkpp)
    • Python binding of Patchwork++ using pybind11 (python_wrapper)
    • Examples codes of C++, Python, and ROS2 :thumbsup:
    • Full suppor of a reproducible SemanticKITTI evaluation harness for both Patchwork and Patchwork++ (python/examples/evaluate_semantickitti.py). In the papers of Patchwork and Patchwork++, we use different evaluation protocols — see USAGE.md §1 for why and §4 for per-sequence numbers.

    If you are familiar with ROS1, you can also visit here and try executing ROS1-based Patchwork++!

    :package: Prerequisite packages

    What we need are just minimal dependencies.

    Ubuntu / Debian:

    sudo apt-get install g++ build-essential libeigen3-dev python3-pip python3-dev cmake -y
    

    macOS (Apple Silicon or Intel):

    brew install cmake
    

    Eigen is fetched automatically by CMake, so no extra system package is required on macOS. The build works with the bundled AppleClang toolchain.

    :gear: How to build & Run

    Python

    The released library is on PyPI:

    pip install pypatchworkpp                # core library
    pip install 'pypatchworkpp[demo]'        # + Open3D for the visual demos
    

    Then import pypatchworkpp in your script — see the Python examples.

    make pyinstall                # equivalent to `pip install ./python/`
    make pyinstall_with_demo      # also installs Open3D >= 0.17.0
    

    C++

    Pure installation

    make cppinstall
    

    Installation with demo

    Only Open3D (> 0.17.0) is additionally installed for visualization purposes.

    make cppinstall_with_demo
    

    How to run the C++ demos is explained here.

    ROS2

    You should not need any extra dependency, just clone and build:

    mkdir -p ~/ros2_ws/src
    cd ~/ros2_ws/src
    git clone https://github.com/url-kaist/patchwork-plusplus.git
    cd ~/ros2_ws
    colcon build --packages-select patchworkpp
    source ./install/setup.bash
    

    How to launch ROS2 nodes is explained here.

    :compass: Choosing an algorithm

    This repository ships two ground segmentation algorithms with the same input/output API. Pick the one that fits your data:

    • Patchwork++ (default): adaptive elevation/flatness thresholds, RNR (intensity-based reflected noise removal), RVPF (vertical structure suppression), and TGR (probability-based ground revert). Best when the LiDAR has reflection artefacts or you want self-tuning thresholds.
    • Patchwork (classic, since 1.1.0): fixed elevation/flatness thresholds with explicit z < -sensor_height - 2.0m cutoff and few-points reject, plus optional ATAT for unknown sensor heights. Often more aggressive on ground-plane noise in heavily cluttered scenes.

    Python:

    import pypatchworkpp as p
    
    pp_default = p.patchworkpp(p.Parameters())          # Patchwork++
    pp_classic = p.patchwork(p.PatchworkParams())       # Patchwork (classic)
    

    ROS2: Patchwork++ is the default; pass algorithm:=patchwork to switch to the classic Patchwork.

    # Default — runs Patchwork++
    ros2 launch patchworkpp patchworkpp.launch.py
    
    # Override to the classic Patchwork
    ros2 launch patchworkpp patchworkpp.launch.py algorithm:=patchwork
    

    :pencil: Citation

    If you use our codes, please cite our paper (arXiv, IEEE Xplore)

    @inproceedings{lee2022patchworkpp,
        title={{Patchwork++: Fast and robust ground segmentation solving partial under-segmentation using 3D point cloud}},
        author={Lee, Seungjae and Lim, Hyungtae and Myung, Hyun},
        booktitle={Proc. IEEE/RSJ Int. Conf. Intell. Robots Syst.},
        year={2022},
        pages={13276-13283}
    }
    

    In addition, you can also check the paper of our baseline, Patchwork. (arXiv, IEEE Xplore)

    @article{lim2021patchwork,
        title={Patchwork: Concentric Zone-based Region-wise Ground Segmentation with Ground Likelihood Estimation Using a 3D LiDAR Sensor},
        author={Lim, Hyungtae and Minho, Oh and Myung, Hyun},
        journal={IEEE Robotics and Automation Letters},
        year={2021}
    }
    

    :triangular_flag_on_post: Tested Environment

    • Ubuntu 18.04 and 20.04, 22.04, and 24.04
    • macOS 14+ (Apple Silicon)
    • CMake 3.25.1 (>=3.20, min. Required to install Open3D)
      • In scripts/install_open3d.bash, the installation of the higher version of CMake is already implemented.
    • Open3D 0.15.2 0.18.0
    • pybind11 v2.2.3
    • Eigen 3.3.7

    :mailbox: Contact Information

    If you have any questions, please do not hesitate to contact us


    Todo List

    • [ ] Support intensity for RNR in master branch
    • [ ] Support Patchwork mode for users who use this repository for baseline comparison purposes
    • [ ] Integrate TBB and optimize the performance