Student: Tin Chon Chan
Mentors: Kunal Tyagi, Markus Vieth, Haritha Jayasinghe
In PCL, there are a variety of filters, many of which contain similar filtering logic in at least part of their code. In the early years, the filters were created by different developers, a unified code design did not emerge organically. As a result, there are many boilerplate snippets throughout the filter module. Further enhancements to the filters, such as parallelizing loops, are challenging due to the necessary boilerplate code requiring changes to all the equivalent code across multiple classes without breaking them.
We found some instances of the boilerplate codes in the voxel filters: ApproximateVoxelGrid
, VoxelGrid
, GridMinimum
, VoxelGridLabel
, UniformSampling
(and also in the binary removal filters)
Our goal was to investigate a unified code design that eliminates redundancy by refactoring similar code pieces across multiple filters without breaking the present API, while simultaneously attempting to simplify implementation and increase runtime speed.
We started with the most often used voxel filters with the many redundancies. After a close inspection, we noticed a similar pattern and boilerplate codes in the existing code. Following that, I proposed different code designs with highly abstracted classes that allow PCL users to simply construct their own grid filter, by enabling some level of customization and maximizing the reusability of our implements. After some discussions with my mentors, we selected some plausible designs and developed prototypes for further discussions. In the end, I extracted the voxel filters logic and implemented them into new building blocks with template metaprogramming. I refactored two voxel filters and applied the new design. It was seen via benchmarks that the new design can eliminate duplicate codes and enhance performance by up to 40%. This design allows PCL users to reuse our existing implementations while focusing on the parts that require separate logic for their custom filter.
In addition to voxel filters, we also explored new code designs for other filters. There is a new proposed filter design that takes a lambda function or functor as the filtering logic. I tried to apply the newly introduced design to some current filters with different approaches. In the end, it proved to have a huge potential that can remove lots of boilerplate code as well as significantly improve the runtime performance of existing filters.
During the course of the project, I realized I didn't have a lot of expertise in code design. Code quality is rarely a concern in academic projects as long as they work, and when I had to develop classes with high abstractions in mind, this deficiency became even more evident. There were different tradeoffs to be made between code design complexity, level of customizability, and upgradeability. Many thanks to my mentors @kunaltyagi @mvieth @haritha-j who provided me with a wealth of useful and timely input on the code designs and quality.
Template metaprogramming is another obstacle for me. This is a skill I never needed in my academic assignments, so it was no surprise that I was totally unaware of it. I spent a lot of time learning the skills and was finally able to apply them during this project.
Finally, because it is not uncommon to filter point clouds with millions of points, performance can easily be a problem hidden elsewhere in the code, especially since everything that can go wrong with deep abstraction of C++. I spent a lot of time testing multiple implementations for the filters to ensure that every line of code is efficient enough. Fortunately, all of the refactored filters perform noticeably better than the original implementations.
VoxelGrid
andVoxelGridLabel
were refactored and implemented in the experimental namespace as a proof of the new code design.VoxelGrid
is now comprised of several building blocks:Voxel
(define the voxel grid cell),VoxelStruct
(implementVoxelGrid
filtering logic),VoxelFilter
(implement API for voxel based grid filters),CartesianFilter
(implement common API for cartesian based grid filter),TransformFilter
(implement the abstracted logic of grid filters, acceptVoxelStruct
as the filtering logic definition).VoxelGridLabel
reused all building blocks other than a custom voxel grid cell.- The code design concept is also documented as a tutorial.
PassThrough
andCropbox
were refactored usingFunctorFilter
. AFunctorFilter
object will be created for each filtering operation inside applyFilter. Only the core logic for filtering a point is needed to implement since the boilerplate iteration is handled byFunctorFilter
.
- Base of grid filters
- VoxelGrid
- VoxelGridLabel
- CropBox & PassThrough
- Add deprecations in current VoxelGrid
- Fix
VoxelGrid
error with point types with label - Finalize API changes for
VoxelGrid
leaf layout (discussion)
- A unified code structure design has been implemented. The new grid filter code design allows users to customize their grid filters while also maximizing the reusability of our implementations.
VoxelGrid
andVoxelGridLabel
were refactored, visible boilerplate codes were eliminated and performance was improved.- Several approaches for integrating
FunctionFilter
were investigated and the new code design was applied toPassThrough
andCropbox
. - It has been shown that
FunctionFilter
is capable of removing many boilerplate codes in the filter module while also noticeably improving runtime performance. - Runtime improvements:
- Up to 40% with
VoxelGrid
andVoxelGridLabel
- Up to 17% with
PassThrough
- Up to 37% with
Cropbox
- Up to 40% with