CustusX  20.03-rc1
An IGT application
cxAirwaysFromCenterline.cpp
Go to the documentation of this file.
1 /*=========================================================================
2 This file is part of CustusX, an Image Guided Therapy Application.
3 
4 Copyright (c) SINTEF Department of Medical Technology.
5 All rights reserved.
6 
7 CustusX is released under a BSD 3-Clause license.
8 
9 See Lisence.txt (https://github.com/SINTEFMedtek/CustusX/blob/master/License.txt) for details.
10 =========================================================================*/
11 
13 #include <boost/math/special_functions/round.hpp>
14 #include <vtkPolyData.h>
15 #include "cxBranchList.h"
16 #include "cxBranch.h"
17 #include "vtkCardinalSpline.h"
18 #include <cxImage.h>
19 #include "cxContourFilter.h"
20 #include <vtkImageData.h>
21 #include <vtkPointData.h>
22 #include "cxVolumeHelpers.h"
23 
24 
25 namespace cx
26 {
27 
29  mBranchListPtr(new BranchList),
30  mAirwaysVolumeBoundaryExtention(10),
31  mAirwaysVolumeBoundaryExtentionTracheaStart(2),
32  mAirwaysVolumeSpacing(0.5)
33 {
34 }
35 
37 {
38 }
39 
41 {
42 
43  int N = centerline_r->GetNumberOfPoints();
44  Eigen::MatrixXd CLpoints(3,N);
45  for(vtkIdType i = 0; i < N; i++)
46  {
47  double p[3];
48  centerline_r->GetPoint(i,p);
49  Eigen::Vector3d position;
50  position(0) = p[0]; position(1) = p[1]; position(2) = p[2];
51  CLpoints.block(0 , i , 3 , 1) = position;
52  }
53  return CLpoints;
54 }
55 
57 {
58  if (mBranchListPtr)
59  mBranchListPtr->deleteAllBranches();
60 
61  Eigen::MatrixXd CLpoints_r = getCenterlinePositions(centerline_r);
62 
63  mBranchListPtr->findBranchesInCenterline(CLpoints_r);
64 
65  mBranchListPtr->smoothBranchPositions(40);
66  mBranchListPtr->interpolateBranchPositions(5);
67 }
68 
69 /*
70  AirwaysFromCenterline::generateTubes makes artificial airway tubes around the input centerline. The radius
71  of the tubes is decided by the generation number, based on Weibel's model of airways. n contradiction to the model,
72  it is set a lower boundary for the tube radius (2 mm) making the peripheral airways larger than in reality,
73  which makes it possible to virtually navigate inside the tubes. The airways are generated by adding a sphere to
74  a volume (image) at each point along every branch. The output is a surface model generated from the volume.
75 */
77 {
78  vtkImageDataPtr airwaysVolumePtr = this->initializeAirwaysVolume();
79 
80  airwaysVolumePtr = addSpheresAlongCenterlines(airwaysVolumePtr);
81 
82  //create contour from image
84  airwaysVolumePtr,
85  1, //treshold
86  false, // reduce resolution
87  true, // smoothing
88  true, // keep topology
89  0, // target decimation
90  30, // number of iterations smoothing
91  0.10 // band pass smoothing
92  );
93 
94  return rawContour;
95 }
96 
98 {
99  std::vector<BranchPtr> branches = mBranchListPtr->getBranches();
100  vtkPointsPtr pointsPtr = vtkPointsPtr::New();
101 
102  int numberOfPoints = 0;
103  for (int i = 0; i < branches.size(); i++)
104  numberOfPoints += branches[i]->getPositions().cols();
105 
106  pointsPtr->SetNumberOfPoints(numberOfPoints);
107 
108  int pointIndex = 0;
109  for (int i = 0; i < branches.size(); i++)
110  {
111  Eigen::MatrixXd positions = branches[i]->getPositions();
112  for (int j = 0; j < positions.cols(); j++)
113  {
114  pointsPtr->SetPoint(pointIndex, positions(0,j), positions(1,j), positions(2,j));
115  pointIndex += 1;
116  }
117  }
118 
119  pointsPtr->GetBounds(mBounds);
120 
121  //Extend bounds to make room for surface model extended from centerline
122  mBounds[0] -= mAirwaysVolumeBoundaryExtention;
123  mBounds[1] += mAirwaysVolumeBoundaryExtention;
124  mBounds[2] -= mAirwaysVolumeBoundaryExtention;
125  mBounds[3] += mAirwaysVolumeBoundaryExtention;
126  mBounds[4] -= mAirwaysVolumeBoundaryExtention;
127  mBounds[5] -= mAirwaysVolumeBoundaryExtentionTracheaStart; // to make top of trachea open
128 
129  mSpacing[0] = mAirwaysVolumeSpacing; //Smaller spacing improves resolution but increases run-time
130  mSpacing[1] = mAirwaysVolumeSpacing;
131  mSpacing[2] = mAirwaysVolumeSpacing;
132 
133  // compute dimensions
134  for (int i = 0; i < 3; i++)
135  mDim[i] = static_cast<int>(std::ceil((mBounds[i * 2 + 1] - mBounds[i * 2]) / mSpacing[i]));
136 
137  mOrigin[0] = mBounds[0] + mSpacing[0] / 2;
138  mOrigin[1] = mBounds[2] + mSpacing[1] / 2;
139  mOrigin[2] = mBounds[4] + mSpacing[2] / 2;
140 
141  vtkImageDataPtr airwaysVolumePtr = generateVtkImageData(mDim, mSpacing, 0);
142  airwaysVolumePtr->SetOrigin(mOrigin);
143 
144  return airwaysVolumePtr;
145 }
146 
147 
149 {
150  std::vector<BranchPtr> branches = mBranchListPtr->getBranches();
151 
152  for (int i = 0; i < branches.size(); i++)
153  {
154  Eigen::MatrixXd positions = branches[i]->getPositions();
155  vtkPointsPtr pointsPtr = vtkPointsPtr::New();
156  int numberOfPositionsInBranch = positions.cols();
157  pointsPtr->SetNumberOfPoints(numberOfPositionsInBranch);
158  double radius = branches[i]->findBranchRadius();
159 
160  for (int j = 0; j < numberOfPositionsInBranch; j++)
161  {
162  double spherePos[3];
163  spherePos[0] = positions(0,j);
164  spherePos[1] = positions(1,j);
165  spherePos[2] = positions(2,j);
166  airwaysVolumePtr = addSphereToImage(airwaysVolumePtr, spherePos, radius);
167  }
168  }
169  return airwaysVolumePtr;
170 }
171 
172 vtkImageDataPtr AirwaysFromCenterline::addSphereToImage(vtkImageDataPtr airwaysVolumePtr, double position[3], double radius)
173 {
174  int value = 1;
175  int centerIndex[3];
176  int sphereBoundingBoxIndex[6];
177 
178  for (int i=0; i<3; i++)
179  {
180  centerIndex[i] = static_cast<int>(boost::math::round( (position[i]-mOrigin[i]) / mSpacing[i] ));
181  sphereBoundingBoxIndex[2*i] = std::max(
182  static_cast<int>(boost::math::round( (position[i]-mOrigin[i] - radius) / mSpacing[i] )),
183  0);
184  sphereBoundingBoxIndex[2*i+1] = std::min(
185  static_cast<int>(boost::math::round( (position[i]-mOrigin[i] + radius) / mSpacing[i] )),
186  mDim[i]-1);
187  }
188 
189 
190  for (int x = sphereBoundingBoxIndex[0]; x<=sphereBoundingBoxIndex[1]; x++)
191  for (int y = sphereBoundingBoxIndex[2]; y<=sphereBoundingBoxIndex[3]; y++)
192  for (int z = sphereBoundingBoxIndex[4]; z<=sphereBoundingBoxIndex[5]; z++)
193  {
194  double distanceFromCenter = sqrt((x-centerIndex[0])*mSpacing[0]*(x-centerIndex[0])*mSpacing[0] +
195  (y-centerIndex[1])*mSpacing[1]*(y-centerIndex[1])*mSpacing[1] +
196  (z-centerIndex[2])*mSpacing[2]*(z-centerIndex[2])*mSpacing[2]);
197 
198  if (distanceFromCenter < radius)
199  {
200  unsigned char* dataPtrImage = static_cast<unsigned char*>(airwaysVolumePtr->GetScalarPointer(x,y,z));
201  dataPtrImage[0] = value;
202  }
203  }
204 
205  return airwaysVolumePtr;
206 }
207 
209 {
210  vtkPolyDataPtr retval = vtkPolyDataPtr::New();
211  vtkPointsPtr points = vtkPointsPtr::New();
212  vtkCellArrayPtr lines = vtkCellArrayPtr::New();
213 
214  if (!mBranchListPtr)
215  return retval;
216 
217  double minPointDistance = 0.5; //mm
218  mBranchListPtr->excludeClosePositionsInCTCenterline(minPointDistance); // to reduce number of positions in smoothed centerline
219 
220  std::vector<BranchPtr> branches = mBranchListPtr->getBranches();
221  int pointIndex = 0;
222 
223  for (int i = 0; i < branches.size(); i++)
224  {
225  Eigen::MatrixXd positions = branches[i]->getPositions();
226  int numberOfPositions = positions.cols();
227 
228  if (branches[i]->getParentBranch()) // Add parents last position to get connected centerlines
229  {
230  Eigen::MatrixXd parentPositions = branches[i]->getParentBranch()->getPositions();
231  points->InsertNextPoint(parentPositions(0,parentPositions.cols()-1),parentPositions(1,parentPositions.cols()-1),parentPositions(2,parentPositions.cols()-1));
232  pointIndex += 1;
233  }
234 
235  for (int j = 0; j < numberOfPositions; j++)
236  {
237  points->InsertNextPoint(positions(0,j),positions(1,j),positions(2,j));
238 
239  if (j>1 || branches[i]->getParentBranch())
240  {
241  vtkIdType connection[2] = {pointIndex-1, pointIndex};
242  lines->InsertNextCell(2, connection);
243  }
244  pointIndex += 1;
245  }
246  }
247 
248  retval->SetPoints(points);
249  retval->SetLines(lines);
250  return retval;
251 }
252 
253 } /* namespace cx */
Vector3D ceil(const Vector3D &a)
Definition: cxVector3D.cpp:84
vtkSmartPointer< class vtkCellArray > vtkCellArrayPtr
vtkImageDataPtr addSphereToImage(vtkImageDataPtr airwaysVolumePtr, double position[3], double radius)
vtkSmartPointer< vtkPoints > vtkPointsPtr
Eigen::MatrixXd getCenterlinePositions(vtkPolyDataPtr centerline_r)
void processCenterline(vtkPolyDataPtr centerline_r)
virtual bool execute()
vtkImageDataPtr generateVtkImageData(Eigen::Array3i dim, Vector3D spacing, const unsigned char initValue, int components)
vtkSmartPointer< vtkPolyData > vtkPolyDataPtr
vtkImageDataPtr addSpheresAlongCenterlines(vtkImageDataPtr airwaysVolumePtr)
vtkSmartPointer< class vtkImageData > vtkImageDataPtr
Vector3D round(const Vector3D &a)
Definition: cxVector3D.cpp:75
Namespace for all CustusX production code.