SMILX  1.01
milxDeformableModel.h
1 /*=========================================================================
2  The Software is copyright (c) Commonwealth Scientific and Industrial Research Organisation (CSIRO)
3  ABN 41 687 119 230.
4  All rights reserved.
5 
6  Licensed under the CSIRO BSD 3-Clause License
7  You may not use this file except in compliance with the License.
8  You may obtain a copy of the License in the file LICENSE.md or at
9 
10  https://stash.csiro.au/projects/SMILI/repos/smili/browse/license.txt
11 
12  Unless required by applicable law or agreed to in writing, software
13  distributed under the License is distributed on an "AS IS" BASIS,
14  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  See the License for the specific language governing permissions and
16  limitations under the License.
17 =========================================================================*/
18 #ifndef __MILXDEFORMABLEMODEL_H
19 #define __MILXDEFORMABLEMODEL_H
20 //ITK
21 #include <itkImage.h>
22 #include <itkVTKPolyDataToMesh.h> //itkVTKGlue
23 #include <itkMeshToVTKPolyData.h> //itkVTKGlue
24 #include <itkLinearInterpolateImageFunction.h>
25 #ifdef ITK_USE_REVIEW //Review only members
26  #include <itkConformalFlatteningMeshFilter.h>
27 #endif
28 //VTK
29 #include <vtkSmartPointer.h>
30 #include <vtkPolyData.h>
31 #include <vtkPointData.h>
32 #include <vtkFloatArray.h>
33 #include <vtkPolyDataToImageStencil.h>
34 #include <vtkImageStencil.h>
35 //SMILI
36 #include <milxGlobal.h>
37 #include <milxMath.h>
38 #include <milxModel.h>
39 #include <milxImage.h>
40 #include <milxFile.h>
41 
42 //enums
43 
44 namespace milx
45 {
53 {
54 public:
64  DeformableModel(vtkSmartPointer<vtkPolyData> model);
69  virtual ~DeformableModel() {}
70 
83  template<typename TImage>
84  void ApplyOrientation(itk::SmartPointer<TImage> image, const bool applyOrigin = true, const bool flipY = false);
93  template<typename TImage>
94  itk::SmartPointer<TImage> VoxeliseAsITKImage(const unsigned char insideValue, double *spacing, double *bounds = NULL, const size_t padVoxels = 1);
99  template<typename MeshType>
100  itk::SmartPointer<MeshType> ConvertVTKPolyDataToITKMesh();
105  template<typename MeshType>
106  void ConvertITKMeshToVTKPolyData(itk::SmartPointer<MeshType> mesh);
107 #ifdef ITK_USE_REVIEW //Review only members
108 
112  void Flatten(const size_t flatMode = 1);
113 #endif
114 
115 
127  template<typename TImage>
128  static vtkSmartPointer<vtkFloatArray> SurfaceScalarsFromImage(vtkSmartPointer<vtkPolyData> surface, itk::SmartPointer<TImage> img, const bool absoluteValues);
134  template<typename TImage>
135  static void MarkSurfaceInsideImage(vtkSmartPointer<vtkPolyData> &surface, itk::SmartPointer<TImage> img, vtkFloatArray *weights, const float outsideValue = 0.0);
137 
138  //Collection operations
148  template<typename TImage>
149  void ApplyOrientationCollection(vtkSmartPointer<vtkPolyDataCollection> collection, itk::SmartPointer<TImage> refImage, const bool applyOrigin = true, const bool flipY = false);
155  template<typename TImage>
156  void VoxeliseCollection(vtkSmartPointer<vtkPolyDataCollection> collection, const coordinateType spacing, std::vector< typename itk::SmartPointer<TImage> > &images);
157 #ifdef ITK_USE_REVIEW //Review only members
158 
162  void FlattenCollection(vtkSmartPointer<vtkPolyDataCollection> collection, const size_t flatMode);
163 #endif
164 
165 
166 protected:
167 
168 private:
169 
170 };
171 
172 template<typename TImage>
173 itk::SmartPointer<TImage> DeformableModel::VoxeliseAsITKImage(const unsigned char insideValue, double *spacing, double *bounds, const size_t padVoxels)
174 {
175  vtkSmartPointer<vtkImageData> img = Model::Voxelise(insideValue, spacing, bounds, padVoxels);
176 
178 }
179 
180 template<typename MeshType>
181 itk::SmartPointer<MeshType> DeformableModel::ConvertVTKPolyDataToITKMesh()
182 {
183  typedef itk::VTKPolyDataToMesh<MeshType> MeshFilterType;
184  typename MeshFilterType::Pointer filter = MeshFilterType::New();
185  filter->SetInput(CurrentModel);
186  try
187  {
188  std::cout << "Converting to ITK Mesh" << std::endl;
189  filter->Update();
190  }
191  catch (itk::ExceptionObject & ex )
192  {
193  PrintError("Failed ITK Conversion");
194  PrintError(ex.GetDescription());
195  }
196 
197  return filter->GetOutput();
198 }
199 
200 template<typename MeshType>
201 void DeformableModel::ConvertITKMeshToVTKPolyData(itk::SmartPointer<MeshType> mesh)
202 {
203  typedef itk::MeshToVTKPolyData<MeshType> MeshFilterType;
204  typename MeshFilterType::Pointer filter = MeshFilterType::New();
205  filter->SetInput(mesh);
206  try
207  {
208  std::cout << "Converting to VTK PolyData" << std::endl;
209  filter->Update();
210  }
211  catch (itk::ExceptionObject & ex )
212  {
213  PrintError("Failed VTK Conversion");
214  PrintError(ex.GetDescription());
215  }
216  vtkSmartPointer<vtkPolyData> convMesh = filter->GetOutput();
217 
218  CurrentModel->DeepCopy(convMesh);
219  std::cout << "Number of Points in VTK PolyData: " << CurrentModel->GetNumberOfPoints() << std::endl;
220  std::cout << "Number of Cells in VTK PolyData: " << CurrentModel->GetNumberOfCells() << std::endl;
221 }
222 
223 #ifdef ITK_USE_REVIEW //Review only members
224 void DeformableModel::Flatten(const size_t flatMode)
225 {
226  //Triangulate
227  Triangulate();
228 
229  //convert to ITK
230  typedef itk::Mesh<vtkFloatingPointType, 3> MeshType;
231  itk::SmartPointer<MeshType> mesh = ConvertVTKPolyDataToITKMesh<MeshType>();
232  std::cout << "Number of Points in ITK Mesh: " << mesh->GetNumberOfPoints() << std::endl;
233 
234  //flatten
235  typedef itk::ConformalFlatteningMeshFilter<MeshType, MeshType> FlatFilterType;
236  FlatFilterType::Pointer filter = FlatFilterType::New();
237  filter->SetInput(mesh);
238  //~ filter->SetPolarCellIdentifier(0);
239  if(flatMode == 1)
240  filter->MapToPlane();
241  else
242  filter->MapToSphere();
243  try
244  {
245  std::cout << "Trying to flatten..." << std::endl;
246  filter->Update();
247  }
248  catch (itk::ExceptionObject & ex )
249  {
250  PrintError("Failed Flattening");
251  PrintError(ex.GetDescription());
252  }
253  itk::SmartPointer<MeshType> flatMesh = filter->GetOutput();
254 
255  //convert back to VTK
256  ConvertITKMeshToVTKPolyData<MeshType>(flatMesh);
257 }
258 #endif
259 
260 template<typename TImage>
261 void DeformableModel::ApplyOrientation(itk::SmartPointer<TImage> image, const bool applyOrigin, const bool flipY)
262 {
264  typename TImage::DirectionType direction = image->GetDirection();
265  typename TImage::PointType origin = image->GetOrigin();
266 
267  coordinate centroid = Math<double>::Centroid(CurrentModel->GetPoints());
268 
269  vtkSmartPointer<vtkMatrix4x4> flipMatrix = vtkSmartPointer<vtkMatrix4x4>::New(); //start with identity matrix
270  flipMatrix->Identity();
271  //Flip the image for VTK coordinate system
272  if(flipY)
273  flipMatrix->SetElement(1,1,-1); //flip
274 
275  std::cout << "Direction to be applied:\n" << direction << std::endl;
276  vtkSmartPointer<vtkMatrix4x4> matrix = vtkSmartPointer<vtkMatrix4x4>::New(); //start with identity matrix
277  matrix->Identity();
278  for (int i = 0; i < 3; i ++)
279  for (int k = 0; k < 3; k ++)
280  matrix->SetElement(i,k, direction(i,k));
281 
282  vtkSmartPointer<vtkTransform> transform = vtkSmartPointer<vtkTransform>::New();
283  transform->Identity();
284  transform->PostMultiply();
285  transform->Concatenate(flipMatrix); //flip
286  transform->Translate(-centroid[0], -centroid[1], -centroid[2]); //remove centroid of mesh
287  transform->Concatenate(matrix); //direction
288  if(applyOrigin)
289  transform->Translate(origin.GetDataPointer()); //add image origin displacement
290 
291  Model::SetTransform(transform);
292 }
293 
294 template<typename TImage>
295 vtkSmartPointer<vtkFloatArray> DeformableModel::SurfaceScalarsFromImage(vtkSmartPointer<vtkPolyData> surface, itk::SmartPointer<TImage> img, const bool absoluteValues)
296 {
297  const int numberOfPoints = surface->GetNumberOfPoints();
298 
299  typedef itk::Point<double, 3> InputImagePointType;
300  typedef itk::ContinuousIndex<double, 3 > ContinuousIndexType;
301 
302  typedef itk::LinearInterpolateImageFunction<TImage, double> InterpolatorType;
303  typename InterpolatorType::Pointer interpolator = InterpolatorType::New();
304  interpolator->SetInputImage(img);
305 
306  vtkSmartPointer<vtkFloatArray> scalars = vtkSmartPointer<vtkFloatArray>::New();
307  scalars->SetName("Distance");
308  scalars->SetNumberOfTuples(numberOfPoints);
309  scalars->SetNumberOfComponents(1);
310 // scalars->FillComponent(0, 0.0);
311 
312  InputImagePointType point;
313  ContinuousIndexType index;
314  for(int i = 0; i < numberOfPoints; i++)
315  {
316  double position[3];
317  surface->GetPoint(i, position);
318 
319  point[0] = position[0];
320  point[1] = position[1];
321  point[2] = position[2];
322 
323  img->TransformPhysicalPointToContinuousIndex(point, index);
324 
325  // If inside, mark
326  if(interpolator->IsInsideBuffer(index))
327  {
328  double valueFound = 0.0;
329  if(absoluteValues)
330  valueFound = fabs(interpolator->EvaluateAtContinuousIndex(index));
331  else
332  valueFound = interpolator->EvaluateAtContinuousIndex(index);
333  scalars->SetTuple1(i, valueFound);
334  }
335  }
336 
337  return scalars;
338 }
339 
340 template<typename TImage>
341 void DeformableModel::MarkSurfaceInsideImage(vtkSmartPointer<vtkPolyData> &surface, itk::SmartPointer<TImage> img, vtkFloatArray *weights, const float outsideValue)
342 {
343  const int numberOfPoints = surface->GetNumberOfPoints();
344  vtkSmartPointer<vtkFloatArray> surfaceWeights = vtkFloatArray::SafeDownCast(surface->GetPointData()->GetScalars());
345  bool hasScalars = false;
346  if(surfaceWeights)
347  hasScalars = true;
348 
349  typedef itk::Point<double, 3> InputImagePointType;
350  typedef itk::ContinuousIndex<double, 3> ContinuousIndexType;
351 
352  weights->SetName("Weights");
353  weights->SetNumberOfTuples(numberOfPoints);
354  weights->SetNumberOfComponents(1);
355  weights->FillComponent(0, outsideValue);
356 
357  typedef itk::LinearInterpolateImageFunction<TImage, double> InterpolatorType;
358  typename InterpolatorType::Pointer interpolator = InterpolatorType::New();
359  interpolator->SetInputImage(img);
360 
361 // std::cout << "Number of Points " << numberOfPoints << std::endl;
362 // std::cout << "Image Spacing " << this->GetInput()->GetSpacing() << std::endl;
363  InputImagePointType point;
364  ContinuousIndexType index;
365  for(int i = 0; i < numberOfPoints; i++)
366  {
367  double position[3];
368  surface->GetPoint(i, position);
369 
370  point[0] = position[0];
371  point[1] = position[1];
372  point[2] = position[2];
373 
374  img->TransformPhysicalPointToContinuousIndex(point, index);
375 
376  // If inside, mark
377  if(interpolator->IsInsideBuffer(index))
378  {
379  if(hasScalars)
380  weights->SetTuple1(i, surfaceWeights->GetTuple1(i));
381  else
382  weights->SetTuple1(i, 1.0);
383  }
384  }
385 
386  surface->GetPointData()->SetScalars(weights);
387 }
388 
389 //Collection ops
390 template<typename TImage>
391 void DeformableModel::ApplyOrientationCollection(vtkSmartPointer<vtkPolyDataCollection> collection, itk::SmartPointer<TImage> refImage, const bool applyOrigin, const bool flipY)
392 {
393  const size_t n = collection->GetNumberOfItems();
394  InternalInPlaceOperation = true;
395 
396  collection->InitTraversal();
397  for(size_t j = 0; j < n; j ++)
398  {
399  vtkSmartPointer<vtkPolyData> mesh = collection->GetNextItem();
400  Model::SetInput(mesh);
401  ApplyOrientation<TImage>(refImage, applyOrigin, flipY);
402  mesh->DeepCopy(Model::Result());
403  }
404 
405  InternalInPlaceOperation = false;
406 }
407 
408 template<typename TImage>
409 void DeformableModel::VoxeliseCollection(vtkSmartPointer<vtkPolyDataCollection> collection, const coordinateType spacing, std::vector< typename itk::SmartPointer<TImage> > &images)
410 {
411  const size_t n = collection->GetNumberOfItems();
412  double isoSpacing[3];
413  InternalInPlaceOperation = true;
414 
415  isoSpacing[0] = spacing;
416  isoSpacing[1] = spacing;
417  isoSpacing[2] = spacing;
418 
419  images.clear();
420  collection->InitTraversal();
421  for(size_t j = 0; j < n; j ++)
422  {
423  vtkSmartPointer<vtkPolyData> mesh = collection->GetNextItem();
424  Model::SetInput(mesh);
425  itk::SmartPointer<TImage> img = VoxeliseAsITKImage<TImage>(1, isoSpacing);
426  images.push_back(img);
427  }
428 
429  InternalInPlaceOperation = false;
430 }
431 
432 #ifdef ITK_USE_REVIEW //Review only members
433 void DeformableModel::FlattenCollection(vtkSmartPointer<vtkPolyDataCollection> collection, const size_t flatMode)
434 {
435  const size_t n = collection->GetNumberOfItems();
436  InternalInPlaceOperation = true;
437 
438  collection->InitTraversal();
439  for(size_t j = 0; j < n; j ++)
440  {
441  vtkSmartPointer<vtkPolyData> mesh = collection->GetNextItem();
442  Model::SetInput(mesh);
443  Flatten(flatMode);
444  mesh->DeepCopy(Model::Result());
445  }
446 
447  InternalInPlaceOperation = false;
448 }
449 #endif
450 
451 } //end namespace milx
452 
453 #endif //__MILXDEFORMABLEMODEL_H
static Type Centroid(const vnl_vector< Type > &data)
Compute the centroid (or the mean) of a data vector.
Definition: milxMath.h:177
itk::SmartPointer< TImage > VoxeliseAsITKImage(const unsigned char insideValue, double *spacing, double *bounds=NULL, const size_t padVoxels=1)
Convert a model to voxelised (imaging) data.
static itk::SmartPointer< TImage > ConvertVTKImageToITKImage(vtkSmartPointer< vtkImageData > img)
Converts a VTK image object to an ITK image object.
Definition: milxImage.h:1093
void PrintError(const std::string msg)
Displays a generic msg to standard error with carriage return.
Definition: milxGlobal.h:202
#define SMILI_EXPORT
DLL Function Symbol for Windows. It is empty for other OSes.
Definition: milxGlobal.h:227
vtkSmartPointer< vtkPolyData > & Result()
Returns the current model, i.e. the result of the latest operation.
Definition: milxModel.h:202
void VoxeliseCollection(vtkSmartPointer< vtkPolyDataCollection > collection, const coordinateType spacing, std::vector< typename itk::SmartPointer< TImage > > &images)
Voxelise a collection of models with isotropic spacing given. A vector of image pointers in set to &#39;i...
void ApplyOrientationCollection(vtkSmartPointer< vtkPolyDataCollection > collection, itk::SmartPointer< TImage > refImage, const bool applyOrigin=true, const bool flipY=false)
Apply orientation/direction of a reference image to a collection of models.
virtual ~DeformableModel()
Standard Destructor.
void SetInput(vtkSmartPointer< vtkPolyData > model)
Assigns the input model to class.
Definition: milxModel.cxx:130
void SetTransform(vtkSmartPointer< vtkAbstractTransform > newTransform)
Transforms the model by given transform.
Definition: milxModel.cxx:143
itk::SmartPointer< MeshType > ConvertVTKPolyDataToITKMesh()
Convert the current vtkPolyData to an itk::Mesh.
void ConvertITKMeshToVTKPolyData(itk::SmartPointer< MeshType > mesh)
Convert an itk::Mesh to the current vtkPolyData.
vtkSmartPointer< vtkImageData > Voxelise(const unsigned char insideValue, double *spacing, double *bounds=NULL, const size_t padVoxels=1)
Definition: milxModel.cxx:766
static void MarkSurfaceInsideImage(vtkSmartPointer< vtkPolyData > &surface, itk::SmartPointer< TImage > img, vtkFloatArray *weights, const float outsideValue=0.0)
Mark existing surface with all parts outside the image as &#39;outsideValue&#39; value. Inside will remain th...
Represents a deformable model (i.e. a model with cells and scalar values that has special members for...
static vtkSmartPointer< vtkFloatArray > SurfaceScalarsFromImage(vtkSmartPointer< vtkPolyData > surface, itk::SmartPointer< TImage > img, const bool absoluteValues)
Returns the scalars of the mesh (float values per vertex) according to the values found within the im...
Represents a model (i.e. a model with cells and scalar values) and their common operations. Also allows batch operations on collection of models.
Definition: milxModel.h:113
void ApplyOrientation(itk::SmartPointer< TImage > image, const bool applyOrigin=true, const bool flipY=false)
Apply the orientation of an image to a model.