12 #include <vtkPointData.h>
13 #include <vtkPolyData.h>
14 #include <vtkPolyDataWriter.h>
15 #include <vtkCellArray.h>
16 #include <vtkMatrix4x4.h>
17 #include <vtkLinearTransform.h>
18 #include <vtkLandmarkTransform.h>
22 #include <boost/math/special_functions/fpclassify.hpp>
29 mCenterlineProcessed(false),
41 if(Tnavigation.empty())
42 return TnavigationIncluded;
43 TnavigationIncluded.push_back(Tnavigation[0]);
44 int numberOfIncluded = 0;
45 size_t numberOfPos = Tnavigation.size();
46 for (
size_t index = 1; index < numberOfPos; index++)
48 double xDistance = (TnavigationIncluded[numberOfIncluded](0,3) - Tnavigation[index](0,3) );
49 double xDistanceSquared = xDistance * xDistance;
50 double yDistance = (TnavigationIncluded[numberOfIncluded](1,3) - Tnavigation[index](1,3) );
51 double yDistanceSquared = yDistance * yDistance;
52 double zDistance = (TnavigationIncluded[numberOfIncluded](2,3) - Tnavigation[index](2,3) );
53 double zDistanceSquared = zDistance * zDistance;
54 double distanceToLastIncluded = sqrt (xDistanceSquared + yDistanceSquared + zDistanceSquared);
56 if (distanceToLastIncluded > 1)
59 TnavigationIncluded.push_back(Tnavigation[index]);
63 return TnavigationIncluded;
70 for (
int i = 0; i < v.size() - 1; i++) {
71 for (
int j = i + 1; j < v.size(); j++) {
73 std::swap(v(i) , v(j));
83 Eigen::VectorXd medianValues(matrix.rows());
84 for (
int i = 0; i < matrix.rows(); i++) {
85 Eigen::MatrixXd sortedMatrix =
sortMatrix(i, matrix);
86 if (sortedMatrix.cols()%2==1) {
87 medianValues(i) = (sortedMatrix(i,(sortedMatrix.cols()+1)/2) );
90 medianValues(i) = ( sortedMatrix(i,sortedMatrix.cols()/2) + sortedMatrix(i,sortedMatrix.cols()/2 - 1) ) / 2;
99 Eigen::VectorXd DAngleSorted =
sortVector(DAngle);
100 int numberOfPositionsIncluded = floor((
double)(DAngle.size() * percentage/100));
101 Eigen::MatrixXd trackingPositionsIncluded(3 , numberOfPositionsIncluded );
102 Eigen::MatrixXd nearestCTPositionsIncluded(3 , numberOfPositionsIncluded );
103 float maxDAngle = DAngleSorted( numberOfPositionsIncluded );
105 for (
int i = 0; i < DAngle.size(); i++)
107 if ((DAngle(i) <= maxDAngle) && (counter < numberOfPositionsIncluded))
109 trackingPositionsIncluded.col(counter) = trackingPositions.col(i);
110 nearestCTPositionsIncluded.col(counter) = nearestCTPositions.col(i);
115 return std::make_pair(trackingPositionsIncluded , nearestCTPositionsIncluded);
123 for (
unsigned i=0; i<positions.cols(); ++i)
125 retval->InsertNextPoint(positions(0,i), positions(1,i), positions(2,i));
138 if (source->GetNumberOfPoints() < 3)
140 std::cout <<
"Warning in performLandmarkRegistration: Need >3 positions, returning identity matrix." << std::endl;
141 return Eigen::Matrix4d::Identity();
145 landmarktransform->SetSourceLandmarks(source);
146 landmarktransform->SetTargetLandmarks(target);
147 landmarktransform->SetModeToRigidBody();
152 vtkMatrix4x4* temp = landmarktransform->GetMatrix();
153 Eigen::Matrix4d tar_M_src;
154 for (
int i = 0; i < 4; i++)
156 for (
int j = 0; j < 4; j++)
158 tar_M_src(i,j) = temp->GetElement(i,j);
162 if ( boost::math::isnan(tar_M_src.sum()) )
164 std::cout <<
"Warning in performLandmarkRegistration: Returning identity matrix due to nan." << std::endl;
165 return Eigen::Matrix4d::Identity();
174 std::vector<Eigen::MatrixXd::Index>
dsearch2n(Eigen::MatrixXd pos1, Eigen::MatrixXd pos2, Eigen::MatrixXd ori1, Eigen::MatrixXd ori2)
176 Eigen::MatrixXd::Index index;
177 std::vector<Eigen::MatrixXd::Index> indexVector;
179 for (
int i = 0; i < pos1.cols(); i++)
181 Eigen::VectorXd D(pos2.cols());
182 Eigen::VectorXd P(pos2.cols());
183 Eigen::VectorXd O(pos2.cols());
184 Eigen::VectorXd R(pos2.cols());
186 for (
int j = 0; j < pos2.cols(); j++)
188 float p0 = ( pos2(0,j) - pos1(0,i) );
189 float p1 = ( pos2(1,j) - pos1(1,i) );
190 float p2 = ( pos2(2,j) - pos1(2,i) );
191 float o0 = fmod( ori2(0,j) - ori1(0,i) , 2 );
192 float o1 = fmod( ori2(1,j) - ori1(1,i) , 2 );
193 float o2 = fmod( ori2(2,j) - ori1(2,i) , 2 );
195 P(j) = sqrt( p0*p0 + p1*p1 + p2*p2 );
196 O(j) = sqrt( o0*o0 + o1*o1 + o2*o2 );
198 if (boost::math::isnan( O(j) ))
201 if ( (o0>2) || (o1>2) || (o2>2) )
202 std::cout <<
"Warning in bronchoscopyRegistration.cpp: Error on oriantation calculation in dsearch2n. Orientation > 2." << std::endl;
207 float alpha = sqrt( R.mean() );
208 if (boost::math::isnan( alpha ))
213 indexVector.push_back(index);
218 std::pair<Eigen::MatrixXd , Eigen::MatrixXd>
RemoveInvalidData(Eigen::MatrixXd positionData, Eigen::MatrixXd orientationData)
220 std::vector<int> indicesToBeDeleted;
222 for (
int i = 0; i < fmin(positionData.cols(), orientationData.cols()); i++)
224 if ( boost::math::isinf( positionData.block(0 , i , 3 , 1).sum() ) || boost::math::isinf( orientationData.block(0 , i , 3 , 1).sum() ) )
225 indicesToBeDeleted.push_back(i);
226 else if (boost::math::isnan( positionData.block(0 , i , 3 , 1).sum() ) || boost::math::isnan( orientationData.block(0 , i , 3 , 1).sum() ))
227 indicesToBeDeleted.push_back(i);
228 else if ( (positionData.block(0 , i , 1 , 1).sum() == 0 && positionData.block(1 , i , 1 , 1).sum() == 0 && positionData.block(2 , i , 1 , 1).sum() == 0) ||
229 (orientationData.block(0 , i , 1 , 1).sum() == 0 && orientationData.block(1 , i , 1 , 1).sum() == 0 && orientationData.block(2 , i , 1 , 1).sum() == 0))
230 indicesToBeDeleted.push_back(i);
233 for (
int i = indicesToBeDeleted.size() - 1; i >= 0; i-- )
235 std::cout <<
"Warning in bronchoscopyRegistration: Removed corrupted data: " << positionData.block(0 , indicesToBeDeleted[i] , 3 , 1) <<
" " << orientationData.block(0 , indicesToBeDeleted[i] , 3 , 1) << std::endl;
236 positionData =
eraseCol(indicesToBeDeleted[i],positionData);
237 orientationData =
eraseCol(indicesToBeDeleted[i],orientationData);
239 return std::make_pair(positionData , orientationData);
244 Eigen::Vector3d position;
245 Eigen::Vector3d orientation;
246 std::vector<int> indicesToBeDeleted;
248 for (
int i = 0; i < T_vector.size(); i++)
250 position = T_vector[i].topRightCorner(3 , 1);
251 orientation = T_vector[i].block(0 , 2 , 3 , 1);
252 if ( boost::math::isinf( position.sum() ) || boost::math::isinf( orientation.sum() ) )
253 indicesToBeDeleted.push_back(i);
254 else if (boost::math::isnan( position.sum() ) || boost::math::isnan( orientation.sum() ))
255 indicesToBeDeleted.push_back(i);
256 else if ( (position[0] == 0 && position[1] == 0 && position[2] == 0) ||
257 (orientation[0] == 0 && orientation[1] == 0 && orientation[2] == 0) )
258 indicesToBeDeleted.push_back(i);
261 for (
int i = indicesToBeDeleted.size() - 1; i >= 0; i-- )
263 std::cout <<
"Warning in bronchoscopyRegistration: Removed corrupted data: " << T_vector[i].topRightCorner(3 , 1) <<
" " << T_vector[i].block(0 , 2 , 3 , 1) << std::endl;
264 T_vector.erase(T_vector.begin() + indicesToBeDeleted[i]);
271 Eigen::Matrix4d registrationMatrix;
272 Eigen::MatrixXd CTPositions;
273 Eigen::MatrixXd CTOrientations;
274 Eigen::MatrixXd trackingPositions(3 , Tnavigation.size());
275 Eigen::MatrixXd trackingOrientations(3, Tnavigation.size());
277 std::vector<BranchPtr>
branchVector = branches->getBranches();
281 if (trackingPositions.cols() < 10)
283 std::cout <<
"Warning: Too few positions in tracking data to perform registration." << std::endl;
284 return Eigen::Matrix4d::Identity();
289 Eigen::MatrixXd CTPositionsNew(CTPositions.rows() , CTPositions.cols() +
branchVector[i]->getPositions().cols());
290 Eigen::MatrixXd CTOrientationsNew(CTOrientations.rows() , CTOrientations.cols() +
branchVector[i]->getOrientations().cols());
291 CTPositionsNew.leftCols(CTPositions.cols()) = CTPositions;
293 CTOrientationsNew.leftCols(CTOrientations.cols()) = CTOrientations;
295 CTPositions.swap(CTPositionsNew);
296 CTOrientations.swap(CTOrientationsNew);
299 if (CTPositions.cols() < 10)
301 std::cout <<
"Warning: Too few positions in centerline to perform registration." << std::endl;
302 return Eigen::Matrix4d::Identity();
305 std::pair<Eigen::MatrixXd , Eigen::MatrixXd> qualityCheckedData =
RemoveInvalidData(CTPositions, CTOrientations);
306 CTPositions = qualityCheckedData.first;
307 CTOrientations = qualityCheckedData.second;
309 for (
int i = 0; i < Tnavigation.size(); i++)
310 Tnavigation[i] = old_rMpr * Tnavigation[i];
314 for (
int i = 0; i < Tnavigation.size(); i++)
316 trackingPositions.block(0 , i , 3 , 1) = Tnavigation[i].topRightCorner(3 , 1);
317 trackingOrientations.block(0 , i , 3 , 1) = Tnavigation[i].block(0 , 2 , 3 , 1);
321 Eigen::MatrixXd::Index maxIndex;
322 trackingPositions.row(2).maxCoeff( &maxIndex );
323 Eigen::Vector3d translation = CTPositions.col(0) - trackingPositions.col(maxIndex);
328 registrationMatrix << 1, 0, 0, translation(0),
329 0, 1, 0, translation(1),
330 0, 0, 1, translation(2),
333 for (
int i = 0; i < Tnavigation.size(); i++)
335 Tnavigation[i] = registrationMatrix * Tnavigation[i];
338 int iterationNumber = 0;
339 int maxIterations = 50;
340 while ( translation.array().abs().sum() > 1 && iterationNumber < maxIterations)
342 for (
int i = 0; i < Tnavigation.size(); i++)
344 trackingPositions.block(0 , i , 3 , 1) = Tnavigation[i].topRightCorner(3 , 1);
345 trackingOrientations.block(0 , i , 3 , 1) = Tnavigation[i].block(0 , 2 , 3 , 1);
350 std::vector<Eigen::MatrixXd::Index> indexVector =
dsearch2n( trackingPositions, CTPositions, trackingOrientations, CTOrientations );
351 Eigen::MatrixXd nearestCTPositions(3,indexVector.size());
352 Eigen::MatrixXd nearestCTOrientations(3,indexVector.size());
353 Eigen::VectorXd DAngle(indexVector.size());
354 for (
int i = 0; i < indexVector.size(); i++)
356 nearestCTPositions.col(i) = CTPositions.col(indexVector[i]);
357 nearestCTOrientations.col(i) = CTOrientations.col(indexVector[i]);
358 float o0 = fmod( trackingOrientations(0,i) - nearestCTOrientations(0,i) , 2 );
359 float o1 = fmod( trackingOrientations(1,i) - nearestCTOrientations(1,i) , 2 );
360 float o2 = fmod( trackingOrientations(2,i) - nearestCTOrientations(2,i) , 2 );
361 DAngle(i) = sqrt(o0*o0+o1*o1+o2*o2);
370 registrationMatrix = tempMatrix * registrationMatrix;
372 for (
int i = 0; i < Tnavigation.size(); i++)
374 Tnavigation[i] = tempMatrix * Tnavigation[i];
377 translation << tempMatrix(0,3), tempMatrix(1,3), tempMatrix(2,3);
379 std::cout <<
"Iteration nr " << iterationNumber <<
" translation: " << translation.array().abs().sum() << std::endl;
382 if (translation.array().abs().sum() > 1)
383 std::cout <<
"Warning: Registration did not converge within " << maxIterations <<
" iterations, which is max number of iterations." << std::endl;
385 return registrationMatrix;
390 Eigen::Matrix4d registrationMatrix;
391 Eigen::MatrixXd CTPositionsFixed;
392 Eigen::MatrixXd CTOrientationsFixed;
393 Eigen::MatrixXd CTPositionsMoving;
394 Eigen::MatrixXd CTOrientationsMoving;
396 std::vector<BranchPtr> branchVectorFixed = branchesFixed->getBranches();
397 CTPositionsFixed = branchVectorFixed[0]->getPositions();
398 CTOrientationsFixed = branchVectorFixed[0]->getOrientations();
400 std::vector<BranchPtr> branchVectorMoving = branchesMoving->getBranches();
401 CTPositionsMoving = branchVectorMoving[0]->getPositions();
402 CTOrientationsMoving = branchVectorMoving[0]->getOrientations();
404 for (
int i = 1; i < branchVectorFixed.size(); i++)
406 Eigen::MatrixXd CTPositionsFixedNew(CTPositionsFixed.rows() , CTPositionsFixed.cols() + branchVectorFixed[i]->getPositions().cols());
407 Eigen::MatrixXd CTOrientationsFixedNew(CTOrientationsFixed.rows() , CTOrientationsFixed.cols() + branchVectorFixed[i]->getOrientations().cols());
408 CTPositionsFixedNew.leftCols(CTPositionsFixed.cols()) = CTPositionsFixed;
409 CTPositionsFixedNew.rightCols(branchVectorFixed[i]->getPositions().cols()) = branchVectorFixed[i]->getPositions();
410 CTOrientationsFixedNew.leftCols(CTOrientationsFixed.cols()) = CTOrientationsFixed;
411 CTOrientationsFixedNew.rightCols(branchVectorFixed[i]->getOrientations().cols()) = branchVectorFixed[i]->getOrientations();
412 CTPositionsFixed.swap(CTPositionsFixedNew);
413 CTOrientationsFixed.swap(CTOrientationsFixedNew);
416 for (
int i = 1; i < branchVectorMoving.size(); i++)
418 Eigen::MatrixXd CTPositionsMovingNew(CTPositionsMoving.rows() , CTPositionsMoving.cols() + branchVectorMoving[i]->getPositions().cols());
419 Eigen::MatrixXd CTOrientationsMovingNew(CTOrientationsMoving.rows() , CTOrientationsMoving.cols() + branchVectorMoving[i]->getOrientations().cols());
420 CTPositionsMovingNew.leftCols(CTPositionsMoving.cols()) = CTPositionsMoving;
421 CTPositionsMovingNew.rightCols(branchVectorMoving[i]->getPositions().cols()) = branchVectorMoving[i]->getPositions();
422 CTOrientationsMovingNew.leftCols(CTOrientationsMoving.cols()) = CTOrientationsMoving;
423 CTOrientationsMovingNew.rightCols(branchVectorMoving[i]->getOrientations().cols()) = branchVectorMoving[i]->getOrientations();
424 CTPositionsMoving.swap(CTPositionsMovingNew);
425 CTOrientationsMoving.swap(CTOrientationsMovingNew);
428 if (CTPositionsFixed.cols() < 10 || CTPositionsMoving.cols() < 10)
430 CX_LOG_WARNING() <<
"Too few positions in centerline to perform registration.";
431 return Eigen::Matrix4d::Identity();
434 std::pair<Eigen::MatrixXd , Eigen::MatrixXd> qualityCheckedDataFixed =
RemoveInvalidData(CTPositionsFixed, CTOrientationsFixed);
435 CTPositionsFixed = qualityCheckedDataFixed.first;
436 CTOrientationsFixed = qualityCheckedDataFixed.second;
438 std::pair<Eigen::MatrixXd , Eigen::MatrixXd> qualityCheckedDataMoving =
RemoveInvalidData(CTPositionsMoving, CTOrientationsMoving);
439 CTPositionsMoving = qualityCheckedDataMoving.first;
440 CTOrientationsMoving = qualityCheckedDataMoving.second;
445 registrationMatrix << 1, 0, 0, translation(0),
446 0, 1, 0, translation(1),
447 0, 0, 1, translation(2),
450 for (
int i = 0; i < CTPositionsMoving.cols(); i++)
452 CTPositionsMoving.col(i) = CTPositionsMoving.col(i) + translation;
455 int iterationNumber = 0;
456 int maxIterations = 200;
457 while ( translation.array().abs().sum() > 0.5 && iterationNumber < maxIterations)
461 std::vector<Eigen::MatrixXd::Index> indexVector =
dsearch2n( CTPositionsMoving, CTPositionsFixed, CTOrientationsMoving, CTOrientationsFixed );
462 Eigen::MatrixXd nearestCTPositions(3,indexVector.size());
463 Eigen::MatrixXd nearestCTOrientations(3,indexVector.size());
464 Eigen::VectorXd DAngle(indexVector.size());
465 for (
int i = 0; i < indexVector.size(); i++)
467 nearestCTPositions.col(i) = CTPositionsFixed.col(indexVector[i]);
468 nearestCTOrientations.col(i) = CTOrientationsFixed.col(indexVector[i]);
469 float o0 = fmod( CTOrientationsMoving(0,i) - nearestCTOrientations(0,i) , 2 );
470 float o1 = fmod( CTOrientationsMoving(1,i) - nearestCTOrientations(1,i) , 2 );
471 float o2 = fmod( CTOrientationsMoving(2,i) - nearestCTOrientations(2,i) , 2 );
472 DAngle(i) = sqrt(o0*o0+o1*o1+o2*o2);
481 registrationMatrix = tempMatrix * registrationMatrix;
483 for (
int i = 0; i < CTPositionsMoving.cols(); i++)
485 CTPositionsMoving.col(i) = tempMatrix.topLeftCorner(3,3) * CTPositionsMoving.col(i) + tempMatrix.topRightCorner(3,1);
488 translation << tempMatrix(0,3), tempMatrix(1,3), tempMatrix(2,3);
492 if (translation.array().abs().sum() > 1)
493 CX_LOG_WARNING() <<
"Registration did not converge within " << maxIterations <<
" iterations, which is max number of iterations.";
495 return registrationMatrix;
501 mBranchListPtr->deleteAllBranches();
504 mBranchListPtr->findBranchesInCenterline(CLpoints);
505 if (numberOfGenerations != 0)
507 mBranchListPtr->selectGenerations(numberOfGenerations);
510 mBranchListPtr->smoothBranchPositions(10);
511 mBranchListPtr->smoothOrientations();
513 double minPointDistance = 0.5;
514 mBranchListPtr->excludeClosePositionsInCTCenterline(minPointDistance);
516 vtkPolyDataPtr retval = mBranchListPtr->createVtkPolyDataFromBranches();
518 std::cout <<
"Number of branches in CT centerline: " << mBranchListPtr->getBranches().size() << std::endl;
520 mCenterlineProcessed =
true;
531 mBranchListPtr = branchList;
533 if (numberOfGenerations != 0)
535 mBranchListPtr->selectGenerations(numberOfGenerations);
538 mCenterlineProcessed =
true;
543 return mBranchListPtr;
552 branchListPtr->findBranchesInCenterline(CLpoints);
554 if (numberOfGenerations != 0)
556 branchListPtr->selectGenerations(numberOfGenerations);
559 branchListPtr->smoothBranchPositions(10);
560 branchListPtr->smoothOrientations();
562 return branchListPtr;
567 if(trackingData_prMt.empty())
568 reportError(
"BronchoscopyRegistration::runBronchoscopyRegistration(): No tracking data");
571 for(TimedTransformMap::iterator iter=trackingData_prMt.begin(); iter!=trackingData_prMt.end(); ++iter)
573 Tnavigation.push_back(iter->second. matrix());
578 Eigen::Matrix4d regMatrix;
579 if (maxDistanceForLocalRegistration != 0)
581 Eigen::MatrixXd trackingPositions_temp(3 , Tnavigation.size());
582 M4Vector Tnavigation_temp = Tnavigation;
583 for (
int i = 0; i < Tnavigation.size(); i++)
585 Tnavigation_temp[i] = old_rMpr * Tnavigation[i];
586 trackingPositions_temp.block(0 , i , 3 , 1) = Tnavigation_temp[i].topRightCorner(3 , 1);
588 BranchListPtr tempPtr = mBranchListPtr->removePositionsForLocalRegistration(trackingPositions_temp, maxDistanceForLocalRegistration);
595 if ( boost::math::isnan(regMatrix.sum()) )
597 std::cout <<
"Warning: Registration matrix contains 'nan' number, using identity matrix." << std::endl;
598 return Eigen::Matrix4d::Identity();
601 if ( boost::math::isinf(regMatrix.sum()) )
603 std::cout <<
"Warning: Registration matrix contains 'inf' number, using identity matrix." << std::endl;
604 return Eigen::Matrix4d::Identity();
607 std::cout <<
"prMt from bronchoscopyRegistration: " << std::endl;
608 for (
int i = 0; i < 4; i++)
609 std::cout << regMatrix.row(i) << std::endl;
617 int numberOfGenerations = 4;
618 Eigen::Matrix4d regMatrix;
628 if ( boost::math::isnan(regMatrix.sum()) )
630 CX_LOG_WARNING() <<
"Registration matrix contains 'nan' number, using identity matrix.";
631 return Eigen::Matrix4d::Identity();
634 if ( boost::math::isinf(regMatrix.sum()) )
636 CX_LOG_WARNING() <<
"Registration matrix contains 'inf' number, using identity matrix.";
637 return Eigen::Matrix4d::Identity();
645 return mCenterlineProcessed;
671 vtkIdType N = linesPolyData->GetNumberOfPoints();
672 Eigen::MatrixXd CLpoints(3,N);
674 for(vtkIdType i = 0; i < N; i++)
677 linesPolyData->GetPoint(i,p);
678 Eigen::Vector3d position;
679 position(0) = p[0]; position(1) = p[1]; position(2) = p[2];
680 CLpoints.block(0 , i , 3 , 1) = rMd.coord(position);