Skip to content

Commit

Permalink
New feature: LiDAR-based panoptic segmentation - EfficientLPS (#359)
Browse files Browse the repository at this point in the history
* Initial Commit.

* Implemented MMDet interface for SemanticKitti Dataset.
Implemented and tested fit() method of EfficientLpsLearner.

* Implemented and tested infer() and visualize() for EfficientLpsLearner.
Moved example_usage.py to its final location.

* Fixed stuff_id in loading pipeline for inference (EfficientLpsLearner.pcl_to_mmdet()).
Improved function signature in example_usage.py for better readability.

* Fixed bug in singlegpu_sample.py configuration.

* Re-Added EfficientLPS submodule.

* Corrected typo in docstring.

* Changed copyright notice to 2022.
Added EfficientLPS submodule to skipped directories in test_license.py.

* Cleaned singlegpu_sample config.

* Type hints and docstrings.

* Typo.

* Added numpy, just in case.

* Finished evaluation methods.

* Docstrings and type hints.

* Added ROS Node

* Updated TODOs

* Added type hint compatibility for pathlib's Path where required.
Minor bug fixes.

* Added UnitTests.

* Added iterator interfaces and unittest for them.

* Commented out semantic kitti dataset iterator interface test.

* Finished ROS Node.

* Finished READMEs.

* Fixed bibtex and added Daniel Büscher to authors.

* Updated to latest commit of EfficientLPS.

* Verified model and test_data downloads.
Cleaned TODOs.

* feat: Fixed mmdet2 conflicts, learner, and added tests

Fixed semantic_kitti.py and efficient_lps_learner.py for mmdet2 conflicts. Also fixed test_efficent_lps.py and added the correct configuration file for semantic_kitti dataset

* feat: changed location for efficentlps submodule into opendr branch

* feat: Changed install.sh for docker environment, will be reverted later

* feat: Updated install.sh for docker container environment

* style: ROS_DISTRO export changed

* feat: Adapted ROS node for EfficientLPS

* install.sh reverted back to normal

* removed eagerx module (deprecated)

* refactor: Renamed model key for semantickitti dataset

* feat: Adding feature for ros pointcloud2 publisher

* feat: Added example usage for EfficientLPS

Added example_usage.py for EfficientLPS and README file.

* feat: Add point cloud 2 publisher

* docs: Fix README files for example usage for both PS & LPS

\

* docs: Adjusted README docs for ROS nodes and learner references

* bridge_update

* [WIP] commit by Niclas

* update submodules

* feat: ROS nodes for PointCloud2 publisher and EfficientLPS ready for testing

* style: Fix for PEP style

* style: Changed the rosmessage of pc2 publisher

* style: pep8 fixes

* pep8 test skip for EfficientLPS added

* Revert changes on install.sh

* Fixed documentation for EfficientLPS node

* remove misplaced example_usage

* style: fixing typo in the comments

* docs: fixing readme file of panoptic segmentation

* Deleting nuscenes

* Adjust dependencies

* Deleting NuScenes from the learner

* style: styling fix for the LPS learner

* style: fix pep8

* fix: deleted nuscenes remainings

* fix: fix test typo

* fix: style and url fix for download method

* Add license to PC2 publisher

* fix: fix the clang format test, skip EfficientLPS

* revert activate.sh

* Rename heading

* feat: Added prepare_data for semantic_kitti.py

* docs: Update README for semantic kitti prepare data function

* style: fix pep8

* fix: Changing copying the files from move to speed up

* docs: Update Performance Evaluation

* refactor: Removing uncessary dependencies and repeating imports to fix pep8

* docs: Fix for conflicting files

* fix: Fixing the readme in the opendr_ws

* refactor: Fixed licenses due to new year

* refactor: Fix license date

* docs: EfficientLPS.md changes wrt. review

* docs: Add PointCloud2 bridge methods to 'opendr_ros_bridge.md'

* docs: Fix documentation in 'projects/opendr_ws/src/opendr_perception/README.md'

* test: Deleted not used test

* fix: Fixed ROS Nodes args and dataset file check for PCL2 and EfficientLPS

* docs: Update ROS nodes README.md according new PCL2 args

* feat: Add argument option to demo for EfficientLPS

* fix pep8

* fix: Removed "awful hack", original repo from 'EfficientLPS' should be updated

* feat: Add link to demo in index.md and update submodule

* docs: Update README.md for ros nodes (perception -> opendr_perception)

* Add changelog entry

* feat: ROS documentation improved and some fixes on ros nodes

* feat: Fix unused numpy import

* docs: Fix wrong revert and add necessary changes

* style(efficientLPS): change the variable name to convenient one

* fix(efficientLPS): Small argument input naming fix

* docs: Fix documentation of EfficientPS arguments

* style(efficientLPS): fix style pep8

* docs(efficientLPS): Quick fixes on documentation

* Empty Commit

* feat(efficientLPS): Add test data download option to PointCloud2 Publisher Node

* feat(efficientLPS): Add prepare data for the EfficientLPS learner

* style(efficientLPS): Fix pep8

* docs(efficientLPS): Add the test data support to documentation, delete the debug lines

* refactor(efficientLPS): Change the naming of the output topic of EfficientLPS

---------

Co-authored-by: Jose Arce y de la Borbolla <joseab10@gmail.com>
Co-authored-by: aselimc <voedisch_local@informatik.uni-freiburg.de>
Co-authored-by: Niclas <49001036+vniclas@users.noreply.github.com>
Co-authored-by: Niclas Vödisch <voedisch@cs.uni-freiburg.de>
  • Loading branch information
5 people authored Feb 7, 2023
1 parent 8f4a452 commit fe34b42
Show file tree
Hide file tree
Showing 34 changed files with 2,721 additions and 22 deletions.
4 changes: 4 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
[submodule "src/opendr/perception/panoptic_segmentation/efficient_ps/algorithm/EfficientPS"]
path = src/opendr/perception/panoptic_segmentation/efficient_ps/algorithm/EfficientPS
url = https://github.com/DeepSceneSeg/EfficientPS.git
[submodule "src/opendr/perception/panoptic_segmentation/efficient_lps/algorithm/EfficientLPS"]
path = src/opendr/perception/panoptic_segmentation/efficient_lps/algorithm/EfficientLPS
url = https://github.com/robot-learning-freiburg/EfficientLPS.git
branch = opendr
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
Released on XX, XX, 2023.

- New Features:
- Added Efficient LiDAR Panoptic Segmentation ([#359](https://github.com/opendr-eu/opendr/pull/359)).
- Added Nanodet 2D Object Detection tool ([#352](https://github.com/opendr-eu/opendr/pull/352)).
- Added C API implementations of NanoDet 2D Object Detection tool ([#352](https://github.com/opendr-eu/opendr/pull/352)).
- Added C API implementations of forward pass of DETR 2D Object Detection tool ([#383](https://github.com/opendr-eu/opendr/pull/383)).
Expand Down
264 changes: 264 additions & 0 deletions docs/reference/efficient-lps.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,264 @@
## efficient_lps module

Panoptic segmentation combines both semantic segmentation and instance segmentation in a single task.
While distinct foreground objects, e.g., cars or pedestrians, receive instance-wise segmentation masks, background classes such as buildings or road surface are combined in class-wide labels.

For this task, EfficientLPS has been included in the OpenDR toolkit.
The model architecture leverages a shared backbone for efficient encoding and fusing of semantically rich multi-scale features.
Two separate network heads create predictions for semantic and instance segmentation, respectively.
The final panoptic fusion model combines the output of the task-specific heads into a single panoptic segmentation map.

Website: [http://lidar-panoptic.cs.uni-freiburg.de](http://lidar-panoptic.cs.uni-freiburg.de) <br>
Arxiv: [https://arxiv.org/abs/2102.08009](https://arxiv.org/abs/2102.08009) <br>
Original GitHub repository: [https://github.com/robot-learning-freiburg/EfficientLPS](https://github.com/robot-learning-freiburg/EfficientLPS)

### Class EfficientLpsLearner
Bases: `engine.learners.Learner`

The *EfficientLpsLearner* class is a wrapper around the EfficientLPS implementation of the original author's repository adding the OpenDR interface.

The [EfficientLpsLearner](/src/opendr/perception/panoptic_segmentation/efficient_lps/efficient_lps_learner.py) class has the following public methods:
#### `EfficientLpsLearner` constructor
```python
EfficientLpsLearner(config_file, lr, iters, batch_size, optimizer, lr_schedule, momentum, weight_decay, optimizer_config, checkpoint_after_iter, temp_path, device, num_workers, seed)
```

Constructor parameters:

- **config_file**: *str*\
Path to the config file that contains the model architecture and the data loading pipelines.
- **lr**: *float, default=0.07*\
Specifies the learning rate used during training.
- **iters**: *int, default=160*\
Specifies the number of iterations used during training.
- **batch_size**: *int, default=1*\
Specifies the size of the batches used during both training and evaluation.
- **optimizer**: *str, default='SGD'*\
Which optimizer to use for training.
- **lr_schedule**: *dict[str, any], default=None*\
Contains additional parameters related to the learning rate.
- **momentum**: *float, default=0.9*\
Specifies the momentum used by the optimizer.
- **weight_decay**: *float, default=0.0001*\
Specifies the weight decay used by the optimizer.
- **optimizer_config**: *dict[str, any], default=None*\
Contains additional parameters related to the optimizer.
- **checkpoint_after_iter**: *int, default=1*\
Specifies the interval in epochs to save checkpoints during training.
- **temp_path**: *Path*, *str, default='../eval_tmp_dir'*\
Path to a temporary folder that will be created to evaluate the model.
- **device**: *str, default='cuda:0'*\
Specifies the device to deploy the model.
- **num_workers**: *int, default=1*\
Specifies the number of workers used by the data loaders.
- **seed**: *float, default=None*\
Specifies the seed to shuffle the data during training.

#### `EfficientLpsLearner.fit`
```python
EfficientLpsLearner.fit(self, dataset, val_dataset, logging_path, silent)
```

Parameters:

- **dataset**: *object*\
Specifies the dataset used to train the model.
Supported datasets are SemanticKitti and NuScenes (Future) (see [readme](../../src/opendr/perception/panoptic_segmentation/datasets/README.md)).
- **val_dataset**: *object*\
If given, this dataset will be used to evaluate the current model after each epoch.
Supported datasets are SemanticKitti and NuScenes (Future) (see [readme](../../src/opendr/perception/panoptic_segmentation/datasets/README.md)).
- **logging_path**: *Path*, *str, default='../logging'*\
Path to store the logging files, e.g., training progress and tensorboard logs.
- **silent**: *bool, default=True*\
If True, disables printing the training progress reports to STDOUT.
The validation will still be shown.

Return:

- **results**: *dict*\
Dictionary with "train" and "val" keys containing the training progress (e.g. losses) and, if a val_dataset is provided, the evaluation results.
#### `EfficientLpsLearner.eval`
```python
EfficientLpsLearner.eval(self, dataset, print_results)
```

Parameters:

- **dataset**: *object*\
Specifies the dataset used to evaluate the model.
Supported datasets are SemanticKitti and NuScenes (Future) (see [readme](../../src/opendr/perception/panoptic_segmentation/datasets/README.md)).
- **print_results**: *bool, default=False*\
If True, the evaluation results will be formatted and printed to STDOUT.

Return:

- **evaluation_results**: *dict*\
Contains the panoptic quality (PQ), segmentation quality (SQ), recognition quality (RQ) and Intersection over Union (IoU).


#### `EfficientLpsLearner.pcl_to_mmdet`
```python
EfficientLpsLearner.pcl_to_mmdet(self, point_cloud, frame_id)
```

Parameters:

- **point_cloud**: *PointCloud*\
Specifies the OpenDR PointCloud object that will be converted to a MMDetector compatible object.
- **frame_id**: *int, default=0*\
Number of the scan frame to be used as its filename.
Inferences will use the same filename.

Return:

- **results**: *dict*\
An MMDetector compatible dictionary containing the PointCloud data and some additional metadata.

#### `EfficientLpsLearner.infer`
```python
EfficientLpsLearner.infer(self, batch, return_raw_logits, projected)
```

Parameters:

- **batch**: *PointCloud*, *List[PointCloud]*\
Point Cloud(s) to feed to the network.
- **return_raw_logits**: *bool, default=False*\
If True, the raw network output will be returned.
Otherwise, the returned object will hold Tuples of Heatmaps of the OpenDR interface.
- **projected**: *bool, default=False*\
If True, output will be returned as 2D heatmaps of the spherical projections of the semantic and instance labels, as well as the spherical projection of the scan's range.
Otherwise, the semantic and instance labels will be returned as Numpy arrays for each point.

Return:

- **results**: *Tuple[Heatmap, Heatmap, Image]*,\
*Tuple[np.ndarray, np.ndarray, None]*,\
*List[Tuple[Heatmap, Heatmap, Image]]*,\
*List[Tuple[np.ndarray, np.ndarray, None]]*\
If *return_raw_logits* is True the raw network output will be returned.
If *return_raw_logits* is True and *projected* is true, the predicted instance and semantic segmentation maps, as well as the scan range map will be returned.
Otherwise, if *return_raw_logits* is True and *projected* is false, the predicted instance and semantic labels for each point will be returned as numpy arrays.

#### `EfficientLpsLearner.save`
```python
EfficientLpsLearner.save(self, path)
```

Parameters:

- **path**: *Path*, *str*\
Specifies the location to save the current model weights.

Return:

- **successful**: *bool*\
Returns True if the weights could be saved.
Otherwise, returns False.

#### `EfficientLpsLearner.load`
```python
EfficientLpsLearner.load(path)
```

Parameters:

- **path**: *Path*, *str*\
Specifies the location to load model weights.

Return:

- **successful**: *bool*\
Returns True if the weights could be loaded.
Otherwise, returns False.

#### `EfficientLpsLearner.download`
```python
EfficientLpsLearner.download(path, mode, trained_on)
```

Parameters:

- **path**: *str*\
Specifies the location to save the downloaded file.
- **mode**: *str, default='model'*\
Valid options are *'model'* to download pre-trained model weights and *'test_data'* to run the unit tests.
- **trained_on**: *str, default='semantickitti'*\
Specifies which model weights to download.
Pre-trained models are available for the SemanticKITTI and NuScenes (Future) datasets.

Return:

- **filename**: *str*\
Absolute path to the downloaded file or directory.

#### `EfficientLpsLearner.visualize`
```python
EfficientLpsLearner.visualize(self, pointcloud, predictions, show_figure, save_figure, figure_filename, figure_size, max_inst, min_alpha, dpi)
```

Parameters:

- **pointcloud**: *PointCloud*\
PointCloud used for inference.
- **prediction**: *Tuple[np.ndarray, np.ndarray]*\
The semantic and instance segmentation labels obtained with the `infer()` method and *projected* set to False.
- **show_figure**: *bool, default=True*\
If True, the generated figure will be shown on screen.
- **save_figure**: *bool, default=False*\
If True, the generated figure will be saved to disk. The **figure_filename** has to be set.
- **figure_filename**: *Path*, *str, default=None*\
The path used to save the figure if **save_figure** is True.
- **figure_size**: *Tuple[float, float], default=(15, 10)*\
The size of the figure in inches.
- **max_inst**: *int, default=20*\
Maximum value that the instance ID can take.
Used for computing the alpha value of a point.
- **min_alpha**: *float, default=0.25*\
Minimum value that a point's alpha value can take, so that it is never fully transparent.
- **dpi**: *int, default=600*\
Resolution of the resulting image, in Dots per Inch.
- **return_pointcloud**: *Optional[bool], default=False*\
If True, returns a PointCloud object with the predicted labels as colors.
- **return_pointcloud_type**: *Optional[str], default=None*\
If return_pointcloud is True, this parameter specifies the type of the returned PointCloud object.
Valid options are "semantic", "instance" and "panoptic".

Return:

- **visualization**: *Union[PointCloud, Image]*\
OpenDR Image of the generated visualization or OpenDR PointCloud with the predicted labels.

#### Performance Evaluation

The speed of pointcloud per second is evaluated for the SemanticKITTI dataset:

| Dataset | ~ | GeForce GTX TITAN X | ~ | Xavier AGX |
|------------|-----------------|---------------------|-----------|------------|
| SemanticKITTI | ~ | 0.53 | ~ | ~ |

The memory and energy usage is evaluated for different datasets.
An NVIDIA Jetson Xavier AGX was used as the reference platform for energy measurements.
The reported memory is the max number seen during evaluation on the respective validation set.
The energy is measured during the evaluation.

| Dataset | Memory (MB) | Energy (Joules) - Total per inference AGX |
|------------------------|-------------|-------------------------------------------|
| SemanticKITTI | ~ | ~ |

The performance is evaluated using three different metrics, namely Panoptic Quality (PQ), Segmentation Quality (SQ), and Recognition Quality (RQ).

| Dataset | PQ | SQ | RQ |
|------------|------|------|------|
| SemanticKITTI | 52.5 | 72.6 | 63.1 |

EfficientPS is compatible with the following platforms:

| Platform | Compatibility |
|----------------------------------------------|---------------|
| x86 - Ubuntu 20.04 (bare installation - CPU) ||
| x86 - Ubuntu 20.04 (bare installation - GPU) | ✔️ |
| x86 - Ubuntu 20.04 (pip installation) ||
| x86 - Ubuntu 20.04 (CPU docker) ||
| x86 - Ubuntu 20.04 (GPU docker) | ✔️ |
| NVIDIA Jetson Xavier AGX | ✔️ |
11 changes: 8 additions & 3 deletions docs/reference/efficient-ps.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@ The *EfficientPsLearner* class is a wrapper around the EfficientPS implementatio
The [EfficientPsLearner](/src/opendr/perception/panoptic_segmentation/efficient_ps/efficient_ps_learner.py) class has the following public methods:
#### `EfficientPsLearner` constructor
```python
EfficientPsLearner(lr, iters, batch_size, optimizer, lr_schedule, momentum, weight_decay, optimizer_config, checkpoint_after_iter, temp_path, device, num_workers, seed, config_file)
EfficientPsLearner(config_file, lr, iters, batch_size, optimizer, lr_schedule, momentum, weight_decay, optimizer_config, checkpoint_after_iter, temp_path, device, num_workers, seed)
```

Constructor parameters:

- **config_file**: *str*\
Path to the config file that contains the model architecture and the data loading pipelines.
- **lr**: *float, default=0.07*\
Specifies the learning rate used during training.
- **iters**: *int, default=160*\
Expand All @@ -51,8 +53,6 @@ Constructor parameters:
Specifies the number of workers used by the data loaders.
- **seed**: *float, default=None*\
Specifies the seed to shuffle the data during training.
- **config_file**: *str, default='../configs/singlegpu_sample.py*\
Path to the config file that contains the model architecture and the data loading pipelines.

#### `EfficientPsLearner.fit`
```python
Expand All @@ -70,6 +70,11 @@ Parameters:
- **silent**: *bool, default=False*\
If True, disables printing the training progress reports to STDOUT. The validation will still be shown.

Return:

- **results**: *dict*\
Dictionary with "train" and "val" keys containing the training progress (e.g. losses) and, if a val_dataset is provided, the evaluation results.

#### `EfficientPsLearner.eval`
```python
EfficientPsLearner.eval(dataset, print_results)
Expand Down
2 changes: 2 additions & 0 deletions docs/reference/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ Neither the copyright holder nor any applicable licensor will be liable for any
- [semantic_segmentation Module](semantic-segmentation.md)
- panoptic segmentation:
- [efficient_ps Module](efficient-ps.md)
- [efficient_lps Module](efficient-lps.md)
- heart anomaly detection:
- [gated_recurrent_unit Module](gated-recurrent-unit-learner.md)
- [attention_neural_bag_of_feature_learner Module](attention-neural-bag-of-feature-learner.md)
Expand Down Expand Up @@ -136,6 +137,7 @@ Neither the copyright holder nor any applicable licensor will be liable for any
- [siamrpn Demo](/projects/python/perception/object_tracking_2d/demos/siamrpn)
- panoptic segmentation:
- [efficient_ps Demo](/projects/python/perception/panoptic_segmentation/efficient_ps)
- [efficient_lps Demo](/projects/python/perception/panoptic_segmentation/efficient_lps)
- semantic segmentation:
- [bisnet Demo](/projects/python/perception/semantic_segmentation/bisenet)
- action recognition:
Expand Down
29 changes: 29 additions & 0 deletions docs/reference/opendr-ros-bridge.md
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,34 @@ Parameters:
- **point_cloud**: *engine.data.PointCloud*\
OpenDR PointCloud to be converted.

#### `ROSBridge.from_ros_point_cloud2`

```python
ROSBridge.from_ros_point_cloud2(self, point_cloud)
```

Converts a ROS PointCloud2 message into an OpenDR PointCloud.

Parameters:

- **point_cloud**: *sensor_msgs.msg.PointCloud2*\
ROS PointCloud2 to be converted.

#### `ROSBridge.to_ros_point_cloud2`

```python
ROSBridge.to_ros_point_cloud2(self, point_cloud, channels)
```
Converts an OpenDR PointCloud message into a ROS PointCloud2.

Parameters:

- **point_cloud**: *engine.data.PointCloud*\
OpenDR PointCloud to be converted.
- **channels**: *str*\
Channels to be included in the PointCloud2 message.
Available channels names are ["rgb", "rgba"]

#### `ROSBridge.from_ros_boxes_3d`

```python
Expand Down Expand Up @@ -424,6 +452,7 @@ Parameters:
5. `geometry_msgs.msg.Pose` is used as an equivalent to `engine.target.Pose` for 3D poses conversion only.
6. `vision_msgs.msg.Detection3DArray` is used as an equivalent to `engine.target.BoundingBox3DList`.
7. `sensor_msgs.msg.PointCloud` is used as an equivalent to `engine.data.PointCloud`.
8. `sensor_msgs.msg.PointCloud2` is used as an equivalent to `engine.data.PointCloud`.

## ROS services
The following ROS services are implemented (`srv` folder):
Expand Down
3 changes: 2 additions & 1 deletion projects/opendr_ws/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ Currently, apart from tools, opendr_ws contains the following ROS nodes (categor
5. [2D Object Detection](src/opendr_perception/README.md#2d-object-detection-ros-nodes)
6. [2D Single Object Tracking](src/opendr_perception/README.md#2d-single-object-tracking-ros-node)
7. [2D Object Tracking](src/opendr_perception/README.md#2d-object-tracking-ros-nodes)
8. [Panoptic Segmentation](src/opendr_perception/README.md#panoptic-segmentation-ros-node)
8. [Vision Based Panoptic Segmentation](src/opendr_perception/README.md#vision-based-panoptic-segmentation-ros-node)
9. [Semantic Segmentation](src/opendr_perception/README.md#semantic-segmentation-ros-node)
10. [Image-based Facial Emotion Estimation](src/opendr_perception/README.md#image-based-facial-emotion-estimation-ros-node)
11. [Landmark-based Facial Expression Recognition](src/opendr_perception/README.md#landmark-based-facial-expression-recognition-ros-node)
Expand All @@ -90,5 +90,6 @@ Currently, apart from tools, opendr_ws contains the following ROS nodes (categor
## Point cloud input
1. [3D Object Detection Voxel](src/opendr_perception/README.md#3d-object-detection-voxel-ros-node)
2. [3D Object Tracking AB3DMOT](src/opendr_perception/README.md#3d-object-tracking-ab3dmot-ros-node)
3. [LiDAR Based Panoptic Segmentation](src/opendr_perception/README.md#lidar-based-panoptic-segmentation-ros-node)
## Biosignal input
1. [Heart Anomaly Detection](src/opendr_perception/README.md#heart-anomaly-detection-ros-node)
Loading

0 comments on commit fe34b42

Please sign in to comment.