iMSTK
Interactive Medical Simulation Toolkit
imstkImageDistanceTransform.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 "imstkImageDistanceTransform.h"
8 #include "imstkGeometryUtilities.h"
9 #include "imstkImageData.h"
10 #include "imstkLogger.h"
11 
12 #include <vtkImageCast.h>
13 #include <vtkImageData.h>
14 #include <vtkImageEuclideanDistance.h>
15 #include <vtkImageMathematics.h>
16 #include <vtkImageShiftScale.h>
17 
18 namespace imstk
19 {
20 ImageDistanceTransform::ImageDistanceTransform()
21 {
23  setRequiredInputType<ImageData>(0);
24 
26  setOutput(std::make_shared<ImageData>(), 0);
27 }
28 
29 std::shared_ptr<ImageData>
30 ImageDistanceTransform::getOutputImage() const
31 {
32  return std::dynamic_pointer_cast<ImageData>(getOutput(0));
33 }
34 
35 void
36 ImageDistanceTransform::setInputImage(std::shared_ptr<ImageData> refImage)
37 {
38  setInput(refImage, 0);
39 }
40 
41 void
43 {
44  std::shared_ptr<ImageData> imageInput = std::dynamic_pointer_cast<ImageData>(getInput(0));
45 
46  if (imageInput == nullptr)
47  {
48  LOG(WARNING) << "Missing input image data";
49  return;
50  }
51 
52  vtkSmartPointer<vtkImageData> imageInputVtk = GeometryUtils::coupleVtkImageData(imageInput);
53 
54  // Compute the inner distance
55  vtkSmartPointer<vtkImageEuclideanDistance> innerDistanceFilter = vtkSmartPointer<vtkImageEuclideanDistance>::New();
56  innerDistanceFilter->SetInputData(imageInputVtk);
57  innerDistanceFilter->ConsiderAnisotropyOn();
58  innerDistanceFilter->SetAlgorithmToSaito();
59  innerDistanceFilter->SetDimensionality(3);
60  innerDistanceFilter->Update();
61  vtkSmartPointer<vtkImageCast> innerCastFilter = vtkSmartPointer<vtkImageCast>::New();
62  innerCastFilter->SetInputData(innerDistanceFilter->GetOutput());
63  innerCastFilter->SetOutputScalarTypeToFloat();
64  innerCastFilter->Update();
65  vtkSmartPointer<vtkImageMathematics> innerSqrtFilter = vtkSmartPointer<vtkImageMathematics>::New();
66  innerSqrtFilter->SetInput1Data(innerCastFilter->GetOutput());
67  innerSqrtFilter->SetOperationToSquareRoot();
68  innerSqrtFilter->Update();
69 
70  // Invert the input mask to compute the outer distance transform
71  double* range = imageInputVtk->GetScalarRange();
72  vtkSmartPointer<vtkImageShiftScale> invertFilter = vtkSmartPointer<vtkImageShiftScale>::New();
73  invertFilter->SetInputData(imageInputVtk);
74  invertFilter->SetShift(-range[1]);
75  invertFilter->SetScale(-1.0);
76  invertFilter->Update();
77 
78  // Compute the outer distance
79  vtkSmartPointer<vtkImageEuclideanDistance> outerDistanceFilter = vtkSmartPointer<vtkImageEuclideanDistance>::New();
80  outerDistanceFilter->SetInputData(invertFilter->GetOutput());
81  outerDistanceFilter->ConsiderAnisotropyOn();
82  outerDistanceFilter->SetAlgorithmToSaito();
83  outerDistanceFilter->SetDimensionality(3);
84  outerDistanceFilter->Update();
85  vtkSmartPointer<vtkImageCast> outerCastFilter = vtkSmartPointer<vtkImageCast>::New();
86  outerCastFilter->SetInputData(outerDistanceFilter->GetOutput());
87  outerCastFilter->SetOutputScalarTypeToFloat();
88  outerCastFilter->Update();
89  vtkSmartPointer<vtkImageMathematics> outerSqrtFilter = vtkSmartPointer<vtkImageMathematics>::New();
90  outerSqrtFilter->SetInput1Data(outerCastFilter->GetOutput());
91  outerSqrtFilter->SetOperationToSquareRoot();
92  outerSqrtFilter->Update();
93 
94  // Inner distance should be negative
95  vtkSmartPointer<vtkImageData> innerImage = innerSqrtFilter->GetOutput();
96  if (!m_UseUnsigned)
97  {
98  vtkSmartPointer<vtkImageShiftScale> negFilter = vtkSmartPointer<vtkImageShiftScale>::New();
99  negFilter->SetInputData(innerSqrtFilter->GetOutput());
100  negFilter->SetScale(-1.0);
101  negFilter->Update();
102  innerImage = negFilter->GetOutput();
103  }
104 
105  // Finally combine the negative and positive
106  vtkSmartPointer<vtkImageMathematics> addImageFilter = vtkSmartPointer<vtkImageMathematics>::New();
107  addImageFilter->SetInput1Data(outerSqrtFilter->GetOutput());
108  addImageFilter->SetInput2Data(innerImage);
109  addImageFilter->SetOperationToAdd();
110  addImageFilter->Update();
111 
112  setOutput(GeometryUtils::copyToImageData(addImageFilter->GetOutput()));
113 }
114 } // namespace imstk
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 requestUpdate() override
Users can implement this for the logic to be run.
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.
void setOutput(std::shared_ptr< Geometry > inputGeometry, const size_t port=0)
Set the output at the port.
void setInputImage(std::shared_ptr< ImageData > refImage)
Required input, port 0.
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)