1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231
|
/**
* @file pcl_don.cpp
* Difference of normals implementation using PCL.
*
* @author Yani Ioannou
* @date 2012-03-11
*/
#include <string>
#include <pcl/io/pcd_io.h>
#include <pcl/features/normal_3d_omp.h>
#include <pcl/filters/conditional_removal.h>
#include <pcl/segmentation/extract_clusters.h>
#include <pcl/filters/voxel_grid.h>
#include <pcl/features/don.h>
#ifdef PCL_ONLY_CORE_POINT_TYPES
#include <pcl/features/impl/normal_3d_omp.hpp>
#include <pcl/segmentation/impl/extract_clusters.hpp>
#endif
using namespace pcl;
using PointT = pcl::PointXYZRGB;
using PointNT = pcl::PointNormal;
using PointOutT = pcl::PointNormal;
using SearchPtr = pcl::search::Search<PointT>::Ptr;
int main (int argc, char *argv[])
{
///The smallest scale to use in the DoN filter.
constexpr double scale1 = 0.2;
///The largest scale to use in the DoN filter.
constexpr double scale2 = 2.0;
///The minimum DoN magnitude to threshold by
constexpr double threshold = 0.25;
///segment scene into clusters with given distance tolerance using euclidean clustering
double segradius = 0.2;
//voxelization factor of pointcloud to use in approximation of normals
bool approx = false;
constexpr double decimation = 100;
if(argc < 3){
std::cerr << "Expected 2 arguments: inputfile outputfile" << std::endl;
return 0;
}
///The file to read from.
std::string infile = argv[1];
///The file to output to.
std::string outfile = argv[2];
// Load cloud in blob format
pcl::PCLPointCloud2 blob;
pcl::io::loadPCDFile (infile, blob);
pcl::PointCloud<PointT>::Ptr cloud (new pcl::PointCloud<PointT>);
std::cout << "Loading point cloud...";
pcl::fromPCLPointCloud2 (blob, *cloud);
std::cout << "done." << std::endl;
SearchPtr tree;
if (cloud->isOrganized ())
{
tree.reset (new pcl::search::OrganizedNeighbor<PointT> ());
}
else
{
tree.reset (new pcl::search::KdTree<PointT> (false));
}
tree->setInputCloud (cloud);
PointCloud<PointT>::Ptr small_cloud_downsampled;
PointCloud<PointT>::Ptr large_cloud_downsampled;
// If we are using approximation
if(approx){
std::cout << "Downsampling point cloud for approximation" << std::endl;
// Create the downsampling filtering object
pcl::VoxelGrid<PointT> sor;
sor.setDownsampleAllData (false);
sor.setInputCloud (cloud);
// Create downsampled point cloud for DoN NN search with small scale
small_cloud_downsampled = PointCloud<PointT>::Ptr(new pcl::PointCloud<PointT>);
float smalldownsample = static_cast<float> (scale1 / decimation);
sor.setLeafSize (smalldownsample, smalldownsample, smalldownsample);
sor.filter (*small_cloud_downsampled);
std::cout << "Using leaf size of " << smalldownsample << " for small scale, " << small_cloud_downsampled->size() << " points" << std::endl;
// Create downsampled point cloud for DoN NN search with large scale
large_cloud_downsampled = PointCloud<PointT>::Ptr(new pcl::PointCloud<PointT>);
constexpr float largedownsample = static_cast<float>(scale2/decimation);
sor.setLeafSize (largedownsample, largedownsample, largedownsample);
sor.filter (*large_cloud_downsampled);
std::cout << "Using leaf size of " << largedownsample << " for large scale, " << large_cloud_downsampled->size() << " points" << std::endl;
}
// Compute normals using both small and large scales at each point
pcl::NormalEstimationOMP<PointT, PointNT> ne;
ne.setInputCloud (cloud);
ne.setSearchMethod (tree);
/**
* NOTE: setting viewpoint is very important, so that we can ensure
* normals are all pointed in the same direction!
*/
ne.setViewPoint(std::numeric_limits<float>::max(),std::numeric_limits<float>::max(),std::numeric_limits<float>::max());
if(scale1 >= scale2){
std::cerr << "Error: Large scale must be > small scale!" << std::endl;
exit(EXIT_FAILURE);
}
//the normals calculated with the small scale
std::cout << "Calculating normals for scale..." << scale1 << std::endl;
pcl::PointCloud<PointNT>::Ptr normals_small_scale (new pcl::PointCloud<PointNT>);
if(approx){
ne.setSearchSurface(small_cloud_downsampled);
}
ne.setRadiusSearch (scale1);
ne.compute (*normals_small_scale);
std::cout << "Calculating normals for scale..." << scale2 << std::endl;
//the normals calculated with the large scale
pcl::PointCloud<PointNT>::Ptr normals_large_scale (new pcl::PointCloud<PointNT>);
if(approx){
ne.setSearchSurface(large_cloud_downsampled);
}
ne.setRadiusSearch (scale2);
ne.compute (*normals_large_scale);
// Create output cloud for DoN results
PointCloud<PointOutT>::Ptr doncloud (new pcl::PointCloud<PointOutT>);
copyPointCloud (*cloud, *doncloud);
std::cout << "Calculating DoN... " << std::endl;
// Create DoN operator
pcl::DifferenceOfNormalsEstimation<PointT, PointNT, PointOutT> don;
don.setInputCloud (cloud);
don.setNormalScaleLarge(normals_large_scale);
don.setNormalScaleSmall(normals_small_scale);
if(!don.initCompute ()){
std::cerr << "Error: Could not initialize DoN feature operator" << std::endl;
exit(EXIT_FAILURE);
}
//Compute DoN
don.computeFeature(*doncloud);
pcl::PCDWriter writer;
// Save DoN features
writer.write<PointOutT> (outfile, *doncloud, false);
//Filter by magnitude
std::cout << "Filtering out DoN mag <= "<< threshold << "..." << std::endl;
// build the condition
pcl::ConditionOr<PointOutT>::Ptr range_cond (new
pcl::ConditionOr<PointOutT> ());
range_cond->addComparison (pcl::FieldComparison<PointOutT>::ConstPtr (new
pcl::FieldComparison<PointOutT> ("curvature", pcl::ComparisonOps::GT, threshold)));
// build the filter
pcl::ConditionalRemoval<PointOutT> condrem;
condrem.setCondition (range_cond);
condrem.setInputCloud (doncloud);
pcl::PointCloud<PointOutT>::Ptr doncloud_filtered (new pcl::PointCloud<PointOutT>);
// apply filter
condrem.filter (*doncloud_filtered);
doncloud = doncloud_filtered;
// Save filtered output
std::cout << "Filtered Pointcloud: " << doncloud->size () << " data points." << std::endl;
std::stringstream ss;
ss << outfile.substr(0,outfile.length()-4) << "_threshold_"<< threshold << "_.pcd";
writer.write<PointOutT> (ss.str (), *doncloud, false);
//Filter by magnitude
std::cout << "Clustering using EuclideanClusterExtraction with tolerance <= "<< segradius << "..." << std::endl;
pcl::search::KdTree<PointOutT>::Ptr segtree (new pcl::search::KdTree<PointOutT>);
segtree->setInputCloud (doncloud);
std::vector<pcl::PointIndices> cluster_indices;
pcl::EuclideanClusterExtraction<PointOutT> ec;
ec.setClusterTolerance (segradius);
ec.setMinClusterSize (50);
ec.setMaxClusterSize (100000);
ec.setSearchMethod (segtree);
ec.setInputCloud (doncloud);
ec.extract (cluster_indices);
int j = 0;
for (const auto& cluster : cluster_indices)
{
pcl::PointCloud<PointOutT>::Ptr cloud_cluster_don (new pcl::PointCloud<PointOutT>);
for (const auto &index : cluster.indices){
cloud_cluster_don->points.push_back ((*doncloud)[index]);
}
cloud_cluster_don->width = cloud_cluster_don->size ();
cloud_cluster_don->height = 1;
cloud_cluster_don->is_dense = true;
std::cout << "PointCloud representing the Cluster: " << cloud_cluster_don->size () << " data points." << std::endl;
std::stringstream ss;
ss << outfile.substr(0,outfile.length()-4) << "_threshold_"<< threshold << "_cluster_" << j << ".pcd";
writer.write<PointOutT> (ss.str (), *cloud_cluster_don, false);
++j;
}
}
|