#if defined (_MSC_VER) && !defined (_WIN64) #pragma warning(disable:4244) // boost::number_distance::distance() // converts 64 to 32 bits integers #endif #include #include #include #include #include #include #include #include #include #include #include #include typedef CGAL::Simple_cartesian Kernel; typedef Kernel::Point_3 Point; typedef Kernel::Iso_cuboid_3 Iso_cuboid_3; typedef CGAL::Point_set_3 Point_set; typedef Point_set::Point_map Pmap; typedef Point_set::Vector_map Vmap; typedef Point_set::Property_map Imap; typedef Point_set::Property_map UCmap; typedef CGAL::Shape_detection::Point_set::Sphere_neighbor_query_for_point_set Neighbor_query; typedef CGAL::Shape_detection::Point_set::Least_squares_plane_fit_region_for_point_set Region_type; typedef CGAL::Shape_detection::Region_growing Region_growing; namespace Classification = CGAL::Classification; namespace Feature = CGAL::Classification::Feature; typedef Classification::Label_handle Label_handle; typedef Classification::Feature_handle Feature_handle; typedef Classification::Label_set Label_set; typedef Classification::Feature_set Feature_set; typedef Classification::Local_eigen_analysis Local_eigen_analysis; typedef Classification::Point_set_feature_generator Feature_generator; typedef Classification::Cluster Cluster; int main (int argc, char** argv) { std::string filename = CGAL::data_file_path("meshes/b9.ply"); std::string filename_config = "data/b9_clusters_config.bin"; if (argc > 1) filename = argv[1]; if (argc > 2) filename_config = argv[2]; std::cerr << "Reading input" << std::endl; Point_set pts; if(!(CGAL::IO::read_point_set(filename, pts, // the PLY reader expects a binary file by default CGAL::parameters::use_binary_mode(true)))) { std::cerr << "Error: cannot read " << filename << std::endl; return EXIT_FAILURE; } std::cerr << "Estimating normals" << std::endl; CGAL::Real_timer t; t.start(); pts.add_normal_map(); CGAL::jet_estimate_normals (pts, 12); t.stop(); std::cerr << "Done in " << t.time() << " second(s)" << std::endl; t.reset(); Feature_set pointwise_features; std::cerr << "Generating pointwise features" << std::endl; t.start(); Feature_generator generator (pts, pts.point_map(), 5); // using 5 scales #ifdef CGAL_LINKED_WITH_TBB pointwise_features.begin_parallel_additions(); #endif generator.generate_point_based_features (pointwise_features); // Generator should only be used with variables defined at the scope // of the generator object, thus we instantiate the normal map // outside of the function Vmap normal_map = pts.normal_map(); generator.generate_normal_based_features (pointwise_features, normal_map); #ifdef CGAL_LINKED_WITH_TBB pointwise_features.end_parallel_additions(); #endif t.stop(); std::cerr << "Done in " << t.time() << " second(s)" << std::endl; /////////////////////////////////////////////////////////////////// //! [Cluster] std::cerr << "Detecting planes and creating clusters" << std::endl; t.start(); const double search_sphere_radius = 1.0; const double max_distance_to_plane = 1.0; const double max_accepted_angle = 25.0; const std::size_t min_region_size = 10; Neighbor_query neighbor_query = CGAL::Shape_detection::Point_set::make_sphere_neighbor_query ( pts, CGAL::parameters::sphere_radius(search_sphere_radius) .point_map(pts.point_map())); Region_type region_type = CGAL::Shape_detection::Point_set::make_least_squares_plane_fit_region( pts, CGAL::parameters::maximum_distance(max_distance_to_plane) .maximum_angle(max_accepted_angle) .minimum_region_size(min_region_size)); Region_growing region_growing ( pts, neighbor_query, region_type); std::vector clusters; region_growing.detect (boost::make_function_output_iterator ([&](const std::pair>& region) -> void { // Create a new cluster. Classification::Cluster cluster (pts, pts.point_map()); for (Point_set::Index idx : region.second) cluster.insert(idx); clusters.push_back(cluster); })); t.stop(); std::cerr << clusters.size() << " clusters created in " << t.time() << " second(s)" << std::endl; t.reset(); //! [Cluster] /////////////////////////////////////////////////////////////////// std::cerr << "Computing cluster features" << std::endl; /////////////////////////////////////////////////////////////////// //! [Eigen] Local_eigen_analysis eigen = Local_eigen_analysis::create_from_point_clusters (clusters); //! [Eigen] /////////////////////////////////////////////////////////////////// t.start(); /////////////////////////////////////////////////////////////////// //! [Features] Feature_set features; // First, compute means of features. features.begin_parallel_additions(); for (std::size_t i = 0; i < pointwise_features.size(); ++ i) features.add (clusters, pointwise_features[i]); features.end_parallel_additions(); // Then, compute variances of features (and remaining cluster features). features.begin_parallel_additions(); for (std::size_t i = 0; i < pointwise_features.size(); ++ i) features.add (clusters, pointwise_features[i], // i^th feature features[i]); // mean of i^th feature features.add (clusters); features.add (clusters); for (std::size_t i = 0; i < 3; ++ i) features.add (clusters, eigen, (unsigned int)(i)); features.end_parallel_additions(); //! [Features] /////////////////////////////////////////////////////////////////// t.stop(); Label_set labels = { "ground", "vegetation", "roof" }; std::vector label_indices(clusters.size(), -1); std::cerr << "Using ETHZ Random Forest Classifier" << std::endl; Classification::ETHZ::Random_forest_classifier classifier (labels, features); std::cerr << "Loading configuration" << std::endl; std::ifstream in_config (filename_config, std::ios_base::in | std::ios_base::binary); classifier.load_configuration (in_config); std::cerr << "Classifying" << std::endl; t.reset(); t.start(); Classification::classify (clusters, labels, classifier, label_indices); t.stop(); std::cerr << "Classification done in " << t.time() << " second(s)" << std::endl; return EXIT_SUCCESS; }