Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor voxel grid #4829

Open
wants to merge 79 commits into
base: master
Choose a base branch
from

Conversation

tin1254
Copy link
Contributor

@tin1254 tin1254 commented Jul 2, 2021

Splitted from #4813

Description

  • Design uniform code structure for existing voxel filters
  • Refactor VoxelGrid such that it inherits from CartesianFilter and TransformFilter
  • Reduce the boilerplate code in grid based filters
  • Improve runtime performance up to 40% faster by using std::unordered_map instead of sorting for grouping points to voxels
  • Implement benchmark comparing the performance of the old and new VoxelGrid implementation
  • Write tutorial to introduce the design concept of new VoxelGrid code structure and TransformFilter

Related

Current issue

  • Throw segfault with label point types (description)
    • Currently it is avoided by having raw pointer of CentroidPoint

TODO

  • Write TransformFilter tutorial
  • Finalize the leaf_layout_ design

Copy link
Member

@kunaltyagi kunaltyagi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Improve performance by using std::unordered_map instead of sorting

@mvieth Should we have a perf comparison using the new benchmarks module?

@tin1254 tin1254 force-pushed the refactor_voxel_grid branch from 9347b5e to a7fe430 Compare July 2, 2021 23:59
Copy link
Contributor Author

@tin1254 tin1254 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

int in vector<int> leaf_layout_ will cause a big headache after upgrading the hashing to use size_t

because the contents in the vector are the indices of voxels, which the total number of voxels can excess the range of int after enlarging the hashing range

If we want to solve limited range issue, all those API will have to be changed definitely
I would suggest to upgrade those API to use vector<size_t>, or even one step further to use unordered_map<size_t,size_t>

Because the purpose of leaf_layout_ is to access voxel index by

voxel_idx = leaf_layout_[point_hash]

it makes more sense to use unordered_map for this. Otherwise we'll need a big vector<size_t> if filtering a large point cloud


/** \brief The leaf layout information for fast access to cells relative to current
* position **/
std::vector<int> leaf_layout_;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

vector<int> ->

vector<size_t> OR unordered_map<size_t,size_t> ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

vector<size_t> if we maintain compatibility, else unordered_map<size_t, size_t>

@tin1254 tin1254 force-pushed the refactor_voxel_grid branch 11 times, most recently from 24e473e to 98e2c2d Compare July 7, 2021 19:46
tin1254 added 10 commits July 7, 2021 21:55
* Implement GridFilter for the common members

* Implement TransformFilter for the abstracted filtering logic
* Showcase the bare bone structure of GridStruct

* Test the functions of GridStruct required in applyFilter

* Test different type of grid
* Move applyFilter to protected

* Remove passing GridFilter pointer to GridStruct as can be done with static cast
* Remove confusing comment in applyFilter

* Add line endings

* Fix typo
* Declare new variables for testing instead of using variables from base class
* Move hashPoint, move checkIfOverflow and rename to checkHashRange
@tin1254 tin1254 force-pushed the refactor_voxel_grid branch from 98e2c2d to 9f36208 Compare July 7, 2021 19:56
@tin1254 tin1254 force-pushed the refactor_voxel_grid branch 2 times, most recently from 55489e2 to 058cdc2 Compare July 10, 2021 23:26
@tin1254 tin1254 changed the title [WIP] Refactor voxel grid Refactor voxel grid Jul 10, 2021
* Pass TransformFilter point to constructor of GridStruct instead of setUp
* Allow reusing VoxelStruct members
* Rename GridIterator to iterator

* Adapt changes in experimental VoxelGrid

* Adapt changes in experimental VoxelGrid test
* Template VoxelStruct with FilterBase
@tin1254 tin1254 force-pushed the refactor_voxel_grid branch 7 times, most recently from 1401a73 to b1e8c1e Compare August 21, 2021 21:14
* Replace point check with existing marcos

* Remove setUp check with different point types

