1 #ifndef CGAL_SURFACE_MESH_SEGMENTATION_H
2 #define CGAL_SURFACE_MESH_SEGMENTATION_H
4 #include <CGAL/internal/Surface_mesh_segmentation/Expectation_maximization.h>
7 #include <CGAL/internal/Surface_mesh_segmentation/SDF_calculation.h>
9 #include <CGAL/Mesh_3/dihedral_angle_3.h>
11 #include <boost/property_map/property_map.hpp>
19 #define CGAL_NORMALIZATION_ALPHA 5.0
20 #define CGAL_CONVEX_FACTOR 0.08
21 #define CGAL_SMOOTHING_LAMBDA_MULTIPLIER 100.0
48 #ifdef CGAL_USE_BOYKOV_KOLMOGOROV_MAXFLOW_SOFTWARE
49 class GraphCut = Alpha_expansion_graph_cut_boykov_kolmogorov,
51 class GraphCut = Alpha_expansion_graph_cut_boost,
53 class Filter = Bilateral_filtering<Polyhedron>
55 class Surface_mesh_segmentation
59 typedef typename Polyhedron::Facet_const_handle Facet_const_handle;
63 typedef typename GeomTraits::Point_3 Point;
65 typedef typename Polyhedron::Facet Facet;
67 typedef typename Polyhedron::Edge_const_iterator Edge_const_iterator;
68 typedef typename Polyhedron::Halfedge_const_handle Halfedge_const_handle;
69 typedef typename Polyhedron::Halfedge_const_iterator Halfedge_const_iterator;
70 typedef typename Polyhedron::Facet_const_iterator Facet_const_iterator;
71 typedef typename Polyhedron::Vertex_const_iterator Vertex_const_iterator;
73 typedef SDF_calculation<Polyhedron, GeomTraits> SDF_calculation_class;
77 const Polyhedron& mesh;
85 Surface_mesh_segmentation(
const Polyhedron& mesh, GeomTraits traits)
86 : mesh(mesh), traits(traits)
87 { CGAL_precondition(mesh.is_pure_triangle()); }
90 template <
class SDFPropertyMap>
91 std::pair<double, double>
92 calculate_sdf_values(
double cone_angle,
int number_of_rays, SDFPropertyMap sdf_pmap)
95 SDF_calculation_class(traits).calculate_sdf_values(mesh, cone_angle, number_of_rays, sdf_pmap);
97 check_zero_sdf_values(sdf_pmap);
98 Filter()(mesh, get_window_size(), sdf_pmap);
99 std::pair<double, double> min_max_sdf_values = linear_normalize_sdf_values(sdf_pmap);
102 return min_max_sdf_values;
105 template <
class FacetSegmentMap,
class SDFPropertyMap>
106 int partition(
int number_of_centers,
double smoothing_lambda, SDFPropertyMap sdf_pmap, FacetSegmentMap segment_pmap)
108 smoothing_lambda = (std::max)(0.0, (std::min)(1.0, smoothing_lambda));
109 smoothing_lambda *= CGAL_SMOOTHING_LAMBDA_MULTIPLIER;
112 std::vector<double> sdf_values;
113 log_normalize_sdf_values(sdf_pmap, sdf_values);
116 Expectation_maximization fitter(number_of_centers, sdf_values,
117 Expectation_maximization::K_MEANS_INITIALIZATION, 1);
119 std::vector<int> labels;
120 fitter.fill_with_center_ids(labels);
122 std::vector<std::vector<double> > probability_matrix;
123 fitter.fill_with_probabilities(probability_matrix);
124 log_normalize_probability_matrix(probability_matrix);
127 std::vector<std::pair<int, int> > edges;
128 std::vector<double> edge_weights;
129 calculate_and_log_normalize_dihedral_angles(smoothing_lambda, edges, edge_weights);
132 GraphCut()(edges, edge_weights, probability_matrix, labels);
133 std::vector<int>::iterator label_it = labels.begin();
134 for(Facet_const_iterator facet_it = mesh.facets_begin(); facet_it != mesh.facets_end();
135 ++facet_it, ++label_it)
137 segment_pmap[facet_it] = *label_it;
140 int number_of_segments = assign_segments(number_of_centers, sdf_pmap, segment_pmap);
141 return number_of_segments;
153 double calculate_dihedral_angle_of_edge(Halfedge_const_handle edge)
const
155 CGAL_precondition(!edge->is_border_edge());
156 const Point& a = edge->vertex()->point();
157 const Point& b = edge->prev()->vertex()->point();
158 const Point& c = edge->next()->vertex()->point();
159 const Point& d = edge->opposite()->next()->vertex()->point();
163 double n_angle = Mesh_3::dihedral_angle(a, b, c, d);
165 bool concave = n_angle > 0;
166 double angle = 1 + ((concave ? -1 : +1) * n_angle);
168 if(!concave) { angle *= CGAL_CONVEX_FACTOR; }
179 template<
class SDFPropertyMap>
180 void log_normalize_sdf_values(SDFPropertyMap sdf_values, std::vector<double>& normalized_sdf_values)
182 normalized_sdf_values.reserve(mesh.size_of_facets());
183 for(Facet_const_iterator facet_it = mesh.facets_begin(); facet_it != mesh.facets_end(); ++facet_it)
185 double log_normalized = log(sdf_values[facet_it] * CGAL_NORMALIZATION_ALPHA + 1) / log(CGAL_NORMALIZATION_ALPHA + 1);
186 normalized_sdf_values.push_back(log_normalized);
195 template<
class SDFPropertyMap>
196 std::pair<double, double> linear_normalize_sdf_values(SDFPropertyMap sdf_values)
198 double max_sdf = -(std::numeric_limits<double>::max)();
199 double min_sdf = (std::numeric_limits<double>::max)();
200 for(Facet_const_iterator facet_it = mesh.facets_begin(); facet_it != mesh.facets_end(); ++facet_it)
202 double sdf_value = sdf_values[facet_it];
203 max_sdf = (std::max)(sdf_value, max_sdf);
204 min_sdf = (std::min)(sdf_value, min_sdf);
206 const double max_min_dif = max_sdf - min_sdf;
207 for(Facet_const_iterator facet_it = mesh.facets_begin(); facet_it != mesh.facets_end(); ++facet_it)
209 sdf_values[facet_it] = (sdf_values[facet_it] - min_sdf) / max_min_dif;
211 return std::make_pair(min_sdf, max_sdf);
224 int get_window_size()
226 double facet_sqrt = std::sqrt(mesh.size_of_facets() / 2000.0);
227 return static_cast<int>(facet_sqrt) + 1;
237 template<
class SDFPropertyMap>
238 void check_zero_sdf_values(SDFPropertyMap sdf_values)
240 std::vector<Facet_const_handle> still_zero_facets;
241 double min_sdf = (std::numeric_limits<double>::max)();
243 for(Facet_const_iterator facet_it = mesh.facets_begin(); facet_it != mesh.facets_end(); ++facet_it)
245 double sdf_value = sdf_values[facet_it];
248 typename Facet::Halfedge_around_facet_const_circulator facet_circulator = facet_it->facet_begin();
249 double total_neighbor_sdf = 0.0;
251 if(!facet_circulator->opposite()->is_border())
253 total_neighbor_sdf += sdf_values[facet_circulator->opposite()->facet()];
255 }
while( ++facet_circulator != facet_it->facet_begin());
257 sdf_value = total_neighbor_sdf / 3.0;
258 sdf_values[facet_it] = sdf_value;
260 if(sdf_value == 0.0) { still_zero_facets.push_back(facet_it); }
261 else { min_sdf = (std::min)(sdf_value, min_sdf); }
263 else { min_sdf = (std::min)(sdf_value, min_sdf); }
267 for(
typename std::vector<Facet_const_handle>::iterator it = still_zero_facets.begin();
268 it != still_zero_facets.end(); ++it)
270 sdf_values[*it] = min_sdf;
279 void log_normalize_probability_matrix(std::vector<std::vector<double> >& probabilities)
const
281 const double epsilon = 5e-6;
282 for(std::vector<std::vector<double> >::iterator it_i = probabilities.begin(); it_i != probabilities.end(); ++it_i)
284 for(std::vector<double>::iterator it = it_i->begin(); it != it_i->end(); ++it)
286 double probability = (std::max)(*it, epsilon);
287 probability = -log(probability);
288 *it = (std::max)(probability, std::numeric_limits<double>::epsilon());
300 void calculate_and_log_normalize_dihedral_angles(
double smoothing_lambda,
301 std::vector<std::pair<int, int> >& edges, std::vector<double>& edge_weights)
const
307 std::map<Facet_const_handle, int> facet_index_map;
309 for(Facet_const_iterator facet_it = mesh.facets_begin(); facet_it != mesh.facets_end();
310 ++facet_it, ++facet_index)
312 facet_index_map[facet_it] = facet_index;
315 const double epsilon = 5e-6;
317 for(Edge_const_iterator edge_it = mesh.edges_begin(); edge_it != mesh.edges_end(); ++edge_it)
319 if(edge_it->is_border_edge()) {
continue; }
320 const int index_f1 = facet_index_map[edge_it->facet()];
321 const int index_f2 = facet_index_map[edge_it->opposite()->facet()];
322 edges.push_back(std::make_pair(index_f1, index_f2));
324 double angle = calculate_dihedral_angle_of_edge(edge_it);
326 if(angle < epsilon) { angle = epsilon; }
328 angle = (std::max)(angle, std::numeric_limits<double>::epsilon());
329 angle *= smoothing_lambda;
330 edge_weights.push_back(angle);
335 struct Sort_pairs_with_second {
336 bool operator() (
const Pair& pair_1,
const Pair& pair_2)
const
338 return pair_1.second < pair_2.second;
360 template<
class SegmentPropertyMap,
class SDFProperyMap>
361 int assign_segments(
int number_of_clusters, SDFProperyMap sdf_values, SegmentPropertyMap segments)
364 int segment_id = number_of_clusters;
365 std::vector<std::pair<int, double> > segments_with_average_sdf_values;
367 for(Facet_const_iterator facet_it = mesh.facets_begin(); facet_it != mesh.facets_end(); ++facet_it)
369 if(segments[facet_it] < number_of_clusters)
371 double average_sdf_value = breadth_first_traversal(facet_it, segment_id, sdf_values, segments);
373 segments_with_average_sdf_values.push_back(std::make_pair(segment_id, average_sdf_value));
378 sort(segments_with_average_sdf_values.begin(), segments_with_average_sdf_values.end(),
379 Sort_pairs_with_second<std::pair<int, double> >());
381 std::vector<int> segment_id_to_sorted_id_map(segments_with_average_sdf_values.size());
382 for(std::size_t index = 0; index < segments_with_average_sdf_values.size(); ++index)
384 int segment_id = segments_with_average_sdf_values[index].first - number_of_clusters;
385 segment_id_to_sorted_id_map[segment_id] = index;
389 for(Facet_const_iterator facet_it = mesh.facets_begin(); facet_it != mesh.facets_end(); ++facet_it)
391 int segment_id = segments[facet_it] - number_of_clusters;
392 segments[facet_it] = segment_id_to_sorted_id_map[segment_id];
394 return segment_id - number_of_clusters;
406 template<
class SegmentPropertyMap,
class SDFProperyMap>
408 breadth_first_traversal(Facet_const_handle root,
int segment_id, SDFProperyMap sdf_values, SegmentPropertyMap segments)
410 std::queue<Facet_const_handle> facet_queue;
411 facet_queue.push(root);
413 int prev_segment_id = segments[root];
414 segments[root] = segment_id;
416 double total_sdf_value = sdf_values[root];
417 int visited_facet_count = 1;
419 while(!facet_queue.empty())
421 Facet_const_handle facet = facet_queue.front();
423 typename Facet::Halfedge_around_facet_const_circulator facet_circulator = facet->facet_begin();
425 if(facet_circulator->opposite()->is_border()) {
continue; }
426 Facet_const_handle neighbor = facet_circulator->opposite()->facet();
427 if(prev_segment_id == segments[neighbor])
429 segments[neighbor] = segment_id;
430 facet_queue.push(neighbor);
432 total_sdf_value += sdf_values[neighbor];
433 ++visited_facet_count;
435 }
while( ++facet_circulator != facet->facet_begin());
440 return total_sdf_value / visited_facet_count;
448 #undef CGAL_NORMALIZATION_ALPHA
449 #undef CGAL_CONVEX_FACTOR
450 #undef CGAL_SMOOTHING_LAMBDA_MULTIPLIER
451 #endif //CGAL_SURFACE_MESH_SEGMENTATION_H