diff --git a/Classification/examples/Classification/example_classification.cpp b/Classification/examples/Classification/example_classification.cpp index 07b1147b47d..b20a7860d69 100644 --- a/Classification/examples/Classification/example_classification.cpp +++ b/Classification/examples/Classification/example_classification.cpp @@ -83,7 +83,7 @@ int main (int argc, char** argv) std::cerr << "Computing features" << std::endl; Feature_set features; - features.begin_parallel_additions(); + features.begin_parallel_additions(); // No effect in sequential mode Feature_handle distance_to_plane = features.add (pts, Pmap(), eigen); Feature_handle dispersion = features.add (pts, Pmap(), grid, @@ -91,7 +91,7 @@ int main (int argc, char** argv) Feature_handle elevation = features.add (pts, Pmap(), grid, radius_dtm); - features.end_parallel_additions(); + features.end_parallel_additions(); // No effect in sequential mode //! [Features] /////////////////////////////////////////////////////////////////// @@ -100,9 +100,15 @@ int main (int argc, char** argv) //! [Labels] Label_set labels; + + // Init name only Label_handle ground = labels.add ("ground"); - Label_handle vegetation = labels.add ("vegetation"); - Label_handle roof = labels.add ("roof"); + + // Init name and color + Label_handle vegetation = labels.add ("vegetation", CGAL::Color(0,255,0)); + + // Init name, Color and standard index (here, ASPRS building index) + Label_handle roof = labels.add ("roof", CGAL::Color (255, 0, 0), 6); //! [Labels] /////////////////////////////////////////////////////////////////// diff --git a/Classification/examples/Classification/example_ethz_random_forest.cpp b/Classification/examples/Classification/example_ethz_random_forest.cpp index 4e625e4381c..0075b870b06 100644 --- a/Classification/examples/Classification/example_ethz_random_forest.cpp +++ b/Classification/examples/Classification/example_ethz_random_forest.cpp @@ -37,7 +37,7 @@ typedef Classification::Point_set_feature_generator int main (int argc, char** argv) { std::string filename = "data/b9_training.ply"; - + if (argc > 1) filename = argv[1]; @@ -46,7 +46,7 @@ int main (int argc, char** argv) std::cerr << "Reading input" << std::endl; in >> pts; - + Imap label_map; bool lm_found = false; std::tie (label_map, lm_found) = pts.property_map ("label"); @@ -57,17 +57,17 @@ int main (int argc, char** argv) } Feature_set features; - + std::cerr << "Generating features" << std::endl; CGAL::Real_timer t; t.start(); Feature_generator generator (pts, pts.point_map(), 5); // using 5 scales - + features.begin_parallel_additions(); generator.generate_point_based_features (features); features.end_parallel_additions(); - + t.stop(); std::cerr << "Done in " << t.time() << " second(s)" << std::endl; @@ -78,10 +78,10 @@ int main (int argc, char** argv) Label_handle roof = labels.add ("roof"); std::vector label_indices(pts.size(), -1); - + std::cerr << "Using ETHZ Random Forest Classifier" << std::endl; Classification::ETHZ::Random_forest_classifier classifier (labels, features); - + std::cerr << "Training" << std::endl; t.reset(); t.start(); @@ -96,7 +96,7 @@ int main (int argc, char** argv) generator.neighborhood().k_neighbor_query(12), 0.2f, 1, label_indices); t.stop(); - + std::cerr << "Classification with graphcut done in " << t.time() << " second(s)" << std::endl; std::cerr << "Precision, recall, F1 scores and IoU:" << std::endl; @@ -123,21 +123,12 @@ int main (int argc, char** argv) for (std::size_t i = 0; i < label_indices.size(); ++ i) { label_map[i] = label_indices[i]; // update label map with computed classification - - Label_handle label = labels[label_indices[i]]; - if (label == ground) - { - red[i] = 245; green[i] = 180; blue[i] = 0; - } - else if (label == vegetation) - { - red[i] = 0; green[i] = 255; blue[i] = 27; - } - else if (label == roof) - { - red[i] = 255; green[i] = 0; blue[i] = 170; - } + Label_handle label = labels[label_indices[i]]; + const CGAL::Color& color = label->color(); + red[i] = color.red(); + green[i] = color.green(); + blue[i] = color.blue(); } // Save configuration for later use @@ -150,6 +141,6 @@ int main (int argc, char** argv) f << pts; std::cerr << "All done" << std::endl; - + return EXIT_SUCCESS; } diff --git a/Classification/examples/Classification/example_opencv_random_forest.cpp b/Classification/examples/Classification/example_opencv_random_forest.cpp index f368ebb9485..2491e05d0a7 100644 --- a/Classification/examples/Classification/example_opencv_random_forest.cpp +++ b/Classification/examples/Classification/example_opencv_random_forest.cpp @@ -37,7 +37,7 @@ typedef Classification::Point_set_feature_generator int main (int argc, char** argv) { std::string filename = "data/b9_training.ply"; - + if (argc > 1) filename = argv[1]; @@ -46,7 +46,7 @@ int main (int argc, char** argv) std::cerr << "Reading input" << std::endl; in >> pts; - + Imap label_map; bool lm_found = false; std::tie (label_map, lm_found) = pts.property_map ("label"); @@ -57,7 +57,7 @@ int main (int argc, char** argv) } Feature_set features; - + std::cerr << "Generating features" << std::endl; CGAL::Real_timer t; t.start(); @@ -67,7 +67,7 @@ int main (int argc, char** argv) features.begin_parallel_additions(); generator.generate_point_based_features (features); features.end_parallel_additions(); - + t.stop(); std::cerr << "Done in " << t.time() << " second(s)" << std::endl; @@ -78,10 +78,10 @@ int main (int argc, char** argv) Label_handle roof = labels.add ("roof"); std::vector label_indices(pts.size(), -1); - + std::cerr << "Using OpenCV Random Forest Classifier" << std::endl; Classification::OpenCV::Random_forest_classifier classifier (labels, features); - + std::cerr << "Training" << std::endl; t.reset(); t.start(); @@ -96,12 +96,12 @@ int main (int argc, char** argv) generator.neighborhood().k_neighbor_query(12), 0.2f, 1, label_indices); t.stop(); - + std::cerr << "Classification with graphcut done in " << t.time() << " second(s)" << std::endl; std::cerr << "Precision, recall, F1 scores and IoU:" << std::endl; Classification::Evaluation evaluation (labels, pts.range(label_map), label_indices); - + for (Label_handle l : labels) { std::cerr << " * " << l->name() << ": " @@ -123,21 +123,12 @@ int main (int argc, char** argv) for (std::size_t i = 0; i < label_indices.size(); ++ i) { label_map[i] = label_indices[i]; // update label map with computed classification - - Label_handle label = labels[label_indices[i]]; - if (label == ground) - { - red[i] = 245; green[i] = 180; blue[i] = 0; - } - else if (label == vegetation) - { - red[i] = 0; green[i] = 255; blue[i] = 27; - } - else if (label == roof) - { - red[i] = 255; green[i] = 0; blue[i] = 170; - } + Label_handle label = labels[label_indices[i]]; + const CGAL::Color& color = label->color(); + red[i] = color.red(); + green[i] = color.green(); + blue[i] = color.blue(); } // Write result @@ -146,6 +137,6 @@ int main (int argc, char** argv) f << pts; std::cerr << "All done" << std::endl; - + return EXIT_SUCCESS; } diff --git a/Classification/examples/Classification/example_tensorflow_neural_network.cpp b/Classification/examples/Classification/example_tensorflow_neural_network.cpp index 9779f201d68..6a454360285 100644 --- a/Classification/examples/Classification/example_tensorflow_neural_network.cpp +++ b/Classification/examples/Classification/example_tensorflow_neural_network.cpp @@ -37,7 +37,7 @@ typedef Classification::Point_set_feature_generator int main (int argc, char** argv) { std::string filename = "data/b9_training.ply"; - + if (argc > 1) filename = argv[1]; @@ -46,7 +46,7 @@ int main (int argc, char** argv) std::cerr << "Reading input" << std::endl; in >> pts; - + Imap label_map; bool lm_found = false; std::tie (label_map, lm_found) = pts.property_map ("label"); @@ -57,17 +57,17 @@ int main (int argc, char** argv) } Feature_set features; - + std::cerr << "Generating features" << std::endl; CGAL::Real_timer t; t.start(); Feature_generator generator (pts, pts.point_map(), 5); // using 5 scales - + features.begin_parallel_additions(); generator.generate_point_based_features (features); features.end_parallel_additions(); - + t.stop(); std::cerr << "Done in " << t.time() << " second(s)" << std::endl; @@ -78,10 +78,10 @@ int main (int argc, char** argv) Label_handle roof = labels.add ("roof"); std::vector label_indices(pts.size(), -1); - + std::cerr << "Using TensorFlow neural network Classifier" << std::endl; Classification::TensorFlow::Neural_network_classifier<> classifier (labels, features); - + std::cerr << "Training" << std::endl; t.reset(); t.start(); @@ -98,12 +98,12 @@ int main (int argc, char** argv) generator.neighborhood().k_neighbor_query(12), 0.2f, 1, label_indices); t.stop(); - + std::cerr << "Classification with graphcut done in " << t.time() << " second(s)" << std::endl; std::cerr << "Precision, recall, F1 scores and IoU:" << std::endl; Classification::Evaluation evaluation (labels, pts.range(ground_truth), label_indices); - + for (Label_handle l : labels) { std::cerr << " * " << l->name() << ": " @@ -125,21 +125,12 @@ int main (int argc, char** argv) for (std::size_t i = 0; i < label_indices.size(); ++ i) { label_map[i] = label_indices[i]; // update label map with computed classification - - Label_handle label = labels[label_indices[i]]; - if (label == ground) - { - red[i] = 245; green[i] = 180; blue[i] = 0; - } - else if (label == vegetation) - { - red[i] = 0; green[i] = 255; blue[i] = 27; - } - else if (label == roof) - { - red[i] = 255; green[i] = 0; blue[i] = 170; - } + Label_handle label = labels[label_indices[i]]; + const CGAL::Color& color = label->color(); + red[i] = color.red(); + green[i] = color.green(); + blue[i] = color.blue(); } // Write result @@ -148,6 +139,6 @@ int main (int argc, char** argv) f << pts; std::cerr << "All done" << std::endl; - + return EXIT_SUCCESS; } diff --git a/Classification/include/CGAL/Classification/Evaluation.h b/Classification/include/CGAL/Classification/Evaluation.h index 1b5294adc7a..0fc096f30c2 100644 --- a/Classification/include/CGAL/Classification/Evaluation.h +++ b/Classification/include/CGAL/Classification/Evaluation.h @@ -38,7 +38,6 @@ namespace Classification { class Evaluation { const Label_set& m_labels; - mutable std::map m_map_labels; std::vector > m_confusion; // confusion matrix public: @@ -56,7 +55,7 @@ public: { init(); } - + /*! \brief Instantiates an evaluation object and computes all @@ -86,9 +85,6 @@ public: /// \cond SKIP_IN_MANUAL void init() { - for (std::size_t i = 0; i < m_labels.size(); ++ i) - m_map_labels[m_labels[i]] = i; - m_confusion.resize (m_labels.size()); for (std::size_t i = 0; i < m_confusion.size(); ++ i) m_confusion[i].resize (m_labels.size(), 0); @@ -103,7 +99,7 @@ public: } /// \endcond - + /*! \brief Append more items to the evaluation object. @@ -129,11 +125,11 @@ public: int res = static_cast(get<1>(p)); if (gt == -1 || res == -1) continue; - + ++ m_confusion[std::size_t(res)][std::size_t(gt)]; - } + } } - + /// @} /// \name Label Evaluation @@ -149,17 +145,17 @@ public: */ float precision (Label_handle label) const { - std::size_t idx = m_map_labels[label]; + std::size_t idx = label->index(); if (!label_has_ground_truth(idx)) return std::numeric_limits::quiet_NaN(); - + std::size_t total = 0; for (std::size_t i = 0; i < m_labels.size(); ++ i) total += m_confusion[idx][i]; if (total == 0) return 0.f; - + return m_confusion[idx][idx] / float(total); } @@ -173,10 +169,10 @@ public: */ float recall (Label_handle label) const { - std::size_t idx = m_map_labels[label]; + std::size_t idx = label->index(); if (!label_has_ground_truth(idx)) return std::numeric_limits::quiet_NaN(); - + std::size_t total = 0; for (std::size_t i = 0; i < m_labels.size(); ++ i) total += m_confusion[i][idx]; @@ -201,7 +197,7 @@ public: if (p == 0.f && r == 0.f) return 0.f; - + return 2.f * p * r / (p + r); } @@ -215,8 +211,8 @@ public: */ float intersection_over_union (Label_handle label) const { - std::size_t idx = m_map_labels[label]; - + std::size_t idx = label->index(); + std::size_t total = 0; for (std::size_t i = 0; i < m_labels.size(); ++ i) { @@ -229,7 +225,7 @@ public: } /// @} - + /// \name Global Evaluation /// @{ @@ -239,11 +235,11 @@ public: */ std::size_t confusion (Label_handle ground_truth, Label_handle result) { - std::size_t idx_gt = m_map_labels[ground_truth]; - std::size_t idx_r = m_map_labels[result]; + std::size_t idx_gt = ground_truth->index(); + std::size_t idx_r = result->index(); return m_confusion[idx_gt][idx_r]; } - + /*! \brief Returns the number of misclassified items. */ @@ -287,7 +283,7 @@ public: } return true_positives / float(total); } - + /*! \brief Returns the mean \f$F_1\f$ score of the training over all labels (see `f1_score()`). @@ -304,7 +300,7 @@ public: } return mean / nb; } - + /*! \brief Returns the mean intersection over union of the training over all labels (see `intersection_over_union()`). @@ -329,7 +325,7 @@ public: /// \name Output Formatting Functions /// @{ - + /*! \brief Outputs the evaluation in a simple ASCII format to the stream `os`. */ @@ -387,7 +383,7 @@ public: << "" << std::endl; const Label_set& labels = evaluation.m_labels; - + os << "