* Template equivalency check with point types
@tin1254 tin1254 force-pushed the refactor_voxel_grid branch from b1e8c1e to 04b8559 Compare August 21, 2021 22:39
* Fix error on MSVC and Mac clang
@@ -26,22 +26,22 @@ struct Voxel {
Centroid() {}
~Centroid() {}

CentroidPoint<PointT> all_fields;
CentroidPoint<PointT>* all_fields;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unique_ptr instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

segfault during move assign again, it throws error while resetting itself

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Definitely needs to be solved properly. Perhaps after GSoC. Please make a big note in the file. Current implementation is not copy-safe

Eigen::Array4f xyz;
};

Voxel(const bool downsample_all_data) : downsample_all_data_(downsample_all_data)
{
num_pt_ = 0;
if (downsample_all_data_)
centroid_.all_fields = CentroidPoint<PointT>();
centroid_.all_fields = new CentroidPoint<PointT>();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Usage of heap doesn't seem right to me. If this is "solving" the segfault, I think the issue might be elsewhere

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does solve the segfault but I have no clue why...

@kunaltyagi
Copy link
Member

The current explanation is a bit too technical and not very friendly for beginners

Inheritance structure of VoxelGrid
----------------------------------

.. image:: images/voxel_grid_code_structure.jpg
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be possible to use plantuml to generate the image and also add that code in the repo?

Copy link
Contributor Author

@tin1254 tin1254 Aug 22, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pcl/doc/doxygen/doxyfile.in

Lines 358 to 360 in 85fc170

PLANTUML_JAR_PATH =
PLANTUML_CFG_FILE =
PLANTUML_INCLUDE_PATH =

Do we have to set up the plugin?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually don't know. I was referring to still adding a png/jpg, but adding a source code as well. If we can use plantuml in doxygen, that'd be crazy.

@larshg @SunBlack Any thoughts?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In case it works, I think using the source code of an image is better, as we can than modify it later if necessary.

5. ``TransformFilter``


``VoxelFilter<VoxelStruct<Voxel<PointT>,PointT>>`` is aliased as ``VoxelGrid<PointT>`` in our source code, it implements the API specified for ``VoxelGrid``.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why don't we keep things simple and just focus on one class at a time instead of all at once?

  • TransformFilter is separate, so it doesn't factor in the tutorial for VoxelGrid at all
  • VoxelStruct without template is used to explain the basic needs for VoxelFilter

Thoughts?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the basic needs for VoxelFilter

like requirements of GridStruct?

VoxelStruct without template

But would it be better if we introduce also Voxel along side? (with template)

TransformFilter is separate, so it doesn't factor in the tutorial for VoxelGrid at all

sounds good, I will write a separate tutorial for TransformFilter .

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, like requirements of GridStruct, but in a very-basic manner.

But would it be better if we introduce also Voxel along side?

You can add it, but it's still a tutorial. Make it as approachable for a new comer as possible.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I rewrote it yesterday to try to just introduce the Voxel, VoxelStruct (and its requirement), and VoxelFilter, the three main pieces of VoxelGrid, while trying to minimize the stuff related to TransformFilter.

Could you take a look to see if it's newcomer-friendly enough? (I don't have much experience in writing such tutorials)

@tin1254 tin1254 force-pushed the refactor_voxel_grid branch from 9b6e67b to 1a47bc6 Compare August 22, 2021 22:02
Introduction
============

This document is intended to explain our new ``VoxelGrid`` design and help you implementing your own grid based filters easily by reusing our implementations.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
This document is intended to explain our new ``VoxelGrid`` design and help you implementing your own grid based filters easily by reusing our implementations.
This document is intended to explain our new ``VoxelGrid`` design and help you implement your own grid based filters easily by reusing our building blocks.


We will explain the pieces composing ``VoxelGrid``, then elaborate their purpose and demonstrate how they can be reused to implement your custom grid filters.

