From 4e1a10cc55fa2f04bab077bbb6dabf0da9b4c363 Mon Sep 17 00:00:00 2001 From: Weixiao GAO Date: Tue, 18 May 2021 19:45:55 +0200 Subject: [PATCH] Add segment area slider --- .../Classification/Classification_plugin.cpp | 144 ++++++++++--- .../Classification/Classification_widget.ui | 192 +++++++++++------- .../Classification/Item_classification_base.h | 4 +- .../Surface_mesh_item_classification.cpp | 39 +++- .../Surface_mesh_item_classification.h | 2 +- src/Plugins/IO/PLY_io_plugin.cpp | 17 ++ src/Scene_surface_mesh_item.cpp | 13 +- src/Scene_surface_mesh_item.h | 20 ++ 8 files changed, 317 insertions(+), 114 deletions(-) diff --git a/src/Plugins/Classification/Classification_plugin.cpp b/src/Plugins/Classification/Classification_plugin.cpp index 8f4b3be..24b74c3 100644 --- a/src/Plugins/Classification/Classification_plugin.cpp +++ b/src/Plugins/Classification/Classification_plugin.cpp @@ -147,31 +147,33 @@ class Polyhedron_demo_classification_plugin : color_att = QColor(75, 75, 77); - connect(ui_widget.help, SIGNAL(clicked()), this, - SLOT(on_help_clicked())); - - ui_widget.help->setVisible(false); - connect(ui_widget.close, SIGNAL(clicked()), this, - SLOT(ask_for_closing())); - ui_widget.close->setVisible(false); - connect(ui_widget.display, SIGNAL(currentIndexChanged(int)), this, SLOT(on_display_button_clicked_with_probability(int))); connect(ui_widget.ProbSpin, SIGNAL(valueChanged(int)), ui_widget.ProbSlider, SLOT(setValue(int))); connect(ui_widget.ProbSlider, SIGNAL(valueChanged(int)), ui_widget.ProbSpin, SLOT(setValue(int))); - connect(ui_widget.ProbSpin, SIGNAL(valueChanged(int)), this, SLOT(on_probability_threshold_changed(int))); - //connect(ui_widget.ProbSlider, SIGNAL(valueChanged(int)), this, SLOT(on_probability_threshold_changed(int))); - connect(ui_widget.ProbSwitcher, SIGNAL(currentIndexChanged(int)), this, SLOT(on_probability_switcher_changed(int))); + connect(ui_widget.SegAreaSlider, SIGNAL(valueChanged(int)), ui_widget.SegAreadoubleSpinBox, SLOT(setValue(int))); + connect(ui_widget.SegAreadoubleSpinBox, SIGNAL(valueChanged(double)), ui_widget.SegAreaSlider, SLOT(setValue(double))); + connect(ui_widget.SegAreadoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(on_segarea_threshold_changed(double))); + connect(ui_widget.SegAreaSwitcher, SIGNAL(currentIndexChanged(int)), this, SLOT(on_segarea_switcher_changed(int))); + connect(ui_widget.SegAreadoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(segarea_double_to_int())); + connect(ui_widget.SegAreaSlider, SIGNAL(valueChanged(int)), this, SLOT(segarea_int_to_double())); + //ui_widget.display->setVisible(false); ui_widget.label->setVisible(false); ui_widget.ProbSwitcher->setVisible(false); ui_widget.ProbSlider->setVisible(false); ui_widget.ProbSpin->setVisible(false); + ui_widget.segment_area_label->setVisible(false); + ui_widget.SegAreaSwitcher->setVisible(false); + ui_widget.SegAreaSlider->setVisible(false); + ui_widget.SegAreadoubleSpinBox->setVisible(false); + + QObject* scene_obj = dynamic_cast(scene_interface); if (scene_obj) { @@ -181,6 +183,13 @@ class Polyhedron_demo_classification_plugin : } virtual void closure() { + ui_widget.ProbSwitcher->setCurrentIndex(0); + ui_widget.ProbSlider->setValue(100); + ui_widget.ProbSpin->setValue(100); + + ui_widget.SegAreaSwitcher->setCurrentIndex(0); + ui_widget.SegAreaSlider->setValue(1000); + ui_widget.SegAreadoubleSpinBox->setValue(100.0); dock_widget->hide(); close_classification(); } @@ -756,12 +765,12 @@ public Q_SLOTS: ++classif->item()->add_label_count; } - bool threshold_based_change_color(Item_classification_base* classif, int index, int threshold, bool below) + bool threshold_based_change_color(Item_classification_base* classif, int index, std::vector &thresholds, std::vector& belows) { float vmin = std::numeric_limits::infinity(); float vmax = std::numeric_limits::infinity(); - classif->threshold_based_change_color(index, threshold, below, &vmin, &vmax); + classif->threshold_based_change_color(index, thresholds, belows, &vmin, &vmax); if (first_activate_times > 1) item_changed(classif->item()); @@ -780,6 +789,10 @@ public Q_SLOTS: ui_widget.label->setEnabled(false); ui_widget.estimated_prg->setEnabled(false); ui_widget.progressBar_2->setEnabled(false); + ui_widget.segment_area_label->setEnabled(false); + ui_widget.SegAreaSlider->setEnabled(false); + ui_widget.SegAreadoubleSpinBox->setEnabled(false); + ui_widget.SegAreaSwitcher->setEnabled(false); ui_widget.ProbSlider->setVisible(false); ui_widget.ProbSpin->setVisible(false); @@ -788,6 +801,10 @@ public Q_SLOTS: ui_widget.label->setVisible(false); ui_widget.estimated_prg->setVisible(false); ui_widget.progressBar_2->setVisible(false); + ui_widget.segment_area_label->setVisible(false); + ui_widget.SegAreaSlider->setVisible(false); + ui_widget.SegAreadoubleSpinBox->setVisible(false); + ui_widget.SegAreaSwitcher->setVisible(false); //progress bar ui_widget.label_3->setEnabled(true); @@ -815,6 +832,10 @@ public Q_SLOTS: ui_widget.label->setEnabled(true); ui_widget.estimated_prg->setEnabled(true); ui_widget.progressBar_2->setEnabled(true); + ui_widget.segment_area_label->setEnabled(true); + ui_widget.SegAreaSlider->setEnabled(true); + ui_widget.SegAreadoubleSpinBox->setEnabled(true); + ui_widget.SegAreaSwitcher->setEnabled(true); ui_widget.ProbSlider->setVisible(true); ui_widget.ProbSpin->setVisible(true); @@ -824,6 +845,10 @@ public Q_SLOTS: ui_widget.view->setVisible(true); ui_widget.estimated_prg->setVisible(true); ui_widget.progressBar_2->setVisible(true); + ui_widget.segment_area_label->setVisible(true); + ui_widget.SegAreaSlider->setVisible(true); + ui_widget.SegAreadoubleSpinBox->setVisible(true); + ui_widget.SegAreaSwitcher->setVisible(true); //progress bar ui_widget.label_3->setEnabled(false); @@ -849,6 +874,11 @@ public Q_SLOTS: ui_widget.ProbSwitcher->setEnabled(false); ui_widget.label_2->setEnabled(false); ui_widget.label->setEnabled(false); + ui_widget.segment_area_label->setEnabled(false); + ui_widget.SegAreaSlider->setEnabled(false); + ui_widget.SegAreadoubleSpinBox->setEnabled(false); + ui_widget.SegAreaSwitcher->setEnabled(false); + //progress bar ui_widget.label_3->setEnabled(false); ui_widget.label_4->setEnabled(false); @@ -873,45 +903,99 @@ public Q_SLOTS: enable_probability_disable_progressbar(); } - int threshold = ui_widget.ProbSlider->value(); - bool below; + classif->m_thresholds[0] = ui_widget.ProbSlider->value(); if (ui_widget.ProbSwitcher->currentIndex() == 0) - below = true; + classif->m_belows[0] = true; else - below = false; + classif->m_belows[0] = false; - threshold_based_change_color(classif, index, threshold, below); - } + //threshold_based_change_color(classif, index, thresholds, below); + classif->m_thresholds[1] = ui_widget.SegAreadoubleSpinBox->value(); + if (ui_widget.SegAreaSwitcher->currentIndex() == 0) + classif->m_belows[1] = true; + else + classif->m_belows[1] = false; + + threshold_based_change_color(classif, index, classif->m_thresholds, classif->m_belows); + } void on_probability_threshold_changed(int value) { Item_classification_base* classif = get_classification(); if (!classif) return; - int threshold = value; - bool below; - if (ui_widget.ProbSwitcher->currentIndex() == 0) below = true; - else below = false; + classif->m_thresholds[0] = value; + + if (ui_widget.ProbSwitcher->currentIndex() == 0) + classif->m_belows[0] = true; + else + classif->m_belows[0] = false; + + int index = ui_widget.display->currentIndex(); + + threshold_based_change_color(classif, index, classif->m_thresholds, classif->m_belows); + //print_message("probability_state_changed!"); + } + + void on_probability_switcher_changed(int value) + { + Item_classification_base* classif = get_classification(); + if (!classif) return; + classif->m_thresholds[0] = ui_widget.ProbSlider->value(); + + if (value == 0) + classif->m_belows[0] = true; + else + classif->m_belows[0] = false; int index = ui_widget.display->currentIndex(); - threshold_based_change_color(classif, index, threshold, below); + threshold_based_change_color(classif, index, classif->m_thresholds, classif->m_belows); //print_message("probability_state_changed!"); } - void on_probability_switcher_changed(int value) { + + void on_segarea_threshold_changed(double value) { Item_classification_base* classif = get_classification(); if (!classif) return; - int threshold = ui_widget.ProbSlider->value(); - bool below; - if (value == 0) below = true; - else below = false; + classif->m_thresholds[1] = value; + if (ui_widget.SegAreaSwitcher->currentIndex() == 0) + classif->m_belows[1] = true; + else + classif->m_belows[1] = false; int index = ui_widget.display->currentIndex(); - threshold_based_change_color(classif, index, threshold, below); + threshold_based_change_color(classif, index, classif->m_thresholds, classif->m_belows); //print_message("probability_state_changed!"); } + void on_segarea_switcher_changed(int value) + { + Item_classification_base* classif = get_classification(); + if (!classif) return; + classif->m_thresholds[1] = ui_widget.SegAreadoubleSpinBox->value(); + if (value == 0) + classif->m_belows[1] = true; + else + classif->m_belows[1] = false; + + int index = ui_widget.display->currentIndex(); + + threshold_based_change_color(classif, index, classif->m_thresholds, classif->m_belows); + //print_message("probability_state_changed!"); + } + + void segarea_double_to_int() + { + int tmp = ui_widget.SegAreadoubleSpinBox->value() * 10.0f; + ui_widget.SegAreaSlider->setValue(tmp); + } + + void segarea_int_to_double() + { + double tmp = double(ui_widget.SegAreaSlider->value()) / 10.0f; + ui_widget.SegAreadoubleSpinBox->setValue(tmp); + } private: Messages_interface* messages; QAction* actionClassification; diff --git a/src/Plugins/Classification/Classification_widget.ui b/src/Plugins/Classification/Classification_widget.ui index d0b122c..1f388e1 100644 --- a/src/Plugins/Classification/Classification_widget.ui +++ b/src/Plugins/Classification/Classification_widget.ui @@ -7,7 +7,7 @@ 0 0 543 - 232 + 228 @@ -27,45 +27,6 @@ - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - :/cgal/icons/resources/help_button.png:/cgal/icons/resources/help_button.png - - - - - - - - - - - :/cgal/icons/check-off.png:/cgal/icons/check-off.png - - - - - @@ -81,37 +42,43 @@ QLayout::SetDefaultConstraint - - - 0 - - - + + + + + false + - + 0 0 + + true + - Editing + below - 1 + 0 + + + 2 - Real colors + below - Editing + above - + false @@ -133,42 +100,33 @@ - - - - false - + + - + 0 0 - - true - - below + Editing - 0 - - - 2 + 1 - below + Real colors - above + Editing - + false @@ -178,7 +136,29 @@ - + + + + false + + + + 0 + 0 + + + + true + + + 100 + + + 100 + + + + false @@ -209,8 +189,24 @@ - - + + + + false + + + + 0 + 0 + + + + Segment Area + + + + + false @@ -220,14 +216,62 @@ 0 + + true + + + + below + + + + + above + + + + + + + + false + + + 1000 + + + 1 + + + 1000 + + + false + + + Qt::Horizontal + + + + + + + false + true + + 1 + - 100 + 100.000000000000000 + + + 0.100000000000000 - 100 + 100.000000000000000 diff --git a/src/Plugins/Classification/Item_classification_base.h b/src/Plugins/Classification/Item_classification_base.h index fb9e2a9..24875a3 100644 --- a/src/Plugins/Classification/Item_classification_base.h +++ b/src/Plugins/Classification/Item_classification_base.h @@ -16,6 +16,8 @@ class Item_classification_base typedef CGAL::Classification::Label_handle Label_handle; typedef CGAL::Classification::Label_set Label_set; + std::vector m_thresholds = { 100.0f, 100.0f }; + std::vector m_belows = { true , true }; public: Item_classification_base() { } @@ -38,7 +40,7 @@ class Item_classification_base virtual void change_color (int index, float* vmin = NULL, float* vmax = NULL) = 0; virtual void update_all_label_color(int &) = 0; - virtual void threshold_based_change_color(int index, int threshold, bool below, float* vmin = NULL, float* vmax = NULL) = 0; + virtual void threshold_based_change_color(int index, std::vector &thresholds, std::vector& belows, float* vmin = NULL, float* vmax = NULL) = 0; // presently only implementated the surface_mesh_item_classification class. virtual bool can_show_probability() = 0; diff --git a/src/Plugins/Classification/Surface_mesh_item_classification.cpp b/src/Plugins/Classification/Surface_mesh_item_classification.cpp index d149717..32ad088 100644 --- a/src/Plugins/Classification/Surface_mesh_item_classification.cpp +++ b/src/Plugins/Classification/Surface_mesh_item_classification.cpp @@ -283,7 +283,14 @@ void Surface_mesh_item_classification::update_all_label_color(int &label_ind) } } -void Surface_mesh_item_classification::threshold_based_change_color(int index, int threshold = 100, bool below = true, float* vmin, float* vmax) +void Surface_mesh_item_classification::threshold_based_change_color +( + int index, + std::vector &thresholds, + std::vector& belows, + float* vmin, + float* vmax +) { m_index_color = index; int index_color = index; @@ -316,16 +323,25 @@ void Surface_mesh_item_classification::threshold_based_change_color(int index, i float div = 1; - float prob_of_face; + float prob_of_face = 0.0f; if (!m_mesh->label_probabilities.empty()) { prob_of_face = m_mesh->label_probabilities[fd]; prob_of_face *= 100; } + float prob_of_face_area = 0.0f; + if (!m_mesh->seg_area_sorted_percentile.empty()) + { + prob_of_face_area = m_mesh->seg_area_sorted_percentile[fd]; + prob_of_face_area *= 100; + } + if (m_mesh->label_probabilities.empty() || - (below && prob_of_face <= threshold) || - (!below && prob_of_face >= threshold)) + ((belows[0] && prob_of_face <= thresholds[0]) || + (!belows[0] && prob_of_face >= thresholds[0])) && + ((belows[1] && prob_of_face_area <= thresholds[1]) || + (!belows[1] && prob_of_face_area >= thresholds[1]))) { if (c != std::size_t(-1) && c < std::size_t(100))//c != std::size_t(-1) && { @@ -395,9 +411,18 @@ void Surface_mesh_item_classification::threshold_based_change_color(int index, i prob_of_face *= 100; } - if (m_mesh->label_probabilities.empty() || - (below && prob_of_face <= threshold) || - (!below && prob_of_face >= threshold)) + float prob_of_face_area = 0.0f; + if (!m_mesh->seg_area_sorted_percentile.empty()) + { + prob_of_face_area = m_mesh->seg_area_sorted_percentile[fd]; + prob_of_face_area *= 100; + } + + if (m_mesh->label_probabilities.empty() || + ((belows[0] && prob_of_face <= thresholds[0]) || + (!belows[0] && prob_of_face >= thresholds[0])) && + ((belows[1] && prob_of_face_area <= thresholds[1]) || + (!belows[1] && prob_of_face_area >= thresholds[1]))) { //show them! if (c != std::size_t(-1) && c < std::size_t(100))//c != std::size_t(-1) && diff --git a/src/Plugins/Classification/Surface_mesh_item_classification.h b/src/Plugins/Classification/Surface_mesh_item_classification.h index f76dc15..458ce0d 100644 --- a/src/Plugins/Classification/Surface_mesh_item_classification.h +++ b/src/Plugins/Classification/Surface_mesh_item_classification.h @@ -149,7 +149,7 @@ class Surface_mesh_item_classification : public Item_classification_base void change_color (int index, float* vmin = NULL, float* vmax = NULL); - void threshold_based_change_color(int index, int threshold, bool below, float* vmin = NULL, float* vmax = NULL); + void threshold_based_change_color(int index, std::vector &thresholds, std::vector& belows, float* vmin = NULL, float* vmax = NULL); bool can_show_probability(); diff --git a/src/Plugins/IO/PLY_io_plugin.cpp b/src/Plugins/IO/PLY_io_plugin.cpp index 97bf403..7e5fdf5 100644 --- a/src/Plugins/IO/PLY_io_plugin.cpp +++ b/src/Plugins/IO/PLY_io_plugin.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include class Polyhedron_demo_ply_plugin : @@ -275,6 +276,7 @@ Polyhedron_demo_ply_plugin::load(QFileInfo fileinfo) { std::map face_visited_check; std::map> textureID_vertices_grouping; std::map> textureID_facets_grouping; + std::set, FaceAreaComp> sorted_ascending_order; BOOST_FOREACH(face_descriptor fd, faces(*(sm_item->polyhedron()))) { if (flabels.empty() == false) @@ -332,11 +334,26 @@ Polyhedron_demo_ply_plugin::load(QFileInfo fileinfo) { Point_3 p_tmp(fvx, fvy, fvz); Vector_3 n_tmp(sm_item->face_normals[fd]); sm_item->face_center_point_set.insert(p_tmp, n_tmp); + + //add face area + sm_item->face_area[fd] = CGAL::Polygon_mesh_processing::face_area(fd, *(sm_item->polyhedron())); + sm_item->seg_area_sorted_percentile[fd] = 0.0f; + sorted_ascending_order.insert(std::make_pair(fd, sm_item->face_area[fd])); ++f_ind; } //update total labeled faces sm_item->total_labeled_faces = total_labeled_faces_i; + //update face area percetile + if (fi_segment_id.empty()) + { + std::set, FaceAreaComp>::iterator it_fdarea = sorted_ascending_order.begin(); + for (int f_area_id = 0; it_fdarea != sorted_ascending_order.end(); it_fdarea++, f_area_id++) + { + sm_item->seg_area_sorted_percentile[it_fdarea->first] = float(f_area_id) / float(faces(*(sm_item->polyhedron())).size()); + } + } + //update face segment id (check if isolated segments are merged as one) //if (fi_segment_id.empty() == false) //{ diff --git a/src/Scene_surface_mesh_item.cpp b/src/Scene_surface_mesh_item.cpp index cb8ff7b..bb068d0 100644 --- a/src/Scene_surface_mesh_item.cpp +++ b/src/Scene_surface_mesh_item.cpp @@ -1608,10 +1608,11 @@ void Scene_surface_mesh_item::computeSegments() if (p->first.is_valid()) { segments[p->second].faces_included.insert(p->first); - segments[p->second].segment_area += CGAL::Polygon_mesh_processing::face_area(p->first, *(this->polyhedron())); + segments[p->second].segment_area += face_area[p->first];//CGAL::Polygon_mesh_processing::face_area(p->first, *(this->polyhedron())); } } + sorted_seg_area_ascending_order.clear(); std::pair minmax_faces_segment = std::make_pair(2147483647, 0); for (std::map::iterator p = segments.begin(); p != segments.end(); p++) { @@ -1627,6 +1628,16 @@ void Scene_surface_mesh_item::computeSegments() minmax_faces_segment.second = p->second.faces_included.size(); minmax_faces_segment_id.second = p->second.id; } + sorted_seg_area_ascending_order.insert(p->second); + } + + std::set::iterator seg_it = sorted_seg_area_ascending_order.begin(); + for (int seg_i = 0; seg_it != sorted_seg_area_ascending_order.end(); seg_it++, seg_i++) + { + for (auto fd : seg_it->faces_included) + { + seg_area_sorted_percentile[fd] = float(seg_i) / float(sorted_seg_area_ascending_order.size()); + } } } diff --git a/src/Scene_surface_mesh_item.h b/src/Scene_surface_mesh_item.h index 9eb5856..f9a0a3f 100644 --- a/src/Scene_surface_mesh_item.h +++ b/src/Scene_surface_mesh_item.h @@ -61,6 +61,23 @@ class Segment } }; + +struct FaceAreaComp +{ + bool operator() (const std::pair &f1, const std::pair &f2) + { + return f1.second < f2.second; + } +}; + +struct SegAreaComp +{ + bool operator() (const Segment &s1, const Segment &s2) + { + return s1.segment_area < s2.segment_area; + } +}; + //class seg_boundary_edge_info { //public: // @@ -171,6 +188,8 @@ class SCENE_SURFACE_MESH_ITEM_EXPORT Scene_surface_mesh_item std::vector texture_name; std::vector texture_images; std::map label_probabilities; + std::map face_area; + std::map seg_area_sorted_percentile; std::map id_face; std::map face_segment_id; std::map vertices_coords; @@ -195,6 +214,7 @@ class SCENE_SURFACE_MESH_ITEM_EXPORT Scene_surface_mesh_item typedef boost::graph_traits::edge_descriptor edge_descriptor; std::map segments; + std::set sorted_seg_area_ascending_order; //std::map boundary_info; std::pair minmax_faces_segment_id = std::make_pair(-1, -1); // record the informations about segments into the map "segments" based on the informations