Statismo  0.10.1
 All Classes Namespaces Functions Typedefs
vtkStandardImageRepresenter.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 #include "vtkStandardImageRepresenter.h"
39 
40 #include <vtkStructuredPointsReader.h>
41 #include <vtkStructuredPointsWriter.h>
42 #include <vtkPointData.h>
43 #include <vtkDataArray.h>
44 #include <vtkVersion.h>
45 
46 #include "CommonTypes.h"
47 #include "HDF5Utils.h"
48 #include "StatismoUtils.h"
49 
50 namespace statismo {
51 
52 template<class TScalar, unsigned PixelDimensions>
53 vtkStandardImageRepresenter<TScalar, PixelDimensions>::vtkStandardImageRepresenter(
54  DatasetConstPointerType reference) :
55  m_reference(vtkStructuredPoints::New()) {
56  this->SetReference(reference);
57 }
58 
59 template<class TScalar, unsigned PixelDimensions>
60 vtkStandardImageRepresenter<TScalar, PixelDimensions>::~vtkStandardImageRepresenter() {
61 
62  if (m_reference != 0) {
63  m_reference->Delete();
64  m_reference = 0;
65  }
66 }
67 
68 template<class TScalar, unsigned PixelDimensions>
69 vtkStandardImageRepresenter<TScalar, PixelDimensions>*
70 vtkStandardImageRepresenter<TScalar, PixelDimensions>::Clone() const {
71  // this works since Create deep copies the reference
72  return Create(m_reference);
73 }
74 
75 template<class TScalar, unsigned PixelDimensions>
76 void vtkStandardImageRepresenter<TScalar, PixelDimensions>::Load(const H5::Group& fg) {
77 
78  vtkStructuredPoints* ref = 0;
79 
80  std::string repName = HDF5Utils::readStringAttribute(fg, "name");
81  if (repName == "vtkStructuredPointsRepresenter" || repName == "itkImageRepresenter" || repName == "itkVectorImageRepresenter") {
82  ref = LoadRefLegacy(fg);
83  } else {
84  ref = LoadRef(fg);
85  }
86  this->SetReference(ref);
87 }
88 
89 template<class TScalar, unsigned PixelDimensions>
90 vtkStructuredPoints* vtkStandardImageRepresenter<TScalar, PixelDimensions>::LoadRef(const H5::Group& fg) const {
91 
92  std::string type = HDF5Utils::readStringAttribute(fg, "datasetType");
93  if (type != "IMAGE") {
94  throw StatisticalModelException(
95  (std::string("Cannot load representer data: The ")
96  + "representer specified in the given hdf5 file is of the wrong type: ("
97  + type + ", expected IMAGE)").c_str());
98  }
99 
100  statismo::VectorType originVec;
101  HDF5Utils::readVector(fg, "origin", originVec);
102 
103  unsigned imageDimension = static_cast<unsigned>(HDF5Utils::readInt(fg,
104  "imageDimension"));
105 
106  if (imageDimension > 3) {
107  throw StatisticalModelException(
108  "this representer does not support images of dimensionality > 3");
109  }
110 
111 
112  double origin[3] = { 0, 0, 0 };
113  for (unsigned i = 0; i < imageDimension; i++) {
114  origin[i] = originVec[i];
115  }
116 
117  statismo::VectorType spacingVec;
118  HDF5Utils::readVector(fg, "spacing", spacingVec);
119  float spacing[3] = { 0, 0, 0 };
120  for (unsigned i = 0; i < imageDimension; i++) {
121  spacing[i] = spacingVec[i];
122  }
123 
124  typename statismo::GenericEigenType<int>::VectorType sizeVec;
125  HDF5Utils::readVectorOfType<int>(fg, "size", sizeVec);
126  int size[3] = { 1, 1, 1 };
127  for (unsigned i = 0; i < imageDimension; i++) {
128  size[i] = sizeVec[i];
129  }
130 
131  H5::Group pdGroup = fg.openGroup("./pointData");
132 
133  typename statismo::GenericEigenType<double>::MatrixType pixelMat;
134  HDF5Utils::readMatrixOfType<double>(pdGroup, "pixelValues", pixelMat);
135  H5::DataSet ds = pdGroup.openDataSet("pixelValues");
136  unsigned int datatype = static_cast<unsigned>(HDF5Utils::readIntAttribute(
137  ds, "datatype"));
138 
139  if (statismo::GetDataTypeId<TScalar>() != datatype) {
140  std::cout
141  << "Warning: The datatype specified for the scalars does not match the TPixel template argument used in this representer."
142  << std::endl;
143  }
144  pdGroup.close();
145 
146  vtkStructuredPoints* newImage = vtkStructuredPoints::New();
147  newImage->SetDimensions(size[0], size[1], size[2]);
148 
149  newImage->SetExtent(0, size[0] - 1, 0, size[1] - 1, 0, size[2] - 1);
150 
151  newImage->SetOrigin(origin[0], origin[1], origin[2]);
152  newImage->SetSpacing(spacing[0], spacing[1], spacing[2]);
153 
154  switch (datatype) {
155  case statismo::SIGNED_CHAR:
156 #if (VTK_MAJOR_VERSION == 5 )
157  newImage->SetScalarTypeToSignedChar();
158  newImage->SetNumberOfScalarComponents( PixelDimensions );
159  newImage->AllocateScalars();
160 #else
161  newImage->AllocateScalars(VTK_SIGNED_CHAR, PixelDimensions);
162 #endif
163  break;
164  case statismo::UNSIGNED_CHAR:
165 #if (VTK_MAJOR_VERSION == 5 )
166  newImage->SetScalarTypeToUnsignedChar();
167  newImage->SetNumberOfScalarComponents( PixelDimensions );
168  newImage->AllocateScalars();
169 #else
170  newImage->AllocateScalars(VTK_UNSIGNED_CHAR, PixelDimensions);
171 #endif
172  break;
173  case statismo::SIGNED_SHORT:
174 #if (VTK_MAJOR_VERSION == 5 )
175  newImage->SetScalarTypeToShort();
176  newImage->SetNumberOfScalarComponents( PixelDimensions );
177  newImage->AllocateScalars();
178 #else
179  newImage->AllocateScalars(VTK_SHORT, PixelDimensions);
180 #endif
181  break;
182  case statismo::UNSIGNED_SHORT:
183 #if (VTK_MAJOR_VERSION == 5 )
184  newImage->SetScalarTypeToUnsignedChar();
185  newImage->SetNumberOfScalarComponents( PixelDimensions );
186  newImage->AllocateScalars();
187 #else
188  newImage->AllocateScalars(VTK_UNSIGNED_SHORT, PixelDimensions);
189 #endif
190  break;
191  case statismo::SIGNED_INT:
192 #if (VTK_MAJOR_VERSION == 5 )
193  newImage->SetScalarTypeToInt();
194  newImage->SetNumberOfScalarComponents( PixelDimensions );
195  newImage->AllocateScalars();
196 #else
197  newImage->AllocateScalars(VTK_INT, PixelDimensions);
198 #endif
199  break;
200  case statismo::UNSIGNED_INT:
201 #if (VTK_MAJOR_VERSION == 5 )
202  newImage->SetScalarTypeToUnsignedInt();
203  newImage->SetNumberOfScalarComponents( PixelDimensions );
204  newImage->AllocateScalars();
205 #else
206  newImage->AllocateScalars(VTK_UNSIGNED_INT, PixelDimensions);
207 #endif
208  break;
209  case statismo::FLOAT:
210 #if (VTK_MAJOR_VERSION == 5 )
211  newImage->SetScalarTypeToFloat();
212  newImage->SetNumberOfScalarComponents( PixelDimensions );
213  newImage->AllocateScalars();
214 #else
215  newImage->AllocateScalars(VTK_FLOAT, PixelDimensions);
216 #endif
217 
218  break;
219  case statismo::DOUBLE:
220 #if (VTK_MAJOR_VERSION == 5 )
221  newImage->SetScalarTypeToDouble();
222  newImage->SetNumberOfScalarComponents( PixelDimensions );
223  newImage->AllocateScalars();
224 #else
225  newImage->AllocateScalars(VTK_DOUBLE, PixelDimensions);
226 #endif
227 
228  break;
229  default:
231  "the datatype found in the statismo model cannot be used for the vtkStandardImageRepresenter");
232  }
233 
234  for (int i = 0; i < size[2]; i++) {
235  for (int j = 0; j < size[1]; j++) {
236  for (int k = 0; k < size[0]; k++) {
237  unsigned index = size[1] * size[0] * i + size[0] * j + k;
238  TScalar* scalarPtr =
239  static_cast<TScalar*>(newImage->GetScalarPointer(k, j,
240  i));
241  for (unsigned d = 0; d < PixelDimensions; d++) {
242  scalarPtr[d] = pixelMat(d, index);
243  }
244  }
245  }
246  }
247 
248  return newImage;
249 
250 }
251 
252 
253 template<class TScalar, unsigned PixelDimensions>
254 vtkStructuredPoints* vtkStandardImageRepresenter<TScalar, PixelDimensions>::LoadRefLegacy(const H5::Group& fg) const {
255 
256  vtkStructuredPoints* ref = vtkStructuredPoints::New();
257 
258  std::string tmpfilename = statismo::Utils::CreateTmpName(".vtk");
259 
260  statismo::HDF5Utils::getFileFromHDF5(fg, "./reference", tmpfilename.c_str());
261 
262  std::remove(tmpfilename.c_str());
263 
264  vtkStructuredPointsReader* reader = vtkStructuredPointsReader::New();
265  reader->SetFileName(tmpfilename.c_str());
266  reader->Update();
267  if (reader->GetErrorCode() != 0) {
268  throw StatisticalModelException((std::string("Could not read file ") + tmpfilename).c_str());
269  }
270 
271  ref->DeepCopy(reader->GetOutput());
272  reader->Delete();
273  return ref;
274 }
275 
276 
277 
278 
279 template<class TScalar, unsigned PixelDimensions>
280 statismo::VectorType vtkStandardImageRepresenter<TScalar, PixelDimensions>::PointToVector(
281  const PointType& pt) const {
282  // a vtk point is always 3 dimensional
283  VectorType v(3);
284  for (unsigned i = 0; i < 3; i++) {
285  v(i) = pt[i];
286  }
287  return v;
288 }
289 
290 template<class TScalar, unsigned PixelDimensions>
291 typename vtkStandardImageRepresenter<TScalar, PixelDimensions>::DatasetPointerType vtkStandardImageRepresenter<
292 TScalar, PixelDimensions>::DatasetToSample(
293  DatasetConstPointerType dataset) const {
294  // for this representer, a dataset is always the same as a sample
295  vtkStructuredPoints* clone = vtkStructuredPoints::New();
296  clone->DeepCopy(const_cast<vtkStructuredPoints*>(dataset));
297 
298  if (const_cast<vtkStructuredPoints*>(m_reference)->GetNumberOfPoints()
299  != const_cast<vtkStructuredPoints*>(dataset)->GetNumberOfPoints()) {
300  throw StatisticalModelException(
301  "The dataset need to have the same number of points as the reference");
302  }
303 
304  return clone;
305 }
306 
307 template<class TScalar, unsigned PixelDimensions>
308 VectorType vtkStandardImageRepresenter<TScalar, PixelDimensions>::SampleToSampleVector(
309  DatasetConstPointerType _sp) const {
310 
311  vtkStructuredPoints* reference =
312  const_cast<vtkStructuredPoints*>(this->m_reference);
313  vtkStructuredPoints* sp = const_cast<vtkStructuredPoints*>(_sp);
314 
315  if (reference->GetNumberOfPoints() != sp->GetNumberOfPoints()) {
316  throw StatisticalModelException(
317  "The sample does not have the correct number of points");
318  }
319 
320  VectorType sample = VectorType::Zero(
321  m_reference->GetNumberOfPoints() * PixelDimensions);
322 
323  vtkDataArray* dataArray = sp->GetPointData()->GetArray(0);
324 
325  // TODO: Make this more efficient using SetVoidArray of vtk
326  // HOWEVER: This is only possible, if we enforce VectorType and
327  // vtkStructuredPoints to have the same data type, e.g. float or int.
328  for (unsigned i = 0; i < m_reference->GetNumberOfPoints(); i++) {
329 
330  double val[PixelDimensions];
331  dataArray->GetTuple(i, val);
332  for (unsigned d = 0; d < PixelDimensions; d++) {
333  unsigned idx = MapPointIdToInternalIdx(i, d);
334  sample(idx) = val[d];
335  }
336  }
337  return sample;
338 }
339 
340 template<class TScalar, unsigned PixelDimensions>
341 typename vtkStandardImageRepresenter<TScalar, PixelDimensions>::DatasetPointerType vtkStandardImageRepresenter<
342 TScalar, PixelDimensions>::SampleVectorToSample(
343  const VectorType& sample) const {
344  vtkStructuredPoints* sp = vtkStructuredPoints::New();
345  vtkStructuredPoints* reference =
346  const_cast<vtkStructuredPoints*>(m_reference);
347  sp->DeepCopy(reference);
348 
349  vtkDataArray* dataArray = sp->GetPointData()->GetArray(0);
350  for (unsigned i = 0; i < GetNumberOfPoints(); i++) {
351  double val[PixelDimensions];
352  for (unsigned d = 0; d < PixelDimensions; d++) {
353  unsigned idx = MapPointIdToInternalIdx(i, d);
354  val[d] = sample(idx);
355  }
356  dataArray->SetTuple(i, val);
357  }
358  //sp->GetPointData()->SetScalars(scalars);
359  return sp;
360 }
361 
362 template<class TScalar, unsigned PixelDimensions>
363 typename vtkStandardImageRepresenter<TScalar, PixelDimensions>::ValueType vtkStandardImageRepresenter<
364 TScalar, PixelDimensions>::PointSampleFromSample(
365  DatasetConstPointerType sample_, unsigned ptid) const {
366  DatasetPointerType sample = const_cast<DatasetPointerType>(sample_);
367  if (ptid >= sample->GetNumberOfPoints()) {
368  throw StatisticalModelException(
369  "invalid ptid provided to PointSampleFromSample");
370  }
371 
372  double doubleVal[PixelDimensions];
373  sample->GetPointData()->GetScalars()->GetTuple(ptid, doubleVal);
374  ValueType val(PixelDimensions);
375 
376  // vtk returns double. We need to convert it to whatever precision we are using in NDPixel
377  for (unsigned i = 0; i < PixelDimensions; i++) {
378  val[i] = static_cast<TScalar>(doubleVal[i]);
379  }
380  return val;
381 }
382 
383 template<class TScalar, unsigned PixelDimensions>
384 statismo::VectorType vtkStandardImageRepresenter<TScalar, PixelDimensions>::PointSampleToPointSampleVector(
385  const ValueType& v) const {
386  VectorType vec(PixelDimensions);
387  for (unsigned i = 0; i < PixelDimensions; i++) {
388  vec[i] = const_cast<ValueType&>(v)[i];
389  vec[i] = v[i];
390  }
391  return vec;
392 }
393 
394 template<class TScalar, unsigned PixelDimensions>
395 typename vtkStandardImageRepresenter<TScalar, PixelDimensions>::ValueType vtkStandardImageRepresenter<
396 TScalar, PixelDimensions>::PointSampleVectorToPointSample(
397  const VectorType& pointSample) const {
398  ValueType value(PixelDimensions);
399 
400  for (unsigned i = 0; i < PixelDimensions; i++)
401  value[i] = pointSample[i];
402 
403  return value;
404 }
405 
406 template<class TScalar, unsigned Dimensions>
407 void vtkStandardImageRepresenter<TScalar, Dimensions>::Save(
408  const H5::Group& fg) const {
409  using namespace H5;
410 
411  // get the effective image dimension, by check the size
412  int* size = m_reference->GetDimensions();
413  unsigned imageDimension = 0;
414  if (size[2] == 1 && size[1] == 1)
415  imageDimension = 1;
416  else if (size[2] == 1)
417  imageDimension = 2;
418  else
419  imageDimension = 3;
420 
421  HDF5Utils::writeInt(fg, "imageDimension", imageDimension);
422 
423  double* origin = m_reference->GetOrigin();
424  statismo::VectorType originVec = statismo::VectorType::Zero(imageDimension);
425  for (unsigned i = 0; i < imageDimension; i++) {
426  originVec(i) = origin[i];
427  }
428  HDF5Utils::writeVector(fg, "origin", originVec);
429 
430  double* spacing = m_reference->GetSpacing();
431  statismo::VectorType spacingVec = statismo::VectorType::Zero(
432  imageDimension);
433  for (unsigned i = 0; i < imageDimension; i++) {
434  spacingVec(i) = spacing[i];
435  }
436  HDF5Utils::writeVector(fg, "spacing", spacingVec);
437 
438  statismo::GenericEigenType<int>::VectorType sizeVec =
439  statismo::GenericEigenType<int>::VectorType::Zero(imageDimension);
440  for (unsigned i = 0; i < imageDimension; i++) {
441  sizeVec(i) = size[i];
442  }
443  HDF5Utils::writeVectorOfType<int>(fg, "size", sizeVec);
444 
445  // VTK does not support image direction. We write the identity matrix
446  statismo::MatrixType directionMat = statismo::MatrixType::Identity(
447  imageDimension, imageDimension);
448  HDF5Utils::writeMatrix(fg, "direction", directionMat);
449 
450  typedef statismo::GenericEigenType<double>::MatrixType DoubleMatrixType;
451  DoubleMatrixType pixelMat(GetDimensions(), GetNumberOfPoints());
452 
453  for (unsigned i = 0; i < static_cast<unsigned>(size[2]); i++) {
454  for (unsigned j = 0; j < static_cast<unsigned>(size[1]); j++) {
455  for (unsigned k = 0; k < static_cast<unsigned>(size[0]); k++) {
456  unsigned ind = i * size[1] * size[0] + j * size[0] + k;
457  TScalar * pixel =
458  static_cast<TScalar*>(m_reference->GetScalarPointer(k,
459  j, i));
460  for (unsigned d = 0; d < GetDimensions(); d++) {
461  pixelMat(d, ind) = pixel[d];
462  }
463  }
464  }
465  }
466 
467  H5::Group pdGroup = fg.createGroup("pointData");
468 
469  H5::DataSet ds = HDF5Utils::writeMatrixOfType<double>(pdGroup,
470  "pixelValues", pixelMat);
471  HDF5Utils::writeIntAttribute(ds, "datatype",
472  statismo::GetDataTypeId<TScalar>());
473  pdGroup.close();
474 
475 }
476 
477 template<class TScalar, unsigned Dimensions>
478 unsigned vtkStandardImageRepresenter<TScalar, Dimensions>::GetNumberOfPoints() const {
479  return GetNumberOfPoints(this->m_reference);
480 }
481 
482 template<class TScalar, unsigned Dimensions>
483 void vtkStandardImageRepresenter<TScalar, Dimensions>::SetReference(
484  const vtkStructuredPoints* reference) {
485 
486  if (m_reference == 0) {
487  m_reference = vtkStructuredPoints::New();
488  }
489  m_reference->DeepCopy(const_cast<vtkStructuredPoints*>(reference));
490  // set the domain
491  DomainType::DomainPointsListType ptList;
492  for (unsigned i = 0; i < m_reference->GetNumberOfPoints(); i++) {
493  double* d = m_reference->GetPoint(i);
494  ptList.push_back(vtkPoint(d));
495  }
496  m_domain = DomainType(ptList);
497 }
498 
499 template<class TScalar, unsigned Dimensions>
500 unsigned vtkStandardImageRepresenter<TScalar, Dimensions>::GetPointIdForPoint(
501  const PointType& pt) const {
502  assert(m_reference != 0);
503  return this->m_reference->FindPoint(const_cast<double*>(pt.data()));
504 }
505 
506 template<class TScalar, unsigned Dimensions>
507 unsigned vtkStandardImageRepresenter<TScalar, Dimensions>::GetNumberOfPoints(
508  vtkStructuredPoints* reference) {
509  return reference->GetNumberOfPoints();
510 }
511 
512 } // namespace statismo
static void writeIntAttribute(const H5::H5Object &fg, const char *name, int value)
Definition: HDF5Utils.hxx:406
static H5::DataSet writeMatrix(const H5::CommonFG &fg, const char *name, const MatrixType &matrix)
Definition: HDF5Utils.hxx:248
static std::string readStringAttribute(const H5::H5Object &group, const char *name)
Definition: HDF5Utils.hxx:397
static H5::DataSet writeInt(const H5::CommonFG &fg, const char *name, int value)
Definition: HDF5Utils.hxx:426
Generic Exception class for the statismo Library.
Definition: Exceptions.h:68
static void readVector(const H5::CommonFG &fg, const char *name, unsigned nElements, VectorType &vector)
Definition: HDF5Utils.hxx:296
static H5::DataSet writeVector(const H5::CommonFG &fg, const char *name, const VectorType &vector)
Definition: HDF5Utils.hxx:363
static void getFileFromHDF5(const H5::CommonFG &fg, const char *name, const char *filename)
Definition: HDF5Utils.hxx:462
Definition: Domain.h:51
static int readInt(const H5::CommonFG &fg, const char *name)
Definition: HDF5Utils.hxx:434
static int readIntAttribute(const H5::H5Object &group, const char *name)
Definition: HDF5Utils.hxx:416