In a high level view, ``VoxelGrid`` is comprised from three important classes:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
In a high level view, ``VoxelGrid`` is comprised from three important classes:
``VoxelGrid`` is composed using three important classes:


In a high level view, ``VoxelGrid`` is comprised from three important classes:

1. ``Voxel``: define the information storing in a single voxel and its operations
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
1. ``Voxel``: define the information storing in a single voxel and its operations
1. ``Voxel``: define the information stored in a single voxel and its operations

In a high level view, ``VoxelGrid`` is comprised from three important classes:

1. ``Voxel``: define the information storing in a single voxel and its operations
2. ``VoxelStruct``: define ``VoxelGrid`` filtering logic
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
2. ``VoxelStruct``: define ``VoxelGrid`` filtering logic
2. ``VoxelStruct``: define the filtering logic

2. ``VoxelStruct``: define ``VoxelGrid`` filtering logic
3. ``VoxelFilter``: implement common set of API for voxel grid filters

Together they form ``VoxelFilter<VoxelStruct<Voxel<PointT>,PointT>>`` which is is aliased as ``VoxelGrid<PointT>`` internally.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add something like: Your custom Voxel Grid Filter would look like: VoxelFilter<MyCustomLogic<MyVoxel>>


.. note::
**Tips**:
If your application needs to filter some incoming point clouds repeatedly,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this tip relevant for MyVoxel? There might be a better place for this top

2. Define a custom VoxelStruct
------------------------------

This is a simple custom ``VoxelStruct`` withs a fixed grid size and fixed condition for selecting eligible voxels.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
This is a simple custom ``VoxelStruct`` withs a fixed grid size and fixed condition for selecting eligible voxels.
This is a simple custom ``VoxelStruct`` with a fixed grid size and fixed condition for selecting eligible voxels.

.. note::
The following member functions except our custom ``myHash`` are mandatory.

.. code-block:: cpp
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be possible to instead add a CMakeLists.txt + source file and refer to the lines in that instead?

--------------------------

With our custom ``Voxel`` and ``VoxelStruct``, we can pass them to ``TransformFilter`` and it will handle everything for you.
Here we pass ``pcl::Filter`` for our non binary removal filter. For binary removal filters, you should pass ``pcl::FilterIndices`` .
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's binary removal?

.. code-block:: cpp

template <typename PointT>
using MyVoxelGrid = TransformFilter<pcl::Filter, MyVoxelStruct<PointT>, PointT>;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use VoxelFilter here instead of TransformFilter?

@tin1254 tin1254 force-pushed the refactor_voxel_grid branch from f89e81e to 2fe2200 Compare September 6, 2021 20:48
@BaltashovIlia
Copy link

Great job.
On Ryzen 5800x + GCC 9.3.0 + pcl default compilation settings:

----------------------------------------------------------------------------
Benchmark                                  Time             CPU   Iterations
----------------------------------------------------------------------------
table_VoxelGrid                         3.56 ms         3.56 ms          197
table_ApproximateVoxelGrid              2.88 ms         2.88 ms          243
table_FunctorVoxelGrid                  2.27 ms         2.27 ms          308
milk_cartoon_VoxelGrid                  4.63 ms         4.63 ms          151
milk_cartoon_ApproximateVoxelGrid       3.22 ms         3.22 ms          217
milk_cartoon_FunctorVoxelGrid           2.66 ms         2.66 ms          261
office_VoxelGrid                        8.06 ms         8.06 ms           86
office_ApproximateVoxelGrid             4.98 ms         4.98 ms          140
office_FunctorVoxelGrid                 6.02 ms         6.02 ms          105
five_people_VoxelGrid                   8.18 ms         8.18 ms           85
five_people_ApproximateVoxelGrid        4.70 ms         4.70 ms          149
five_people_FunctorVoxelGrid            4.04 ms         4.04 ms          171

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
module: filters priority: gsoc Reason for prioritization
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants