Skip to content

Repository files navigation

pcod-common


Documentation

Shared Preprocessing and Postprocessing Library for Point Cloud Object Detection

This repository provides shared C++ and Python components for point cloud object detection training, model export, and ROS 2 inference. Using the same geometry, decoding, non-maximum suppression (NMS), and model-manifest implementations keeps the training and inference pipelines consistent.

The library includes PBOD decoding, rotated NMS, point filtering, CUDA kernels for pillarization and rotated NMS, and a model-manifest schema shared by the C++ and Python APIs.

πŸš€ Quick Start β€’ πŸ’» Development β€’ πŸ“ Documentation

Important

This repository is part of OpenADS, the Open Automated Driving Systems project. OpenADS and its modules have been initiated and are currently being maintained by the Institute for Automotive Engineering (ika) at RWTH Aachen University.

πŸš€ Quick Start

Requirements

  • CMake 3.16 or newer
  • A C++17 compiler
  • yaml-cpp
  • Python 3.12 or newer for the Python package
  • Optional: a CUDA toolkit compatible with the installed PyTorch build and a CUDA-capable GPU for the CUDA extensions

C++ Installation

Clone, build, and install the C++ library:

git clone https://github.com/openads-project/pcod-common.git
cmake -S pcod-common -B build/pcod-common -DPCOD_COMMON_BUILD_TESTS=OFF
cmake --build build/pcod-common
cmake --install build/pcod-common --prefix /path/to/prefix

After installation, link your CMake target to the package:

find_package(pcod_common CONFIG REQUIRED)
target_link_libraries(my_target PRIVATE pcod_common::pcod_common)

When using a custom installation prefix, add it to CMAKE_PREFIX_PATH when configuring the consuming project, for example with -DCMAKE_PREFIX_PATH=/path/to/prefix.

Alternatively, add this repository directly to your CMake project:

add_subdirectory(pcod-common)
target_link_libraries(my_target PRIVATE pcod_common)

Python Installation

Install the Python package from the repository root:

pip install .

Python Usage Example

from pcod_common.preprocessing.pillars import PillarPreprocessor, PillarPreprocessorConfig

config = PillarPreprocessorConfig(
    x_min=-50.0,
    x_max=50.0,
    y_min=-50.0,
    y_max=50.0,
    z_min=-2.0,
    z_max=3.0,
    voxel_x=0.2,
    voxel_y=0.2,
    point_feature_dim=1,
)
preprocessor = PillarPreprocessor(config)

πŸ’» Development

Repository Layout

  • include/pcod_common/: public C++ headers
  • src/: C++ implementations
  • csrc/: CUDA/C++ kernels for PyTorch extensions
  • python/pcod_common/: Python package sources
  • schemas/: JSON schema for the model manifest
  • tests/: C++ tests
  • python/tests/: Python tests

C++ Tests

On Debian or Ubuntu, install the required build dependencies and run the test suite:

apt-get update && apt-get install -y cmake g++ pkg-config libyaml-cpp-dev python3 python3-yaml
cmake -S . -B build -DPCOD_COMMON_BUILD_TESTS=ON
cmake --build build
ctest --test-dir build

Some C++ tests compare the Python and C++ contracts and require python3 to be available on PATH.

Python Tests

Install the package in editable mode with its development dependencies and run the test suite:

pip install -e ".[dev]"
pytest

python/tests/test_postprocess.py requires PyTorch and TorchVision. Tests whose optional dependencies or CUDA extensions are unavailable are skipped; the manifest tests still run.

Build Python Distributions

Build and validate the wheel and source distribution from the repository root:

