File: example_cluster_classification.cpp

package info (click to toggle)
cgal 6.0.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 141,840 kB
  • sloc: cpp: 797,081; ansic: 203,398; sh: 490; python: 411; makefile: 286; javascript: 174
file content (206 lines) | stat: -rw-r--r-- 7,471 bytes parent folder | download
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
#if defined (_MSC_VER) && !defined (_WIN64)
#pragma warning(disable:4244) // boost::number_distance::distance()
                              // converts 64 to 32 bits integers
#endif

#include <cstdlib>
#include <fstream>
#include <iostream>
#include <string>

#include <boost/iterator/function_output_iterator.hpp>

#include <CGAL/Simple_cartesian.h>
#include <CGAL/Classification.h>
#include <CGAL/Point_set_3.h>
#include <CGAL/Point_set_3/IO.h>
#include <CGAL/jet_estimate_normals.h>
#include <CGAL/Shape_detection/Region_growing.h>
#include <CGAL/Real_timer.h>

typedef CGAL::Simple_cartesian<double> Kernel;
typedef Kernel::Point_3                Point;
typedef Kernel::Iso_cuboid_3           Iso_cuboid_3;

typedef CGAL::Point_set_3<Point> Point_set;

typedef Point_set::Point_map                   Pmap;
typedef Point_set::Vector_map                  Vmap;
typedef Point_set::Property_map<int>           Imap;
typedef Point_set::Property_map<unsigned char> UCmap;


typedef CGAL::Shape_detection::Point_set::Sphere_neighbor_query_for_point_set<Point_set>                Neighbor_query;
typedef CGAL::Shape_detection::Point_set::Least_squares_plane_fit_region_for_point_set<Point_set>       Region_type;
typedef CGAL::Shape_detection::Region_growing<Neighbor_query, Region_type>                              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<Kernel, Point_set, Pmap> Feature_generator;
typedef Classification::Cluster<Point_set, Pmap>                             Cluster;

int main (int argc, char** argv)
{
  std::string filename        = CGAL::data_file_path("points_3/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<CGAL::Parallel_if_available_tag> (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<Cluster> clusters;
  region_growing.detect
    (boost::make_function_output_iterator
     ([&](const std::pair<Kernel::Plane_3, std::vector<Point_set::Index>>& region) -> void {

        // Create a new cluster.
        Classification::Cluster<Point_set, Pmap> 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<Feature::Cluster_mean_of_feature> (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<Feature::Cluster_variance_of_feature> (clusters,
                                                        pointwise_features[i], // i^th feature
                                                        features[i]);          // mean of i^th feature

  features.add<Feature::Cluster_size> (clusters);
  features.add<Feature::Cluster_vertical_extent> (clusters);

  for (std::size_t i = 0; i < 3; ++ i)
    features.add<Feature::Eigenvalue> (clusters, eigen, (unsigned int)(i));

  features.end_parallel_additions();

  //! [Features]
  ///////////////////////////////////////////////////////////////////

  t.stop();

  Label_set labels = { "ground", "vegetation", "roof" };

  std::vector<int> 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<CGAL::Parallel_if_available_tag> (clusters, labels, classifier, label_indices);
  t.stop();

  std::cerr << "Classification done in " << t.time() << " second(s)" << std::endl;
  return EXIT_SUCCESS;
}