This repository contains a pipeline for planar shape detection [1, 2] from point clouds. The source code is written in C++ and Python bindings are provided for the main functionality.
- Reading of point clouds (.ply) or vertex groups (.vg, .npz) as input
- Planar shape detection based on a robust and efficient region growing algorithm [1] (also in CGAL)
- Planar shape refinement based on an optimization that seeks the best trade-off between fidelity, completeness and simplicity of the configuration [2]
- Writing of planar shapes as 2D convex hulls, alpha shapes or minimal rectangles (.ply) or as vertex groups (.vg, .npz, .ply).
First, clone this repository and create a new conda environment called psdr. Then, install and test PSDR, its Python bindings and all necessary dependencies.
git clone https://github.com/raphaelsulzer/psdr.git
cd psdr
conda create --name psdr && conda activate psdr
conda install -y -c conda-forge xtensor xtensor-io spdlog cgal anaconda::mpfr yaml-cpp omnia::eigen3
# Windows only: symlink eigen3/Eigen to Eigen
ln -s $CONDA_PREFIX/Library/include/eigen3/Eigen $CONDA_PREFIX/Library/include/Eigen
# Linux/MacOS only: symlink eigen3/Eigen to Eigen
ln -s $CONDA_PREFIX/include/eigen3/Eigen $CONDA_PREFIX/include/Eigen
pip install psdr/.
python -m unittest test.py
If all tests complete successfully you are ready to use PSDR.
from pypsdr import psdr
# initialise a planar shape detector
ps = psdr(verbosity=1)
# load input point cloud
ps.load_points("example/data/anchor/pointcloud.ply")
bb_diagonal = ps.get_bounding_box_diagonal()
# detect planar shapes with fitting tolerance epsilon = 1% of the pointcloud's bounding box diagonal
ps.detect(epsilon=0.01*bb_diagonal,min_inliers=50,knn=10,normal_th=0.8)
# refine planar shape configuration until convergence (i.e. no limit on number of iterations)
ps.refine(max_iterations=-1)
# if the point cloud is very large (e.g. > 2M points) you can also set a time limit
ps.refine(max_seconds=180)
# export planar shapes
ps.save("example/data/anchor/convexes.ply","convex")
ps.save("example/data/anchor/rectangles.ply","rectangles")
ps.save("example/data/anchor/alpha_shapes.ply","alpha")
ps.save("example/data/anchor/point_groups.ply","pointcloud")
ps.save("example/data/anchor/point_groups.vg")
ps.save("example/data/anchor/point_groups.npz")
For more Python examples see the example/python
folder.
auto SD = Shape_Detector();
SD.load_points(example/data/anchor/pointcloud.ply);
SD.set_detection_parameters(20,0.02,0.8,10);
auto SC = Shape_Container(&SD);
SC.detect();
SC.refine(10);
SC.save("example/data/gargoyle/groups.npz");
SC.save("example/data/gargoyle/rectangles.ply","rectangle");
For a cmake project that uses PSDR see the example/cpp
folder.
@article{1,
title={Creating large-scale city models from 3D-point clouds: a robust approach with hybrid representation},
author={Lafarge, Florent and Mallet, Cl{\'e}ment},
journal={International journal of computer vision},
volume={99},
pages={69--85},
year={2012},
publisher={Springer}
}
@inproceedings{2,
title={Finding Good Configurations of Planar Primitives in Unorganized Point Clouds},
author={Yu, Mulin and Lafarge, Florent},
booktitle={Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition},
pages={6367--6376},
year={2022}
}
If you use this library in your work, please consider citing the above papers and this repository:
@misc{sulzer2023psdr,
author = {Sulzer, Raphael and Yu, Mulin and Lafarge, Florent},
title = {pyPSDR: Planar shape detection from point clouds},
year = {2023},
howpublished = {GitHub Repository},
url = {https://github.com/raphaelsulzer/psdr}
}