Fraxinus  18.10
An IGT application
cxBranchList.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 #include "cxBranchList.h"
12 #include "cxBranch.h"
13 #include "cxMesh.h"
14 #include "cxVector3D.h"
15 #include <vtkPolyData.h>
16 #include <vtkCardinalSpline.h>
17 
18 
19 typedef vtkSmartPointer<class vtkCardinalSpline> vtkCardinalSplinePtr;
20 
21 namespace cx
22 {
23 
25 {
26 
27 }
28 
29 
31 {
32 // for (int i = 0; i < mBranches.size(); i++)
33 // mBranches[i]->~Branch();
34 }
35 
37 {
38  mBranches.push_back(b);
39 }
40 
42 {
43  for( int i = 0; i < mBranches.size(); i++ )
44  {
45  if (b == mBranches[i])
46  {
47  mBranches.erase(mBranches.begin() + i);
48  return;
49  }
50  }
51 }
52 
54 {
55  mBranches.clear();
56 }
57 
58 std::vector<BranchPtr> BranchList::getBranches()
59 {
60  return mBranches;
61 }
62 
63 void BranchList::selectGenerations(int maxGeneration)
64 {
65  std::vector<int> branchNumbersToBeDeleted;
66  for( int i = 0; i < mBranches.size(); i++ )
67  {
68  int generationCounter = 1;
69  BranchPtr currentBranch = mBranches[i];
70  while (currentBranch->getParentBranch()){
71  generationCounter++;
72  currentBranch = currentBranch->getParentBranch();
73  if (generationCounter > maxGeneration)
74  {
75  branchNumbersToBeDeleted.push_back(i);
76  break;
77  }
78  }
79 
80  }
81 
82  for ( int i = branchNumbersToBeDeleted.size() - 1; i >= 0; i-- )
83  deleteBranch(mBranches[branchNumbersToBeDeleted[i]]);
84 }
85 
86 
88 {
89  for (int i = 0; i < mBranches.size(); i++)
90  {
91  Eigen::MatrixXd positions = mBranches[i]->getPositions();
92  Eigen::MatrixXd diff = positions.rightCols(positions.cols() - 1) - positions.leftCols(positions.cols() - 1);
93  Eigen::MatrixXd orientations(positions.rows(),positions.cols());
94  orientations.leftCols(orientations.cols() - 1) = diff / diff.norm();
95  orientations.rightCols(1) = orientations.col(orientations.cols() - 1);
96  mBranches[i]->setOrientations(orientations);
97  }
98 }
99 
101 {
102  for (int i = 0; i < mBranches.size(); i++)
103  {
104  Eigen::MatrixXd orientations = mBranches[i]->getOrientations();
105  Eigen::MatrixXd newOrientations(orientations.rows(),orientations.cols());
106  int numberOfColumns = orientations.cols();
107  for (int j = 0; j < numberOfColumns; j++)
108  {
109  newOrientations.col(j) = orientations.block(0,std::max(j-2,0),orientations.rows(),std::min(5,numberOfColumns-j)).rowwise().mean(); //smoothing
110  newOrientations.col(j) = newOrientations.col(j) / newOrientations.col(j).norm(); // normalizing
111  }
112  mBranches[i]->setOrientations(newOrientations);
113  }
114 }
115 
116 void BranchList::interpolateBranchPositions(int interpolationFactor){
117 
118  for (int i = 0; i < mBranches.size(); i++)
119  {
120  Eigen::MatrixXd positions = mBranches[i]->getPositions();
121 
122  if (mBranches[i]->getParentBranch()) // Add parents last position to interpolate between branches
123  {
124  Eigen::MatrixXd parentPositions = mBranches[i]->getParentBranch()->getPositions();
125  Eigen::MatrixXd positionsResized(positions.rows(), positions.cols()+1);
126  positionsResized.col(0) = parentPositions.rightCols(1);
127  positionsResized.rightCols(positions.cols()) = positions;
128  positions = positionsResized;
129  }
130 
131  std::vector<Eigen::Vector3d> interpolatedPositions;
132  for (int j = 0; j < positions.cols()-1; j++)
133  {
134  for (int k = 0; k < interpolationFactor; k++){
135  Eigen::Vector3d interpolationPoint;
136  interpolationPoint[0] = (positions(0,j)*(interpolationFactor-k) + positions(0,j+1)*(k) ) / interpolationFactor;
137  interpolationPoint[1] = (positions(1,j)*(interpolationFactor-k) + positions(1,j+1)*(k) ) / interpolationFactor;
138  interpolationPoint[2] = (positions(2,j)*(interpolationFactor-k) + positions(2,j+1)*(k) ) / interpolationFactor;
139  interpolatedPositions.push_back(interpolationPoint);
140  }
141  }
142  if (mBranches[i]->getParentBranch()) // Remove parents last position after interpolation
143  {
144  Eigen::MatrixXd positionsResized(positions.rows(), positions.cols()-1);
145  positionsResized = positions.rightCols(positionsResized.cols());
146  positions = positionsResized;
147  }
148  Eigen::MatrixXd interpolationResult(3 , interpolatedPositions.size());
149  for (int j = 0; j < interpolatedPositions.size(); j++)
150  {
151  interpolationResult(0,j) = interpolatedPositions[j](0);
152  interpolationResult(1,j) = interpolatedPositions[j](1);
153  interpolationResult(2,j) = interpolatedPositions[j](2);
154  }
155  mBranches[i]->setPositions(interpolationResult);
156  }
157 
158 }
159 
160 void BranchList::smoothBranchPositions(int controlPointDistance)
161 {
162  for (int i = 0; i < mBranches.size(); i++)
163  {
164  Eigen::MatrixXd positions = mBranches[i]->getPositions();
165  int numberOfInputPoints = positions.cols();
166  //int controlPointFactor = 10;
167  //int numberOfControlPoints = numberOfInputPoints / controlPointFactor;
168  double branchLength = (positions.rightCols(1) - positions.leftCols(1)).norm();
169  int numberOfControlPoints = std::ceil(branchLength/controlPointDistance);
170  numberOfControlPoints = std::max(numberOfControlPoints, 2); // at least two control points
171 
172  vtkCardinalSplinePtr splineX = vtkSmartPointer<vtkCardinalSpline>::New();
173  vtkCardinalSplinePtr splineY = vtkSmartPointer<vtkCardinalSpline>::New();
174  vtkCardinalSplinePtr splineZ = vtkSmartPointer<vtkCardinalSpline>::New();
175 
176  //add control points to spline
177  for(int j=0; j<numberOfControlPoints; j++)
178  {
179  int indexP = (j*numberOfInputPoints)/numberOfControlPoints;
180 
181  splineX->AddPoint(indexP,positions(0,indexP));
182  splineY->AddPoint(indexP,positions(1,indexP));
183  splineZ->AddPoint(indexP,positions(2,indexP));
184  }
185  //Always add the last point to complete spline
186  splineX->AddPoint(numberOfInputPoints-1,positions(0,numberOfInputPoints-1));
187  splineY->AddPoint(numberOfInputPoints-1,positions(1,numberOfInputPoints-1));
188  splineZ->AddPoint(numberOfInputPoints-1,positions(2,numberOfInputPoints-1));
189 
190  //evaluate spline - get smoothed positions
191  Eigen::MatrixXd smoothingResult(3 , numberOfInputPoints);
192  for(int j=0; j<numberOfInputPoints; j++)
193  {
194  double splineParameter = j;
195  smoothingResult(0,j) = splineX->Evaluate(splineParameter);
196  smoothingResult(1,j) = splineY->Evaluate(splineParameter);
197  smoothingResult(2,j) = splineZ->Evaluate(splineParameter);
198  }
199  mBranches[i]->setPositions(smoothingResult);
200  }
201 }
202 
203 void BranchList::findBranchesInCenterline(Eigen::MatrixXd positions_r)
204 {
205  positions_r = sortMatrix(2,positions_r);
206  Eigen::MatrixXd positionsNotUsed_r = positions_r;
207 
208 // int minIndex;
209  int index;
210  int splitIndex;
211  Eigen::MatrixXd::Index startIndex;
212  BranchPtr branchToSplit;
213  while (positionsNotUsed_r.cols() > 0)
214  {
215  if (!mBranches.empty())
216  {
217  double minDistance = 1000;
218  for (int i = 0; i < mBranches.size(); i++)
219  {
220  std::pair<std::vector<Eigen::MatrixXd::Index>, Eigen::VectorXd> distances;
221  distances = dsearchn(positionsNotUsed_r, mBranches[i]->getPositions());
222  double d = distances.second.minCoeff(&index);
223  if (d < minDistance)
224  {
225  minDistance = d;
226  branchToSplit = mBranches[i];
227  startIndex = index;
228  if (minDistance < 2)
229  break;
230  }
231  }
232  std::pair<Eigen::MatrixXd::Index, double> dsearchResult = dsearch(positionsNotUsed_r.col(startIndex) , branchToSplit->getPositions());
233  splitIndex = dsearchResult.first;
234  }
235  else //if this is the first branch. Select the top position (Trachea).
236  startIndex = positionsNotUsed_r.cols() - 1;
237 
238  std::pair<Eigen::MatrixXd,Eigen::MatrixXd > connectedPointsResult = findConnectedPointsInCT(startIndex , positionsNotUsed_r);
239  Eigen::MatrixXd branchPositions = connectedPointsResult.first;
240  positionsNotUsed_r = connectedPointsResult.second;
241 
242  if (branchPositions.cols() >= 5) //only include brances of length >= 5 points
243  {
244  BranchPtr newBranch = BranchPtr(new Branch());
245  newBranch->setPositions(branchPositions);
246  mBranches.push_back(newBranch);
247 
248  if (mBranches.size() > 1) // do not try to split another branch when the first branch is processed
249  {
250  if ((splitIndex + 1 >= 5) && (branchToSplit->getPositions().cols() - splitIndex - 1 >= 5))
251  //do not split branch if the new branch is close to the edge of the branch
252  //if the new branch is not close to one of the edges of the
253  //connected existing branch: Split the existing branch
254  {
255  BranchPtr newBranchFromSplit = BranchPtr(new Branch());
256  Eigen::MatrixXd branchToSplitPositions = branchToSplit->getPositions();
257  newBranchFromSplit->setPositions(branchToSplitPositions.rightCols(branchToSplitPositions.cols() - splitIndex - 1));
258  branchToSplit->setPositions(branchToSplitPositions.leftCols(splitIndex + 1));
259  mBranches.push_back(newBranchFromSplit);
260  newBranchFromSplit->setParentBranch(branchToSplit);
261  newBranch->setParentBranch(branchToSplit);
262  newBranchFromSplit->setChildBranches(branchToSplit->getChildBranches());
263  branchVector branchToSplitChildren = branchToSplit->getChildBranches();
264  for (int i = 0; i < branchToSplitChildren.size(); i++)
265  branchToSplitChildren[i]->setParentBranch(newBranchFromSplit);
266  branchToSplit->deleteChildBranches();
267  branchToSplit->addChildBranch(newBranchFromSplit);
268  branchToSplit->addChildBranch(newBranch);
269  }
270  else if (splitIndex + 1 < 5)
271  // If the new branch is close to the start of the existing
272  // branch: Connect it to the same position start as the
273  // existing branch
274  {
275  newBranch->setParentBranch(branchToSplit->getParentBranch());
276  if(branchToSplit->getParentBranch())
277  branchToSplit->getParentBranch()->addChildBranch(newBranch);
278  }
279  else if (branchToSplit->getPositions().cols() - splitIndex - 1 < 5)
280  // If the new branch is close to the end of the existing
281  // branch: Connect it to the end of the existing branch
282  {
283  newBranch->setParentBranch(branchToSplit);
284  branchToSplit->addChildBranch(newBranch);
285  }
286 
287  }
288 
289  }
290  }
291 }
292 
293 
294 BranchListPtr BranchList::removePositionsForLocalRegistration(Eigen::MatrixXd trackingPositions, double maxDistance)
295 {
296  BranchListPtr retval = BranchListPtr(new BranchList());
297  BranchPtr b;
298  for (int i = 0; i < mBranches.size(); i++)
299  {
300  b = BranchPtr(new Branch());
301  b->setPositions(mBranches[i]->getPositions());
302  b->setOrientations(mBranches[i]->getOrientations());
303  retval->addBranch(b);
304  }
305 
306  std::vector<BranchPtr> branches = retval->getBranches();
307  Eigen::MatrixXd positions;
308  Eigen::MatrixXd orientations;
309  for (int i = 0; i < branches.size(); i++)
310  {
311  positions = branches[i]->getPositions();
312  orientations = branches[i]->getOrientations();
313  std::pair<std::vector<Eigen::MatrixXd::Index>, Eigen::VectorXd> distanceData;
314  distanceData = dsearchn(positions, trackingPositions);
315  Eigen::VectorXd distance = distanceData.second;
316  for (int j = positions.cols() - 1; j >= 0; j--)
317  {
318  if (distance(j) > maxDistance)
319  {
320  positions = eraseCol(j, positions);
321  orientations = eraseCol(j, orientations);
322  }
323  }
324  branches[i]->setPositions(positions);
325  branches[i]->setOrientations(orientations);
326  }
327  return retval;
328 }
329 
348 vtkPolyDataPtr BranchList::createVtkPolyDataFromBranches(bool fullyConnected, bool straightBranches) const
349 {
350  vtkPolyDataPtr retval = vtkPolyDataPtr::New();
351  vtkPointsPtr points = vtkPointsPtr::New();
352  vtkCellArrayPtr lines = vtkCellArrayPtr::New();
353 
354  int positionCounter = 0;
355  for (size_t i = 0; i < mBranches.size(); ++i)
356  {
357  Eigen::MatrixXd positions = mBranches[i]->getPositions();
358  if(straightBranches)
359  {
360  ++positionCounter;
361  points->InsertNextPoint(positions(0,0),positions(1,0),positions(2,0));
362  points->InsertNextPoint(positions(0,positions.cols()-1),positions(1,positions.cols()-1),positions(2,positions.cols()-1));
363  vtkIdType connection[2] = {positionCounter-1, positionCounter};
364  lines->InsertNextCell(2, connection);
365  ++positionCounter;
366  }
367  else
368  {
369  for (int j = 0; j < positions.cols(); ++j)
370  {
371  ++positionCounter;
372  points->InsertNextPoint(positions(0,j),positions(1,j),positions(2,j));
373  if (j < positions.cols()-1)
374  {
375  vtkIdType connection[2] = {positionCounter-1, positionCounter};
376  lines->InsertNextCell(2, connection);
377  }
378  }
379  }
380  }
381  if(fullyConnected)
382  {
383  int this_branchs_first_point_in_full_polydata_point_list = 0;
384  for(size_t i = 0; i < mBranches.size(); ++i)
385  {
386  if(i>0)
387  {
388  if(!straightBranches)
389  this_branchs_first_point_in_full_polydata_point_list += mBranches[i-1]->getPositions().cols();
390  else
391  this_branchs_first_point_in_full_polydata_point_list += 2;
392  }
393  int parent_index_in_branch_list = mBranches[i]->findParentIndex(mBranches);
394 
395  if(parent_index_in_branch_list > -1)
396  {
397  int parent_branch_last_point_in_full_polydata = 0;
398  for(int j = 0; j <= parent_index_in_branch_list; ++j)
399  {
400  if(!straightBranches)
401  parent_branch_last_point_in_full_polydata += mBranches[j]->getPositions().cols() - 1;
402  else
403  parent_branch_last_point_in_full_polydata += (1 + j*2);
404  }
405  vtkIdType connection[2] = {parent_branch_last_point_in_full_polydata, this_branchs_first_point_in_full_polydata_point_list};
406  lines->InsertNextCell(2, connection);
407  }
408 
409  }
410 
411  }
412  retval->SetPoints(points);
413  retval->SetLines(lines);
414 
415  return retval;
416 }
417 
418 Eigen::MatrixXd sortMatrix(int rowNumber, Eigen::MatrixXd matrix)
419 {
420  for (int i = 0; i < matrix.cols() - 1; i++) {
421  for (int j = i + 1; j < matrix.cols(); j++) {
422  if (matrix(rowNumber,i) > matrix(rowNumber,j)){
423  matrix.col(i).swap(matrix.col(j));
424  }
425  }
426  }
427 return matrix;
428 }
429 
430 
431 
432 Eigen::MatrixXd eraseCol(int removeIndex, Eigen::MatrixXd positions)
433 {
434  positions.block(0 , removeIndex , positions.rows() , positions.cols() - removeIndex - 1) = positions.rightCols(positions.cols() - removeIndex - 1);
435  positions.conservativeResize(Eigen::NoChange, positions.cols() - 1);
436  return positions;
437 }
438 
439 std::pair<Eigen::MatrixXd::Index, double> dsearch(Eigen::Vector3d p, Eigen::MatrixXd positions)
440 {
441  Eigen::MatrixXd::Index index;
442  // find nearest neighbour
443  (positions.colwise() - p).colwise().squaredNorm().minCoeff(&index);
444  double d = (positions.col(index) - p).norm();
445 
446  return std::make_pair(index , d);
447 }
448 
449 std::pair<std::vector<Eigen::MatrixXd::Index>, Eigen::VectorXd > dsearchn(Eigen::MatrixXd p1, Eigen::MatrixXd p2)
450 {
451  Eigen::MatrixXd::Index index;
452  std::vector<Eigen::MatrixXd::Index> indexVector;
453  Eigen::VectorXd D(p1.cols());
454  for (int i = 0; i < p1.cols(); i++)
455  {
456  // find nearest neighbour
457  (p2.colwise() - p1.col(i)).colwise().squaredNorm().minCoeff(&index);
458  D(i) = (p2.col(index) - p1.col(i)).norm();
459  indexVector.push_back(index);
460  }
461  return std::make_pair(indexVector , D);
462 }
463 
464 std::pair<Eigen::MatrixXd,Eigen::MatrixXd > findConnectedPointsInCT(int startIndex , Eigen::MatrixXd positionsNotUsed)
465 {
466  //Eigen::MatrixXd branchPositions(positionsNotUsed.rows(), positionsNotUsed.cols());
467  Eigen::MatrixXd thisPosition(3,1);
468  std::vector<Eigen::MatrixXd> branchPositionsVector;
469  thisPosition = positionsNotUsed.col(startIndex);
470  branchPositionsVector.push_back(thisPosition); //add first position to branch
471  positionsNotUsed = eraseCol(startIndex,positionsNotUsed);; //remove first position from list of remaining points
472 
473  while (positionsNotUsed.cols() > 0)
474  {
475  std::pair<Eigen::MatrixXd::Index, double > minDistance = dsearch(thisPosition, positionsNotUsed);
476  Eigen::MatrixXd::Index index = minDistance.first;
477  double d = minDistance.second;
478  if (d > 3) // more than 3 mm distance to closest point --> branch is compledted
479  break;
480 
481  thisPosition = positionsNotUsed.col(index);
482  positionsNotUsed = eraseCol(index,positionsNotUsed);
483  //add position to branch
484  branchPositionsVector.push_back(thisPosition);
485 
486  }
487 
488  Eigen::MatrixXd branchPositions(3,branchPositionsVector.size());
489 
490  for (int j = 0; j < branchPositionsVector.size(); j++)
491  {
492  branchPositions.block(0,j,3,1) = branchPositionsVector[j];
493  }
494 
495  return std::make_pair(branchPositions, positionsNotUsed);
496 }
497 
498 
499 }//namespace cx
virtual ~BranchList()
Vector3D ceil(const Vector3D &a)
Definition: cxVector3D.cpp:84
std::pair< Eigen::MatrixXd, Eigen::MatrixXd > findConnectedPointsInCT(int startIndex, Eigen::MatrixXd positionsNotUsed)
void interpolateBranchPositions(int interpolationFactor)
vtkSmartPointer< class vtkCellArray > vtkCellArrayPtr
boost::shared_ptr< class BranchList > BranchListPtr
BranchListPtr removePositionsForLocalRegistration(Eigen::MatrixXd trackingPositions, double maxDistance)
vtkSmartPointer< vtkPoints > vtkPointsPtr
void addBranch(BranchPtr b)
void deleteAllBranches()
boost::shared_ptr< class Branch > BranchPtr
vtkSmartPointer< class vtkCardinalSpline > vtkCardinalSplinePtr
vtkSmartPointer< class vtkCardinalSpline > vtkCardinalSplinePtr
Definition: cxAccusurf.cpp:17
vtkPolyDataPtr createVtkPolyDataFromBranches(bool fullyConnected=false, bool straightBranches=false) const
BranchList::createVtkPolyDataFromBranches Return a VtkPolyData object created from the branches in th...
std::pair< Eigen::MatrixXd::Index, double > dsearch(Eigen::Vector3d p, Eigen::MatrixXd positions)
void calculateOrientations()
void smoothBranchPositions(int controlPointDistance)
std::vector< BranchPtr > getBranches()
void deleteBranch(BranchPtr b)
vtkSmartPointer< vtkPolyData > vtkPolyDataPtr
void findBranchesInCenterline(Eigen::MatrixXd positions_r)
class org_custusx_registration_method_bronchoscopy_EXPORT Branch
Definition: cxBranch.h:26
std::pair< std::vector< Eigen::MatrixXd::Index >, Eigen::VectorXd > dsearchn(Eigen::MatrixXd p1, Eigen::MatrixXd p2)
Eigen::MatrixXd eraseCol(int removeIndex, Eigen::MatrixXd positions)
void selectGenerations(int maxGeneration)
Eigen::MatrixXd sortMatrix(int rowNumber, Eigen::MatrixXd matrix)
void smoothOrientations()
std::vector< BranchPtr > branchVector
Definition: cxBranch.h:28
Namespace for all CustusX production code.