Detailed Results

" << std::endl << "" << std::endl << " " << std::endl @@ -414,7 +410,7 @@ public: << " " << std::endl << " " << std::endl << " " << std::endl; - + os << "
" << std::endl; os << "

Confusion Matrix

" << std::endl @@ -444,7 +440,7 @@ public: os << " " << sum << "" << std::endl; os << " " << std::endl; } - + os << " " << std::endl << " GROUND TRUTH" << std::endl; std::size_t total = 0; @@ -461,18 +457,17 @@ href=\"https://doc.cgal.org/latest/Classification/index.html\">CGAL \ Classification package.

" << std::endl << "" << std::endl << "" << std::endl; - + return os; } - + /// @} }; - + } // namespace Classification } // namespace CGAL #endif // CGAL_CLASSIFICATION_EVALUATION_H - diff --git a/Classification/include/CGAL/Classification/Label.h b/Classification/include/CGAL/Classification/Label.h index b0bf875d0a5..c112997daab 100644 --- a/Classification/include/CGAL/Classification/Label.h +++ b/Classification/include/CGAL/Classification/Label.h @@ -13,6 +13,7 @@ #define CGAL_CLASSIFICATION_LABEL_H #include +#include #include @@ -20,6 +21,10 @@ namespace CGAL { namespace Classification { +/// \cond SKIP_IN_MANUAL +class Label_set; +/// \endcond + /*! \ingroup PkgClassificationLabel @@ -32,19 +37,56 @@ class Label private: std::string m_name; + std::size_t m_index; + std::size_t m_standard_index; + CGAL::Color m_color; + + friend Label_set; public: - /*! - \param name name of the classification label (e.g. vegetation). - */ - Label (std::string name) : m_name (name) { } + /// \cond SKIP_IN_MANUAL + // Undocumented: Labels should be created by the set + Label (std::string name, std::size_t index, std::size_t standard_index, + const CGAL::Color& color) + : m_name (name), m_index (index), m_standard_index (standard_index) + , m_color (color) + { } + /// \endcond + /*! + returns the name of the classification label (e.g. vegetation). + */ const std::string& name() const { return m_name; } - /// \cond SKIP_IN_MANUAL void set_name (const std::string& name) { m_name = name; } - /// \endcond + + /*! + returns the index of the classification label in the label set. + + \note This index cannot be changed by the user and is handled directly by the label set. + */ + std::size_t index() const { return m_index; } + + /*! + returns the standard index of the classification label (i.e. index in the ASPRS standard). + + \note This index is purely user-oriented and is not used by the classification algorithms. + */ + std::size_t standard_index() const { return m_standard_index; } + + void set_standard_index(std::size_t idx) { m_standard_index = idx; } + + /*! + returns the color used to represent the label. + + \note The color is purely user-oriented and is not used by the + classification algorithms. It is not to be confused with a color + attribute embedded in a data set which _can_ be used (see + `Color_channel`). + */ + const CGAL::Color& color() const { return m_color; } + void set_color (const Color& color) { m_color = color; } }; #ifdef DOXYGEN_RUNNING diff --git a/Classification/include/CGAL/Classification/Label_set.h b/Classification/include/CGAL/Classification/Label_set.h index 8720060b5e8..c4fab84a9d3 100644 --- a/Classification/include/CGAL/Classification/Label_set.h +++ b/Classification/include/CGAL/Classification/Label_set.h @@ -16,6 +16,8 @@ #include +#include + #include namespace CGAL { @@ -32,6 +34,8 @@ algorithms. class Label_set { using Base = std::vector; + + CGAL::Random m_random; Base m_labels; public: @@ -52,14 +56,69 @@ public: Label_set(std::initializer_list labels) { for (const char* l : labels) - m_labels.push_back (std::make_shared(l)); + add (l); } /*! \brief Adds a label. + \note Names, standard indices and colors are not used for + identification: two labels in the same set can have the same name, + standard index or color, but not the same handle. Each call to + `add()` generates a new distinct label. + + \param name name of the label. + + \param color used to represent the label. + + \param standard_index standard index of the classification label + (i.e. index in the ASPRS standard). + + \return a handle to the newly added label. + */ + Label_handle add (const char* name, + CGAL::Color color, + std::size_t standard_index = -1) + { + Label_handle out = std::make_shared + (name, m_labels.size(), standard_index, color); + m_labels.push_back (out); + return out; + } + + + /*! + \brief Adds a label with default standard index and color. + + This functions tries to map label names to standard ASPRS labels + and automatically picks the `standard_index` and `color` of the + label: + + - \"unassigned\" is given standard index 2 and color `(0, 0, 0)` + - \"ground\" is given standard index 2 and color `(186, 189, 182)` + - \"low_vegetation\" is given standard index 3 and color `(78, 154, 6)` + - \"medium_vegetation\" is given standard index 4 and color `(138, 226, 52)` + - \"high_vegetation\" is given standard index 5 and color `(204, 255, 201)` + - \"building\" is given standard index 6 and color `(245, 121, 0)` + - \"noise\" is given standard index 7 and color `(128, 0, 0)` + - \"reserved\" is given standard index 8 and color `(233, 185, 110)` + - \"water\" is given standard index 9 and color `(114, 159, 207)` + - \"rail\" is given standard index 10 and color `(136, 46, 25)` + - \"road_surface\" is given standard index 11 and color `(56, 56, 56)` + - \"reserved_2\" is given standard index 12 and color `(193, 138, 51)` + - \"wire_guard\" is given standard index 13 and color `(37, 61, 136)` + - \"wire_conductor\" is given standard index 14 and color `(173, 127, 168)` + - \"transmission_tower\" is given standard index 15 and color `(136, 138, 133)` + - \"wire_connect\" is given standard index 16 and color `(145, 64, 236)` + - \"bridge_deck\" is given standard index 17 and color `(213, 93, 93)` + - \"high_noise\" is given standard index 18 and color `(255, 0, 0)` + + If the name is not found, the label is given standard index + `std::size_t(-1)` and a random color. + \note Names are not used for identification: two labels in the - same set can have the same name (but not the same handle). + same set can have the same name but not the same handle. Each call + to `add()` generates a new distinct label. \param name name of the label. @@ -67,10 +126,77 @@ public: */ Label_handle add (const char* name) { - Label_handle out = std::make_shared (name); - m_labels.push_back (out); - return out; + static std::unordered_map > init_map; + if (init_map.empty()) + { + init_map.insert (std::make_pair ("unassigned", + std::make_pair (2, CGAL::Color (0, 0, 0)))); + init_map.insert (std::make_pair ("ground", + std::make_pair (2, CGAL::Color (186, 189, 182)))); + init_map.insert (std::make_pair ("low_vegetation", + std::make_pair (3, CGAL::Color (78, 154, 6)))); + init_map.insert (std::make_pair ("medium_vegetation", + std::make_pair (4, CGAL::Color (138, 226, 52)))); + init_map.insert (std::make_pair ("high_vegetation", + std::make_pair (5, CGAL::Color (204, 255, 201)))); + init_map.insert (std::make_pair ("building", + std::make_pair (6, CGAL::Color (245, 121, 0)))); + init_map.insert (std::make_pair ("noise", + std::make_pair (7, CGAL::Color (128, 0, 0)))); + init_map.insert (std::make_pair ("reserved", + std::make_pair (8, CGAL::Color (233, 185, 110)))); + init_map.insert (std::make_pair ("water", + std::make_pair (9, CGAL::Color (114, 159, 207)))); + init_map.insert (std::make_pair ("rail", + std::make_pair (10, CGAL::Color (136, 46, 25)))); + init_map.insert (std::make_pair ("road_surface", + std::make_pair (11, CGAL::Color (56, 56, 56)))); + init_map.insert (std::make_pair ("reserved_2", + std::make_pair (12, CGAL::Color (193, 138, 51)))); + init_map.insert (std::make_pair ("wire_guard", + std::make_pair (13, CGAL::Color (37, 61, 136)))); + init_map.insert (std::make_pair ("wire_conductor", + std::make_pair (14, CGAL::Color (173, 127, 168)))); + init_map.insert (std::make_pair ("wire_conduct", + std::make_pair (14, CGAL::Color (173, 127, 168)))); + init_map.insert (std::make_pair ("transmission_tower", + std::make_pair (15, CGAL::Color (136, 138, 133)))); + init_map.insert (std::make_pair ("trans_tower", + std::make_pair (15, CGAL::Color (136, 138, 133)))); + init_map.insert (std::make_pair ("wire_connect", + std::make_pair (16, CGAL::Color (145, 64, 236)))); + init_map.insert (std::make_pair ("bridge_deck", + std::make_pair (17, CGAL::Color (213, 93, 93)))); + init_map.insert (std::make_pair ("high_noise", + std::make_pair (18, CGAL::Color (255, 0, 0)))); + + // Undocumented additions + init_map.insert (std::make_pair ("low_veget", + std::make_pair (3, CGAL::Color (78, 154, 6)))); + init_map.insert (std::make_pair ("medium_veget", + std::make_pair (4, CGAL::Color (138, 226, 52)))); + init_map.insert (std::make_pair ("vegetation", + std::make_pair (4, CGAL::Color (138, 226, 52)))); + init_map.insert (std::make_pair ("high_veget", + std::make_pair (5, CGAL::Color (204, 255, 201)))); + init_map.insert (std::make_pair ("roof", + std::make_pair (6, CGAL::Color (245, 121, 0)))); + init_map.insert (std::make_pair ("facade", + std::make_pair (-1, CGAL::Color (77, 131, 186)))); + } + + std::string sname (name); + auto found = init_map.find (sname); + if (found == init_map.end()) + return add (name, + CGAL::Color ((unsigned char)(m_random.get_int(64, 192)), + (unsigned char)(m_random.get_int(64, 192)), + (unsigned char)(m_random.get_int(64, 192)))); + + // else + return add (name, found->second.second, found->second.first); } + /// \endcond /*! \brief Removes a label. @@ -82,17 +208,14 @@ public: */ bool remove (Label_handle label) { - std::size_t idx = (std::size_t)(-1); - for (std::size_t i = 0; i < m_labels.size(); ++ i) - if (m_labels[i] == label) - { - m_labels.erase (m_labels.begin() + i); - idx = i; - break; - } - if (idx == (std::size_t)(-1)) + if (label->index() >= m_labels.size() + || m_labels[label->index()] != label) return false; + for (std::size_t i = label->index() + 1; i < m_labels.size(); ++ i) + m_labels[i]->m_index --; + m_labels.erase (m_labels.begin() + label->index()); + return true; } @@ -117,7 +240,6 @@ public: return m_labels[i]; } - /*! \brief Removes all labels. */ @@ -125,8 +247,6 @@ public: { m_labels.clear(); } - - }; diff --git a/Classification/include/CGAL/Classification/Mesh_feature_generator.h b/Classification/include/CGAL/Classification/Mesh_feature_generator.h index cb5c37f9e34..706cfed73de 100644 --- a/Classification/include/CGAL/Classification/Mesh_feature_generator.h +++ b/Classification/include/CGAL/Classification/Mesh_feature_generator.h @@ -34,19 +34,7 @@ #include -#include -#include -#include -#include -#include - #include -#include - -#ifdef CGAL_LINKED_WITH_TBB -#include -#include -#endif // CGAL_LINKED_WITH_TBB namespace CGAL { diff --git a/Classification/include/CGAL/Classification/Point_set_feature_generator.h b/Classification/include/CGAL/Classification/Point_set_feature_generator.h index 98f86bc37c8..ba0c92f444a 100644 --- a/Classification/include/CGAL/Classification/Point_set_feature_generator.h +++ b/Classification/include/CGAL/Classification/Point_set_feature_generator.h @@ -34,14 +34,7 @@ #include #include -#include -#include -#include -#include -#include - #include -#include namespace CGAL { diff --git a/Polyhedron/demo/Polyhedron/Plugins/Classification/Cluster_classification.cpp b/Polyhedron/demo/Polyhedron/Plugins/Classification/Cluster_classification.cpp index fa29d05a15c..91034c56d2b 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Classification/Cluster_classification.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Classification/Cluster_classification.cpp @@ -51,7 +51,7 @@ Cluster_classification::Cluster_classification(Scene_points_with_normal_item* po bool classif_found = false; boost::tie (m_classif, classif_found) = m_points->point_set()->add_property_map("label", -1); - training_found = !training_found; // add_property_map returns false if + training_found = !training_found; // add_property_map returns false if classif_found = !classif_found; // property was already there bool las_found = false; @@ -76,11 +76,11 @@ Cluster_classification::Cluster_classification(Scene_points_with_normal_item* po training_found = true; } } - + if (training_found || classif_found) { std::vector used_indices; - + for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->first_selected(); ++ it) { @@ -122,12 +122,12 @@ Cluster_classification::Cluster_classification(Scene_points_with_normal_item* po ++ current_idx; } - + for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->first_selected(); ++ it) { int c = m_cluster_id[*it]; - + if (training_found) { if (std::size_t(current_idx) != used_indices.size()) // Empty indices -> reorder indices in point set @@ -153,7 +153,7 @@ Cluster_classification::Cluster_classification(Scene_points_with_normal_item* po m_clusters[c].label() = m_classif[*it]; } } - + std::map label_names; if (las_found) // Use LAS standard { @@ -196,7 +196,7 @@ Cluster_classification::Cluster_classification(Scene_points_with_normal_item* po } } } - + for (std::size_t i = 0; i < used_indices.size(); ++ i) { if (used_indices[i] == -1) @@ -213,8 +213,6 @@ Cluster_classification::Cluster_classification(Scene_points_with_normal_item* po oss << "label_" << i; new_label = m_labels.add(oss.str().c_str()); } - - m_label_colors.push_back (this->get_new_label_color (new_label->name())); } } else @@ -223,11 +221,8 @@ Cluster_classification::Cluster_classification(Scene_points_with_normal_item* po m_labels.add("vegetation"); m_labels.add("roof"); m_labels.add("facade"); - - for (std::size_t i = 0; i < m_labels.size(); ++ i) - m_label_colors.push_back (this->get_new_label_color (m_labels[i]->name())); } - + update_comments_of_point_set_item(); m_sowf = new Sum_of_weighted_features (m_labels, m_features); @@ -256,7 +251,7 @@ Cluster_classification::Cluster_classification(Scene_points_with_normal_item* po m_cluster_id))); std::set > adjacencies; - + for (Delaunay::Finite_edges_iterator it = dt.finite_edges_begin(); it != dt.finite_edges_end(); ++ it) { @@ -315,13 +310,13 @@ Cluster_classification::~Cluster_classification() m_classif[*it] = -1; } } - + // For LAS saving, convert classification info in the LAS standard // if (m_input_is_las) { Point_set::Property_map las_classif = m_points->point_set()->add_property_map("classification", 0).first; - + std::vector label_indices; unsigned char custom = 19; @@ -372,14 +367,14 @@ Cluster_classification::~Cluster_classification() unsigned char lc = 1; // unclassified in LAS standard if (c != -1) lc = label_indices[std::size_t(c)]; - + las_classif[*it] = lc; int t = m_training[*it]; unsigned char lt = 1; // unclassified in LAS standard if (t != -1) lt = label_indices[std::size_t(t)]; - + m_training[*it] = int(lt); } @@ -406,7 +401,7 @@ void Cluster_classification::backup_existing_colors_and_add_new() m_points->point_set()->remove_colors(); } - + m_points->point_set()->add_colors(); } @@ -419,7 +414,7 @@ void Cluster_classification::reset_colors() for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->first_selected(); ++ it) m_points->point_set()->set_color(*it, m_color[*it]); - + m_points->point_set()->remove_property_map(m_color); } } @@ -429,19 +424,19 @@ void Cluster_classification::change_color (int index, float* vmin, float* vmax) m_index_color = index; int index_color = real_index_color(); - + // Colors static Color_ramp ramp; ramp.build_rainbow(); reset_indices(); - + if (index_color == -1) // item color m_points->point_set()->remove_colors(); else { if (!m_points->point_set()->has_colors()) m_points->point_set()->add_colors(); - + if (index_color == 0) // real colors { @@ -459,11 +454,11 @@ void Cluster_classification::change_color (int index, float* vmin, float* vmax) if (cid != -1) { std::size_t c = m_clusters[cid].label(); - + if (c != std::size_t(-1)) - color = m_label_colors[c]; + color = label_qcolor (m_labels[std::size_t(c)]); } - + m_points->point_set()->set_color(*it, color); } } @@ -475,18 +470,18 @@ void Cluster_classification::change_color (int index, float* vmin, float* vmax) QColor color (0, 0, 0); int cid = m_cluster_id[*it]; float div = 1; - + if (cid != -1) { int c = m_clusters[cid].training(); int c2 = m_clusters[cid].label(); - + if (c != -1) - color = m_label_colors[std::size_t(c)]; - + color = label_qcolor (m_labels[std::size_t(c)]); + if (c != c2) div = 2; - } + } m_points->point_set()->set_color(*it, color.red() / div, color.green() / div, color.blue() / div); } } @@ -496,7 +491,7 @@ void Cluster_classification::change_color (int index, float* vmin, float* vmax) it != m_points->point_set()->first_selected(); ++ it) { int cid = m_cluster_id[*it]; - + if (cid != -1) { srand(cid); @@ -549,7 +544,7 @@ void Cluster_classification::change_color (int index, float* vmin, float* vmax) float min = std::numeric_limits::max(); float max = -std::numeric_limits::max(); - + if (vmin != NULL && vmax != NULL && *vmin != std::numeric_limits::infinity() && *vmax != std::numeric_limits::infinity()) @@ -572,7 +567,7 @@ void Cluster_classification::change_color (int index, float* vmin, float* vmax) } } } - + for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->first_selected(); ++ it) { @@ -582,7 +577,7 @@ void Cluster_classification::change_color (int index, float* vmin, float* vmax) float v = (feature->value(cid) - min) / (max - min); if (v < 0.f) v = 0.f; if (v > 1.f) v = 1.f; - + m_points->point_set()->set_color(*it, ramp.r(v) * 255, ramp.g(v) * 255, ramp.b(v) * 255); } else @@ -597,7 +592,7 @@ void Cluster_classification::change_color (int index, float* vmin, float* vmax) } } } - + for (Point_set::const_iterator it = m_points->point_set()->first_selected(); it != m_points->point_set()->end(); ++ it) m_points->point_set()->set_color(*it, 255, 0, 0); @@ -606,7 +601,7 @@ void Cluster_classification::change_color (int index, float* vmin, float* vmax) int Cluster_classification::real_index_color() const { int out = m_index_color; - + if (out == 0 && m_color == Point_set::Property_map()) out = -1; return out; @@ -629,7 +624,7 @@ void Cluster_classification::compute_features (std::size_t nb_scales, float voxe CGAL_assertion (!(m_points->point_set()->empty())); reset_indices(); - + std::cerr << "Computing pointwise features with " << nb_scales << " scale(s) and "; if (voxel_size == -1) std::cerr << "automatic voxel size" << std::endl; @@ -642,9 +637,9 @@ void Cluster_classification::compute_features (std::size_t nb_scales, float voxe bool normals = m_points->point_set()->has_normal_map(); if (normals) normal_map = m_points->point_set()->normal_map(); - + bool colors = (m_color != Point_set::Property_map()); - + Point_set::Property_map echo_map; bool echo; boost::tie (echo_map, echo) = m_points->point_set()->template property_map("echo"); @@ -654,10 +649,10 @@ void Cluster_classification::compute_features (std::size_t nb_scales, float voxe Feature_set pointwise_features; Generator generator (*(m_points->point_set()), m_points->point_set()->point_map(), nb_scales, voxel_size); - + CGAL::Real_timer t; t.start(); - + #ifdef CGAL_LINKED_WITH_TBB pointwise_features.begin_parallel_additions(); #endif @@ -669,11 +664,11 @@ void Cluster_classification::compute_features (std::size_t nb_scales, float voxe generator.generate_color_based_features (pointwise_features, m_color); if (echo) generator.generate_echo_based_features (pointwise_features, echo_map); - + #ifdef CGAL_LINKED_WITH_TBB pointwise_features.end_parallel_additions(); #endif - + add_remaining_point_set_properties_as_features(pointwise_features); t.stop(); @@ -692,29 +687,29 @@ void Cluster_classification::compute_features (std::size_t nb_scales, float voxe m_features.template add (m_clusters, pointwise_features[i]); } - + #ifdef CGAL_LINKED_WITH_TBB m_features.end_parallel_additions(); m_features.begin_parallel_additions(); #endif - + for (std::size_t i = 0; i < pointwise_features.size(); ++ i) { m_features.template add (m_clusters, pointwise_features[i], m_features[i]); - } - + } + add_cluster_features(); #ifdef CGAL_LINKED_WITH_TBB m_features.end_parallel_additions(); #endif - + t.stop(); std::cerr << m_features.size() << " feature(s) computed in " << t.time() << " second(s)" << std::endl; - + delete m_sowf; m_sowf = new Sum_of_weighted_features (m_labels, m_features); if (m_ethz != NULL) @@ -756,7 +751,7 @@ void Cluster_classification::select_random_region() selected.push_back (*it); else unselected.push_back (*it); - + for (std::size_t i = 0; i < unselected.size(); ++ i) *(m_points->point_set()->begin() + i) = unselected[i]; for (std::size_t i = 0; i < selected.size(); ++ i) @@ -764,13 +759,13 @@ void Cluster_classification::select_random_region() m_points->point_set()->set_first_selected (m_points->point_set()->begin() + unselected.size()); - + } void Cluster_classification::add_remaining_point_set_properties_as_features(Feature_set& feature_set) { const std::vector& prop = m_points->point_set()->base().properties(); - + for (std::size_t i = 0; i < prop.size(); ++ i) { if (prop[i] == "index" || @@ -823,7 +818,7 @@ void Cluster_classification::train(int classifier, const QMultipleInputDialog& d std::vector nb_label (m_labels.size(), 0); std::size_t nb_total = 0; - + std::vector training; training.reserve (m_clusters.size()); for (std::size_t i = 0; i < m_clusters.size(); ++ i) @@ -835,12 +830,12 @@ void Cluster_classification::train(int classifier, const QMultipleInputDialog& d ++ nb_total; } } - + std::cerr << nb_total << " cluster(s) used for training (" << 100. * (nb_total / double(m_clusters.size())) << "% of the total):" << std::endl; for (std::size_t i = 0; i < m_labels.size(); ++ i) std::cerr << " * " << m_labels[i]->name() << ": " << nb_label[i] << " clusters(s)" << std::endl; - + std::vector indices (m_clusters.size(), -1); if (classifier == CGAL_CLASSIFICATION_SOWF_NUMBER) @@ -908,14 +903,14 @@ void Cluster_classification::train(int classifier, const QMultipleInputDialog& d while (iss >> s) hidden_layers.push_back (std::size_t(s)); } - + m_neural_network->train (training, dialog.get("restart")->isChecked(), dialog.get("trials")->value(), dialog.get("learning_rate")->value(), dialog.get("batch_size")->value(), hidden_layers); - + CGAL::Classification::classify (m_clusters, m_labels, *m_neural_network, indices, m_label_probabilities); @@ -924,7 +919,7 @@ void Cluster_classification::train(int classifier, const QMultipleInputDialog& d for (std::size_t i = 0; i < m_clusters.size(); ++ i) m_clusters[i].label() = indices[i]; - + if (m_index_color == 1 || m_index_color == 2) change_color (m_index_color); } @@ -973,7 +968,6 @@ bool Cluster_classification::run (int method, int classifier, run (method, *m_neural_network, subdivisions, smoothing); #endif } - + return true; } - diff --git a/Polyhedron/demo/Polyhedron/Plugins/Classification/Cluster_classification.h b/Polyhedron/demo/Polyhedron/Plugins/Classification/Cluster_classification.h index df0d0ceca21..01d180bc3c2 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Classification/Cluster_classification.h +++ b/Polyhedron/demo/Polyhedron/Plugins/Classification/Cluster_classification.h @@ -208,7 +208,7 @@ class Cluster_classification : public Item_classification_base = new Scene_points_with_normal_item; points_item->setName (QString("%1 (%2)").arg(name).arg(m_labels[label]->name().c_str())); - points_item->setColor (m_label_colors[label]); + points_item->setColor (label_qcolor (m_labels[label])); for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->end(); ++ it) { @@ -231,7 +231,7 @@ class Cluster_classification : public Item_classification_base { points_item[i] = new Scene_points_with_normal_item; points_item[i]->setName (QString("%1 (%2)").arg(name).arg(m_labels[i]->name().c_str())); - points_item[i]->setColor (m_label_colors[i]); + points_item[i]->setColor (label_qcolor (m_labels[i])); items.push_back (points_item[i]); } diff --git a/Polyhedron/demo/Polyhedron/Plugins/Classification/Item_classification_base.h b/Polyhedron/demo/Polyhedron/Plugins/Classification/Item_classification_base.h index bd72eb80df9..5d763d90b2f 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Classification/Item_classification_base.h +++ b/Polyhedron/demo/Polyhedron/Plugins/Classification/Item_classification_base.h @@ -52,9 +52,9 @@ public: #ifdef CGAL_LINKED_WITH_TENSORFLOW typedef CGAL::Classification::TensorFlow::Neural_network_classifier<> Neural_network; #endif - + public: - + Item_classification_base() { } virtual ~Item_classification_base() { } @@ -66,7 +66,7 @@ public: virtual void compute_features (std::size_t nb_scales, float voxel_size) = 0; virtual std::string feature_statistics () const { return std::string(); } - + virtual void add_selection_to_training_set (std::size_t label) = 0; virtual void reset_training_set (std::size_t label) = 0; virtual void reset_training_set_of_selection() = 0; @@ -76,7 +76,7 @@ public: virtual void validate_selection () = 0; virtual void train(int classifier, const QMultipleInputDialog&) = 0; virtual bool run (int method, int classifier, std::size_t subdivisions, double smoothing) = 0; - + virtual void update_color () = 0; virtual void change_color (int index, float* vmin = NULL, float* vmax = NULL) = 0; virtual CGAL::Three::Scene_item* generate_one_item (const char* name, @@ -85,19 +85,23 @@ public: const char* name) const = 0; bool features_computed() const { return (m_features.size() != 0); } - std::size_t number_of_features() const { return m_features.size(); } + std::size_t number_of_features() const { return m_features.size(); } Feature_handle feature(std::size_t i) { return m_features[i]; } float weight (Feature_handle f) const { return m_sowf->weight(f); } void set_weight (Feature_handle f, float w) const { m_sowf->set_weight(f,w); } Sum_of_weighted_features::Effect effect (Label_handle l, Feature_handle f) const { return m_sowf->effect(l,f); } void set_effect (Label_handle l, Feature_handle f, Sum_of_weighted_features::Effect e) { m_sowf->set_effect (l, f, e); } - + + QColor label_qcolor (Label_handle l) const + { + return QColor (l->color().red(), l->color().green(), l->color().blue()); + } + virtual QColor add_new_label (const char* name) { m_labels.add(name); - m_label_colors.push_back (get_new_label_color (name)); - + delete m_sowf; m_sowf = new Sum_of_weighted_features (m_labels, m_features); @@ -113,13 +117,12 @@ public: delete m_neural_network; m_neural_network = new Neural_network (m_labels, m_features); #endif - - return m_label_colors.back(); + + return label_qcolor (m_labels[m_labels.size() - 1]); } virtual void remove_label (std::size_t position) { m_labels.remove(m_labels[position]); - m_label_colors.erase (m_label_colors.begin() + position); delete m_sowf; m_sowf = new Sum_of_weighted_features (m_labels, m_features); @@ -137,11 +140,10 @@ public: m_neural_network = new Neural_network (m_labels, m_features); #endif } - + virtual void clear_labels () { m_labels.clear(); - m_label_colors.clear(); delete m_sowf; m_sowf = new Sum_of_weighted_features (m_labels, m_features); @@ -256,69 +258,24 @@ public: } } - const QColor& label_color(std::size_t i) const { return m_label_colors[i]; } + QColor label_color(std::size_t i) const + { + return label_qcolor (m_labels[i]); + } void change_label_color (std::size_t position, const QColor& color) { - m_label_colors[position] = color; + m_labels[position]->set_color + (CGAL::Color (color.red(), color.green(), color.blue())); } void change_label_name (std::size_t position, const std::string& name) { m_labels[position]->set_name (name); } - QColor get_new_label_color (const std::string& name) - { - QColor color (64 + rand() % 192, - 64 + rand() % 192, - 64 + rand() % 192); - - if (name == "ground") - color = QColor (186, 189, 182); - else if (name == "low_veget") - color = QColor (78, 154, 6); - else if (name == "med_veget" - || name == "vegetation") - color = QColor (138, 226, 52); - else if (name == "high_veget") - color = QColor (204, 255, 201); - else if (name == "building" - || name == "roof") - color = QColor (245, 121, 0); - else if (name == "noise") - color = QColor (0, 0, 0); - else if (name == "reserved") - color = QColor (233, 185, 110); - else if (name == "water") - color = QColor (114, 159, 207); - else if (name == "rail") - color = QColor (136, 46, 25); - else if (name == "road_surface") - color = QColor (56, 56, 56); - else if (name == "reserved_2") - color = QColor (193, 138, 51); - else if (name == "wire_guard") - color = QColor (37, 61, 136); - else if (name == "wire_conduct") - color = QColor (173, 127, 168); - else if (name == "trans_tower") - color = QColor (136, 138, 133); - else if (name == "wire_connect") - color = QColor (145, 64, 236); - else if (name == "bridge_deck") - color = QColor (213, 93, 93); - else if (name == "high_noise") - color = QColor (255, 0, 0); - else if (name == "facade") - color = QColor (77, 131, 186); - - return color; - } - protected: Label_set m_labels; Feature_set m_features; - std::vector m_label_colors; Sum_of_weighted_features* m_sowf; ETHZ_random_forest* m_ethz; #ifdef CGAL_LINKED_WITH_OPENCV @@ -327,7 +284,7 @@ protected: #ifdef CGAL_LINKED_WITH_TENSORFLOW Neural_network* m_neural_network; #endif - + }; diff --git a/Polyhedron/demo/Polyhedron/Plugins/Classification/Point_set_item_classification.cpp b/Polyhedron/demo/Polyhedron/Plugins/Classification/Point_set_item_classification.cpp index fa6197b4c44..0602ab30c00 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Classification/Point_set_item_classification.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Classification/Point_set_item_classification.cpp @@ -48,7 +48,7 @@ Point_set_item_classification::Point_set_item_classification(Scene_points_with_n bool classif_found = false; boost::tie (m_classif, classif_found) = m_points->point_set()->add_property_map("label", -1); - training_found = !training_found; // add_property_map returns false if + training_found = !training_found; // add_property_map returns false if classif_found = !classif_found; // property was already there bool las_found = false; @@ -73,11 +73,11 @@ Point_set_item_classification::Point_set_item_classification(Scene_points_with_n training_found = true; } } - + if (training_found || classif_found) { std::vector used_indices; - + for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->first_selected(); ++ it) { @@ -140,7 +140,7 @@ Point_set_item_classification::Point_set_item_classification(Scene_points_with_n } } } - + std::map label_names; if (las_found) // Use LAS standard { @@ -183,7 +183,7 @@ Point_set_item_classification::Point_set_item_classification(Scene_points_with_n } } } - + for (std::size_t i = 0; i < used_indices.size(); ++ i) { if (used_indices[i] == -1) @@ -200,8 +200,6 @@ Point_set_item_classification::Point_set_item_classification(Scene_points_with_n oss << "label_" << i; new_label = m_labels.add(oss.str().c_str()); } - - m_label_colors.push_back (this->get_new_label_color (new_label->name())); } } else @@ -210,11 +208,8 @@ Point_set_item_classification::Point_set_item_classification(Scene_points_with_n m_labels.add("vegetation"); m_labels.add("roof"); m_labels.add("facade"); - - for (std::size_t i = 0; i < m_labels.size(); ++ i) - m_label_colors.push_back (this->get_new_label_color (m_labels[i]->name())); } - + update_comments_of_point_set_item(); m_sowf = new Sum_of_weighted_features (m_labels, m_features); @@ -257,7 +252,7 @@ Point_set_item_classification::~Point_set_item_classification() { Point_set::Property_map las_classif = m_points->point_set()->add_property_map("classification", 0).first; - + std::vector label_indices; unsigned char custom = 19; @@ -308,14 +303,14 @@ Point_set_item_classification::~Point_set_item_classification() unsigned char lc = 1; // unclassified in LAS standard if (c != -1) lc = label_indices[std::size_t(c)]; - + las_classif[*it] = lc; int t = m_training[*it]; unsigned char lt = 1; // unclassified in LAS standard if (t != -1) lt = label_indices[std::size_t(t)]; - + m_training[*it] = int(lt); } @@ -365,19 +360,19 @@ void Point_set_item_classification::change_color (int index, float* vmin, float* m_index_color = index; int index_color = real_index_color(); - + // Colors static Color_ramp ramp; ramp.build_rainbow(); reset_indices(); - + if (index_color == -1) // item color m_points->point_set()->remove_colors(); else { if (!m_points->point_set()->has_colors()) m_points->point_set()->add_colors(); - + if (index_color == 0) // real colors { @@ -392,9 +387,9 @@ void Point_set_item_classification::change_color (int index, float* vmin, float* { QColor color (0, 0, 0); std::size_t c = m_classif[*it]; - + if (c != std::size_t(-1)) - color = m_label_colors[c]; + color = label_qcolor (m_labels[c]); m_points->point_set()->set_color(*it, color); } @@ -407,10 +402,10 @@ void Point_set_item_classification::change_color (int index, float* vmin, float* QColor color (0, 0, 0); int c = m_training[*it]; int c2 = m_classif[*it]; - + if (c != -1) - color = m_label_colors[std::size_t(c)]; - + color = label_qcolor (m_labels[std::size_t(c)]); + float div = 1; if (c != c2) div = 2; @@ -449,7 +444,7 @@ void Point_set_item_classification::change_color (int index, float* vmin, float* return; } Feature_handle feature = m_features[corrected_index]; - + float min = std::numeric_limits::max(); float max = -std::numeric_limits::max(); @@ -477,7 +472,7 @@ void Point_set_item_classification::change_color (int index, float* vmin, float* float v = (feature->value(*it) - min) / (max - min); if (v < 0.f) v = 0.f; if (v > 1.f) v = 1.f; - + m_points->point_set()->set_color(*it, ramp.r(v) * 255, ramp.g(v) * 255, ramp.b(v) * 255); } @@ -489,7 +484,7 @@ void Point_set_item_classification::change_color (int index, float* vmin, float* } } } - + for (Point_set::const_iterator it = m_points->point_set()->first_selected(); it != m_points->point_set()->end(); ++ it) m_points->point_set()->set_color(*it, 255, 0, 0); @@ -498,7 +493,7 @@ void Point_set_item_classification::change_color (int index, float* vmin, float* int Point_set_item_classification::real_index_color() const { int out = m_index_color; - + if (out == 0 && m_color == Point_set::Property_map()) out = -1; return out; @@ -524,7 +519,7 @@ void Point_set_item_classification::compute_features (std::size_t nb_scales, flo delete m_generator; reset_indices(); - + std::cerr << "Computing features with " << nb_scales << " scale(s) and "; if (voxel_size == -1) std::cerr << "automatic voxel size" << std::endl; @@ -537,9 +532,9 @@ void Point_set_item_classification::compute_features (std::size_t nb_scales, flo bool normals = m_points->point_set()->has_normal_map(); if (normals) normal_map = m_points->point_set()->normal_map(); - + bool colors = (m_color != Point_set::Property_map()); - + Point_set::Property_map echo_map; bool echo; boost::tie (echo_map, echo) = m_points->point_set()->template property_map("echo"); @@ -550,7 +545,7 @@ void Point_set_item_classification::compute_features (std::size_t nb_scales, flo CGAL::Real_timer t; t.start(); - + #ifdef CGAL_LINKED_WITH_TBB m_features.begin_parallel_additions(); #endif @@ -562,7 +557,7 @@ void Point_set_item_classification::compute_features (std::size_t nb_scales, flo m_generator->generate_color_based_features (m_features, m_color); if (echo) m_generator->generate_echo_based_features (m_features, echo_map); - + #ifdef CGAL_LINKED_WITH_TBB m_features.end_parallel_additions(); #endif @@ -635,7 +630,7 @@ void Point_set_item_classification::select_random_region() current_idx ++; else unselected.push_back (*it); - + } else { @@ -651,7 +646,7 @@ void Point_set_item_classification::select_random_region() else unselected.push_back (*it); } - + for (std::size_t i = 0; i < unselected.size(); ++ i) *(m_points->point_set()->begin() + i) = unselected[i]; for (std::size_t i = 0; i < selected.size(); ++ i) @@ -665,7 +660,7 @@ void Point_set_item_classification::select_random_region() void Point_set_item_classification::add_remaining_point_set_properties_as_features() { const std::vector& prop = m_points->point_set()->base().properties(); - + for (std::size_t i = 0; i < prop.size(); ++ i) { if (prop[i] == "index" || @@ -715,13 +710,13 @@ void Point_set_item_classification::train(int classifier, const QMultipleInputDi m_label_probabilities.resize (m_labels.size()); for (std::size_t i = 0; i < m_label_probabilities.size(); ++ i) m_label_probabilities[i].resize (m_points->point_set()->size(), -1); - + std::vector training (m_points->point_set()->size(), -1); std::vector indices (m_points->point_set()->size(), -1); std::vector nb_label (m_labels.size(), 0); std::size_t nb_total = 0; - + for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->first_selected(); ++ it) { @@ -803,24 +798,24 @@ void Point_set_item_classification::train(int classifier, const QMultipleInputDi while (iss >> s) hidden_layers.push_back (std::size_t(s)); } - + m_neural_network->train (training, dialog.get("restart")->isChecked(), dialog.get("trials")->value(), dialog.get("learning_rate")->value(), dialog.get("batch_size")->value(), hidden_layers); - + CGAL::Classification::classify (*(m_points->point_set()), m_labels, *m_neural_network, indices, m_label_probabilities); #endif } - + for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->first_selected(); ++ it) m_classif[*it] = indices[*it]; - + if (m_index_color == 1 || m_index_color == 2) change_color (m_index_color); } @@ -869,7 +864,6 @@ bool Point_set_item_classification::run (int method, int classifier, run (method, *m_neural_network, subdivisions, smoothing); #endif } - + return true; } - diff --git a/Polyhedron/demo/Polyhedron/Plugins/Classification/Point_set_item_classification.h b/Polyhedron/demo/Polyhedron/Plugins/Classification/Point_set_item_classification.h index 075c9b812fb..af60911a858 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Classification/Point_set_item_classification.h +++ b/Polyhedron/demo/Polyhedron/Plugins/Classification/Point_set_item_classification.h @@ -224,7 +224,8 @@ class Point_set_item_classification : public Item_classification_base = new Scene_points_with_normal_item; points_item->setName (QString("%1 (%2)").arg(name).arg(m_labels[label]->name().c_str())); - points_item->setColor (m_label_colors[label]); + points_item->setColor (label_qcolor (m_labels[label])); + for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->end(); ++ it) { @@ -243,7 +244,7 @@ class Point_set_item_classification : public Item_classification_base { points_item[i] = new Scene_points_with_normal_item; points_item[i]->setName (QString("%1 (%2)").arg(name).arg(m_labels[i]->name().c_str())); - points_item[i]->setColor (m_label_colors[i]); + points_item[i]->setColor (label_qcolor (m_labels[i])); items.push_back (points_item[i]); } diff --git a/Polyhedron/demo/Polyhedron/Plugins/Classification/Surface_mesh_item_classification.cpp b/Polyhedron/demo/Polyhedron/Plugins/Classification/Surface_mesh_item_classification.cpp index 89838e0c0de..6a6f1081eaf 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Classification/Surface_mesh_item_classification.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Classification/Surface_mesh_item_classification.cpp @@ -28,10 +28,7 @@ Surface_mesh_item_classification::Surface_mesh_item_classification(Scene_surface m_labels.add("vegetation"); m_labels.add("roof"); m_labels.add("facade"); - - for (std::size_t i = 0; i < m_labels.size(); ++ i) - m_label_colors.push_back (this->get_new_label_color (m_labels[i]->name())); - + m_sowf = new Sum_of_weighted_features (m_labels, m_features); m_ethz = NULL; #ifdef CGAL_LINKED_WITH_OPENCV @@ -106,9 +103,9 @@ void Surface_mesh_item_classification::change_color (int index, float* vmin, flo { QColor color (128, 128, 128); std::size_t c = m_classif[fd]; - + if (c != std::size_t(-1)) - color = m_label_colors[c]; + color = label_qcolor (m_labels[c]); m_color[fd] = CGAL::Color(color.red(), color.green(), color.blue()); } @@ -120,10 +117,10 @@ void Surface_mesh_item_classification::change_color (int index, float* vmin, flo QColor color (128, 128, 128); std::size_t c = m_training[fd]; std::size_t c2 = m_classif[fd]; - + if (c != std::size_t(-1)) - color = m_label_colors[c]; - + color = label_qcolor(m_labels[c]); + float div = 1; if (c != c2) div = 2; @@ -166,12 +163,12 @@ void Surface_mesh_item_classification::change_color (int index, float* vmin, flo std::cerr << "Error: trying to access feature " << corrected_index << " out of " << m_features.size() << std::endl; return; } - + Feature_handle feature = m_features[corrected_index]; float min = std::numeric_limits::max(); float max = -std::numeric_limits::max(); - + if (vmin != NULL && vmax != NULL && *vmin != std::numeric_limits::infinity() && *vmax != std::numeric_limits::infinity()) @@ -189,18 +186,18 @@ void Surface_mesh_item_classification::change_color (int index, float* vmin, flo min = feature->value(fd); } } - + for(face_descriptor fd : faces(*(m_mesh->polyhedron()))) { float v = (feature->value(fd) - min) / (max - min); if (v < 0.f) v = 0.f; if (v > 1.f) v = 1.f; - + m_color[fd] = CGAL::Color((unsigned char)(ramp.r(v) * 255), (unsigned char)(ramp.g(v) * 255), (unsigned char)(ramp.b(v) * 255)); } - + if (vmin != NULL && vmax != NULL) { *vmin = min; @@ -217,16 +214,16 @@ void Surface_mesh_item_classification::compute_features (std::size_t nb_scales, std::cerr << "automatic voxel size" << std::endl; else std::cerr << "voxel size = " << voxel_size << std::endl; - + m_features.clear(); if (m_generator != NULL) delete m_generator; Face_center_map fc_map (m_mesh->polyhedron()); - + m_generator = new Generator (*(m_mesh->polyhedron()), fc_map, nb_scales, voxel_size); - + #ifdef CGAL_LINKED_WITH_TBB m_features.begin_parallel_additions(); #endif @@ -237,7 +234,7 @@ void Surface_mesh_item_classification::compute_features (std::size_t nb_scales, #ifdef CGAL_LINKED_WITH_TBB m_features.end_parallel_additions(); #endif - + delete m_sowf; m_sowf = new Sum_of_weighted_features (m_labels, m_features); if (m_ethz != NULL) @@ -280,7 +277,7 @@ void Surface_mesh_item_classification::train (int classifier, const QMultipleInp std::vector nb_label (m_labels.size(), 0); std::size_t nb_total = 0; - + for(face_descriptor fd : faces(*(m_mesh->polyhedron()))) { training[fd] = m_training[fd]; @@ -290,12 +287,12 @@ void Surface_mesh_item_classification::train (int classifier, const QMultipleInp ++ nb_total; } } - + std::cerr << nb_total << " face(s) used for training (" << 100. * (nb_total / double(m_mesh->polyhedron()->faces().size())) << "% of the total):" << std::endl; for (std::size_t i = 0; i < m_labels.size(); ++ i) std::cerr << " * " << m_labels[i]->name() << ": " << nb_label[i] << " face(s)" << std::endl; - + if (classifier == CGAL_CLASSIFICATION_SOWF_NUMBER) { m_sowf->train(training, dialog.get("trials")->value()); @@ -362,14 +359,14 @@ void Surface_mesh_item_classification::train (int classifier, const QMultipleInp while (iss >> s) hidden_layers.push_back (std::size_t(s)); } - + m_neural_network->train (training, dialog.get("restart")->isChecked(), dialog.get("trials")->value(), dialog.get("learning_rate")->value(), dialog.get("batch_size")->value(), hidden_layers); - + CGAL::Classification::classify (m_mesh->polyhedron()->faces(), m_labels, *m_neural_network, indices, m_label_probabilities); @@ -425,6 +422,6 @@ bool Surface_mesh_item_classification::run (int method, int classifier, run (method, *m_neural_network, subdivisions, smoothing); #endif } - + return true; }