Surface Mesh Segmentation
 All Classes Namespaces Files Functions Typedefs Pages
Filters.h
Go to the documentation of this file.
1 #ifndef CGAL_SURFACE_MESH_SEGMENTATION_FILTERS_H
2 #define CGAL_SURFACE_MESH_SEGMENTATION_FILTERS_H
3 
10 #include <vector>
11 #include <map>
12 #include <algorithm>
13 #include <queue>
14 
15 namespace CGAL {
17 namespace internal {
18 
19 template<class Polyhedron>
20 class Neighbor_selector_by_edge;
21 
22 template<class Polyhedron>
23 class Neighbor_selector_by_vertex;
24 
26 template <class Polyhedron, class NeighborSelector = Neighbor_selector_by_edge<Polyhedron> >
27 class Bilateral_filtering
28 {
29 public:
40  template<class ValuePropertyMap>
41  void operator()(const Polyhedron& mesh,
42  int window_size,
43  ValuePropertyMap values) const
44  {
45  typedef typename Polyhedron::Facet_const_handle Facet_const_handle;
46  typedef typename Polyhedron::Facet_const_iterator Facet_const_iterator;
47 
48  std::vector<double> smoothed_values; // holds smoothed values
49  smoothed_values.reserve(mesh.size_of_facets());
50 
51  for(Facet_const_iterator facet_it = mesh.facets_begin(); facet_it != mesh.facets_end(); ++facet_it)
52  {
53  std::map<Facet_const_handle, int> neighbors;
54  NeighborSelector()(facet_it, window_size, neighbors); // gather neighbors in the window
55 
56  // calculate deviation for range weighting.
57  double current_sdf_value = values[facet_it];
58  double deviation = 0.0;
59  for(typename std::map<Facet_const_handle, int>::iterator it = neighbors.begin(); it != neighbors.end(); ++it)
60  {
61  deviation += std::pow(values[it->first] - current_sdf_value, 2);
62  }
63  deviation = std::sqrt(deviation / neighbors.size());
64  if(deviation == 0.0)
65  {
66  //this might happen. In case there is no neighbors (i.e. NeighborSelector() returns just the parameter facet)
67  // . Or all neighbor facets have same sdf value.
68  smoothed_values.push_back(current_sdf_value);
69  continue;
70  }
71  // smooth
72  double total_sdf_value = 0.0, total_weight = 0.0;
73  for(typename std::map<Facet_const_handle, int>::iterator it = neighbors.begin(); it != neighbors.end(); ++it)
74  {
75  double spatial_weight = gaussian_function(it->second, window_size / 2.0); // window_size => 2*sigma
76  double range_weight = gaussian_function(values[it->first] - current_sdf_value, 1.5 * deviation);
77  // we can use just spatial_weight for Gauissian filtering
78  double weight = spatial_weight * range_weight;
79 
80  total_sdf_value += values[it->first] * weight;
81  total_weight += weight;
82  }
83  smoothed_values.push_back(total_sdf_value / total_weight);
84  }
85  // put smoothed values back again to values pmap.
86  std::vector<double>::iterator smoothed_value_it = smoothed_values.begin();
87  for(Facet_const_iterator facet_it = mesh.facets_begin(); facet_it != mesh.facets_end();
88  ++facet_it, ++smoothed_value_it)
89  {
90  values[facet_it] = *smoothed_value_it;
91  }
92  }
93 private:
95  double gaussian_function(double value, double deviation) const
96  {
97  return exp(-0.5 * (std::pow(value / deviation, 2)));
98  }
99 };
100 
102 template <class Polyhedron, class NeighborSelector = Neighbor_selector_by_vertex<Polyhedron> >
103 class Median_filtering
104 {
105 public:
114  template<class ValuePropertyMap>
115  void operator()(const Polyhedron& mesh,
116  int window_size,
117  ValuePropertyMap values) const
118  {
119  typedef typename Polyhedron::Facet_const_handle Facet_const_handle;
120  typedef typename Polyhedron::Facet_const_iterator Facet_const_iterator;
121 
122  std::vector<double> smoothed_values;
123  smoothed_values.reserve(mesh.size_of_facets());
124  for(Facet_const_iterator facet_it = mesh.facets_begin(); facet_it != mesh.facets_end(); ++facet_it)
125  {
126  std::map<Facet_const_handle, int> neighbors;
127  NeighborSelector()(facet_it, window_size, neighbors); // gather neighbors in the window
128 
129  std::vector<double> neighbor_values;
130  neighbor_values.reserve(neighbors.size());
131  for(typename std::map<Facet_const_handle, int>::iterator it = neighbors.begin(); it != neighbors.end(); ++it)
132  {
133  neighbor_values.push_back(values[it->first]);
134  }
135  // Find median.
136  int half_neighbor_count = neighbor_values.size() / 2;
137  std::nth_element(neighbor_values.begin(), neighbor_values.begin() + half_neighbor_count, neighbor_values.end());
138  double median_sdf = neighbor_values[half_neighbor_count];
139  if(neighbor_values.size() % 2 == 0)
140  {
141  median_sdf += *std::max_element(neighbor_values.begin(), neighbor_values.begin() + half_neighbor_count);
142  median_sdf /= 2;
143  }
144  smoothed_values.push_back(median_sdf);
145  }
146  // put smoothed values back again to values pmap.
147  std::vector<double>::iterator smoothed_value_it = smoothed_values.begin();
148  for(Facet_const_iterator facet_it = mesh.facets_begin(); facet_it != mesh.facets_end();
149  ++facet_it, ++index)
150  {
151  values[facet_it] = *smoothed_value_it;
152  }
153  }
154 };
155 
157 template<class Polyhedron>
158 class Neighbor_selector_by_edge
159 {
160 private:
161  typedef typename Polyhedron::Facet::Halfedge_around_facet_const_circulator Halfedge_around_facet_const_circulator;
162 public:
163  typedef typename Polyhedron::Facet_const_handle Facet_const_handle;
170  void operator()(Facet_const_handle facet,
171  int max_level,
172  std::map<Facet_const_handle, int>& neighbors) const
173  {
174  typedef std::pair<Facet_const_handle, int> Facet_level_pair;
175 
176  std::queue<Facet_level_pair> facet_queue;
177  facet_queue.push(Facet_level_pair(facet, 0));
178  neighbors.insert(facet_queue.front());
179 
180  while(!facet_queue.empty())
181  {
182  const Facet_level_pair& pair = facet_queue.front();
183 
184  Halfedge_around_facet_const_circulator facet_circulator = pair.first->facet_begin();
185  do {
186  if(!facet_circulator->opposite()->is_border())
187  {
188  Facet_level_pair new_pair(facet_circulator->opposite()->facet(), pair.second + 1);
189  if(neighbors.insert(new_pair).second && new_pair.second < max_level) // first insert new_pair to map
190  { // if insertion is OK, then check its level
191  facet_queue.push(new_pair); // if its level is equal to max_level do not put it in
192  } // queue since we do not want to traverse its neighbors
193  }
194  } while(++facet_circulator != pair.first->facet_begin());
195 
196  facet_queue.pop();
197  }
198  }
199 };
200 
202 template<class Polyhedron>
203 class Neighbor_selector_by_vertex
204 {
205 private:
206  typedef typename Polyhedron::Facet::Halfedge_around_vertex_const_circulator Halfedge_around_vertex_const_circulator;
207  typedef typename Polyhedron::Halfedge_const_iterator Halfedge_const_iterator;
208  typedef typename Polyhedron::Vertex_const_iterator Vertex_const_iterator;
209 public:
210  typedef typename Polyhedron::Facet_const_handle Facet_const_handle;
217  void operator()(Facet_const_handle facet,
218  int max_level,
219  std::map<Facet_const_handle, int>& neighbors) const
220  {
221  typedef std::pair<Facet_const_handle, int> Facet_level_pair;
222 
223  std::queue<Facet_level_pair> facet_queue;
224  facet_queue.push(Facet_level_pair(facet, 0));
225  neighbors.insert(facet_queue.front());
226 
227  while(!facet_queue.empty())
228  {
229  const Facet_level_pair& pair = facet_queue.front();
230 
231  Facet_const_handle facet_front = pair.first;
232  Halfedge_const_iterator edge = facet_front->halfedge();
233  do { // loop on three vertices of the facet
234  Vertex_const_iterator vertex = edge->vertex();
235  Halfedge_around_vertex_const_circulator vertex_circulator = vertex->vertex_begin();
236  do { // for each vertex loop on incoming edges (through those edges loop on neighbor facets which includes the vertex)
237  if(!vertex_circulator->is_border())
238  {
239  Facet_level_pair new_pair(vertex_circulator->opposite()->facet(), pair.second + 1);
240  if(neighbors.insert(new_pair).second && new_pair.second < max_level) // first insert new_pair to map
241  { // if insertion is OK, then check its level
242  facet_queue.push(new_pair); // if its level is equal to max_level do not put it in
243  } // queue since we do not want to traverse its childs
244  }
245  } while(++vertex_circulator != vertex->vertex_begin());
246  } while((edge = edge->next()) != facet_front->halfedge());
247 
248  facet_queue.pop();
249  }
250  }
251 };
252 }//namespace internal
254 }//namespace CGAL
255 #endif //CGAL_SURFACE_MESH_SEGMENTATION_FILTERS_H