Fraxinus  18.10
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  std::vector<BranchPtr> branches = mBranchListPtr->getBranches();
218  int pointIndex = 0;
219 
220  for (int i = 0; i < branches.size(); i++)
221  {
222  Eigen::MatrixXd positions = branches[i]->getPositions();
223  int numberOfPositions = positions.cols();
224 
225  if (branches[i]->getParentBranch()) // Add parents last position to get connected centerlines
226  {
227  Eigen::MatrixXd parentPositions = branches[i]->getParentBranch()->getPositions();
228  points->InsertNextPoint(parentPositions(0,parentPositions.cols()-1),parentPositions(1,parentPositions.cols()-1),parentPositions(2,parentPositions.cols()-1));
229  pointIndex += 1;
230  }
231 
232  for (int j = 0; j < numberOfPositions; j++)
233  {
234  points->InsertNextPoint(positions(0,j),positions(1,j),positions(2,j));
235 
236  if (j>1 || branches[i]->getParentBranch())
237  {
238  vtkIdType connection[2] = {pointIndex-1, pointIndex};
239  lines->InsertNextCell(2, connection);
240  }
241  pointIndex += 1;
242  }
243  }
244 
245  retval->SetPoints(points);
246  retval->SetLines(lines);
247  return retval;
248 }
249 
250 } /* 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.