1 #if defined (_MSC_VER) && !defined (_WIN64)
2 #pragma warning(disable:4244) // boost::number_distance::distance()
3                               // converts 64 to 32 bits integers
4 #endif
5 
6 #include "Point_set_item_classification.h"
7 #include "Color_ramp.h"
8 
9 #include <CGAL/Timer.h>
10 #include <CGAL/Memory_sizer.h>
11 
12 #include <CGAL/Three/Viewer_interface.h>
13 
14 #include <set>
15 #include <stack>
16 #include <algorithm>
17 #include <boost/array.hpp>
18 
Point_set_item_classification(Scene_points_with_normal_item * points)19 Point_set_item_classification::Point_set_item_classification(Scene_points_with_normal_item* points)
20   : m_points (points)
21   , m_generator (nullptr)
22   , m_input_is_las (false)
23 {
24   m_index_color = 1;
25 
26   reset_indices();
27 
28   Point_set::Property_map<int> cluster_id;
29   bool cluster_found = false;
30   boost::tie (cluster_id, cluster_found) = m_points->point_set()->property_map<int>("shape");
31   if (cluster_found)
32   {
33     for (Point_set::const_iterator it = m_points->point_set()->begin();
34          it != m_points->point_set()->first_selected(); ++ it)
35     {
36       int c = cluster_id[*it];
37       if (c == -1)
38         continue;
39       if (std::size_t(c) >= m_clusters.size())
40         m_clusters.resize (c + 1);
41       m_clusters[c].inliers.push_back (*it);
42     }
43   }
44 
45   backup_existing_colors_and_add_new();
46   bool training_found = false;
47   boost::tie (m_training, training_found) = m_points->point_set()->add_property_map<int>("training", -1);
48   bool classif_found = false;
49   boost::tie (m_classif, classif_found) = m_points->point_set()->add_property_map<int>("label", -1);
50 
51   training_found = !training_found; // add_property_map returns false if
52   classif_found = !classif_found;   // property was already there
53 
54   bool las_found = false;
55 
56   if (!classif_found)
57   {
58     Point_set::Property_map<unsigned char> las_classif;
59     boost::tie (las_classif, las_found) = m_points->point_set()->property_map<unsigned char>("classification");
60     if (las_found)
61     {
62       m_input_is_las = true;
63       for (Point_set::const_iterator it = m_points->point_set()->begin();
64            it != m_points->point_set()->first_selected(); ++ it)
65       {
66         unsigned char uc = las_classif[*it];
67         m_classif[*it] = int(uc);
68         if (!training_found)
69           m_training[*it] = int(uc);
70       }
71       m_points->point_set()->remove_property_map (las_classif);
72       classif_found = true;
73       training_found = true;
74     }
75   }
76 
77   if (training_found || classif_found)
78   {
79     std::vector<int> used_indices;
80 
81     for (Point_set::const_iterator it = m_points->point_set()->begin();
82          it != m_points->point_set()->first_selected(); ++ it)
83     {
84       if (training_found)
85       {
86         int l = m_training[*it];
87         if (l >= 0)
88         {
89           if (std::size_t(l) >= used_indices.size())
90             used_indices.resize(std::size_t(l + 1), -1);
91           used_indices[std::size_t(l)] = 0;
92         }
93       }
94       if (classif_found)
95       {
96         int l = m_classif[*it];
97         if (l >= 0)
98         {
99           if (std::size_t(l) >= used_indices.size())
100             used_indices.resize(std::size_t(l + 1), -1);
101           used_indices[std::size_t(l)] = 0;
102         }
103       }
104     }
105 
106     // map indices to filtered indices
107     int current_idx = 0;
108     for (std::size_t i = 0; i < used_indices.size(); ++ i)
109     {
110       if (las_found && (i < 2))
111       {
112         used_indices[i] = -1;
113         continue;
114       }
115       if (used_indices[i] == -1)
116         continue;
117 
118       used_indices[i] = current_idx;
119       ++ current_idx;
120     }
121 
122     if (std::size_t(current_idx) != used_indices.size()) // Empty indices -> reorder indices in point set
123     {
124       for (Point_set::const_iterator it = m_points->point_set()->begin();
125            it != m_points->point_set()->first_selected(); ++ it)
126       {
127         if (training_found)
128         {
129           if (las_found && (m_training[*it] == 0 || m_training[*it] == 1)) // Unclassified class in LAS
130             m_training[*it] = -1;
131           else if (m_training[*it] != -1)
132             m_training[*it] = used_indices[std::size_t(m_training[*it])];
133         }
134         if (classif_found)
135         {
136           if (las_found && (m_classif[*it] == 0 || m_classif[*it] == 1)) // Unclassified class in LAS
137             m_classif[*it] = -1;
138           else if (m_classif[*it] != -1)
139             m_classif[*it] = used_indices[std::size_t(m_classif[*it])];
140         }
141       }
142     }
143 
144     std::map<int, std::string> label_names;
145     if (las_found) // Use LAS standard
146     {
147       // label_names.insert (std::make_pair (0, std::string("never_clfied")));
148       // label_names.insert (std::make_pair (1, std::string("unclassified")));
149       label_names.insert (std::make_pair (2, std::string("ground")));
150       label_names.insert (std::make_pair (3, std::string("low_veget")));
151       label_names.insert (std::make_pair (4, std::string("med_veget")));
152       label_names.insert (std::make_pair (5, std::string("high_veget")));
153       label_names.insert (std::make_pair (6, std::string("building")));
154       label_names.insert (std::make_pair (7, std::string("noise")));
155       label_names.insert (std::make_pair (8, std::string("reserved")));
156       label_names.insert (std::make_pair (9, std::string("water")));
157       label_names.insert (std::make_pair (10, std::string("rail")));
158       label_names.insert (std::make_pair (11, std::string("road_surface")));
159       label_names.insert (std::make_pair (12, std::string("reserved_2")));
160       label_names.insert (std::make_pair (13, std::string("wire_guard")));
161       label_names.insert (std::make_pair (14, std::string("wire_conduct")));
162       label_names.insert (std::make_pair (15, std::string("trans_tower")));
163       label_names.insert (std::make_pair (16, std::string("wire_connect")));
164       label_names.insert (std::make_pair (17, std::string("bridge_deck")));
165       label_names.insert (std::make_pair (18, std::string("high_noise")));
166     }
167     else // Try to recover label names from PLY comments
168     {
169 
170       const std::string& comments = m_points->comments();
171       std::istringstream stream (comments);
172       std::string line;
173       while (getline(stream, line))
174       {
175         std::stringstream iss (line);
176         std::string tag;
177         if (iss >> tag && tag == "label")
178         {
179           int idx;
180           std::string name;
181           if (iss >> idx >> name)
182             label_names.insert (std::make_pair (idx, name));
183         }
184       }
185     }
186 
187     for (std::size_t i = 0; i < used_indices.size(); ++ i)
188     {
189       if (used_indices[i] == -1)
190         continue;
191 
192       Label_handle new_label;
193       std::map<int, std::string>::iterator found
194         = label_names.find (int(i));
195       if (found != label_names.end())
196         new_label = m_labels.add(found->second.c_str());
197       else
198       {
199         std::ostringstream oss;
200         oss << "label_" << i;
201         new_label = m_labels.add(oss.str().c_str());
202       }
203     }
204   }
205   else
206   {
207     m_labels.add("ground");
208     m_labels.add("vegetation");
209     m_labels.add("roof");
210     m_labels.add("facade");
211   }
212 
213   update_comments_of_point_set_item();
214 
215   m_sowf = new Sum_of_weighted_features (m_labels, m_features);
216   m_ethz = nullptr;
217 #ifdef CGAL_LINKED_WITH_OPENCV
218   m_random_forest = nullptr;
219 #endif
220 }
221 
222 
~Point_set_item_classification()223 Point_set_item_classification::~Point_set_item_classification()
224 {
225   if (m_sowf != nullptr)
226     delete m_sowf;
227   if (m_ethz != nullptr)
228     delete m_ethz;
229 #ifdef CGAL_LINKED_WITH_OPENCV
230   if (m_random_forest != nullptr)
231     delete m_random_forest;
232 #endif
233 #ifdef CGAL_LINKED_WITH_TENSORFLOW
234   if (m_neural_network != nullptr)
235     delete m_neural_network;
236 #endif
237   if (m_generator != nullptr)
238     delete m_generator;
239   if (m_points != nullptr)
240   {
241     // For LAS saving, convert classification info in the LAS standard
242     QString filename = m_points->property("source filename").toString();
243 
244     if (m_input_is_las ||
245         (!filename.isEmpty() && (filename.endsWith(QString(".las")) ||
246                                  filename.endsWith(QString(".LAS")) ||
247                                  filename.endsWith(QString(".laz")) ||
248                                  filename.endsWith(QString(".LAZ")))))
249     {
250       Point_set::Property_map<unsigned char> las_classif
251         = m_points->point_set()->add_property_map<unsigned char>("classification", 0).first;
252 
253       std::vector<unsigned char> label_indices;
254 
255       unsigned char custom = 19;
256       for (std::size_t i = 0; i < m_labels.size(); ++ i)
257       {
258         if (m_labels[i]->name() == "ground")
259           label_indices.push_back (2);
260         else if (m_labels[i]->name() == "low_veget")
261           label_indices.push_back (3);
262         else if (m_labels[i]->name() == "med_veget" || m_labels[i]->name() == "vegetation")
263           label_indices.push_back (4);
264         else if (m_labels[i]->name() == "high_veget")
265           label_indices.push_back (5);
266         else if (m_labels[i]->name() == "building" || m_labels[i]->name() == "roof")
267           label_indices.push_back (6);
268         else if (m_labels[i]->name() == "noise")
269           label_indices.push_back (7);
270         else if (m_labels[i]->name() == "reserved" || m_labels[i]->name() == "facade")
271           label_indices.push_back (8);
272         else if (m_labels[i]->name() == "water")
273           label_indices.push_back (9);
274         else if (m_labels[i]->name() == "rail")
275           label_indices.push_back (10);
276         else if (m_labels[i]->name() == "road_surface")
277           label_indices.push_back (11);
278         else if (m_labels[i]->name() == "reserved_2")
279           label_indices.push_back (12);
280         else if (m_labels[i]->name() == "wire_guard")
281           label_indices.push_back (13);
282         else if (m_labels[i]->name() == "wire_conduct")
283           label_indices.push_back (14);
284         else if (m_labels[i]->name() == "trans_tower")
285           label_indices.push_back (15);
286         else if (m_labels[i]->name() == "wire_connect")
287           label_indices.push_back (16);
288         else if (m_labels[i]->name() == "bridge_deck")
289           label_indices.push_back (17);
290         else if (m_labels[i]->name() == "high_noise")
291           label_indices.push_back (18);
292         else
293           label_indices.push_back (custom ++);
294       }
295 
296       for (Point_set::const_iterator it = m_points->point_set()->begin();
297            it != m_points->point_set()->end(); ++ it)
298       {
299         int c = m_classif[*it];
300         unsigned char lc = 1; // unclassified in LAS standard
301         if (c != -1)
302           lc = label_indices[std::size_t(c)];
303 
304         las_classif[*it] = lc;
305 
306         int t = m_training[*it];
307         unsigned char lt = 1; // unclassified in LAS standard
308         if (t != -1)
309           lt = label_indices[std::size_t(t)];
310 
311         m_training[*it] = int(lt);
312       }
313 
314       m_points->point_set()->remove_property_map (m_classif);
315     }
316 
317     reset_colors();
318     erase_item();
319   }
320 
321 }
322 
323 
backup_existing_colors_and_add_new()324 void Point_set_item_classification::backup_existing_colors_and_add_new()
325 {
326   if (m_points->point_set()->has_colors())
327     {
328       m_color = m_points->point_set()->add_property_map<CGAL::IO::Color>("real_color").first;
329       for (Point_set::const_iterator it = m_points->point_set()->begin();
330            it != m_points->point_set()->first_selected(); ++ it)
331         m_color[*it] = CGAL::IO::Color((unsigned char)(255 * m_points->point_set()->red(*it)),
332                                    (unsigned char)(255 * m_points->point_set()->green(*it)),
333                                    (unsigned char)(255 * m_points->point_set()->blue(*it)));
334 
335       m_points->point_set()->remove_colors();
336     }
337 
338   m_points->point_set()->add_colors();
339 }
340 
reset_colors()341 void Point_set_item_classification::reset_colors()
342 {
343   if (m_color == Point_set::Property_map<CGAL::IO::Color>())
344     m_points->point_set()->remove_colors();
345   else
346     {
347       for (Point_set::const_iterator it = m_points->point_set()->begin();
348            it != m_points->point_set()->first_selected(); ++ it)
349         m_points->point_set()->set_color(*it, m_color[*it]);
350 
351       m_points->point_set()->remove_property_map(m_color);
352     }
353 }
354 
change_color(int index,float * vmin,float * vmax)355 void Point_set_item_classification::change_color (int index, float* vmin, float* vmax)
356 {
357   m_index_color = index;
358 
359   int index_color = real_index_color();
360 
361   // Colors
362   static Color_ramp ramp;
363   ramp.build_rainbow();
364   reset_indices();
365 
366   if (index_color == -1) // item color
367     m_points->point_set()->remove_colors();
368   else
369   {
370     if (!m_points->point_set()->has_colors())
371       m_points->point_set()->add_colors();
372 
373     if (index_color == 0) // real colors
374     {
375 
376       for (Point_set::const_iterator it = m_points->point_set()->begin();
377            it != m_points->point_set()->first_selected(); ++ it)
378         m_points->point_set()->set_color(*it, m_color[*it]);
379     }
380     else if (index_color == 1) // classif
381     {
382       for (Point_set::const_iterator it = m_points->point_set()->begin();
383            it != m_points->point_set()->first_selected(); ++ it)
384       {
385         QColor color (0, 0, 0);
386         std::size_t c = m_classif[*it];
387 
388         if (c != std::size_t(-1))
389           color = label_qcolor (m_labels[c]);
390 
391         m_points->point_set()->set_color(*it, color);
392       }
393     }
394     else if (index_color == 2) // training
395     {
396       for (Point_set::const_iterator it = m_points->point_set()->begin();
397            it != m_points->point_set()->first_selected(); ++ it)
398       {
399         QColor color (0, 0, 0);
400         int c = m_training[*it];
401         int c2 = m_classif[*it];
402 
403         if (c != -1)
404           color = label_qcolor (m_labels[std::size_t(c)]);
405 
406         float div = 1;
407         if (c != c2)
408           div = 2;
409 
410         m_points->point_set()->set_color(*it, color.red() / div, color.green() / div, color.blue() / div);
411       }
412     }
413     else
414     {
415       std::size_t corrected_index = index_color - 3;
416       if (corrected_index < m_labels.size()) // Display label probabilities
417       {
418         if (m_label_probabilities.size() <= corrected_index ||
419             m_label_probabilities[corrected_index].size() != m_points->point_set()->size())
420         {
421           for (Point_set::const_iterator it = m_points->point_set()->begin();
422                it != m_points->point_set()->first_selected(); ++ it)
423             m_points->point_set()->set_color(*it);
424         }
425         else
426         {
427           for (Point_set::const_iterator it = m_points->point_set()->begin();
428                it != m_points->point_set()->first_selected(); ++ it)
429           {
430             float v = (std::max)(0.f, (std::min)(1.f, m_label_probabilities[corrected_index][*it]));
431             m_points->point_set()->set_color(*it, ramp.r(v) * 255, ramp.g(v) * 255, ramp.b(v) * 255);
432           }
433         }
434       }
435       else
436       {
437         corrected_index -= m_labels.size();
438         if (corrected_index >= m_features.size())
439         {
440           std::cerr << "Error: trying to access feature " << corrected_index << " out of " << m_features.size() << std::endl;
441           return;
442         }
443         Feature_handle feature = m_features[corrected_index];
444 
445         float min = (std::numeric_limits<float>::max)();
446         float max = -(std::numeric_limits<float>::max)();
447 
448         if (vmin != nullptr && vmax != nullptr
449             && *vmin != std::numeric_limits<float>::infinity()
450             && *vmax != std::numeric_limits<float>::infinity())
451         {
452           min = *vmin;
453           max = *vmax;
454         }
455         else
456         {
457           for (Point_set::const_iterator it = m_points->point_set()->begin();
458                it != m_points->point_set()->end(); ++ it)
459           {
460             float v = feature->value(*it);
461             min = (std::min) (min, v);
462             max = (std::max) (max, v);
463           }
464         }
465 
466         for (Point_set::const_iterator it = m_points->point_set()->begin();
467              it != m_points->point_set()->first_selected(); ++ it)
468         {
469           float v = (feature->value(*it) - min) / (max - min);
470           if (v < 0.f) v = 0.f;
471           if (v > 1.f) v = 1.f;
472 
473           m_points->point_set()->set_color(*it, ramp.r(v) * 255, ramp.g(v) * 255, ramp.b(v) * 255);
474         }
475 
476         if (vmin != nullptr && vmax != nullptr)
477         {
478           *vmin = min;
479           *vmax = max;
480         }
481       }
482     }
483   }
484 
485   for (Point_set::const_iterator it = m_points->point_set()->first_selected();
486        it != m_points->point_set()->end(); ++ it)
487     m_points->point_set()->set_color(*it, 255, 0, 0);
488 }
489 
real_index_color() const490 int Point_set_item_classification::real_index_color() const
491 {
492   int out = m_index_color;
493 
494   if (out == 0 && m_color == Point_set::Property_map<CGAL::IO::Color>())
495     out = -1;
496   return out;
497 }
498 
reset_indices()499 void Point_set_item_classification::reset_indices ()
500 {
501   Point_set::Property_map<Point_set::Index> indices
502     = m_points->point_set()->property_map<Point_set::Index>("index").first;
503 
504   m_points->point_set()->unselect_all();
505   Point_set::Index idx;
506   ++ idx;
507   for (std::size_t i = 0; i < m_points->point_set()->size(); ++ i)
508     *(indices.begin() + i) = idx ++;
509 }
510 
compute_features(std::size_t nb_scales,float voxel_size)511 void Point_set_item_classification::compute_features (std::size_t nb_scales, float voxel_size)
512 {
513   CGAL_assertion (!(m_points->point_set()->empty()));
514 
515   if (m_generator != nullptr)
516     delete m_generator;
517 
518   reset_indices();
519 
520   std::cerr << "Computing features with " << nb_scales << " scale(s) and ";
521   if (voxel_size == -1)
522     std::cerr << "automatic voxel size" << std::endl;
523   else
524     std::cerr << "voxel size = " << voxel_size << std::endl;
525 
526   m_features.clear();
527 
528   Point_set::Vector_map normal_map;
529   bool normals = m_points->point_set()->has_normal_map();
530   if (normals)
531     normal_map = m_points->point_set()->normal_map();
532 
533   bool colors = (m_color != Point_set::Property_map<CGAL::IO::Color>());
534 
535   Point_set::Property_map<boost::uint8_t> echo_map;
536   bool echo;
537   boost::tie (echo_map, echo) = m_points->point_set()->template property_map<boost::uint8_t>("echo");
538   if (!echo)
539     boost::tie (echo_map, echo) = m_points->point_set()->template property_map<boost::uint8_t>("number_of_returns");
540 
541   m_generator = new Generator (*(m_points->point_set()), m_points->point_set()->point_map(), nb_scales, voxel_size);
542 
543   CGAL::Real_timer t;
544   t.start();
545 
546 #ifdef CGAL_LINKED_WITH_TBB
547   m_features.begin_parallel_additions();
548 #endif
549 
550   m_generator->generate_point_based_features(m_features);
551   if (normals)
552     m_generator->generate_normal_based_features (m_features, normal_map);
553   if (colors)
554     m_generator->generate_color_based_features (m_features, m_color);
555   if (echo)
556     m_generator->generate_echo_based_features (m_features, echo_map);
557 
558 #ifdef CGAL_LINKED_WITH_TBB
559   m_features.end_parallel_additions();
560 #endif
561 
562   add_remaining_point_set_properties_as_features();
563 
564   delete m_sowf;
565   m_sowf = new Sum_of_weighted_features (m_labels, m_features);
566   if (m_ethz != nullptr)
567   {
568     delete m_ethz;
569     m_ethz = nullptr;
570   }
571 #ifdef CGAL_LINKED_WITH_OPENCV
572   if (m_random_forest != nullptr)
573   {
574     delete m_random_forest;
575     m_random_forest = nullptr;
576   }
577 #endif
578 
579   t.stop();
580   std::cerr << m_features.size() << " feature(s) computed in " << t.time() << " second(s)" << std::endl;
581 }
582 
select_random_region()583 void Point_set_item_classification::select_random_region()
584 {
585   m_points->point_set()->reset_indices();
586 
587   std::vector<std::size_t> selected;
588   std::vector<std::size_t> unselected;
589 
590   // If no cluster, fallback mode on grid or region selection
591   if (m_clusters.empty())
592   {
593     std::size_t scale = (rand() % m_generator->number_of_scales());
594 
595     bool use_grid = (rand() % 2);
596 
597     if (use_grid)
598     {
599       std::size_t x = (rand() % m_generator->grid(scale).width());
600       std::size_t y = (rand() % m_generator->grid(scale).height());
601       std::copy (m_generator->grid(scale).indices_begin(x,y),
602                  m_generator->grid(scale).indices_end(x,y),
603                  std::back_inserter (selected));
604     }
605     else
606     {
607       m_generator->neighborhood(0).sphere_neighbor_query (m_generator->radius_neighbors(scale))
608         (*(m_points->point_set()->points().begin() + (rand() % m_points->point_set()->size())),
609          std::back_inserter (selected));
610     }
611 
612     if (selected.empty())
613       return;
614 
615     std::sort (selected.begin(), selected.end());
616     std::size_t current_idx = 0;
617     for (Point_set::const_iterator it = m_points->point_set()->begin();
618          it != m_points->point_set()->end(); ++ it)
619       if (std::size_t(*it) == selected[current_idx])
620         current_idx ++;
621       else
622         unselected.push_back (*it);
623 
624   }
625   else
626   {
627     std::size_t c = rand() % m_clusters.size();
628     std::set<Point_set::Index> in_cluster;
629     for (std::size_t i = 0; i < m_clusters[c].size(); ++ i)
630       in_cluster.insert (m_clusters[c][i]);
631 
632     for (Point_set::const_iterator it = m_points->point_set()->begin();
633          it != m_points->point_set()->end(); ++ it)
634       if (in_cluster.find (*it) != in_cluster.end())
635         selected.push_back (*it);
636       else
637         unselected.push_back (*it);
638   }
639 
640   for (std::size_t i = 0; i < unselected.size(); ++ i)
641     *(m_points->point_set()->begin() + i) = unselected[i];
642   for (std::size_t i = 0; i < selected.size(); ++ i)
643     *(m_points->point_set()->begin() + (unselected.size() + i)) = selected[i];
644 
645   m_points->point_set()->set_first_selected
646     (m_points->point_set()->begin() + unselected.size());
647 
648 }
649 
add_remaining_point_set_properties_as_features()650 void Point_set_item_classification::add_remaining_point_set_properties_as_features()
651 {
652   const std::vector<std::string>& prop = m_points->point_set()->base().properties();
653 
654   for (std::size_t i = 0; i < prop.size(); ++ i)
655   {
656     if (prop[i] == "index" ||
657         prop[i] == "point" ||
658         prop[i] == "normal" ||
659         prop[i] == "echo" ||
660         prop[i] == "number_of_returns" ||
661         prop[i] == "training" ||
662         prop[i] == "label" ||
663         prop[i] == "classification" ||
664         prop[i] == "scan_direction_flag" ||
665         prop[i] == "real_color" ||
666         prop[i] == "shape" ||
667         prop[i] == "red" || prop[i] == "green" || prop[i] == "blue" ||
668         prop[i] == "r" || prop[i] == "g" || prop[i] == "b")
669       continue;
670 
671     if (try_adding_simple_feature<boost::int8_t>(prop[i]))
672       continue;
673     if (try_adding_simple_feature<boost::uint8_t>(prop[i]))
674       continue;
675     if (try_adding_simple_feature<boost::int16_t>(prop[i]))
676       continue;
677     if (try_adding_simple_feature<boost::uint16_t>(prop[i]))
678       continue;
679     if (try_adding_simple_feature<boost::int32_t>(prop[i]))
680       continue;
681     if (try_adding_simple_feature<boost::uint32_t>(prop[i]))
682       continue;
683     if (try_adding_simple_feature<float>(prop[i]))
684       continue;
685     if (try_adding_simple_feature<double>(prop[i]))
686       continue;
687   }
688 }
689 
train(int classifier,const QMultipleInputDialog & dialog)690 void Point_set_item_classification::train(int classifier, const QMultipleInputDialog& dialog)
691 {
692   if (m_features.size() == 0)
693     {
694       std::cerr << "Error: features not computed" << std::endl;
695       return;
696     }
697   reset_indices();
698 
699   m_label_probabilities.clear();
700   m_label_probabilities.resize (m_labels.size());
701   for (std::size_t i = 0; i < m_label_probabilities.size(); ++ i)
702     m_label_probabilities[i].resize (m_points->point_set()->size(), -1);
703 
704   std::vector<int> training (m_points->point_set()->size(), -1);
705   std::vector<int> indices (m_points->point_set()->size(), -1);
706 
707   std::vector<std::size_t> nb_label (m_labels.size(), 0);
708   std::size_t nb_total = 0;
709 
710   for (Point_set::const_iterator it = m_points->point_set()->begin();
711        it != m_points->point_set()->first_selected(); ++ it)
712   {
713     training[*it] = m_training[*it];
714     if (training[*it] != -1)
715     {
716       nb_label[std::size_t(training[*it])] ++;
717       ++ nb_total;
718     }
719   }
720 
721   std::cerr << nb_total << " point(s) used for training ("
722             << 100. * (nb_total / double(m_points->point_set()->size())) << "% of the total):" << std::endl;
723   for (std::size_t i = 0; i < m_labels.size(); ++ i)
724     std::cerr << " * " << m_labels[i]->name() << ": " << nb_label[i] << " point(s)" << std::endl;
725 
726   if (classifier == CGAL_CLASSIFICATION_SOWF_NUMBER)
727   {
728     m_sowf->train<Concurrency_tag>(training, dialog.get<QSpinBox>("trials")->value());
729     CGAL::Classification::classify<Concurrency_tag> (*(m_points->point_set()),
730                                                      m_labels, *m_sowf,
731                                                      indices, m_label_probabilities);
732   }
733   else if (classifier == CGAL_CLASSIFICATION_ETHZ_NUMBER)
734   {
735     if (m_ethz != nullptr)
736       delete m_ethz;
737     m_ethz = new ETHZ_random_forest (m_labels, m_features);
738     m_ethz->train<Concurrency_tag>(training, true,
739                                    dialog.get<QSpinBox>("num_trees")->value(),
740                                    dialog.get<QSpinBox>("max_depth")->value());
741     CGAL::Classification::classify<Concurrency_tag> (*(m_points->point_set()),
742                                                      m_labels, *m_ethz,
743                                                      indices, m_label_probabilities);
744   }
745   else if (classifier == CGAL_CLASSIFICATION_OPENCV_NUMBER)
746   {
747 #ifdef CGAL_LINKED_WITH_OPENCV
748     if (m_random_forest != nullptr)
749       delete m_random_forest;
750     m_random_forest = new Random_forest (m_labels, m_features,
751                                          dialog.get<QSpinBox>("max_depth")->value(), 5, 15,
752                                          dialog.get<QSpinBox>("num_trees")->value());
753     m_random_forest->train (training);
754     CGAL::Classification::classify<Concurrency_tag> (*(m_points->point_set()),
755                                                      m_labels, *m_random_forest,
756                                                      indices, m_label_probabilities);
757 #endif
758   }
759 
760   for (Point_set::const_iterator it = m_points->point_set()->begin();
761        it != m_points->point_set()->first_selected(); ++ it)
762     m_classif[*it] = indices[*it];
763 
764   if (m_index_color == 1 || m_index_color == 2)
765      change_color (m_index_color);
766 }
767 
run(int method,int classifier,std::size_t subdivisions,double smoothing)768 bool Point_set_item_classification::run (int method, int classifier,
769                                          std::size_t subdivisions,
770                                          double smoothing)
771 {
772   if (m_features.size() == 0)
773     {
774       std::cerr << "Error: features not computed" << std::endl;
775       return false;
776     }
777   reset_indices();
778 
779   if (classifier == CGAL_CLASSIFICATION_SOWF_NUMBER)
780     run (method, *m_sowf, subdivisions, smoothing);
781   else if (classifier == CGAL_CLASSIFICATION_ETHZ_NUMBER)
782   {
783     if (m_ethz == nullptr)
784     {
785       std::cerr << "Error: ETHZ Random Forest must be trained or have a configuration loaded first" << std::endl;
786       return false;
787     }
788     run (method, *m_ethz, subdivisions, smoothing);
789   }
790   else if (classifier == CGAL_CLASSIFICATION_OPENCV_NUMBER)
791   {
792 #ifdef CGAL_LINKED_WITH_OPENCV
793     if (m_random_forest == nullptr)
794     {
795       std::cerr << "Error: OpenCV Random Forest must be trained or have a configuration loaded first" << std::endl;
796       return false;
797     }
798     run (method, *m_random_forest, subdivisions, smoothing);
799 #endif
800   }
801 
802   return true;
803 }
804