DataOp.h
Go to the documentation of this file.
1 /*
2  * Medical Image Registration ToolKit (MIRTK)
3  *
4  * Copyright 2013-2015 Imperial College London
5  * Copyright 2013-2015 Andreas Schuh
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 
20 
21 /// @file mirtk/DataOp.h
22 /// @brief Defines base class and I/O functions for arbitrary 1D data sequences
23 ///
24 /// Functions to manipulate the data are defined in mirtkDataFunctions.h.
25 /// Statistics of the data sequence such as mean and variance or percentiles
26 /// can be computed using the operators found in mirtkDataStatistics.h.
27 /// The data operators are used in particular by the calculate.cc tool for
28 /// which they were originally developed. They were added to the linear
29 /// algebra library because they are useful to compute common statistics or
30 /// perform basic mathematical operations on a data sequence such as an image
31 /// or attributes of a VTK point set.
32 ///
33 /// @sa mirtkDataFunctions.h
34 /// @sa mirtkDataStatistics.h
35 #ifndef MIRTK_DataOp_H
36 #define MIRTK_DataOp_H
37 
38 #include "mirtk/ImageConfig.h"
39 
40 #include "mirtk/Math.h"
41 #include "mirtk/Stream.h"
42 #include "mirtk/Voxel.h"
43 #include "mirtk/ImageAttributes.h"
44 
45 #if MIRTK_Image_WITH_VTK
46 # include "vtkSmartPointer.h"
47 # include "vtkDataSet.h"
48 # include "vtkDataArray.h"
49 #endif
50 
51 
52 namespace mirtk { namespace data {
53 
54 
55 // =============================================================================
56 // Base class of data operations
57 // =============================================================================
58 
59 // -----------------------------------------------------------------------------
60 /// Base class of all data operations
61 class Op
62 {
63 public:
64 
65  /// Destructor
66  virtual ~Op() {}
67 
68  /// Process given data
69  virtual void Process(int, double *, bool * = NULL) = 0;
70 
71 #if MIRTK_Image_WITH_VTK
72  /// Process given vtkDataArray
73  virtual void Process(vtkDataArray *data, bool *mask = nullptr)
74  {
75  const int n = static_cast<int>(data->GetNumberOfTuples() * data->GetNumberOfComponents());
76  if (data->GetDataType() == VTK_DOUBLE) {
77  this->Process(n, reinterpret_cast<double *>(data->GetVoidPointer(0)), mask);
78  } else {
79  UniquePtr<double[]> _data(new double[n]);
80  double *tuple = _data.get();
81  for (vtkIdType i = 0; i < data->GetNumberOfTuples(); ++i) {
82  data->GetTuple(i, tuple);
83  tuple += data->GetNumberOfComponents();
84  }
85  this->Process(n, _data.get(), mask);
86  tuple = _data.get();
87  for (vtkIdType i = 0; i < data->GetNumberOfTuples(); ++i) {
88  data->SetTuple(i, tuple);
89  tuple += data->GetNumberOfComponents();
90  }
91  }
92  }
93 #endif
94 };
95 
96 // =============================================================================
97 // I/O functions
98 // =============================================================================
99 
100 // -----------------------------------------------------------------------------
101 /// Enumeration of supported input data file types
103 {
104  UnknownDataFile,
105  IMAGE,
106  LEGACY_VTK,
107  XML_VTK
108 };
109 
110 /// Get (or guess) type of input file
111 DataFileType FileType(const char *name);
112 
113 // -----------------------------------------------------------------------------
114 /// Read data sequence from any supported input file type
115 int Read(const char *name,
116  UniquePtr<double[]> &data,
117  int *dtype = nullptr,
118  ImageAttributes *attr = nullptr,
119  #if MIRTK_Image_WITH_VTK
120  vtkSmartPointer<vtkDataSet> *dataset = nullptr,
121  #else
122  void * = nullptr,
123  #endif
124  const char *scalars_name = nullptr,
125  bool cell_data = false);
126 
127 // -----------------------------------------------------------------------------
128 /// Write data sequence
129 class Write : public Op
130 {
131  /// Name of output file
132  mirtkPublicAttributeMacro(string, FileName);
133 
134 #if MIRTK_Image_WITH_VTK
135 
136  /// VTK input dataset whose scalar data was modified
137  mirtkPublicAttributeMacro(vtkSmartPointer<vtkDataSet>, DataSet);
138 
139  /// Name of input data array
140  mirtkPublicAttributeMacro(string, ArrayName);
141 
142  /// Name of output data array
143  mirtkPublicAttributeMacro(string, OutputName);
144 
145  /// Whether to add data as cell data instead of point data
146  mirtkPublicAttributeMacro(bool, AsCellData);
147 
148 #endif // MIRTK_Image_WITH_VTK
149 
150  /// Attributes of input image whose data was modified
151  mirtkPublicAttributeMacro(ImageAttributes, Attributes);
152 
153  /// Output data type
154  mirtkPublicAttributeMacro(int, DataType);
155 
156 public:
157 
158  /// Constructor
159 #if MIRTK_Image_WITH_VTK
160 
161  Write(const char *fname, int dtype = MIRTK_VOXEL_DOUBLE,
163  vtkDataSet *dataset = nullptr,
164  const char *array_name = nullptr,
165  const char *output_name = nullptr,
166  bool cell_data = false)
167  :
168  _FileName(fname),
169  _DataSet(dataset),
170  _AsCellData(cell_data),
171  _Attributes(attr),
172  _DataType(dtype)
173  {
174  if (array_name) _ArrayName = array_name;
175  if (output_name) _OutputName = output_name;
176  }
177 
178 #else // MIRTK_Image_WITH_VTK
179 
180  Write(const char *fname, int dtype = MIRTK_VOXEL_DOUBLE,
182  :
183  _FileName(fname),
184  _Attributes(attr),
185  _DataType(dtype)
186  {}
187 
188 #endif // MIRTK_Image_WITH_VTK
189 
190  /// Process given data
191  virtual void Process(int n, double *data, bool * = nullptr);
192 
193 };
194 
195 // =============================================================================
196 // Auxiliary macros for subclass implementation
197 // =============================================================================
198 
199 // -----------------------------------------------------------------------------
200 // Add Calculate function that takes a vtkDataArray as argument
201 // and computes a single return value
202 //
203 // Subclass must implement:
204 // template <class T> double Calculate(int n, const T *data, const bool *mask)
205 #if MIRTK_Image_WITH_VTK
206  #define mirtkCalculateVtkDataArray1() \
207  static double Calculate(vtkDataArray *data, const bool *mask = NULL) \
208  { \
209  const void *p = data->GetVoidPointer(0); \
210  const int n = static_cast<int>(data->GetNumberOfTuples() * \
211  data->GetNumberOfComponents()); \
212  switch (data->GetDataType()) { \
213  case VTK_SHORT: return Calculate(n, reinterpret_cast<const short *>(p), mask); \
214  case VTK_INT: return Calculate(n, reinterpret_cast<const int *>(p), mask); \
215  case VTK_FLOAT: return Calculate(n, reinterpret_cast<const float *>(p), mask); \
216  case VTK_DOUBLE: return Calculate(n, reinterpret_cast<const double *>(p), mask); \
217  default: \
218  cerr << "Unsupported vtkDataArray type: " << data->GetDataType() << endl; \
219  exit(1); \
220  } \
221  return numeric_limits<double>::quiet_NaN(); \
222  }
223 #else
224  #define mirtkCalculateVtkDataArray1()
225 #endif
226 
227 // -----------------------------------------------------------------------------
228 // Add Calculate function that takes a vtkDataArray as argument
229 // and computes two return values
230 //
231 // Subclass must implement:
232 // template <class T>
233 // void Calculate(double &, double &, int n, const T *data, const bool *mask)
234 #if MIRTK_Image_WITH_VTK
235  #define mirtkCalculateVtkDataArray2() \
236  static void Calculate(double &v1, double &v2, vtkDataArray *data, const bool *mask = NULL) \
237  { \
238  const void *p = data->GetVoidPointer(0); \
239  const int n = static_cast<int>(data->GetNumberOfTuples() * \
240  data->GetNumberOfComponents()); \
241  switch (data->GetDataType()) { \
242  case VTK_SHORT: Calculate(v1, v2, n, reinterpret_cast<const short *>(p), mask); break; \
243  case VTK_INT: Calculate(v1, v2, n, reinterpret_cast<const int *>(p), mask); break; \
244  case VTK_FLOAT: Calculate(v1, v2, n, reinterpret_cast<const float *>(p), mask); break; \
245  case VTK_DOUBLE: Calculate(v1, v2, n, reinterpret_cast<const double *>(p), mask); break; \
246  default: \
247  cerr << "Unsupported vtkDataArray type: " << data->GetDataType() << endl; \
248  exit(1); \
249  } \
250  }
251 #else
252  #define mirtkCalculateVtkDataArray2()
253 #endif
254 
255 
256 } } // namespace mirtk::data
257 
258 #endif
int Read(const char *name, UniquePtr< double[]> &data, int *dtype=nullptr, ImageAttributes *attr=nullptr, void *=nullptr, const char *scalars_name=nullptr, bool cell_data=false)
Read data sequence from any supported input file type.
string FileName(const char *, ExtensionMode=EXT_Default)
Get file name of file path excl. file extension.
Write(const char *fname, int dtype=MIRTK_VOXEL_DOUBLE, ImageAttributes attr=ImageAttributes())
Constructor.
Definition: DataOp.h:180
Base class of all data operations.
Definition: DataOp.h:61
DataFileType
Enumeration of supported input data file types.
Definition: DataOp.h:102
Definition: IOConfig.h:41
virtual ~Op()
Destructor.
Definition: DataOp.h:66
Write data sequence.
Definition: DataOp.h:129
virtual void Process(int, double *, bool *=NULL)=0
Process given data.
DataFileType FileType(const char *name)
Get (or guess) type of input file.