vedi
vedi

Reputation: 11

Is there any way to reduce execution time of Radius outlier removal [pcl outlier removal]?

Now I work in Point Cloud, in my case, my Point Cloud is noisy in outlier, I want to clear the noise, so I go with the Radius outlier filter in PCL. The execution time of small clouds is good, but the time will increase as the point cloud size increases.

pcl::RadiusOutlierRemoval<pcl::PointXYZ> outrem;
 outrem.setInputCloud(box_cloud);
outrem.setRadiusSearch(0.007);
outrem.setMinNeighborsInRadius (150);
outrem.setKeepOrganized(false);
// apply filter
outrem.filter (*box_cloud);** 

In my case, it takes around 15 seconds.

Looking for a solution to reduce this time.

Upvotes: 1

Views: 1728

Answers (2)

mgrova
mgrova

Reputation: 11

I hope it is not too late for this answer.

Another possible approach is to split the point cloud into chunks and process them asynchronously using modern C++ features.

First, a function is created to simplify the reading of the code.

pcl::PointCloud<pcl::PointXYZ>::Ptr filterAsyncChunk(pcl::PointCloud<pcl::PointXYZ>::Ptr input_chunk, 
 double radius,int min_neighbors) {
    pcl::PointCloud<pcl::PointXYZ>::Ptr output_chunk(new pcl::PointCloud<pcl::PointXYZ>);
    pcl::RadiusOutlierRemoval<pcl::PointXYZ> outrem;
    outrem.setInputCloud(input_chunk);
    outrem.setRadiusSearch(radius);
    outrem.setMinNeighborsInRadius(min_neighbors);
    outrem.filter(*output_chunk);

    return output_chunk;
}

Using std::async and std::future, the chunks created are processed asynchronously.

void parallelRadiusOutlierRemovalAsync(
 pcl::PointCloud<pcl::PointXYZ>::Ptr input_cloud, pcl::PointCloud<pcl::PointXYZ>::Ptr output_cloud, 
 double radius, int min_neighbors, int num_threads) {
    int chunk_size = input_cloud->points.size() / num_threads;
    std::vector<std::future<pcl::PointCloud<pcl::PointXYZ>::Ptr>> futures;

    // Divide the input cloud into chunks and process each with std::async
    for (int i = 0; i < num_threads; ++i) {
        pcl::PointCloud<pcl::PointXYZ>::Ptr chunk(new pcl::PointCloud<pcl::PointXYZ>);
        int start_idx = i * chunk_size;
        int end_idx = (i == num_threads - 1) ? input_cloud->points.size()
                                        : (i + 1) * chunk_size;

        chunk->points.insert(chunk->points.end(),
                            input_cloud->points.begin() + start_idx,
                            input_cloud->points.begin() + end_idx);

        futures.emplace_back(std::async(std::launch::async, filterAsyncChunk, chunk,
                                        radius, min_neighbors));
    }

    // Wait for all futures and combine results
    for (auto &fut : futures) {
        *output_cloud += *fut.get();
    }
}

To use it, the function call would be very simple. The point cloud shall be divided into as many chunks as the number of threads to be used.

...

pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered(new pcl::PointCloud<pcl::PointXYZ>());

const double search_radius{0.2};
const int min_neighbours{10};
const int num_threads{10}; // If you want to use all available threads, use: 'std::thread::hardware_concurrency()'
parallelRadiusOutlierRemovalAsync(input_cloud, cloud_filtered, search_radius, min_neighbours, num_threads);

I hope this can help.

Marco.

Upvotes: 1

Mark Loyman
Mark Loyman

Reputation: 2170

pcl::RadiusOutlierRemoval

Iterates through the entire input once, and for each point, retrieves the number of neighbors within a certain radius.

So the runtime depends on the number of points in the cloud, and the search radius (the larger the radius, the slower the tree queries will be).

Possible approaches:

  1. If some points are definitely not outliers, you can exclude them using: setIndices(). For example, if you know that all your outliers have dark color (intensity < I), than you can pre-select all indices of points with intensity < I using pcl::PassThrough.
  2. Reduce search radius (and min neighbors accordingly).
  3. I believe the algorithm isn't parallelized internally. So you can split the work across multiple threads, each removing outliers from a subset of the cloud. Note that the division should be spatial and not based on indices - pcl::CropBox may be used for this.
  4. "Approximated Radius Removal" can be achieved using pcl::OctreePointCloud by iterating leaf voxel and counting number of points within a voxel (if a voxel contains less than X points, then all points in voxel should be removed).

Upvotes: 1

Related Questions