iMSTK
Interactive Medical Simulation Toolkit
imstkSurfaceMeshImageMask.cpp
1 /*
2 ** This file is part of the Interactive Medical Simulation Toolkit (iMSTK)
3 ** iMSTK is distributed under the Apache License, Version 2.0.
4 ** See accompanying NOTICE for details.
5 */
6 
7 #include "imstkSurfaceMeshImageMask.h"
8 #include "imstkCleanMesh.h"
9 #include "imstkGeometryUtilities.h"
10 #include "imstkImageData.h"
11 #include "imstkLogger.h"
12 #include "imstkSurfaceMesh.h"
13 
14 #include <vtkImageData.h>
15 #include <vtkImageStencil.h>
16 #include <vtkPolyData.h>
17 #include <vtkPolyDataToImageStencil.h>
18 
19 namespace imstk
20 {
21 SurfaceMeshImageMask::SurfaceMeshImageMask()
22 {
24  setRequiredInputType<SurfaceMesh>(0);
25  setOptionalInputType<ImageData>(1);
26 
28  setOutput(std::make_shared<ImageData>(), 0);
29 }
30 
31 void
32 SurfaceMeshImageMask::setReferenceImage(std::shared_ptr<ImageData> refImage)
33 {
34  setInput(refImage, 1);
35 }
36 
37 void
38 SurfaceMeshImageMask::setInputMesh(std::shared_ptr<SurfaceMesh> mesh)
39 {
40  setInput(mesh, 0);
41 }
42 
43 std::shared_ptr<ImageData>
44 SurfaceMeshImageMask::getOutputImage() const
45 {
46  return std::static_pointer_cast<ImageData>(getOutput(0));
47 }
48 
49 void
51 {
52  std::shared_ptr<SurfaceMesh> surfMeshInput = std::dynamic_pointer_cast<SurfaceMesh>(getInput(0));
53  std::shared_ptr<ImageData> refImageInput = std::dynamic_pointer_cast<ImageData>(getInput(1));
54 
55  if (surfMeshInput == nullptr)
56  {
57  LOG(WARNING) << "Missing input surface mesh";
58  return;
59  }
60 
61  Vec3d spacing;
62  int extent[6];
63  Vec3d origin;
64  if (refImageInput != nullptr)
65  {
66  spacing = refImageInput->getSpacing();
67 
68  origin = refImageInput->getOrigin();
69 
70  const Vec3i& dim = refImageInput->getDimensions();
71  extent[0] = 0;
72  extent[1] = dim[0] - 1;
73  extent[2] = 0;
74  extent[3] = dim[1] - 1;
75  extent[4] = 0;
76  extent[5] = dim[2] - 1;
77  }
78  else
79  {
80  if (m_Dimensions[0] == -1 || m_Dimensions[1] == -1 || m_Dimensions[2] == -1)
81  {
82  LOG(WARNING) << "No reference image or desired image dimensions.";
83  return;
84  }
85  Vec3d min;
86  Vec3d max;
87  surfMeshInput->computeBoundingBox(min, max);
88 
89  Vec3d size = max - min;
90 
91  // Compute spacing required for given dimension
92  spacing = size.cwiseQuotient(m_Dimensions.cast<double>());
93 
94  // Increase bounds by px length
95  min -= spacing * m_BorderExtent;
96  max += spacing * m_BorderExtent;
97 
98  size = max - min;
99 
100  extent[0] = 0;
101  extent[1] = (m_Dimensions[0] + m_BorderExtent) - 1;
102  extent[2] = 0;
103  extent[3] = (m_Dimensions[1] + m_BorderExtent) - 1;
104  extent[4] = 0;
105  extent[5] = (m_Dimensions[2] + m_BorderExtent) - 1;
106 
107  origin = min - m_BorderExtent * spacing;
108  }
109 
110  // Allocate a new white image
111  vtkNew<vtkImageData> baseImage;
112  baseImage->SetSpacing(spacing.data());
113  baseImage->SetExtent(extent);
114  baseImage->SetOrigin(origin.data());
115  baseImage->AllocateScalars(VTK_FLOAT, 1);
116  int* dim = baseImage->GetDimensions();
117  std::fill_n(static_cast<float*>(baseImage->GetScalarPointer()), dim[0] * dim[1] * dim[2], 1.0f);
118 
119  // Creates a new image mask from this polygon using a reference mask
120  vtkNew<vtkPolyDataToImageStencil> poly2Stencil;
121  poly2Stencil->SetInputData(GeometryUtils::copyToVtkPolyData(surfMeshInput));
122  poly2Stencil->SetOutputOrigin(origin.data());
123  poly2Stencil->SetOutputSpacing(spacing.data());
124  poly2Stencil->SetOutputWholeExtent(extent);
125  poly2Stencil->Update();
126  vtkNew<vtkImageStencil> imgStencil;
127  imgStencil->SetInputData(baseImage);
128  imgStencil->SetStencilData(poly2Stencil->GetOutput());
129  imgStencil->ReverseStencilOff();
130  imgStencil->SetBackgroundValue(0.0);
131  imgStencil->Update();
132 
133  // Set the output
134  setOutput(GeometryUtils::copyToImageData(imgStencil->GetOutput()));
135 }
136 } // namespace imstk
vtkSmartPointer< vtkPolyData > copyToVtkPolyData(std::shared_ptr< LineMesh > imstkMesh)
Converts imstk line mesh into a vtk polydata.
std::shared_ptr< Geometry > getInput(size_t port=0) const
Returns input geometry given port, returns nullptr if doesn&#39;t exist.
Compound Geometry.
void setReferenceImage(std::shared_ptr< ImageData > refImage)
Optional input, used for information (dimensions, spacing, etc)
void setNumOutputPorts(const size_t numPorts)
Get/Set the amount of output ports.
std::shared_ptr< Geometry > getOutput(size_t port=0) const
Returns output geometry given port, returns nullptr if doesn&#39;t exist.
void setInput(std::shared_ptr< Geometry > inputGeometry, size_t port=0)
Set the input at the port.
Represents a set of triangles & vertices via an array of Vec3d double vertices & Vec3i integer indice...
void setOutput(std::shared_ptr< Geometry > inputGeometry, const size_t port=0)
Set the output at the port.
void setNumInputPorts(const size_t numPorts)
Get/Set the amount of input ports.
Class to represent 1, 2, or 3D image data (i.e. structured points)
void requestUpdate() override
Users can implement this for the logic to be run.