Fraxinus  17.12
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) 2008-2014, SINTEF Department of Medical Technology
5 All rights reserved.
6 
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9 
10 1. Redistributions of source code must retain the above copyright notice,
11  this list of conditions and the following disclaimer.
12 
13 2. Redistributions in binary form must reproduce the above copyright notice,
14  this list of conditions and the following disclaimer in the documentation
15  and/or other materials provided with the distribution.
16 
17 3. Neither the name of the copyright holder nor the names of its contributors
18  may be used to endorse or promote products derived from this software
19  without specific prior written permission.
20 
21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
25 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 =========================================================================*/
32 #include "cxBranchList.h"
33 #include "cxBranch.h"
34 #include "cxMesh.h"
35 #include "cxVector3D.h"
36 #include <vtkPolyData.h>
37 #include <vtkCardinalSpline.h>
38 
39 
40 typedef vtkSmartPointer<class vtkCardinalSpline> vtkCardinalSplinePtr;
41 
42 namespace cx
43 {
44 
46 {
47 
48 }
49 
50 
52 {
53 // for (int i = 0; i < mBranches.size(); i++)
54 // mBranches[i]->~Branch();
55 }
56 
58 {
59  mBranches.push_back(b);
60 }
61 
63 {
64  for( int i = 0; i < mBranches.size(); i++ )
65  {
66  if (b == mBranches[i])
67  {
68  mBranches.erase(mBranches.begin() + i);
69  return;
70  }
71  }
72 }
73 
75 {
76  mBranches.clear();
77 }
78 
79 std::vector<BranchPtr> BranchList::getBranches()
80 {
81  return mBranches;
82 }
83 
84 void BranchList::selectGenerations(int maxGeneration)
85 {
86  std::vector<int> branchNumbersToBeDeleted;
87  for( int i = 0; i < mBranches.size(); i++ )
88  {
89  int generationCounter = 1;
90  BranchPtr currentBranch = mBranches[i];
91  while (currentBranch->getParentBranch()){
92  generationCounter++;
93  currentBranch = currentBranch->getParentBranch();
94  if (generationCounter > maxGeneration)
95  {
96  branchNumbersToBeDeleted.push_back(i);
97  break;
98  }
99  }
100 
101  }
102 
103  for ( int i = branchNumbersToBeDeleted.size() - 1; i >= 0; i-- )
104  deleteBranch(mBranches[branchNumbersToBeDeleted[i]]);
105 }
106 
107 
109 {
110  for (int i = 0; i < mBranches.size(); i++)
111  {
112  Eigen::MatrixXd positions = mBranches[i]->getPositions();
113  Eigen::MatrixXd diff = positions.rightCols(positions.cols() - 1) - positions.leftCols(positions.cols() - 1);
114  Eigen::MatrixXd orientations(positions.rows(),positions.cols());
115  orientations.leftCols(orientations.cols() - 1) = diff / diff.norm();
116  orientations.rightCols(1) = orientations.col(orientations.cols() - 1);
117  mBranches[i]->setOrientations(orientations);
118  }
119 }
120 
122 {
123  for (int i = 0; i < mBranches.size(); i++)
124  {
125  Eigen::MatrixXd orientations = mBranches[i]->getOrientations();
126  Eigen::MatrixXd newOrientations(orientations.rows(),orientations.cols());
127  int numberOfColumns = orientations.cols();
128  for (int j = 0; j < numberOfColumns; j++)
129  {
130  newOrientations.col(j) = orientations.block(0,std::max(j-2,0),orientations.rows(),std::min(5,numberOfColumns-j)).rowwise().mean(); //smoothing
131  newOrientations.col(j) = newOrientations.col(j) / newOrientations.col(j).norm(); // normalizing
132  }
133  mBranches[i]->setOrientations(newOrientations);
134  }
135 }
136 
137 void BranchList::interpolateBranchPositions(int interpolationFactor){
138 
139  for (int i = 0; i < mBranches.size(); i++)
140  {
141  Eigen::MatrixXd positions = mBranches[i]->getPositions();
142  std::vector<Eigen::Vector3d> interpolatedPositions;
143  for (int j = 0; j < positions.cols()-1; j++)
144  {
145  for (int k = 0; k < interpolationFactor; k++){
146  Eigen::Vector3d interpolationPoint;
147  interpolationPoint[0] = (positions(0,j)*(interpolationFactor-k) + positions(0,j+1)*(k) ) / interpolationFactor;
148  interpolationPoint[1] = (positions(1,j)*(interpolationFactor-k) + positions(1,j+1)*(k) ) / interpolationFactor;
149  interpolationPoint[2] = (positions(2,j)*(interpolationFactor-k) + positions(2,j+1)*(k) ) / interpolationFactor;
150  interpolatedPositions.push_back(interpolationPoint);
151  }
152  }
153  Eigen::MatrixXd interpolationResult(3 , interpolatedPositions.size());
154  for (int j = 0; j < interpolatedPositions.size(); j++)
155  {
156  interpolationResult(0,j) = interpolatedPositions[j](0);
157  interpolationResult(1,j) = interpolatedPositions[j](1);
158  interpolationResult(2,j) = interpolatedPositions[j](2);
159  }
160  mBranches[i]->setPositions(interpolationResult);
161  }
162 
163 }
164 
165 void BranchList::smoothBranchPositions(int controlPointDistance)
166 {
167  for (int i = 0; i < mBranches.size(); i++)
168  {
169  Eigen::MatrixXd positions = mBranches[i]->getPositions();
170  int numberOfInputPoints = positions.cols();
171  //int controlPointFactor = 10;
172  //int numberOfControlPoints = numberOfInputPoints / controlPointFactor;
173  double branchLength = (positions.rightCols(1) - positions.leftCols(1)).norm();
174  int numberOfControlPoints = std::ceil(branchLength/controlPointDistance);
175  numberOfControlPoints = std::max(numberOfControlPoints, 2); // at least two control points
176 
177  vtkCardinalSplinePtr splineX = vtkSmartPointer<vtkCardinalSpline>::New();
178  vtkCardinalSplinePtr splineY = vtkSmartPointer<vtkCardinalSpline>::New();
179  vtkCardinalSplinePtr splineZ = vtkSmartPointer<vtkCardinalSpline>::New();
180 
181  //add control points to spline
182  for(int j=0; j<numberOfControlPoints; j++)
183  {
184  int indexP = (j*numberOfInputPoints)/numberOfControlPoints;
185 
186  splineX->AddPoint(indexP,positions(0,indexP));
187  splineY->AddPoint(indexP,positions(1,indexP));
188  splineZ->AddPoint(indexP,positions(2,indexP));
189  }
190  //Always add the last point to complete spline
191  splineX->AddPoint(numberOfInputPoints-1,positions(0,numberOfInputPoints-1));
192  splineY->AddPoint(numberOfInputPoints-1,positions(1,numberOfInputPoints-1));
193  splineZ->AddPoint(numberOfInputPoints-1,positions(2,numberOfInputPoints-1));
194 
195  //evaluate spline - get smoothed positions
196  Eigen::MatrixXd smoothingResult(3 , numberOfInputPoints);
197  for(int j=0; j<numberOfInputPoints; j++)
198  {
199  double splineParameter = j;
200  smoothingResult(0,j) = splineX->Evaluate(splineParameter);
201  smoothingResult(1,j) = splineY->Evaluate(splineParameter);
202  smoothingResult(2,j) = splineZ->Evaluate(splineParameter);
203  }
204  mBranches[i]->setPositions(smoothingResult);
205  }
206 }
207 
208 void BranchList::findBranchesInCenterline(Eigen::MatrixXd positions_r)
209 {
210  positions_r = sortMatrix(2,positions_r);
211  Eigen::MatrixXd positionsNotUsed_r = positions_r;
212 
213 // int minIndex;
214  int index;
215  int splitIndex;
216  Eigen::MatrixXd::Index startIndex;
217  BranchPtr branchToSplit;
218  while (positionsNotUsed_r.cols() > 0)
219  {
220  if (!mBranches.empty())
221  {
222  double minDistance = 1000;
223  for (int i = 0; i < mBranches.size(); i++)
224  {
225  std::pair<std::vector<Eigen::MatrixXd::Index>, Eigen::VectorXd> distances;
226  distances = dsearchn(positionsNotUsed_r, mBranches[i]->getPositions());
227  double d = distances.second.minCoeff(&index);
228  if (d < minDistance)
229  {
230  minDistance = d;
231  branchToSplit = mBranches[i];
232  startIndex = index;
233  if (minDistance < 2)
234  break;
235  }
236  }
237  std::pair<Eigen::MatrixXd::Index, double> dsearchResult = dsearch(positionsNotUsed_r.col(startIndex) , branchToSplit->getPositions());
238  splitIndex = dsearchResult.first;
239  }
240  else //if this is the first branch. Select the top position (Trachea).
241  startIndex = positionsNotUsed_r.cols() - 1;
242 
243  std::pair<Eigen::MatrixXd,Eigen::MatrixXd > connectedPointsResult = findConnectedPointsInCT(startIndex , positionsNotUsed_r);
244  Eigen::MatrixXd branchPositions = connectedPointsResult.first;
245  positionsNotUsed_r = connectedPointsResult.second;
246 
247  if (branchPositions.cols() >= 5) //only include brances of length >= 5 points
248  {
249  BranchPtr newBranch = BranchPtr(new Branch());
250  newBranch->setPositions(branchPositions);
251  mBranches.push_back(newBranch);
252 
253  if (mBranches.size() > 1) // do not try to split another branch when the first branch is processed
254  {
255  if ((splitIndex + 1 >= 5) && (branchToSplit->getPositions().cols() - splitIndex - 1 >= 5))
256  //do not split branch if the new branch is close to the edge of the branch
257  //if the new branch is not close to one of the edges of the
258  //connected existing branch: Split the existing branch
259  {
260  BranchPtr newBranchFromSplit = BranchPtr(new Branch());
261  Eigen::MatrixXd branchToSplitPositions = branchToSplit->getPositions();
262  newBranchFromSplit->setPositions(branchToSplitPositions.rightCols(branchToSplitPositions.cols() - splitIndex - 1));
263  branchToSplit->setPositions(branchToSplitPositions.leftCols(splitIndex + 1));
264  mBranches.push_back(newBranchFromSplit);
265  newBranchFromSplit->setParentBranch(branchToSplit);
266  newBranch->setParentBranch(branchToSplit);
267  newBranchFromSplit->setChildBranches(branchToSplit->getChildBranches());
268  branchVector branchToSplitChildren = branchToSplit->getChildBranches();
269  for (int i = 0; i < branchToSplitChildren.size(); i++)
270  branchToSplitChildren[i]->setParentBranch(newBranchFromSplit);
271  branchToSplit->deleteChildBranches();
272  branchToSplit->addChildBranch(newBranchFromSplit);
273  branchToSplit->addChildBranch(newBranch);
274  }
275  else if (splitIndex + 1 < 5)
276  // If the new branch is close to the start of the existing
277  // branch: Connect it to the same position start as the
278  // existing branch
279  {
280  newBranch->setParentBranch(branchToSplit->getParentBranch());
281  if(branchToSplit->getParentBranch())
282  branchToSplit->getParentBranch()->addChildBranch(newBranch);
283  }
284  else if (branchToSplit->getPositions().cols() - splitIndex - 1 < 5)
285  // If the new branch is close to the end of the existing
286  // branch: Connect it to the end of the existing branch
287  {
288  newBranch->setParentBranch(branchToSplit);
289  branchToSplit->addChildBranch(newBranch);
290  }
291 
292  }
293 
294  }
295  }
296 }
297 
298 
299 BranchListPtr BranchList::removePositionsForLocalRegistration(Eigen::MatrixXd trackingPositions, double maxDistance)
300 {
301  BranchListPtr retval = BranchListPtr(new BranchList());
302  BranchPtr b;
303  for (int i = 0; i < mBranches.size(); i++)
304  {
305  b = BranchPtr(new Branch());
306  b->setPositions(mBranches[i]->getPositions());
307  b->setOrientations(mBranches[i]->getOrientations());
308  retval->addBranch(b);
309  }
310 
311  std::vector<BranchPtr> branches = retval->getBranches();
312  Eigen::MatrixXd positions;
313  Eigen::MatrixXd orientations;
314  for (int i = 0; i < branches.size(); i++)
315  {
316  positions = branches[i]->getPositions();
317  orientations = branches[i]->getOrientations();
318  std::pair<std::vector<Eigen::MatrixXd::Index>, Eigen::VectorXd> distanceData;
319  distanceData = dsearchn(positions, trackingPositions);
320  Eigen::VectorXd distance = distanceData.second;
321  for (int j = positions.cols() - 1; j >= 0; j--)
322  {
323  if (distance(j) > maxDistance)
324  {
325  positions = eraseCol(j, positions);
326  orientations = eraseCol(j, orientations);
327  }
328  }
329  branches[i]->setPositions(positions);
330  branches[i]->setOrientations(orientations);
331  }
332  return retval;
333 }
334 
353 vtkPolyDataPtr BranchList::createVtkPolyDataFromBranches(bool fullyConnected, bool straightBranches) const
354 {
355  vtkPolyDataPtr retval = vtkPolyDataPtr::New();
356  vtkPointsPtr points = vtkPointsPtr::New();
357  vtkCellArrayPtr lines = vtkCellArrayPtr::New();
358 
359  int positionCounter = 0;
360  for (size_t i = 0; i < mBranches.size(); ++i)
361  {
362  Eigen::MatrixXd positions = mBranches[i]->getPositions();
363  if(straightBranches)
364  {
365  ++positionCounter;
366  points->InsertNextPoint(positions(0,0),positions(1,0),positions(2,0));
367  points->InsertNextPoint(positions(0,positions.cols()-1),positions(1,positions.cols()-1),positions(2,positions.cols()-1));
368  vtkIdType connection[2] = {positionCounter-1, positionCounter};
369  lines->InsertNextCell(2, connection);
370  ++positionCounter;
371  }
372  else
373  {
374  for (int j = 0; j < positions.cols(); ++j)
375  {
376  ++positionCounter;
377  points->InsertNextPoint(positions(0,j),positions(1,j),positions(2,j));
378  if (j < positions.cols()-1)
379  {
380  vtkIdType connection[2] = {positionCounter-1, positionCounter};
381  lines->InsertNextCell(2, connection);
382  }
383  }
384  }
385  }
386  if(fullyConnected)
387  {
388  int this_branchs_first_point_in_full_polydata_point_list = 0;
389  for(size_t i = 0; i < mBranches.size(); ++i)
390  {
391  if(i>0)
392  {
393  if(!straightBranches)
394  this_branchs_first_point_in_full_polydata_point_list += mBranches[i-1]->getPositions().cols();
395  else
396  this_branchs_first_point_in_full_polydata_point_list += 2;
397  }
398  int parent_index_in_branch_list = mBranches[i]->findParentIndex(mBranches);
399 
400  if(parent_index_in_branch_list > -1)
401  {
402  int parent_branch_last_point_in_full_polydata = 0;
403  for(int j = 0; j <= parent_index_in_branch_list; ++j)
404  {
405  if(!straightBranches)
406  parent_branch_last_point_in_full_polydata += mBranches[j]->getPositions().cols() - 1;
407  else
408  parent_branch_last_point_in_full_polydata += (1 + j*2);
409  }
410  vtkIdType connection[2] = {parent_branch_last_point_in_full_polydata, this_branchs_first_point_in_full_polydata_point_list};
411  lines->InsertNextCell(2, connection);
412  }
413 
414  }
415 
416  }
417  retval->SetPoints(points);
418  retval->SetLines(lines);
419 
420  return retval;
421 }
422 
423 Eigen::MatrixXd sortMatrix(int rowNumber, Eigen::MatrixXd matrix)
424 {
425  for (int i = 0; i < matrix.cols() - 1; i++) {
426  for (int j = i + 1; j < matrix.cols(); j++) {
427  if (matrix(rowNumber,i) > matrix(rowNumber,j)){
428  matrix.col(i).swap(matrix.col(j));
429  }
430  }
431  }
432 return matrix;
433 }
434 
435 
436 
437 Eigen::MatrixXd eraseCol(int removeIndex, Eigen::MatrixXd positions)
438 {
439  positions.block(0 , removeIndex , positions.rows() , positions.cols() - removeIndex - 1) = positions.rightCols(positions.cols() - removeIndex - 1);
440  positions.conservativeResize(Eigen::NoChange, positions.cols() - 1);
441  return positions;
442 }
443 
444 std::pair<Eigen::MatrixXd::Index, double> dsearch(Eigen::Vector3d p, Eigen::MatrixXd positions)
445 {
446  Eigen::MatrixXd::Index index;
447  // find nearest neighbour
448  (positions.colwise() - p).colwise().squaredNorm().minCoeff(&index);
449  double d = (positions.col(index) - p).norm();
450 
451  return std::make_pair(index , d);
452 }
453 
454 std::pair<std::vector<Eigen::MatrixXd::Index>, Eigen::VectorXd > dsearchn(Eigen::MatrixXd p1, Eigen::MatrixXd p2)
455 {
456  Eigen::MatrixXd::Index index;
457  std::vector<Eigen::MatrixXd::Index> indexVector;
458  Eigen::VectorXd D(p1.cols());
459  for (int i = 0; i < p1.cols(); i++)
460  {
461  // find nearest neighbour
462  (p2.colwise() - p1.col(i)).colwise().squaredNorm().minCoeff(&index);
463  D(i) = (p2.col(index) - p1.col(i)).norm();
464  indexVector.push_back(index);
465  }
466  return std::make_pair(indexVector , D);
467 }
468 
469 std::pair<Eigen::MatrixXd,Eigen::MatrixXd > findConnectedPointsInCT(int startIndex , Eigen::MatrixXd positionsNotUsed)
470 {
471  //Eigen::MatrixXd branchPositions(positionsNotUsed.rows(), positionsNotUsed.cols());
472  Eigen::MatrixXd thisPosition(3,1);
473  std::vector<Eigen::MatrixXd> branchPositionsVector;
474  thisPosition = positionsNotUsed.col(startIndex);
475  branchPositionsVector.push_back(thisPosition); //add first position to branch
476  positionsNotUsed = eraseCol(startIndex,positionsNotUsed);; //remove first position from list of remaining points
477 
478  while (positionsNotUsed.cols() > 0)
479  {
480  std::pair<Eigen::MatrixXd::Index, double > minDistance = dsearch(thisPosition, positionsNotUsed);
481  Eigen::MatrixXd::Index index = minDistance.first;
482  double d = minDistance.second;
483  if (d > 3) // more than 3 mm distance to closest point --> branch is compledted
484  break;
485 
486  thisPosition = positionsNotUsed.col(index);
487  positionsNotUsed = eraseCol(index,positionsNotUsed);
488  //add position to branch
489  branchPositionsVector.push_back(thisPosition);
490 
491  }
492 
493  Eigen::MatrixXd branchPositions(3,branchPositionsVector.size());
494 
495  for (int j = 0; j < branchPositionsVector.size(); j++)
496  {
497  branchPositions.block(0,j,3,1) = branchPositionsVector[j];
498  }
499 
500  return std::make_pair(branchPositions, positionsNotUsed);
501 }
502 
503 
504 }//namespace cx
virtual ~BranchList()
Vector3D ceil(const Vector3D &a)
Definition: cxVector3D.cpp:105
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:47
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:49
Namespace for all CustusX production code.