diff --git a/docs/filters.md b/docs/filters.md new file mode 100644 index 000000000..8866e34b9 --- /dev/null +++ b/docs/filters.md @@ -0,0 +1,101 @@ +# Point Filters + +Point filters run for every decoded point, reducing pointcloud size right at the decode stage. +This can speed up the later parts of pointcloud processing pipelines by reducing the number of points copied between and processed by modules. + +## Configuration + +Filters are configured via the ROS parameter namespace `point_filters`. + +```yaml +{ + point_filters: + filter_type_a: + # config for filter_type_a goes here + filter_type_b: + # ... +} +``` + +Where each `filter_type` can be specified at most once. +The configuration options available depend on the respective filter type. + +Filters can also be set during runtime, e.g. via: + +```shell +ros2 param set /hesai_ros_wrapper_node point_filters.filter_type_a ...' +``` + +## Supported Filters + +The following filter types are supported: + +| Filter Name | Filter Type | +| ---------------------- | ----------------- | +| Downsample Mask Filter | `downsample_mask` | + +Below, each filter type is documented in detail. + +### Downsample Mask Filter + +This filter takes a greyscale PNG image that represents polar coordinates (x=azimuth, y=elevation) +and downsamples the pointcloud according to the lightness values of the image's pixels. + + +!!! note + For ring-based sensors, `y` represents the `channel` as a proxy for `elevation`. + The image height has to be equal to the sensor's number of channels. + + +The input image is dithered to a boolean mask: + +| Stage | Image | +| :----------------------------------------- | :---------------------------------------------------: | +| Input greyscale mask | ![Greyscale mask](filters/at128_test_roi.png) | +| Internal dithered mask generated by Nebula | ![Dithered mask](filters/at128_test_roi_dithered.png) | + +The decoded points are then kept/discarded based on that mask: + +| ![Pointcloud density](filters/at128_test_roi_cloud.png) | ![Pointcloud closeup](filters/at128_test_roi_cloud_closeup.png) | +| -------------------------------------------------------------------------------------- | --------------------------------------------------------------- | +| Pointcloud output (2D azimuth-elevation view, points are blurred to visualize density) | Close-up view of (bottom left of the pointcloud) | + +#### Configuration Options + +Configuration is done in the following format: + +```yaml +downsample_mask: + path: /path/to/mask.png +``` + +Or, during runtime, by setting: + +```shell +ros2 param set /hesai_ros_wrapper_node point_filters.downsample_mask.path /path/to/mask.png' +``` + +The filter can be disabled by omitting the `downsample_mask` config item, or by setting `path` to an empty string: + +```shell +ros2 param set /hesai_ros_wrapper_node point_filters.downsample_mask.path ""' +``` + +#### Behavior + +- Greyscale values are quantized to the nearest 10th (yielding 11 quantization levels in total) +- Mask resolution is dictated by the sensor's maximum FoV, the number of channels (for rotational LiDARs) and the peak angular resolution: + - For a 40-channel LiDAR with `360 deg` FoV and `0.1 deg` peak azimuth resolution, the mask has to be `(360 / 0.1, 40) = (3600, 40)` pixels + - Currently, non-rotational LiDARs are not yet supported +- Image editors like GIMP use perceptual color profiles, which can lead to unexpected results (more/less downsampling than expected). Check the generated `_dithered.png` mask to see if you are affected. +- Dithering performed by Nebula is spatial only, meaning that it stays constant over time. Decoded points are checked against the nearest pixel in the dithered mask + +## Compatibility Chart + +| Filter | Hesai | Robosense | Velodyne | +| --------------- | :---: | :-------: | :------: | +| Downsample Mask | ✅ | ❌ | ❌ | + +Compatibility: +✅: compatible +❌: incompatible diff --git a/docs/filters/at128_test_roi.png b/docs/filters/at128_test_roi.png new file mode 100644 index 000000000..5a880abbf Binary files /dev/null and b/docs/filters/at128_test_roi.png differ diff --git a/docs/filters/at128_test_roi_cloud.png b/docs/filters/at128_test_roi_cloud.png new file mode 100644 index 000000000..cf021775a Binary files /dev/null and b/docs/filters/at128_test_roi_cloud.png differ diff --git a/docs/filters/at128_test_roi_cloud_closeup.png b/docs/filters/at128_test_roi_cloud_closeup.png new file mode 100644 index 000000000..daf352439 Binary files /dev/null and b/docs/filters/at128_test_roi_cloud_closeup.png differ diff --git a/docs/filters/at128_test_roi_dithered.png b/docs/filters/at128_test_roi_dithered.png new file mode 100644 index 000000000..92e378c6a Binary files /dev/null and b/docs/filters/at128_test_roi_dithered.png differ diff --git a/docs/index.md b/docs/index.md index 602333bf0..4975bbfab 100644 --- a/docs/index.md +++ b/docs/index.md @@ -25,6 +25,7 @@ Nebula works with ROS 2 and is the recommended sensor driver for the [Autoware]( - [Design](design.md) - [Parameters](parameters.md) - [Point cloud types](point_types.md) +- [Point filters](filters.md) ## Supported sensors diff --git a/docs/parameters.md b/docs/parameters.md index a985e7a4b..ff96e0162 100644 --- a/docs/parameters.md +++ b/docs/parameters.md @@ -94,3 +94,7 @@ This parameter is used to set this preference. ### `dual_return_distance_threshold` For multiple returns that are close together, the points will be fused into one if they are below this threshold (in meters). + +### `point_filters` + +Filters that are applied while decoding the pointcloud. For the full reference, see [Point filters](filters.md).