OMToolkit  1.0
The polygonal mesh processing tool.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
OMFilter.hxx
Go to the documentation of this file.
1 //==============================================================================
14 #ifndef _OM_FILTER_HXX_
15 #define _OM_FILTER_HXX_
16 
19 // Constructor - initializes vital variables and makes a liaison with target mesh
20 // @param mesh Mesh to work with
22 template <class Mesh, class MatrixT>
24 {
25  m_mesh = mesh;
26  m_loaded = false;
27  m_numKernels = 0;
28 }
29 
31 // Saves maximal value of attached vertex matrix into attribute vector
32 // Save is done by push back
33 // @param matrixHandle Handle to a matrix - universal property handle
34 // @return True if all computation completed successfully
36 template <class Mesh, class MatrixT>
37 bool OMFilter<Mesh, MatrixT>::MaxAll(const OpenMesh::VPropHandleT<MatrixT> &matrixHandle)
38 {
39  Mesh::VertexIter end = m_mesh->vertices_end();
40  for (Mesh::VertexIter vertex = m_mesh->vertices_begin(); vertex != end; ++vertex)
41  m_mesh->getAttributes(vertex).push_back(m_mesh->property(matrixHandle, vertex).maxCoeff());
42  return true;
43 }
44 
46 // Saves median value of attached vertex matrix into attribute vector
47 // Save is done by push back
48 // @param matrixHandle Handle to a matrix - universal property handle
49 // @return True if all computation completed successfully
51 template <class Mesh, class MatrixT>
52 bool OMFilter<Mesh, MatrixT>::MedianAll(const OpenMesh::VPropHandleT<MatrixT> &matrixHandle)
53 {
54  Mesh::VertexIter end = m_mesh->vertices_end();
55  MatrixT current;
56  Scalar *data;
57  Scalar *dataCopy;
58  int size;
59  for (Mesh::VertexIter vertex = m_mesh->vertices_begin(); vertex != end; ++vertex)
60  {
61  current = m_mesh->property(matrixHandle, vertex);
62  data = current.data();
63  size = current.size();
64  dataCopy = new Scalar[size];
65  memcpy(dataCopy, data, size * sizeof(Scalar));
66 
67  std::sort(&(dataCopy[0]), &(dataCopy[size]));
68  m_mesh->getAttributes(vertex).push_back(dataCopy[size/2]);
69  delete dataCopy;
70  }
71  return true;
72 }
73 
75 // Saves mean value of attached vertex matrix into attribute vector
76 // Save is done by push back
77 // @param matrixHandle Handle to a matrix - universal property handle
78 // @return True if all computation completed successfully
80 template <class Mesh, class MatrixT>
81 bool OMFilter<Mesh, MatrixT>::MeanAll(const OpenMesh::VPropHandleT<MatrixT> &matrixHandle)
82 {
83  Mesh::VertexIter end = m_mesh->vertices_end();
84  MatrixT current;
85  Scalar *data;
86  int size;
87  for (Mesh::VertexIter vertex = m_mesh->vertices_begin(); vertex != end; ++vertex)
88  {
89  current = m_mesh->property(matrixHandle, vertex);
90  data = current.data();
91  size = current.size();
92  Scalar sum = 0.0;
93  for (int i = 0; i < size; ++i)
94  sum += data[i];
95  m_mesh->getAttributes(vertex).push_back(sum /= (Scalar)size);
96  }
97  return true;
98 }
99 
100 
102 // Saves a variance of attached vertex matrix from a plane into attribute vector
103 // Save is done by push back
104 // @param matrixHandle Handle to a matrix - universal property handle
105 // @return True if all computation completed successfully
107 template <class Mesh, class MatrixT>
108 bool OMFilter<Mesh, MatrixT>::VarianceAll(const OpenMesh::VPropHandleT<MatrixT> &matrixHandle)
109 {
110  Mesh::VertexIter end = m_mesh->vertices_end();
111  MatrixT current;
112  Scalar *data;
113  int size;
114  for (Mesh::VertexIter vertex = m_mesh->vertices_begin(); vertex != end; ++vertex)
115  {
116  current = m_mesh->property(matrixHandle, vertex);
117  data = current.data();
118  size = current.size();
119  Scalar sum = 0.0;
120  Scalar variance = 0.0;
121  for (int i = 0; i < size; ++i)
122  sum += data[i];
123 
124  sum /= (Scalar)size;
125  for (int i = 0; i < size; ++i)
126  variance += data[i] - sum;
127 
128  m_mesh->getAttributes(vertex).push_back(variance /= (Scalar)size);
129  }
130  return true;
131 }
133 // Saves minimal value of attached vertex matrix into attribute vector
134 // Save is done by push back
135 // @param matrixHandle Handle to a matrix - universal property handle
136 // @return True if all computation completed successfully
138 template <class Mesh, class MatrixT>
139 bool OMFilter<Mesh, MatrixT>::MinAll(const OpenMesh::VPropHandleT<MatrixT> &matrixHandle)
140 {
141  Mesh::VertexIter end = m_mesh->vertices_end();
142  for (Mesh::VertexIter vertex = m_mesh->vertices_begin(); vertex != end; ++vertex)
143  m_mesh->getAttributes(vertex).push_back(m_mesh->property(matrixHandle, vertex).minCoeff());
144  return true;
145 }
146 
148 // Saves a max distance of attached vertex matrix from a plane into attribute vector
149 // Save is done by push back
150 // @param matrixHandle Handle to a matrix - universal property handle
151 // @return True if all computation completed successfully
153 template <class Mesh, class MatrixT>
154 bool OMFilter<Mesh, MatrixT>::AbsAll(const OpenMesh::VPropHandleT<MatrixT> &matrixHandle)
155 {
156  Mesh::VertexIter end = m_mesh->vertices_end();
157  Scalar min, max;
158  for (Mesh::VertexIter vertex = m_mesh->vertices_begin(); vertex != end; ++vertex)
159  {
160  min = abs(m_mesh->property(matrixHandle, vertex).minCoeff());
161  max = abs(m_mesh->property(matrixHandle, vertex).maxCoeff());
162  m_mesh->getAttributes(vertex).push_back(min > max ? min : max);
163  }
164  return true;
165 }
166 
168 // Filters matrices attached to each vertex and returns value in the middle
169 // Provides only fast filtering - computes only value in the middle of a matrix
170 // Vertex matrix must have the same size asi filter kernel
171 // Kernel must be loaded from file before calling this function
172 // Result is saved into attribute vector (push back)
173 // If there is multiple filtering kernels, result is computed as eucleidian norm of result vector
174 // (result = sqrt(x^2 + y^2 + ... + z^2))
175 // @param matrixHandle Handle to a matrix - universal property handle
176 // @return True if all computation completed successfully
178 template <class Mesh, class MatrixT>
179 bool OMFilter<Mesh, MatrixT>::FilterAll(const OpenMesh::VPropHandleT<MatrixT> &matrixHandle)
180 {
181  if (m_loaded)
182  {
183  Mesh::VertexIter end = m_mesh->vertices_end();
184  MatrixT current;
185  int rows = m_filterKernel[0].rows();
186  int cols = m_filterKernel[0].cols();
187  for (Mesh::VertexIter vertex = m_mesh->vertices_begin(); vertex != end; ++vertex)
188  {
189  current = m_mesh->property(matrixHandle, vertex);
190  if (rows < current.rows() || cols < current.cols())
191  filterOneSmall(vertex.handle(), matrixHandle);
192  else
193  m_mesh->getAttributes(vertex).push_back(filterOne(vertex.handle(), matrixHandle));
194  }
195  return true;
196  }
197  else
198  return false;
199 
200 }
201 
203 // Multiplies each element of the matrix with corresponding weight in filter matrix
204 // Vertex matrix must have the same size asi filter kernel
205 // Kernel must be loaded from file before calling this function
206 // If there is multiple filtering kernels, weighting is computed in series
207 // @param matrixHandle Handle to a matrix - universal property handle
208 // @return True if all computation completed successfully
210 template <class Mesh, class MatrixT>
211 bool OMFilter<Mesh, MatrixT>::WeightAll(const OpenMesh::VPropHandleT<MatrixT> &matrixHandle)
212 {
213  if (m_loaded)
214  {
215  Mesh::VertexIter end = m_mesh->vertices_end();
216  MatrixT current;
217  int rows = m_filterKernel[0].rows();
218  int cols = m_filterKernel[0].cols();
219  for (Mesh::VertexIter vertex = m_mesh->vertices_begin(); vertex != end; ++vertex)
220  {
221  current = m_mesh->property(matrixHandle, vertex);
222  if (rows != current.rows() || cols != current.cols()) return false;
223 
224  weightOne(vertex.handle(), matrixHandle);
225  }
226  return true;
227  }
228  else
229  return false;
230 }
231 
233 // Helper function which computes fast filtering of one matrix (used in FilterAll)
234 // @param vertex Vertex on which we are doing computations
235 // @param matrixHandle Handle to a matrix - universal property handle
236 // @return value in the middle of matrix
238 template <class Mesh, class MatrixT>
239 typename OMFilter<Mesh, MatrixT>::Scalar OMFilter<Mesh, MatrixT>::filterOne(typename Mesh::VertexHandle &vertex, const OpenMesh::VPropHandleT<MatrixT> &matrixHandle)
240 {
241  // load matrix data
242  Scalar *first = m_mesh->property(matrixHandle, vertex).data();
243  Scalar *filter = NULL;
244  Scalar result = 0.0;
245 
246  for (unsigned int i = 0; i < m_numKernels; ++i)
247  {
248  Scalar aux = 0.0;
249  filter = m_filterKernel[i].data();
250  int i_max = m_filterKernel[i].size();
251  for (int j = 0; j < i_max; ++j) aux += filter[j] * first[j];
252  result += aux * aux;
253  }
254  return sqrt(result);
255 }
256 
258 // Helper function which computes fast filtering of one matrix (smaller filter kernel than tangent matrix)
259 // @param vertex Vertex on which we are doing computations
260 // @param matrixHandle Handle to a matrix - universal property handle
262 template <class Mesh, class MatrixT>
263 void OMFilter<Mesh, MatrixT>::filterOneSmall(typename Mesh::VertexHandle &vertex, const OpenMesh::VPropHandleT<MatrixT> &matrixHandle)
264 {
265  MatrixT matrix = m_mesh->property(matrixHandle, vertex);
266  int rows = matrix.rows();
267  MatrixT aux(rows, rows);
268 
269  MatrixT filter = m_filterKernel[0];
270  int rowsF = filter.rows();
271 
272  int half = rowsF/2;
273 
274  // convolution
275  for (int r = 0; r < rows; ++r)
276  for (int c = 0; c < rows; ++c)
277  {
278  Scalar result = 0.0;
279  for (int rF = -half; rF <= half; ++rF)
280  for (int cF = -half; cF <= half; ++cF)
281  {
282  if (r+rF < 0 || c+cF < 0 || r+rF >= rows || r+rF >= rows) continue;
283  else
284  {
285  result += matrix(r+rF, c+cF) * filter(rF+half, cF+half);
286  }
287  }
288  aux(r, c) = result;
289  }
290 
291  m_mesh->property(matrixHandle, vertex) = aux;
292 }
293 
295 // Helper function which multiplies each matrix element with corresponding weight saved in filter matrix
296 // @param vertex Vertex on which we are doing computations
297 // @param matrixHandle Handle to a matrix - universal property handle
299 template <class Mesh, class MatrixT>
300 void OMFilter<Mesh, MatrixT>::weightOne(typename Mesh::VertexHandle &vertex, const OpenMesh::VPropHandleT<MatrixT> &matrixHandle)
301 {
302  // load matrix data
303  Scalar *first = m_mesh->property(matrixHandle, vertex).data();
304  Scalar *filter = NULL;
305  for (unsigned int i = 0; i < m_numKernels; ++i)
306  {
307  filter = m_filterKernel[i].data();
308  int i_max = m_filterKernel[i].size();
309  for (int i = 0; i < i_max; ++i) first[i] = filter[i] * first[i];
310  }
311 }
312 
314 // Function loads a file with saved filter matrix
315 // File can contain multiple matrices - all are loaded
316 // Structure of a file is following:
317 //
318 // Matrix 2 2
319 // 3 4
320 // 1 2
321 //
322 // First row contains keyword Matrix with specified dimensions, the other rows contains values
323 // After this, another header can follow with second matrix
324 // @param filename File name
325 // @return True, if loaded successfully
327 template <class Mesh, class MatrixT>
328 bool OMFilter<Mesh, MatrixT>::LoadFile(std::string filename)
329 {
330  std::ifstream file;
331  file.open(filename);
332 
333  // check if file is open
334  if (!file.is_open()) return false;
335  m_filterKernel.clear();
336  m_numKernels = 0;
337 
338  // while not eof, we read
339  while (!file.eof())
340  {
341  std::string header;
342  file >> header;
343 
344  // check header
345  if (header != "Matrix") return false;
346  int rows, cols;
347  file >> rows;
348  file >> cols;
349 
350  // check rows and cols information
351  if (rows <= 0 || cols <= 0) return false;
352 
353  m_filterKernel.push_back(MatrixT(rows, cols));
354 
355  // read matrix
356  for (int r = 0; r < rows; ++r)
357  for (int c = 0; c < rows; ++c)
358  {
359  if (file.eof()) return false;
360  file >> m_filterKernel.back()(r, c);
361  }
362  ++m_numKernels;
363  // if there is not end of file, continue with another kernel
364  }
365  file.close();
366  m_loaded = true;
367  if (m_filterKernel.size() > 0)
368  {
369  int rows = m_filterKernel[0].rows();
370  int cols = m_filterKernel[0].cols();
371  for (unsigned int i = 0; i < m_filterKernel.size(); ++i)
372  {
373  if (rows != m_filterKernel[i].rows() || cols != m_filterKernel[i].cols()) return false;
374  }
375  }
376  return true;
377 }
378 
380 // Function saves internal matrices into file
381 // @param filename File name
382 // @return True, if saved successfully
384 template <class Mesh, class MatrixT>
385 bool OMFilter<Mesh, MatrixT>::SaveFile(std::string filename)
386 {
387  std::ofstream file;
388  file.open(filename);
389 
390  // check if file is open
391  if (!file.is_open() || !m_loaded) return false;
392 
393  // write all kernels
394  for (unsigned int i = 0; i < m_numKernels; ++i)
395  {
396  // header + dimensions
397  file << "Matrix ";
398  file << m_filterKernel[i].rows() << " "<< m_filterKernel[i].cols() << std::endl;
399 
400  // each cell
401  for (int r = 0; r < m_filterKernel[i].rows(); ++r)
402  {
403  for (int c = 0; c < m_filterKernel[i].cols(); ++c)
404  file << m_filterKernel[i](r, c) << " ";
405  file << std::endl;
406  }
407  file << std::endl;
408  }
409  // close file
410  file.close();
411  return true;
412 }
413 
414 #endif // _OM_FILTER_HXX_