Statismo  0.10.1
 All Classes Namespaces Functions Typedefs
itkStandardMeshRepresenter.hxx
1 /*
2  * This file is part of the statismo library.
3  *
4  * Author: Marcel Luethi (marcel.luethi@unibas.ch)
5  *
6  * Copyright (c) 2011 University of Basel
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * Redistributions of source code must retain the above copyright notice,
14  * this list of conditions and the following disclaimer.
15  *
16  * Redistributions in binary form must reproduce the above copyright
17  * notice, this list of conditions and the following disclaimer in the
18  * documentation and/or other materials provided with the distribution.
19  *
20  * Neither the name of the project's author nor the names of its
21  * contributors may be used to endorse or promote products derived from
22  * this software without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
30  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
31  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
32  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
33  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
34  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35  *
36  */
37 
38 #ifndef __itkStandardMeshRepresenter_hxx
39 #define __itkStandardMeshRepresenter_hxx
40 
41 #include "itkStandardMeshRepresenter.h"
42 
43 #include <iostream>
44 
45 #include <itkIdentityTransform.h>
46 #include <itkMeshFileReader.h>
47 #include <itkMeshFileWriter.h>
48 #include <itkPoint.h>
49 #include <itkTransformMeshFilter.h>
50 #include <itkVector.h>
51 
52 #include "HDF5Utils.h"
53 #include "StatismoUtils.h"
54 
55 namespace itk {
56 
57 template <class TPixel, unsigned MeshDimension>
58 StandardMeshRepresenter<TPixel, MeshDimension>::StandardMeshRepresenter()
59  : m_reference(0) {
60 }
61 template <class TPixel, unsigned MeshDimension>
62 StandardMeshRepresenter<TPixel, MeshDimension>::~StandardMeshRepresenter() {
63 }
64 
65 template <class TPixel, unsigned MeshDimension>
66 StandardMeshRepresenter<TPixel, MeshDimension>*
67 StandardMeshRepresenter<TPixel, MeshDimension>::Clone() const {
68 
69  StandardMeshRepresenter* clone = new StandardMeshRepresenter();
70  clone->Register();
71 
72  typename MeshType::Pointer clonedReference = this->CloneDataset(m_reference);
73  clone->SetReference(clonedReference);
74  return clone;
75 }
76 
77 
78 template <class TPixel, unsigned MeshDimension>
79 void
80 StandardMeshRepresenter<TPixel, MeshDimension>::Load(const H5::Group& fg) {
81 
82  std::string repName = statismo::HDF5Utils::readStringAttribute(fg, "name");
83  if (repName == "vtkPolyDataRepresenter" || repName == "itkMeshRepresenter") {
84  this->SetReference(LoadRefLegacy(fg));
85  } else {
86  this->SetReference(LoadRef(fg));
87  }
88 }
89 
90 template <class TPixel, unsigned MeshDimension>
91 typename StandardMeshRepresenter<TPixel, MeshDimension>::MeshType::Pointer
92 StandardMeshRepresenter<TPixel, MeshDimension>::LoadRef(const H5::Group& fg) const {
93 
94  statismo::MatrixType vertexMat;
95  statismo::HDF5Utils::readMatrix(fg, "./points", vertexMat);
96 
97  typedef typename statismo::GenericEigenType<unsigned int>::MatrixType UIntMatrixType;
98  UIntMatrixType cellsMat;
99  statismo::HDF5Utils::readMatrixOfType<unsigned int>(fg, "./cells", cellsMat);
100 
101  unsigned nVertices = vertexMat.cols();
102  unsigned nCells = cellsMat.cols();
103  unsigned cellDim = cellsMat.rows();
104 
105 
106  typename MeshType::Pointer mesh = MeshType::New();
107 
108  // add points
109  for (unsigned i = 0; i < nVertices; i++) {
110  typename MeshType::PointType p;
111  p[0] = vertexMat(0, i);
112  p[1] = vertexMat(1, i);
113  p[2] = vertexMat(2, i);
114  mesh->SetPoint(i, p);
115  }
116 
117  // add cells
118  typedef typename MeshType::CellType::CellAutoPointer CellAutoPointer;
119  typedef itk::LineCell< typename MeshType::CellType > LineType;
120  typedef itk::TriangleCell < typename MeshType::CellType > TriangleCellType;
121 
122  CellAutoPointer cell;
123 
124  for (unsigned i = 0; i < nCells; i++) {
125  if (cellDim == 2) {
126  cell.TakeOwnership( new LineType );
127  } else if (cellDim == 3) {
128  cell.TakeOwnership( new TriangleCellType);
129  } else {
130  throw statismo::StatisticalModelException("This representer currently supports only line and triangle cells");
131  }
132 
133  for (unsigned d = 0; d < cellDim; d++) {
134  cell->SetPointId(d, cellsMat(d, i));
135  }
136  mesh->SetCell( i, cell );
137  }
138 
139  // currently this representer supports only pointdata of type scalar
140  if (statismo::HDF5Utils::existsObjectWithName(fg, "pointData")) {
141  H5::Group pdGroup = fg.openGroup("./pointData");
142 
143  if (statismo::HDF5Utils::existsObjectWithName(pdGroup, "scalars")) {
144  H5::DataSet ds = pdGroup.openDataSet("scalars");
145  unsigned type = static_cast<unsigned>(statismo::HDF5Utils::readIntAttribute(ds, "datatype"));
146  if (type != PixelConversionTrait<TPixel>::GetDataType()) {
147  std::cout << "Warning: The datatype specified for the scalars does not match the TPixel template argument used in this representer." << std::endl;
148  }
149  statismo::MatrixTypeDoublePrecision scalarMatDouble;
150  statismo::HDF5Utils::readMatrixOfType<double>(pdGroup, "scalars", scalarMatDouble);
151  statismo::MatrixType scalarMat = scalarMatDouble.cast<statismo::ScalarType>();
152  assert(static_cast<unsigned>(scalarMatDouble.cols()) == mesh->GetNumberOfPoints());
153  typename MeshType::PointDataContainerPointer pd = MeshType::PointDataContainer::New();
154 
155  for (unsigned i = 0; i < scalarMatDouble.cols(); i++) {
156  TPixel v = PixelConversionTrait<TPixel>::FromVector(scalarMat.col(i));
157  pd->InsertElement(i, v);
158  }
159  mesh->SetPointData(pd);
160  }
161 
162  pdGroup.close();
163  }
164 
165  return mesh;
166 }
167 
168 
169 template <class TPixel, unsigned MeshDimension>
170 typename StandardMeshRepresenter<TPixel, MeshDimension>::MeshType::Pointer
171 StandardMeshRepresenter<TPixel, MeshDimension>::LoadRefLegacy(const H5::Group& fg) const {
172 
173  std::string tmpfilename = statismo::Utils::CreateTmpName(".vtk");
174  statismo::HDF5Utils::getFileFromHDF5(fg, "./reference", tmpfilename.c_str());
175 
176 
177  typename itk::MeshFileReader<MeshType>::Pointer reader = itk::MeshFileReader<MeshType>::New();
178  reader->SetFileName(tmpfilename);
179  try {
180  reader->Update();
181  } catch (itk::MeshFileReaderException& e) {
182  throw statismo::StatisticalModelException((std::string("Could not read file ") + tmpfilename).c_str());
183  }
184 
185  typename MeshType::Pointer mesh = reader->GetOutput();
186  std::remove(tmpfilename.c_str());
187  return mesh;
188 
189 }
190 
191 
192 template <class TPixel, unsigned MeshDimension>
193 void
195  m_reference = reference;
196 
197  // We create a list of poitns for the domain.
198  // Furthermore, we cache for all the points of the reference, as these are the most likely ones
199  // we have to look up later.
200  typename DomainType::DomainPointsListType domainPointList;
201 
202  typename PointsContainerType::Pointer points = m_reference->GetPoints();
203  typename PointsContainerType::Iterator pointIterator= points->Begin();
204  unsigned id = 0;
205  while( pointIterator != points->End() ) {
206  domainPointList.push_back(pointIterator.Value());
207  m_pointCache.insert(std::pair<PointType, unsigned>(pointIterator.Value(), id));
208  ++pointIterator;
209  ++id;
210  }
211  m_domain = DomainType(domainPointList);
212 
213 }
214 
215 template <class TPixel, unsigned MeshDimension>
216 statismo::VectorType
218  statismo::VectorType v(PointType::GetPointDimension());
219  for (unsigned i = 0; i < PointType::GetPointDimension(); i++) {
220  v(i) = pt[i];
221  }
222  return v;
223 
224 }
225 
226 template <class TPixel, unsigned MeshDimension>
227 typename StandardMeshRepresenter<TPixel, MeshDimension>::DatasetPointerType
229  // we don't do any alignment, but simply return a clone of the dataset
230  return this->CloneDataset(ds);
231 }
232 
233 template <class TPixel, unsigned MeshDimension>
234 statismo::VectorType
236  statismo::VectorType sample(GetNumberOfPoints() * GetDimensions());
237 
238  typename PointsContainerType::Pointer points = mesh->GetPoints();
239 
240  typename PointsContainerType::Iterator pointIterator= points->Begin();
241  unsigned id = 0;
242  while( pointIterator != points->End() ) {
243  for (unsigned d = 0; d < GetDimensions(); d++) {
244  unsigned idx = this->MapPointIdToInternalIdx(id, d);
245  sample[idx] = pointIterator.Value()[d];
246  }
247  ++pointIterator;
248  ++id;
249  }
250  return sample;
251 }
252 
253 
254 
255 template <class TPixel, unsigned MeshDimension>
256 typename StandardMeshRepresenter<TPixel, MeshDimension>::DatasetPointerType
258  typename MeshType::Pointer mesh = this->CloneDataset(m_reference);
259  typename PointsContainerType::Pointer points = mesh->GetPoints();
260  typename PointsContainerType::Iterator pointsIterator = points->Begin();
261 
262  unsigned ptId = 0;
263  while( pointsIterator != points->End() ) {
264  ValueType v;
265  for (unsigned d = 0; d < GetDimensions(); d++) {
266  unsigned idx = this->MapPointIdToInternalIdx(ptId, d);
267  v[d] = sample[idx];
268  }
269  mesh->SetPoint(ptId, v);
270 
271  ++ptId;
272  ++pointsIterator;
273  }
274  return mesh;
275 }
276 
277 template <class TPixel, unsigned MeshDimension>
278 typename StandardMeshRepresenter<TPixel, MeshDimension>::ValueType
279 StandardMeshRepresenter<TPixel, MeshDimension>::PointSampleFromSample(DatasetConstPointerType sample, unsigned ptid) const {
280  if (ptid >= sample->GetNumberOfPoints()) {
281  throw statismo::StatisticalModelException("invalid ptid provided to PointSampleFromSample");
282  }
283 
284  return sample->GetPoint(ptid);
285 }
286 
287 
288 template <class TPixel, unsigned MeshDimension>
289 typename StandardMeshRepresenter<TPixel, MeshDimension>::ValueType
291  ValueType value;
292  for (unsigned d = 0; d < GetDimensions(); d++) {
293  value[d] = pointSample[d];
294  }
295  return value;
296 }
297 template <class TPixel, unsigned MeshDimension>
298 statismo::VectorType
300  statismo::VectorType vec(GetDimensions());
301  for (unsigned d = 0; d < GetDimensions(); d++) {
302  vec[d] = v[d];
303  }
304  return vec;
305 }
306 
307 
308 template <class TPixel, unsigned MeshDimension>
309 void
311  using namespace H5;
312 
313  statismo::MatrixType vertexMat = statismo::MatrixType::Zero(3, m_reference->GetNumberOfPoints());
314 
315  for (unsigned i = 0; i < m_reference->GetNumberOfPoints(); i++) {
316  typename MeshType::PointType pt = m_reference->GetPoint(i);
317  for (unsigned d = 0; d < 3; d++) {
318  vertexMat(d, i) = pt[d];
319  }
320  }
321  statismo::HDF5Utils::writeMatrix(fg, "./points", vertexMat);
322 
323  // check the dimensionality of a face (i.e. the number of points it has). We assume that
324  // all the cells are the same.
325  unsigned numPointsPerCell = 0;
326  if (m_reference->GetNumberOfCells() > 0) {
327  typename MeshType::CellAutoPointer cellPtr;
328  m_reference->GetCell(0, cellPtr);
329  numPointsPerCell = cellPtr->GetNumberOfPoints();
330  }
331 
332  typedef typename statismo::GenericEigenType<unsigned int>::MatrixType UIntMatrixType;
333  UIntMatrixType facesMat = UIntMatrixType::Zero(numPointsPerCell, m_reference->GetNumberOfCells());
334 
335 
336  for (unsigned i = 0; i < m_reference->GetNumberOfCells(); i++) {
337  typename MeshType::CellAutoPointer cellPtr;
338  m_reference->GetCell(i, cellPtr);
339  assert(numPointsPerCell == cellPtr->GetNumberOfPoints());
340  for (unsigned d = 0; d < numPointsPerCell; d++) {
341  facesMat(d, i) = cellPtr->GetPointIds()[d];
342  }
343  }
344 
345  H5::Group pdGroup = fg.createGroup("pointData");
346 
347  typename MeshType::PointDataContainerPointer pd = m_reference->GetPointData();
348  if (pd.IsNotNull() && pd->Size() == m_reference->GetNumberOfPoints()) {
349  unsigned numComponents = PixelConversionTrait<TPixel>::ToVector(pd->GetElement(0)).rows();
350 
351  statismo::MatrixType scalarsMat = statismo::MatrixType::Zero(numComponents, m_reference->GetNumberOfPoints());
352  for (unsigned i = 0; i < m_reference->GetNumberOfPoints(); i++) {
353  scalarsMat.col(i) = PixelConversionTrait<TPixel>::ToVector(pd->GetElement(i));
354  }
355  statismo::MatrixTypeDoublePrecision scalarsMatDouble = scalarsMat.cast<double>();
356  H5::DataSet ds = statismo::HDF5Utils::writeMatrixOfType<double>(pdGroup, "scalars", scalarsMatDouble);
357  statismo::HDF5Utils::writeIntAttribute(ds, "datatype", PixelConversionTrait<TPixel>::GetDataType());
358  }
359 
360 
361  statismo::HDF5Utils::writeMatrixOfType<unsigned int>(fg, "./cells", facesMat);
362 }
363 
364 
365 template <class TPixel, unsigned MeshDimension>
366 unsigned
368  return this->m_reference->GetNumberOfPoints();
369 }
370 
371 
372 template <class TPixel, unsigned MeshDimension>
373 unsigned
375  int ptId = -1;
376 
377  // check whether the point is cached, otherwise look for it
378  typename PointCacheType::const_iterator got = m_pointCache.find (pt);
379  if (got == m_pointCache.end()) {
380  ptId = FindClosestPoint(m_reference, pt);
381  m_pointCache.insert(std::pair<PointType, unsigned>(pt, ptId));
382  } else {
383  ptId = got->second;
384  }
385  assert(ptId != -1);
386  return static_cast<unsigned>(ptId);
387 }
388 
389 
390 
391 template <class TPixel, unsigned MeshDimension>
392 typename StandardMeshRepresenter<TPixel, MeshDimension>::DatasetPointerType
393 StandardMeshRepresenter<TPixel, MeshDimension>::CloneDataset(DatasetConstPointerType mesh) const {
394 
395  // cloning is cumbersome - therefore we let itk do the job for, and use perform a
396  // Mesh transform using the identity transform. This should result in a perfect clone.
397 
398  typedef itk::IdentityTransform<TPixel, MeshDimension> IdentityTransformType;
399  typedef itk::TransformMeshFilter<MeshType, MeshType, IdentityTransformType> TransformMeshFilterType;
400 
401  typename TransformMeshFilterType::Pointer tf = TransformMeshFilterType::New();
402  tf->SetInput(mesh);
403  typename IdentityTransformType::Pointer idTrans = IdentityTransformType::New();
404  tf->SetTransform(idTrans);
405  tf->Update();
406 
407  typename MeshType::Pointer clone = tf->GetOutput();
408  clone->DisconnectPipeline();
409  return clone;
410 }
411 
412 template <class TPixel, unsigned MeshDimension>
413 unsigned
414 StandardMeshRepresenter<TPixel, MeshDimension>::FindClosestPoint(const MeshType* mesh, const PointType pt) const {
415  throw statismo::StatisticalModelException("Not implemented. Currently only points of the reference can be used.");
416 }
417 
418 } // namespace itk
419 
420 #endif
static bool existsObjectWithName(const H5::CommonFG &fg, const std::string &name)
Definition: HDF5Utils.hxx:542
static void writeIntAttribute(const H5::H5Object &fg, const char *name, int value)
Definition: HDF5Utils.hxx:406
statismo::VectorType SampleToSampleVector(DatasetConstPointerType sample) const
Definition: itkStandardMeshRepresenter.hxx:235
A representer for scalar valued itk Meshs.
Definition: itkStandardMeshRepresenter.h:90
static void readMatrix(const H5::CommonFG &fg, const char *name, MatrixType &matrix)
Definition: HDF5Utils.hxx:154
ValueType PointSampleFromSample(DatasetConstPointerType sample, unsigned ptid) const
Definition: itkStandardMeshRepresenter.hxx:279
virtual unsigned GetPointIdForPoint(const PointType &point) const
Definition: itkStandardMeshRepresenter.hxx:374
static H5::DataSet writeMatrix(const H5::CommonFG &fg, const char *name, const MatrixType &matrix)
Definition: HDF5Utils.hxx:248
statismo::VectorType PointSampleToPointSampleVector(const ValueType &v) const
Definition: itkStandardMeshRepresenter.hxx:299
void Save(const H5::Group &fg) const
Definition: itkStandardMeshRepresenter.hxx:310
static std::string readStringAttribute(const H5::H5Object &group, const char *name)
Definition: HDF5Utils.hxx:397
DatasetPointerType SampleVectorToSample(const statismo::VectorType &sample) const
Definition: itkStandardMeshRepresenter.hxx:257
Generic Exception class for the statismo Library.
Definition: Exceptions.h:68
void SetReference(DatasetPointerType ds)
Definition: itkStandardMeshRepresenter.hxx:194
float ScalarType
the type that is used for all vector and matrices throughout the library.
Definition: CommonTypes.h:60
ValueType PointSampleVectorToPointSample(const statismo::VectorType &pointSample) const
Definition: itkStandardMeshRepresenter.hxx:290
static void getFileFromHDF5(const H5::CommonFG &fg, const char *name, const char *filename)
Definition: HDF5Utils.hxx:462
DatasetPointerType DatasetToSample(DatasetConstPointerType ds) const
Definition: itkStandardMeshRepresenter.hxx:228
Definition: Domain.h:51
virtual unsigned GetNumberOfPoints() const
return the number of points of the reference
Definition: itkStandardMeshRepresenter.hxx:367
static int readIntAttribute(const H5::H5Object &group, const char *name)
Definition: HDF5Utils.hxx:416