#ifndef AREAFROMCONCAVEHULL_H //PCL #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // STL #include // own #include "removeconcavehullframe.h" #include "../h/inrange.h" #define AREAFROMCONCAVEHULL_H template class AreaFromConcaveHull: public pcl::PCLBase { protected: typedef typename pcl::PointCloud::Ptr PointCloudPtr; typedef typename pcl::PointCloud::ConstPtr PointCloudConstPtr; public: typedef boost::shared_ptr< AreaFromConcaveHull > Ptr; typedef boost::shared_ptr< const AreaFromConcaveHull > ConstPtr; AreaFromConcaveHull () : lineDistThreshold_ (0.1), pointIncrement_ (0.1), area_ (0.0), kdRadius_ (1), coefficients_ (new pcl::ModelCoefficients), gridLine_ (new pcl::PointCloud), extractedLine_ (new pcl::PointCloud) { }; // inline void setPointIncrement(float inc) {pointIncrement_ = inc;} inline void setKdTreeRadius(float radius) {kdRadius_ = radius;} inline void setLineDistThreshold(float threshold) {lineDistThreshold_ = threshold;} void greedyArea(float &area); void detectLines(typename pcl::PointCloud::Ptr cloud_out); void calculateAreaFromHull(typename pcl::PointCloud::Ptr cloudOut); void makeGridLine(); virtual ~AreaFromConcaveHull () { } protected: float kdRadius_; float area_; /** \brief The grid spacing in x,yz, direction. Smaller values lead to to larger and denser point clouds (default: 0.25). */ const float pointIncrement_; float lineDistThreshold_; /** \brief An input point cloud describing the surface that is to be used for nearest neighbors estimation. */ using pcl::PCLBase::input_; /** \brief The subtracted (inverted) point cloud. */ typename pcl::PointCloud::Ptr extractedLine_; typename pcl::PointCloud::Ptr gridLine_; pcl::ModelCoefficients::Ptr coefficients_; }; template void AreaFromConcaveHull::greedyArea(float &area){ // read in parameter file std::vector params; readParamsFromFile("../cfg/GreedyArea.cfg", params, true); typename pcl::PointCloud::Ptr cloudWithNormals (new pcl::PointCloud); typename pcl::PointCloud::Ptr cloudWithNormalsMLS (new pcl::PointCloud); typename pcl::PointCloud::Ptr inputXYZ (new pcl::PointCloud); typename pcl::PointCloud::Ptr filteredXYZ (new pcl::PointCloud); // manually copy all points over to pointXYZ data type pcl::PointXYZ p; for (int i = 0; i < input_->points.size(); i++){ p.x= input_->points[i].x; p.y= input_->points[i].y; p.z= input_->points[i].z; inputXYZ->points.push_back(p); } inputXYZ->width = inputXYZ->points.size(); inputXYZ->height = 1; // Create the filtering object pcl::StatisticalOutlierRemoval sor; sor.setInputCloud (inputXYZ); sor.setMeanK (50); sor.setStddevMulThresh (0.75); sor.filter (*inputXYZ); pcl::PointIndices::Ptr inliers (new pcl::PointIndices); // Create the segmentation object pcl::SACSegmentation seg; // Optional seg.setOptimizeCoefficients (true); // Mandatory seg.setModelType (pcl::SACMODEL_PLANE); seg.setMethodType (pcl::SAC_RANSAC); seg.setDistanceThreshold (params[0]); seg.setInputCloud (inputXYZ); seg.segment (*inliers, *coefficients_); pcl::ExtractIndices extract; extract.setInputCloud (inputXYZ); extract.setIndices (inliers); extract.setNegative (false); // extract.filter (*filteredXYZ); extract.filter (*inputXYZ); // estimate normals typename pcl::NormalEstimation ne; ne.setInputCloud (inputXYZ); typename pcl::search::KdTree::Ptr tree (new pcl::search::KdTree ()); ne.setSearchMethod (tree); // Use all neighbors in a sphere of radius 3cm ne.setRadiusSearch (params[1]); ne.compute (*cloudWithNormals); // concaternate the normals and the input xyz data pcl::concatenateFields(*inputXYZ, *cloudWithNormals, *cloudWithNormals); /* typename pcl::search::KdTree::Ptr treemls (new pcl::search::KdTree ()); // Init object (second point type is for the normals, even if unused) //viewer (inputXYZ); pcl::MovingLeastSquares mls; mls.setInputCloud (inputXYZ); mls.setComputeNormals(true); mls.setSearchRadius (0.1); mls.setSearchMethod(treemls); mls.setPolynomialFit (false); //mls.setPolynomialOrder (2); //mls.setUpsamplingMethod (pcl::MovingLeastSquares::RANDOM_UNIFORM_DENSITY); //mls.setUpsamplingMethod (pcl::MovingLeastSquares::VOXEL_GRID_DILATION); //mls.setDilationVoxelSize (0.1); //mls.setDilationIterations(5); //mls.setUpsamplingRadius (0.5); //mls.setUpsamplingStepSize (0.3); // Reconstruct std::cout << "starting MovingLeastSqr Normal Estimation and Smoothing..."; mls.process (*cloudWithNormalsMLS); std::cout << "Process completed." << std::endl; // viewer (*cloudWithNormalsMLS); */ typename pcl::search::KdTree::Ptr tree1 (new pcl::search::KdTree ()); pcl::GreedyProjectionTriangulation gp; pcl::PolygonMesh mesh; // GreedyTriangulation gp.setInputCloud(cloudWithNormals); gp.setSearchMethod(tree1); /*gp.setMu(2.20); gp.setSearchRadius(10.40); gp.setMaximumNearestNeighbors(500); gp.setMaximumSurfaceAngle(M_PI/4); gp.setMaximumAngle(3*M_PI/4); gp.setMinimumAngle(M_PI/18); */ gp.setMu(params[2]); gp.setSearchRadius(params[3]); gp.setMaximumNearestNeighbors(params[4]); gp.setMaximumSurfaceAngle(params[5]); gp.setMaximumAngle(params[6]); gp.setMinimumAngle(params[7]); gp.setNormalConsistency(bool(params[8])); std::cout << "\nstarting reconstructing surface mesh..." << std::endl; std::cout << " \n"; gp.reconstruct(mesh); std::cout << "Process completed." << std::endl; /**/ /* pcl::Poisson poisson; poisson.setDepth(9); poisson.setInputCloud(cloudWithNormals); poisson.reconstruct(mesh); */ cout<<"The size of polygons is "< cloud1; cloud1=*inputXYZ; int index_p1,index_p2,index_p3; float x1,x2,x3,y1,y2,y3,z1,z2,z3,a,b,c,q; for(int i=0;i viewer (new pcl::visualization::PCLVisualizer ("3D Viewer Greedy Mesh Reconstruction")); viewer->setBackgroundColor (0, 0, 0); viewer->addPolygonMesh(mesh,"meshes",0); viewer->addCoordinateSystem (1.0); viewer->initCameraParameters (); while (!viewer->wasStopped ()){ viewer->spinOnce (100); boost::this_thread::sleep (boost::posix_time::microseconds (100000)); } } template void AreaFromConcaveHull::makeGridLine(){ PointInT startPt, endPt, minPt, maxPt; pcl::getMinMax3D(*extractedLine_, minPt, maxPt); size_t nPts = extractedLine_->points.size(); startPt = extractedLine_->points[0]; endPt = extractedLine_->points[nPts-1]; ////////// detect plane //////////////////////////////// pcl::PointIndices::Ptr inliers (new pcl::PointIndices); // Create the segmentation object pcl::SACSegmentation seg; // Optional seg.setOptimizeCoefficients (true); // Mandatory seg.setModelType (pcl::SACMODEL_PLANE); seg.setMethodType (pcl::SAC_RANSAC); seg.setDistanceThreshold (lineDistThreshold_); seg.setInputCloud (input_); seg.segment (*inliers, *coefficients_); std::cout << "Normalized coeffs of Pt-Normal Eq. (Ax+By+Cz=D): " << coefficients_->values[0] << " " << coefficients_->values[1] << " " << coefficients_->values[2] << " " << coefficients_->values[3] << std::endl; float z = (startPt.z + endPt.z) / 2.0; PointInT point; // construct new points on the plane by rearranging the point normal equation for one of the coordinates. for (float x=minPt.x; x<=maxPt.x; x+=pointIncrement_) { for (float y=minPt.y; y<= maxPt.y; y+=pointIncrement_) { point.x = x; if (coefficients_->values[1] != 0) // to avoid division by zero point.y = -1.0 * (1.0 * coefficients_->values[3] + coefficients_->values[0] * x + coefficients_->values[2] * z ) / coefficients_->values[1] ; else // divisor is set to 0.0000001 if the coefficient is zero point.y = -1.0 * (1.0 * coefficients_->values[3] + coefficients_->values[0] * x + coefficients_->values[2] * z ) / 0.000001 ; point.z = z; gridLine_->points.push_back (point); } } std::cerr << "GridLine_ has: " << gridLine_->points.size () << " points. " << std::endl; viewer (gridLine_); } template void AreaFromConcaveHull::detectLines(typename pcl::PointCloud::Ptr cloudOut){ typename pcl::PointCloud::Ptr cloudFiltered (new pcl::PointCloud); pcl::copyPointCloud(*input_, *cloudFiltered); pcl::ExtractIndices extract; pcl::PointIndices::Ptr inliers (new pcl::PointIndices); // Create the segmentation object pcl::SACSegmentation seg; // Optional seg.setOptimizeCoefficients (true); // Mandatory //seg.setModelType (pcl::SACMODEL_LINE); seg.setModelType(pcl::SACMODEL_LINE); seg.setMethodType (pcl::SAC_RANSAC); seg.setDistanceThreshold (lineDistThreshold_); seg.setInputCloud (cloudFiltered); seg.segment (*inliers, *coefficients_); std::cerr << "PointCloud after LINE segmentation has: " << inliers->indices.size () << " inliers." << std::endl; // Extract the inliers extract.setInputCloud (cloudFiltered); extract.setIndices (inliers); extract.setNegative (false); extract.filter (*extractedLine_); viewer (extractedLine_); Eigen::VectorXf coeffs_; std::vector indx; std::vector distToModel; indx.push_back(*inliers->indices.begin()); indx.push_back(*inliers->indices.end()); pcl::SampleConsensusModelLine segLine(input_, false); segLine.setInputCloud(input_); segLine.computeModelCoefficients(indx,coeffs_); segLine.getDistancesToModel(coeffs_, distToModel); std::cout << coeffs_ << std::endl; makeGridLine(); pcl::copyPointCloud(*gridLine_, *cloudOut); } #endif // AREAFROMCONCAVEHULL_H