CustusX  15.8
An IGT application
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
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 
38 
39 
40 namespace cx
41 {
42 
44 {
45 
46 }
47 
48 
50 {
51 // for (int i = 0; i < mBranches.size(); i++)
52 // mBranches[i]->~Branch();
53 }
54 
56 {
57  mBranches.push_back(b);
58 }
59 
61 {
62  for( int i = 0; i < mBranches.size(); i++ )
63  {
64  if (b == mBranches[i])
65  {
66  mBranches.erase(mBranches.begin() + i);
67  return;
68  }
69  }
70 }
71 
73 {
74  mBranches.clear();
75 }
76 
77 std::vector<BranchPtr> BranchList::getBranches()
78 {
79  return mBranches;
80 }
81 
82 void BranchList::selectGenerations(int maxGeneration)
83 {
84  std::vector<int> branchNumbersToBeDeleted;
85  for( int i = 0; i < mBranches.size(); i++ )
86  {
87  int generationCounter = 1;
88  BranchPtr currentBranch = mBranches[i];
89  while (currentBranch->getParentBranch()){
90  generationCounter++;
91  currentBranch = currentBranch->getParentBranch();
92  if (generationCounter > maxGeneration)
93  {
94  branchNumbersToBeDeleted.push_back(i);
95  break;
96  }
97  }
98 
99  }
100 
101  for ( int i = branchNumbersToBeDeleted.size() - 1; i >= 0; i-- )
102  deleteBranch(mBranches[branchNumbersToBeDeleted[i]]);
103 }
104 
105 
107 {
108  for (int i = 0; i < mBranches.size(); i++)
109  {
110  Eigen::MatrixXd positions = mBranches[i]->getPositions();
111  Eigen::MatrixXd diff = positions.rightCols(positions.cols() - 1) - positions.leftCols(positions.cols() - 1);
112  Eigen::MatrixXd orientations(positions.rows(),positions.cols());
113  orientations.leftCols(orientations.cols() - 1) = diff / diff.norm();
114  orientations.rightCols(1) = orientations.col(orientations.cols() - 1);
115  mBranches[i]->setOrientations(orientations);
116  }
117 }
118 
120 {
121  for (int i = 0; i < mBranches.size(); i++)
122  {
123  Eigen::MatrixXd orientations = mBranches[i]->getOrientations();
124  Eigen::MatrixXd newOrientations(orientations.rows(),orientations.cols());
125  int numberOfColumns = orientations.cols();
126  for (int j = 0; j < numberOfColumns; j++)
127  {
128  newOrientations.col(j) = orientations.block(0,std::max(j-2,0),orientations.rows(),std::min(5,numberOfColumns-j)).rowwise().mean(); //smoothing
129  newOrientations.col(j) = newOrientations.col(j) / newOrientations.col(j).norm(); // normalizing
130  }
131  mBranches[i]->setOrientations(newOrientations);
132  }
133 }
134 
135 
136 void BranchList::findBranchesInCenterline(Eigen::MatrixXd positions)
137 {
138  positions = sortMatrix(2,positions);
139  Eigen::MatrixXd positionsNotUsed = positions;
140 
141 // int minIndex;
142  int index;
143  int splitIndex;
144  Eigen::MatrixXd::Index startIndex;
145  BranchPtr branchToSplit;
146  while (positionsNotUsed.cols() > 0)
147  {
148  if (!mBranches.empty())
149  {
150  double minDistance = 1000;
151  for (int i = 0; i < mBranches.size(); i++)
152  {
153  std::pair<std::vector<Eigen::MatrixXd::Index>, Eigen::VectorXd> distances;
154  distances = dsearchn(positionsNotUsed, mBranches[i]->getPositions());
155  double d = distances.second.minCoeff(&index);
156  if (d < minDistance)
157  {
158  minDistance = d;
159  branchToSplit = mBranches[i];
160  startIndex = index;
161  if (minDistance < 2)
162  break;
163  }
164  }
165  std::pair<Eigen::MatrixXd::Index, double> dsearchResult = dsearch(positionsNotUsed.col(startIndex) , branchToSplit->getPositions());
166  splitIndex = dsearchResult.first;
167  }
168  else //if this is the first branch. Select the top position (Trachea).
169  startIndex = positionsNotUsed.cols() - 1;
170 
171  std::pair<Eigen::MatrixXd,Eigen::MatrixXd > connectedPointsResult = findConnectedPointsInCT(startIndex , positionsNotUsed);
172  Eigen::MatrixXd branchPositions = connectedPointsResult.first;
173  positionsNotUsed = connectedPointsResult.second;
174 
175  if (branchPositions.cols() >= 5) //only include brances of length >= 5 points
176  {
177  BranchPtr newBranch = BranchPtr(new Branch());
178  newBranch->setPositions(branchPositions);
179  mBranches.push_back(newBranch);
180 
181  if (mBranches.size() > 1) // do not try to split another branch when the first branch is processed
182  {
183  if ((splitIndex + 1 >= 5) && (branchToSplit->getPositions().cols() - splitIndex - 1 >= 5))
184  //do not split branch if the new branch is close to the edge of the branch
185  //if the new branch is not close to one of the edges of the
186  //connected existing branch: Split the existing branch
187  {
188  BranchPtr newBranchFromSplit = BranchPtr(new Branch());
189  Eigen::MatrixXd branchToSplitPositions = branchToSplit->getPositions();
190  newBranchFromSplit->setPositions(branchToSplitPositions.rightCols(branchToSplitPositions.cols() - splitIndex - 1));
191  branchToSplit->setPositions(branchToSplitPositions.leftCols(splitIndex + 1));
192  mBranches.push_back(newBranchFromSplit);
193  newBranchFromSplit->setParentBranch(branchToSplit);
194  newBranch->setParentBranch(branchToSplit);
195  newBranchFromSplit->setChildBranches(branchToSplit->getChildBranches());
196  branchVector branchToSplitChildren = branchToSplit->getChildBranches();
197  for (int i = 0; i < branchToSplitChildren.size(); i++)
198  branchToSplitChildren[i]->setParentBranch(newBranchFromSplit);
199  branchToSplit->deleteChildBranches();
200  branchToSplit->addChildBranch(newBranchFromSplit);
201  branchToSplit->addChildBranch(newBranch);
202  }
203  else if (splitIndex + 1 < 5)
204  // If the new branch is close to the start of the existing
205  // branch: Connect it to the same position start as the
206  // existing branch
207  {
208  newBranch->setParentBranch(branchToSplit->getParentBranch());
209  branchToSplit->getParentBranch()->addChildBranch(newBranch);
210  }
211  else if (branchToSplit->getPositions().cols() - splitIndex - 1 < 5)
212  // If the new branch is close to the end of the existing
213  // branch: Connect it to the end of the existing branch
214  {
215  newBranch->setParentBranch(branchToSplit);
216  branchToSplit->addChildBranch(newBranch);
217  }
218 
219  }
220 
221  }
222  }
223 }
224 
225 
226 BranchListPtr BranchList::removePositionsForLocalRegistration(Eigen::MatrixXd trackingPositions, double maxDistance)
227 {
228  BranchListPtr retval = BranchListPtr(new BranchList());
229  BranchPtr b;
230  for (int i = 0; i < mBranches.size(); i++)
231  {
232  b = BranchPtr(new Branch());
233  b->setPositions(mBranches[i]->getPositions());
234  b->setOrientations(mBranches[i]->getOrientations());
235  retval->addBranch(b);
236  }
237 
238  std::vector<BranchPtr> branches = retval->getBranches();
239  Eigen::MatrixXd positions;
240  Eigen::MatrixXd orientations;
241  for (int i = 0; i < branches.size(); i++)
242  {
243  positions = branches[i]->getPositions();
244  orientations = branches[i]->getOrientations();
245  std::pair<std::vector<Eigen::MatrixXd::Index>, Eigen::VectorXd> distanceData;
246  distanceData = dsearchn(positions, trackingPositions);
247  Eigen::VectorXd distance = distanceData.second;
248  for (int j = positions.cols() - 1; j <= 0; j--)
249  {
250  if (distance(j) > maxDistance)
251  {
252  positions = eraseCol(j, positions);
253  orientations = eraseCol(j, orientations);
254  }
255  }
256  branches[i]->setPositions(positions);
257  branches[i]->setOrientations(orientations);
258  }
259  return retval;
260 }
261 
262 Eigen::MatrixXd sortMatrix(int rowNumber, Eigen::MatrixXd matrix)
263 {
264  for (int i = 0; i < matrix.cols() - 1; i++) {
265  for (int j = i + 1; j < matrix.cols(); j++) {
266  if (matrix(rowNumber,i) > matrix(rowNumber,j)){
267  matrix.col(i).swap(matrix.col(j));
268  }
269  }
270  }
271 return matrix;
272 }
273 
274 
275 
276 Eigen::MatrixXd eraseCol(int removeIndex, Eigen::MatrixXd positions)
277 {
278  positions.block(0 , removeIndex , positions.rows() , positions.cols() - removeIndex - 1) = positions.rightCols(positions.cols() - removeIndex - 1);
279  positions.conservativeResize(Eigen::NoChange, positions.cols() - 1);
280  return positions;
281 }
282 
283 std::pair<Eigen::MatrixXd::Index, double> dsearch(Eigen::Vector3d p, Eigen::MatrixXd positions)
284 {
285  Eigen::MatrixXd::Index index;
286  // find nearest neighbour
287  (positions.colwise() - p).colwise().squaredNorm().minCoeff(&index);
288  double d = (positions.col(index) - p).norm();
289 
290  return std::make_pair(index , d);
291 }
292 
293 std::pair<std::vector<Eigen::MatrixXd::Index>, Eigen::VectorXd > dsearchn(Eigen::MatrixXd p1, Eigen::MatrixXd p2)
294 {
295  Eigen::MatrixXd::Index index;
296  std::vector<Eigen::MatrixXd::Index> indexVector;
297  Eigen::VectorXd D(p1.cols());
298  for (int i = 0; i < p1.cols(); i++)
299  {
300  // find nearest neighbour
301  (p2.colwise() - p1.col(i)).colwise().squaredNorm().minCoeff(&index);
302  D(i) = (p2.col(index) - p1.col(i)).norm();
303  indexVector.push_back(index);
304  }
305  return std::make_pair(indexVector , D);
306 }
307 
308 std::pair<Eigen::MatrixXd,Eigen::MatrixXd > findConnectedPointsInCT(int startIndex , Eigen::MatrixXd positionsNotUsed)
309 {
310  //Eigen::MatrixXd branchPositions(positionsNotUsed.rows(), positionsNotUsed.cols());
311  Eigen::MatrixXd thisPosition(3,1);
312  std::vector<Eigen::MatrixXd> branchPositionsVector;
313  thisPosition = positionsNotUsed.col(startIndex);
314  branchPositionsVector.push_back(thisPosition); //add first position to branch
315  positionsNotUsed = eraseCol(startIndex,positionsNotUsed);; //remove first position from list of remaining points
316 
317  while (positionsNotUsed.cols() > 0)
318  {
319  std::pair<Eigen::MatrixXd::Index, double > minDistance = dsearch(thisPosition, positionsNotUsed);
320  Eigen::MatrixXd::Index index = minDistance.first;
321  double d = minDistance.second;
322  if (d > 3) // more than 3 mm distance to closest point --> branch is compledted
323  break;
324 
325  thisPosition = positionsNotUsed.col(index);
326  positionsNotUsed = eraseCol(index,positionsNotUsed);
327  //add position to branch
328  branchPositionsVector.push_back(thisPosition);
329 
330  }
331 
332  Eigen::MatrixXd branchPositions(3,branchPositionsVector.size());
333 
334  for (int j = 0; j < branchPositionsVector.size(); j++)
335  {
336  branchPositions.block(0,j,3,1) = branchPositionsVector[j];
337  }
338 
339  return std::make_pair(branchPositions, positionsNotUsed);
340 }
341 
342 
343 }//namespace cx
virtual ~BranchList()
std::pair< Eigen::MatrixXd, Eigen::MatrixXd > findConnectedPointsInCT(int startIndex, Eigen::MatrixXd positionsNotUsed)
boost::shared_ptr< class BranchList > BranchListPtr
BranchListPtr removePositionsForLocalRegistration(Eigen::MatrixXd trackingPositions, double maxDistance)
void findBranchesInCenterline(Eigen::MatrixXd positions)
void addBranch(BranchPtr b)
void deleteAllBranches()
boost::shared_ptr< class Branch > BranchPtr
std::pair< Eigen::MatrixXd::Index, double > dsearch(Eigen::Vector3d p, Eigen::MatrixXd positions)
void calculateOrientations()
std::vector< BranchPtr > getBranches()
void deleteBranch(BranchPtr b)
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