python3 -m pip install build twine
python3 -m build
python3 -m twine check dist/*

Published distributions include the model-manifest schema and the C++/CUDA sources required to build the optional PyTorch extensions at runtime. Validating a distribution does not require a GPU. Compiling the extensions requires Ninja and a CUDA toolkit compatible with the installed PyTorch build; running them requires a CUDA-capable GPU.

Development Container

A basic development container configuration is provided in .devcontainer/. In the container, install the system and Python dependencies, including PyTorch, and run:

sudo apt-get update
sudo apt-get install -y pkg-config libyaml-cpp-dev
pip install -e ".[dev]"
cmake -S . -B build -DPCOD_COMMON_BUILD_TESTS=ON
cmake --build build
ctest --test-dir build
pytest

CUDA kernels are built on demand by the PyTorch extension loaders in python/pcod_common/torch_extensions/.

C++ Usage Example

This example demonstrates point filtering and PBOD decoding with the C++ API. It uses four pillars and two classes to keep the control flow easy to follow.

#include "pcod_common/pbod_postprocess.hpp"
#include "pcod_common/pillar_grid.hpp"
#include "pcod_common/point_preprocess.hpp"

#include <vector>

int main() {
  pcod_common::PointPreprocessConfig pre_cfg;
  pre_cfg.x_min = -1.0f;
  pre_cfg.x_max = 1.0f;
  pre_cfg.y_min = -1.0f;
  pre_cfg.y_max = 1.0f;
  pre_cfg.z_min = -1.0f;
  pre_cfg.z_max = 1.0f;
  pre_cfg.normalization_type = pcod_common::PointFeatureNormalizationType::kValueThreshold;
  pre_cfg.value_threshold = 10.0f;

  // 1) Basic point filtering (range checks + optional masks).
  pcod_common::PointPreprocessor preprocessor(pre_cfg);
  if (!preprocessor.IsPointValid(0.5f, 0.1f, 0.0f)) {
    return 1;
  }

  // 2) Build a 2x2 pillar grid so the decoder has a center location.
  pcod_common::PillarGrid grid = pcod_common::BuildPillarGrid(
      {2, 2}, {{{0.0f, 2.0f}, {0.0f, 2.0f}, {0.0f, 1.0f}}}, 1, 1);

  // 3) Dummy model outputs for four pillars and two classes.
  //    Two pillars will be filtered out by the score threshold below.
  const int num_pillars = 4;
  const int num_classes = 2;
  float focal_logits[num_pillars] = {2.0f, -2.0f, 2.0f, -2.0f};
  float class_logits[num_pillars * num_classes] = {
      0.1f, 0.9f, 0.1f, 0.9f, 0.1f, 0.9f, 0.1f, 0.9f};
  std::vector<float> size_posterior(num_pillars * num_classes * 3, 1.0f);
  std::vector<float> reg_logits(num_pillars * num_classes * 7, 0.0f);

  pcod_common::PbodOutputsView view;
  view.focal_logits = focal_logits;
  view.size_posterior = size_posterior.data();
  view.class_logits = class_logits;
  view.reg_logits = reg_logits.data();
  view.num_pillars = num_pillars;
  view.num_classes = num_classes;
  view.reg_dim = 7;

  // 4) Decode into bounding boxes (class list sets the output metadata).
  pcod_common::PbodPostprocessConfig post_cfg;
  post_cfg.class_names = {"car", "pedestrian"};
  post_cfg.score_thresholds = {0.5f};

  auto boxes = pcod_common::DecodePbod(view, grid, post_cfg);
  const std::size_t expected_boxes = 2;
  return boxes.size() == expected_boxes ? 0 : 1;
}

Model Manifest

Each exported model bundle contains a model_manifest.yml file with three sections:

  • artifact: bundle metadata and references to files within the bundle
  • frozen_contract: model settings that inference applications cannot override and that must match the exported model
  • runtime_defaults: default inference settings that applications may override

The ROS 2 inference node uses frozen_contract as the authoritative model configuration and initializes overridable ROS parameters, such as preprocessing.point_feature.value_threshold and the NMS thresholds, from runtime_defaults. The schema is defined in schemas/model_manifest.schema.json.

Integration Notes

  • For training and model export, include pcod-common as a Git submodule and add it to the Python environment, for example with pip install -e pcod-common.
  • For ROS 2 inference, include pcod-common as a Git submodule and link against the C++ library.

For a complete ROS 2 integration example, see point_cloud_object_detection, which includes pcod-common as a Git submodule and links against its C++ library.

πŸ“ Documentation

Implementation details are available in the Source Code Documentation.

βš–οΈ Licensing

The source code in this repository is licensed under Apache-2.0, see LICENSE.

πŸ™ Acknowledgements

Development and maintenance of this repository are supported by the following projects. We acknowledge the funding of the respective institutions.

Project Funding Institution Grant Number
AIGGREGATE πŸ‡ͺπŸ‡Ί European Union 101202457

Funded by the European Union. Views and opinions expressed are however those of the author(s) only and do not necessarily reflect those of the European Union or the European Climate, Infrastructure and Environment Executive Agency (CINEA). Neither the European Union nor CINEA can be held responsible for them.

About

Shared Preprocessing and Postprocessing Library for Point Cloud Object Detection

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages