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