CustusX  15.8
An IGT application
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
SeansVesselReg.cxx
Go to the documentation of this file.
1 #include "SeansVesselReg.hxx"
2 #include "HackTPSTransform.hxx"
3 
4 #include <iostream>
5 #include <time.h>
6 #include <fstream>
7 
8 #include <QFileInfo>
9 
10 #include "cxImage.h"
11 #include "cxTypeConversions.h"
13 #include "cxReporter.h"
14 #include <boost/math/special_functions/fpclassify.hpp>
15 
16 #include "vtkClipPolyData.h"
17 #include "vtkPlanes.h"
18 #include "cxLogger.h"
19 #include "vtkPoints.h"
20 #include "vtkPolyData.h"
21 #include "vtkCellArray.h"
22 #include "vtkCellLocator.h"
23 #include "vtkMINCImageReader.h"
24 #include "vtkTransform.h"
25 #include "vtkImageData.h"
26 #include "vtkGeneralTransform.h"
27 #include "vtkMath.h"
28 #include "vtkSortDataArray.h"
29 #include "vtkMaskPoints.h"
30 #include "vtkPointData.h"
31 #include "vtkLandmarkTransform.h"
32 #include "vtkFloatArray.h"
33 #include "cxMesh.h"
34 
35 namespace cx
36 {
37 
38 SeansVesselReg::SeansVesselReg()// : mInvertedTransform(false)
39 {
40  mt_auto_lts = true;
41  mt_ltsRatio = 80;
43  mt_lambda = 0;
44  mt_sigma = 1.0;
45  mt_doOnlyLinear = false;
46  mt_sampleRatio = 1;
49  mt_verbose = false;
50  mt_maximumDurationSeconds = 1E6; // Random high number
51 }
52 
54 {
55 }
56 
62 bool SeansVesselReg::execute(DataPtr source, DataPtr target, QString logPath)
63 {
64  if (mt_verbose)
65  {
66  reporter()->sendDebug("SOURCE: " + source->getUid());
67  reporter()->sendDebug("TARGET: " + target->getUid());
68 
69  std::cout << "stop Threshold:" << mt_distanceDeltaStopThreshold << endl;
70  std::cout << "sigma:" << mt_sigma << endl;
71  std::cout << "lts Ratio:" << mt_ltsRatio << endl;
72  std::cout << "linear flag:" << mt_doOnlyLinear << endl;
73  std::cout << "sample flag:" << mt_sampleRatio << endl;
74  std::cout << "single Point Threshold:" << mt_singlePointThreshold << endl;
75  }
76  QTime start = QTime::currentTime();
77 
78  // create a context containing all input, temporaries and output.
79  ContextPtr context = this->createContext(source, target);
80 
81  if (!context)
82  return false;
83 
84  if (mt_auto_lts)
85  {
86  context = this->linearRefineAllLTS(context);
87  report(QString("Auto LTS: Found best match using %1\%.").arg(context->mLtsRatio));
88  }
89  else
90  {
91  this->linearRefine(context);
92  }
93 
94  // add a nonlinear step to the end:
95  if (!mt_doOnlyLinear)
96  {
97  this->performOneRegistration(context, false);
98  }
99 
100  printOutResults(logPath + "/Vessel_Based_Registration_", context->mConcatenation);
101 
102  if (mt_verbose)
103  std::cout << QString("\n\nV2V Execution time: %1s").arg(start.secsTo(QTime::currentTime())) << endl;
104 
105  mLastRun = context;
106 // mLinearTransformResult = this->getLinearTransform(context->mConcatenation);
107 
108  return true;
109 }
110 
116 {
117  // all lts values to search along:
118  std::vector<int> lts;
119  lts.push_back(40);
120  lts.push_back(50);
121  lts.push_back(60);
122  lts.push_back(70);
123  lts.push_back(75);
124  lts.push_back(80);
125  lts.push_back(85);
126  lts.push_back(90);
127  lts.push_back(95);
128  lts.push_back(100);
129 
130  std::vector<ContextPtr> paths;
131 
132  // iterate along all paths
133  for (unsigned i=0; i<lts.size(); ++i)
134  {
135  ContextPtr current = this->splitContext(seed);
136  paths.push_back(current);
137  current->mLtsRatio = lts[i];
138  this->linearRefine(current);
139  if (mt_verbose)
140  std::cout << QString("LTS=%1, metric=%2").arg(current->mLtsRatio).arg(current->mMetric) << std::endl;
141  }
142 
143  // search for best path
144  int bestPath = 0;
145  for (unsigned i=0; i<paths.size(); ++i)
146  {
147  if (paths[i]->mMetric < paths[bestPath]->mMetric)
148  bestPath = i;
149  }
150 
151  // return value
152  return paths[bestPath];
153 }
154 
159 {
160  // Perform registrations iteratively until convergence is reached:
161  double previousMetric = 1E6;
162  QDateTime t0 = QDateTime::currentDateTime();
163  for (int iteration = 1; iteration < mt_maximumNumberOfIterations && (t0.msecsTo(QDateTime::currentDateTime()) < mt_maximumDurationSeconds*1000); ++iteration)
164  {
165  this->performOneRegistration(context, true);
166  double difference = context->mMetric - previousMetric;
167 
168  if (mt_verbose)
169  {
170 // std::cout << myNumberOfIterations << " ";
171 // std::cout.flush();
172  std::cout << QString("iteration\t%1\trms:\t%2").arg(iteration).arg(context->mMetric) << std::endl;
173  }
174 
175  // Check for convergence
176  if (fabs(difference) < mt_distanceDeltaStopThreshold)
177  break;
178 
179  previousMetric = context->mMetric;
180  }
181 }
182 
187 {
188  ContextPtr retval = ContextPtr(new Context);
189 
190  retval->mLtsRatio = context->mLtsRatio;
191  retval->mInvertedTransform = context->mInvertedTransform;
192 
193  // constant data: shallow copy
194  retval->mTargetPointLocator = context->mTargetPointLocator;
195  retval->mTargetPoints = context->mTargetPoints;
196 
197  // will be modified: deep copy
198  retval->mSourcePoints = vtkPointsPtr::New();
199  retval->mSourcePoints->DeepCopy(context->mSourcePoints);
200 
201  // return value: initialize only
202  retval->mConcatenation = vtkGeneralTransformPtr::New();;
203 // retval->mTransform = context->mTransform;
204  retval->mMetric = 0;
205 
206  return retval;
207 }
208 
213 {
214  vtkPolyDataPtr targetPolyData = this->convertToPolyData(target);
215  vtkPolyDataPtr inputSourcePolyData = this->convertToPolyData(source);
216 // targetPolyData->Update();
217 // inputSourcePolyData->Update();
218  //Make sure we have stuff to work with
219  if (!inputSourcePolyData->GetNumberOfPoints() || !targetPolyData->GetNumberOfPoints())
220  {
221  std::cerr << "Can't execute with empty source or target data" << std::endl;
222  return ContextPtr();
223  }
224 
225  double margin = 40;
226  vtkPolyDataPtr sourcePolyData = this->crop(inputSourcePolyData, targetPolyData, margin);
227 
228  //Make sure we have stuff to work with
229  if (!sourcePolyData->GetNumberOfPoints() || !targetPolyData->GetNumberOfPoints())
230  {
231  std::cerr << "Can't execute with empty source or target data" << std::endl;
232  return ContextPtr();
233  }
234 
235  ContextPtr context = ContextPtr(new Context);
236 
237  context->mConcatenation = vtkGeneralTransformPtr::New();
238  context->mInvertedTransform = false;
239 
240  // Algorithm requires #source < #target
241  // swap if this is not the case
242  if (sourcePolyData->GetNumberOfPoints() > targetPolyData->GetNumberOfPoints())
243  {
244  //INVERT
245  if (mt_verbose)
246  std::cout << "inverted vessel reg" << std::endl;
247  context->mInvertedTransform = true;
248  std::swap(sourcePolyData, targetPolyData);
249  }
250 
251  vtkIdType numPoints = sourcePolyData->GetNumberOfPoints();
252  if (mt_verbose)
253  {
254  std::cout << "total number of source points:" << numPoints << ", target points: " << targetPolyData->GetNumberOfPoints() << endl;
255  std::cout << "number of source points to be sampled:" << ((int) (numPoints * mt_ltsRatio) / 100) << "\n" << endl;
256  }
257 
258 
259  // Create locator for target points
260  context->mTargetPoints = targetPolyData;
261  context->mTargetPointLocator = vtkCellLocatorPtr::New();
262  context->mTargetPointLocator->SetDataSet(targetPolyData);
263  context->mTargetPointLocator->SetNumberOfCellsPerBucket(1);
264  context->mTargetPointLocator->BuildLocator();
265 
266  //Since we are going to play with the data, we have to make a copy
267  context->mSourcePoints = vtkPointsPtr::New();
268  context->mSourcePoints->DeepCopy(sourcePolyData->GetPoints());
269 
270  context->mLtsRatio = mt_ltsRatio;
271 
272  return context;
273 }
274 
282 {
283  // total number of source points:
284  int numPoints = context->mSourcePoints->GetNumberOfPoints();
285  // number of source points used in each iteration (the rest is temporarily rejected from the computation)
286  int nb_points = ((int) (numPoints * context->mLtsRatio) / 100);
287 // std::cout << QString("onestep %1/%2").arg(nb_points).arg(numPoints) << std::endl;
288 
289  // - closestPoint is used so that the internal state of LandmarkTransform remains
290  // correct whenever the iteration process is stopped (hence its source
291  // and landmark points might be used in a vtkThinPlateSplineTransform).
292  vtkPointsPtr closestPoint = vtkPointsPtr::New();
293  closestPoint->SetNumberOfPoints(numPoints);
294 
295  // Fill points with the closest points to each vertex in input
296  vtkFloatArrayPtr residuals = vtkFloatArrayPtr::New();
297  residuals->SetNumberOfValues(numPoints);
298 
299  vtkIdListPtr IdList = vtkIdListPtr::New();
300  IdList->SetNumberOfIds(numPoints);
301  double total_distance = 0;
302  double distanceSquared = 0;
303  //Find closest points to all source points
304  for (int i = 0; i < numPoints; ++i)
305  {
306  //Check the distance to neighbouring points (neighbours should be matched to nearby points)
307  vtkIdType cell_id;
308  int sub_id;
309  double outPoint[3];
310  context->mTargetPointLocator->FindClosestPoint(context->mSourcePoints->GetPoint(i), outPoint, cell_id, sub_id, distanceSquared);
311  closestPoint->SetPoint(i, outPoint);
312  if ((boost::math::isnan)(distanceSquared))
313  {
314  std::cout << "nan found during findClosestPoint!" << std::endl;
315  {
316  context->mMetric = 1E6;
317  return;
318  }
319  }
320  residuals->InsertValue(i, distanceSquared);
321  IdList->InsertId(i, i);
322  total_distance += sqrt(distanceSquared);
323  }
324 
325  // quality of the current iteration
326  context->mMetric = total_distance / numPoints;
327 
328  vtkSortDataArrayPtr sort = vtkSortDataArrayPtr::New();
329  sort->Sort(residuals, IdList);
330  context->mSortedSourcePoints = this->createSortedPoints(IdList, context->mSourcePoints, nb_points);
331  context->mSortedTargetPoints = this->createSortedPoints(IdList, closestPoint, nb_points);
332 }
333 
346 {
347  // compute distances if not already done.
348  if (!context->mSortedSourcePoints || !context->mSortedTargetPoints)
349  this->computeDistances(context);
350 
351  if (!context->mSortedSourcePoints || !context->mSortedTargetPoints)
352  return;
353 
354  if (linear)
355  {
356  context->mTransform = linearRegistration(context->mSortedSourcePoints, context->mSortedTargetPoints);
357  }
358  else
359  {
360  context->mTransform = nonLinearRegistration(context->mSortedSourcePoints, context->mSortedTargetPoints);
361  }
362 
363  // Transform the source points with the transform found during this iteration,
364  // in order to use an updated guess for the next iteration
365  context->mSourcePoints = this->transformPoints(context->mSourcePoints, context->mTransform);
366 
367  // clear sorting data - enables us to call iteratively without fuss.
368  context->mSortedSourcePoints = vtkPointsPtr();
369  context->mSortedTargetPoints = vtkPointsPtr();
370 
371  // add transform from this iteration to the total
372  context->mConcatenation->Concatenate(context->mTransform);
373 }
374 
379 vtkPointsPtr SeansVesselReg::createSortedPoints(vtkIdListPtr sortedIDList, vtkPointsPtr unsortedPoints, int numPoints)
380 {
381  vtkPointsPtr retval = vtkPointsPtr::New();
382  retval->SetNumberOfPoints(numPoints);
383 
384  double temp_point[3];
385 
386  for (int i = 0; i < numPoints; ++i)
387  {
388  vtkIdType index = sortedIDList->GetId(i);
389  unsortedPoints->GetPoint(index, temp_point); // source points to use in tps
390  retval->SetPoint(i, temp_point);
391  }
392 
393  return retval;
394 }
395 
400 {
401 // QTime start = QTime::currentTime();
402 
403  int N = input->GetNumberOfPoints();
404  vtkPointsPtr retval = vtkPointsPtr::New();
405  retval->SetNumberOfPoints(N);
406 
407  //Transform ALL source points
408  double temp[3];
409  for (int i = 0; i < N; ++i)
410  {
411  transform->InternalTransformPoint(input->GetPoint(i), temp);
412  retval->SetPoint(i, temp);
413  }
414 
415 // std::cout << QString("\nV2V Transform time: %1s").arg(start.secsTo(QTime::currentTime())) << endl;
416  return retval;
417 }
418 
420  vtkPointsPtr sortedTargetPoints)
421 {
422 // std::cout << "linear" << std::endl;
423  //Build landmark transform
424  vtkLandmarkTransformPtr lmt = vtkLandmarkTransformPtr::New();
425  lmt->SetSourceLandmarks(sortedSourcePoints);
426  lmt->SetTargetLandmarks(sortedTargetPoints);
427  lmt->SetModeToRigidBody();
428  lmt->Modified();
429  lmt->Update();
430 
431  return lmt;
432 }
433 
435  vtkPointsPtr sortedTargetPoints)
436 {
437 // std::cout << "nonlinear" << std::endl;
438  vtkPolyDataPtr tpsSourcePolyData = this->convertToPolyData(sortedSourcePoints);
439  vtkPolyDataPtr tpsTargetPolyData = this->convertToPolyData(sortedTargetPoints);
440 
441  vtkMaskPointsPtr mask1 = vtkMaskPointsPtr::New();
442  mask1->SetInputData(tpsSourcePolyData);
443  mask1->SetOnRatio(mt_sampleRatio);
444  mask1->Update();
445  vtkMaskPointsPtr mask2 = vtkMaskPointsPtr::New();
446  mask2->SetInputData(tpsTargetPolyData);
447  mask2->SetOnRatio(mt_sampleRatio);
448  mask2->Update();
449 
450  // Build the thin plate spline transform
451  vtkThinPlateSplineTransformPtr tps = vtkThinPlateSplineTransformPtr::New();
452  tps->SetSourceLandmarks(mask1->GetOutput()->GetPoints());
453  tps->SetTargetLandmarks(mask2->GetOutput()->GetPoints());
454  tps->SetBasisToR();
455  tps->SetSigma(mt_sigma);
456  QTime start = QTime::currentTime();
457  tps->Update();
458  std::cout << QString("\nV2V NL time: %1s").arg(start.secsTo(QTime::currentTime())) << endl;
459 
460  return tps;
461 }
462 
464 {
465  ImagePtr image = boost::dynamic_pointer_cast<Image>(data);
466  MeshPtr mesh = boost::dynamic_pointer_cast<Mesh>(data);
467 
468  if (image)
469  {
470  //Grab the information from the files of target then
471  //filter out points not fit for the threshold
472  return this->extractPolyData(image, mt_singlePointThreshold, 0);
473  }
474  else if (mesh)
475  {
476  return mesh->getTransformedPolyData(mesh->get_rMd());
477  }
478 
479  return vtkPolyDataPtr();
480 }
481 
483 {
484  if (mInvertedTransform)
485  {
486  return mTargetPoints;
487  }
488  else
489  {
491  }
492 }
493 
495 {
496  if (mInvertedTransform)
497  {
498  return SeansVesselReg::convertToPolyData(mSourcePoints);
499  }
500  else
501  {
502  return mTargetPoints;
503  }
504 }
505 
507 {
508  vtkCellArrayPtr cellArray = vtkCellArrayPtr::New();
509  int N = input->GetNumberOfPoints();
510 
511  for (int i=0; i<N ; ++i)
512  {
513  cellArray->InsertNextCell(1);
514  cellArray->InsertCellPoint(i);
515  }
516 
517  vtkPolyDataPtr retval = vtkPolyDataPtr::New();
518  retval->SetPoints(input);
519  retval->SetVerts(cellArray);
520 
521  return retval;
522 }
523 
525 {
526  for (int q = 0; q < points->GetNumberOfPoints(); ++q)
527  {
528  Vector3D p(points->GetPoint(q));
529  std::cout << q << "\t" << p[0] << " " << p[1] << " " << p[2] << " " << std::endl;
530  }
531 }
532 
534 {
535  print(data->GetPoints());
536 }
537 
543 {
544  // use the bounding box of target to clip the source data.
545  fixed->GetPoints()->ComputeBounds();
546  double* targetBounds = fixed->GetPoints()->GetBounds();
547  targetBounds[0] -= margin;
548  targetBounds[1] += margin;
549  targetBounds[2] -= margin;
550  targetBounds[3] += margin;
551  targetBounds[4] -= margin;
552  targetBounds[5] += margin;
553 
554  // clip the source data with a box
555  vtkPlanesPtr box = vtkPlanesPtr::New();
556  // std::cout << "bounds" << std::endl;
557  box->SetBounds(targetBounds);
558  if (mt_verbose)
559  std::cout << "bb: " << DoubleBoundingBox3D(targetBounds) << std::endl;
560  vtkClipPolyDataPtr clipper = vtkClipPolyDataPtr::New();
561  clipper->SetInputData(input);
562  clipper->SetClipFunction(box);
563  clipper->SetInsideOut(true);
564  clipper->Update();
565 
566  int oldSource = input->GetPoints()->GetNumberOfPoints();
567  int clippedSource = clipper->GetOutput()->GetPoints()->GetNumberOfPoints();
568 
569  if (clippedSource < oldSource)
570  {
571  double ratio = double(oldSource - clippedSource) / double(oldSource);
572  if (mt_verbose)
573  std::cout << "Removed " << ratio * 100 << "%" << " of the source data. Outside the target data bounds." << std::endl;
574  }
575 
576  return clipper->GetOutput();
577 }
578 
580 {
581  if (!context)
582  context = mLastRun;
583 
584  Transform3D retval = this->getLinearTransform(context->mConcatenation);
585  if (context->mInvertedTransform)
586  retval = retval.inv();
587 
588  return retval;
589 }
590 
592 {
593  if (!context)
594  context = mLastRun;
595  return context->mMetric;
596 }
597 
599 {
600  if (!context)
601  context = mLastRun;
602  return context->mLtsRatio;
603 }
604 
607 Transform3D SeansVesselReg::getLinearTransform(vtkGeneralTransformPtr myConcatenation)
608 {
609  vtkMatrix4x4Ptr l_tempMatrix = vtkMatrix4x4Ptr::New();
610  vtkMatrix4x4Ptr l_resultMatrix = vtkMatrix4x4Ptr::New();
611 
612  if (mt_doOnlyLinear)
613  l_tempMatrix->DeepCopy(((vtkLandmarkTransform*) myConcatenation->GetConcatenatedTransform(0))->GetMatrix());
614 
615  l_resultMatrix->Identity();
616  for (int i = 1; i < myConcatenation->GetNumberOfConcatenatedTransforms(); ++i)
617  {
618  vtkMatrix4x4::Multiply4x4(l_tempMatrix,
619  ((vtkLandmarkTransform*) myConcatenation->GetConcatenatedTransform(i))->GetMatrix(), l_resultMatrix);
620  l_tempMatrix->DeepCopy(l_resultMatrix);
621 
622  }
623 
624  return Transform3D(l_resultMatrix).inverse();
625 }
626 
627 void SeansVesselReg::printOutResults(QString fileNamePrefix, vtkGeneralTransformPtr myConcatenation)
628 {
629 
630  vtkMatrix4x4Ptr l_tempMatrix = vtkMatrix4x4Ptr::New();
631  vtkMatrix4x4Ptr l_resultMatrix = vtkMatrix4x4Ptr::New();
632 
633  if (mt_doOnlyLinear)
634  l_tempMatrix->DeepCopy(((vtkLandmarkTransform*) myConcatenation->GetConcatenatedTransform(0))->GetMatrix());
635 
636  l_resultMatrix->Identity();
637  for (int i = 1; i < myConcatenation->GetNumberOfConcatenatedTransforms(); ++i)
638  {
639  vtkMatrix4x4::Multiply4x4(l_tempMatrix,
640  ((vtkLandmarkTransform*) myConcatenation->GetConcatenatedTransform(i))->GetMatrix(), l_resultMatrix);
641  l_tempMatrix->DeepCopy(l_resultMatrix);
642 
643  }
644  if (mt_verbose)
645  std::cout << "Filenameprefix: " << fileNamePrefix << std::endl;
646 
647  //std::string logsFolder = string_cast(cx::stateService()->getPatientData()->getActivePatientFolder())+"/Logs/";
648  //std::string logsFolder = "~/Patients/Logs/";
649  std::string nonLinearFile = fileNamePrefix.toStdString();
650  nonLinearFile += "--NonLinear";
651  nonLinearFile += ".txt";
652 
653  std::string linearFile = fileNamePrefix.toStdString();
654  linearFile += "--Linear";
655  linearFile += ".txt";
656 
657  if (mt_verbose)
658  std::cout << "Writing Results to " << nonLinearFile << " and " << linearFile << std::endl;
659 
660  if (!mt_doOnlyLinear)
661  {
662  ofstream file_out(nonLinearFile.c_str());
663 
664  //Non-linear Warped Transform
665  HackTPSTransform* l_theWarpTransform = ((HackTPSTransform*) myConcatenation->GetConcatenatedTransform(0));
666 
667  // Write the header
668  file_out << "MNI Transform File\n" << std::endl;
669  //file_out<<"SeansWarpyTransforms: source"<<std::endl;
670  //file_out<<"SeansWarpyTransforms: target\n"<<std::endl;
671  file_out << "Transform_Type = Thin_Plate_Spline_Transform;" << std::endl;
672  file_out << "Invert_Flag = True;" << std::endl;
673  file_out << "Number_Dimensions = 3;" << std::endl;
674  int n = l_theWarpTransform->GetSourceLandmarks()->GetNumberOfPoints();
675 
676  const double* const * theWarpMatrix = l_theWarpTransform->GetWarpMatrix();
677  double point[3];
678  file_out << "Points = " << std::endl;
679  for (int i = 0; i < n; i++)
680  {
681  l_theWarpTransform->GetSourceLandmarks()->GetPoint(i, point);
682  file_out << point[0] << " " << point[1] << " " << point[2];
683  if (i == n - 1)
684  file_out << ";" << std::endl;
685  else
686  file_out << std::endl;
687  }
688 
689  file_out << "Displacements = " << std::endl;
690  for (int i = 0; i < n + 4; i++)
691  {
692  file_out << theWarpMatrix[i][0] << " " << theWarpMatrix[i][1] << " " << theWarpMatrix[i][2];
693  if (i == n + 3)
694  file_out << ";" << std::endl;
695  else
696  file_out << std::endl;
697  }
698 
699  file_out.close();
700 
701  }
702 
703  ofstream file_out2(linearFile.c_str());
704 
705  //Linear Transform
706  file_out2 << "MNI Transform File\n" << std::endl;
707  //file_out2<<"SeansLinearTransforms: source"<<std::endl;
708  //file_out2<<"SeansLinearTransforms: target\n"<<std::endl;
709  file_out2 << "Transform_Type = Linear;" << std::endl;
710  file_out2 << "Linear_Transform = ";
711  file_out2 << std::endl;
712 
713  for (int i = 0; i < 3; i++)
714  {
715  for (int j = 0; j < 4; j++)
716  {
717 
718  file_out2 << l_resultMatrix->GetElement(i, j);
719  if (j != 3)
720  file_out2 << " ";
721  }
722  if (i == 2)
723  file_out2 << ";" << std::endl;
724  else
725  file_out2 << std::endl;
726  }
727  file_out2.close();
728 }
729 
731 // *
732 // */
733 //ImagePtr SeansVesselReg::loadMinc(char* p_dataFile)
734 //{
735 // time_t sec1 = clock();
736 // std::cout << "Reading " << p_dataFile << " -> ";
737 // std::cout.flush();
738 
739 // //Read data input file
740 // vtkMINCImageReaderPtr l_dataReader = vtkMINCImageReaderPtr::New();
741 // l_dataReader->SetFileName(p_dataFile);
742 // l_dataReader->Update();
743 
744 // double l_dataOrigin[3];
745 // l_dataReader->GetOutput()->GetOrigin(l_dataOrigin);
746 // std::cout << (clock() - sec1) / (double) CLOCKS_PER_SEC << " secs...DONE -> Processing...";
747 // std::cout.flush();
748 // int l_dimensions[3];
749 // l_dataReader->GetOutput()->GetDimensions(l_dimensions);
750 
751 // //set the transform
752 // vtkTransformPtr l_dataTransform = vtkTransformPtr::New();
753 // l_dataTransform->SetMatrix(l_dataReader->GetDirectionCosines());
754 // l_dataTransform->Translate(l_dataReader->GetDataOrigin());
755 // l_dataTransform->GetInverse()->TransformPoint(l_dataOrigin, l_dataOrigin);
756 // l_dataTransform->Translate(l_dataOrigin);
757 // l_dataTransform->Scale(l_dataReader->GetOutput()->GetSpacing());
758 
759 // Transform3D rMd(l_dataTransform->GetMatrix());
760 
761 // // TODO: ensure rMd is correct in CustusX terms
762 
763 // QFile file(p_dataFile);
764 // QFileInfo info(file);
765 // QString uid(info.completeBaseName() + "_minc_%1");
766 // QString name = uid;
767 
768 // ImagePtr image = dataManager()->createImage(l_dataReader->GetOutput(), uid, name);
769 // image->get_rMd_History()->addRegistration(RegistrationTransform(rMd, QDateTime::currentDateTime(),
770 // "from Minc file"));
771 
772 // return image;
773 //}
774 
780 vtkPolyDataPtr SeansVesselReg::extractPolyData(ImagePtr image, int p_neighborhoodFilterThreshold,
781  double p_BoundingBox[6])
782 {
783  vtkPolyDataPtr p_thePolyData = vtkPolyDataPtr::New();
784 
785  int l_dimensions[3];
786  image->getBaseVtkImageData()->GetDimensions(l_dimensions);
787  Vector3D spacing(image->getBaseVtkImageData()->GetSpacing());
788 
789  //set the transform
790  vtkTransformPtr l_dataTransform = vtkTransformPtr::New();
791  l_dataTransform->SetMatrix(image->get_rMd().getVtkMatrix());
792 
793  int l_startPosX, l_startPosY, l_startPosZ; //Beginings of neighborhood offsets
794  int l_stopPosX, l_stopPosY, l_stopPosZ; //Ends of neighborhood offsets
795  int i, j, k, ii, jj, kk, l_counts = 0; //Counter variables
796 
797  bool l_isNeighborFound; //Boolean for loop breakout
798 
799  //dimensions, fast if we first deref it in to variables
800  int l_dimX = l_dimensions[0];
801  int l_dimY = l_dimensions[1];
802  int l_dimZ = l_dimensions[2];
803 
804  double l_tempPoint[3];
805  //Offsets variables
806  int l_offsetI = 0;
807  int l_offsetJ = 0;
808  int l_offsetK = 0;
809  int l_kkjjOffset = 0;
810  int l_kkjjiiOffset = 0;
811  int l_offsetConstIJ = l_dimX * l_dimY;
812 
813  vtkDataArrayPtr l_allTheData = image->getBaseVtkImageData()->GetPointData()->GetScalars();
814  vtkPointsPtr l_dataPoints = vtkPointsPtr::New();
815  vtkCellArrayPtr l_dataCellArray = vtkCellArrayPtr::New();
816 
817  //Loop through the entire volume and precalculate the offsets for each
818  //point along with the points neighborhood offset
819  for (k = 0; k < l_dimZ; ++k)
820  {
821  //the start and stop offsets for the Z neighborhood (a gap in a cube)
822  l_startPosZ = k - p_neighborhoodFilterThreshold;
823  if (l_startPosZ < 0)
824  l_startPosZ = 0;
825  else
826  l_startPosZ *= l_offsetConstIJ;
827 
828  l_stopPosZ = k + p_neighborhoodFilterThreshold;
829  if (l_stopPosZ >= l_dimZ)
830  l_stopPosZ = (l_dimZ - 1) * l_offsetConstIJ;
831  else
832  l_stopPosZ *= l_offsetConstIJ;
833 
834  l_offsetK = k * l_offsetConstIJ;
835 
836  for (j = 0; j < l_dimY; ++j)
837  {
838  //the start and stop offsets for the Y neighborhood (a hole through a cube)
839  l_startPosY = j - p_neighborhoodFilterThreshold;
840  if (l_startPosY < 0)
841  l_startPosY = 0;
842  else
843  l_startPosY *= l_dimX;
844 
845  l_stopPosY = j + p_neighborhoodFilterThreshold;
846  if (l_stopPosY >= l_dimY)
847  l_stopPosY = (l_dimY - 1) * l_dimX;
848  else
849  l_stopPosY *= l_dimX;
850 
851  l_offsetJ = l_offsetK + (j * l_dimX);
852 
853  for (i = 0; i < l_dimX; ++i)
854  {
855  //the start and stop offsets for the X neighborhood (a voxel)
856  l_startPosX = i - p_neighborhoodFilterThreshold;
857  if (l_startPosX < 0)
858  l_startPosX = 0;
859 
860  l_stopPosX = i + p_neighborhoodFilterThreshold;
861  if (l_stopPosX >= l_dimX)
862  l_stopPosX = l_dimX - 1;
863 
864  l_offsetI = l_offsetJ + i;
865  l_isNeighborFound = 0;
866 
867  //See if this voxel contain a vessel center, if so do some more processing
868  if (*(l_allTheData->GetTuple(l_offsetI)))
869  {
870  // added by CA: use spacing when creating point. TODO: check with Ingrid if any other data are affected.
871  l_tempPoint[0] = spacing[0] * i;
872  l_tempPoint[1] = spacing[1] * j;
873  l_tempPoint[2] = spacing[2] * k;
874  l_dataTransform->TransformPoint(l_tempPoint, l_tempPoint);
875 
876  //Do stuff if there is no bounding box, or if there is one check if the
877  //point is in the bounding box
878  if (!p_BoundingBox || (p_BoundingBox[0] < l_tempPoint[0] && p_BoundingBox[1] > l_tempPoint[0]
879  && p_BoundingBox[2] < l_tempPoint[1] && p_BoundingBox[3] > l_tempPoint[1] && p_BoundingBox[4]
880  < l_tempPoint[2] && p_BoundingBox[5] > l_tempPoint[2]))
881  {
882  //Loop through the neigbors of the point and see if they are vessel centers
883  //if one of them is it then write the point down
884  for (kk = l_startPosZ; kk <= l_stopPosZ && !l_isNeighborFound; kk += l_offsetConstIJ)
885  {
886  for (jj = l_startPosY; jj <= l_stopPosY && !l_isNeighborFound; jj += l_dimX)
887  {
888  l_kkjjOffset = kk + jj;
889 
890  for (ii = l_startPosX; ii <= l_stopPosX && !l_isNeighborFound; ++ii)
891  {
892  l_kkjjiiOffset = ii + l_kkjjOffset;
893 
894  if (l_offsetI != l_kkjjiiOffset && //ignore if it is the current point
895  *(l_allTheData->GetTuple(l_kkjjiiOffset))) //check if vessel center
896  {
897  l_isNeighborFound = 1;
898  l_dataPoints->InsertNextPoint(l_tempPoint);
899  l_dataCellArray->InsertNextCell(1);
900  l_dataCellArray->InsertCellPoint(l_counts++);
901  }
902  }
903  }
904  }
905  }
906  }
907  }
908  }
909  }
910 
911  p_thePolyData->SetPoints(l_dataPoints);
912  p_thePolyData->SetVerts(l_dataCellArray);
913 
914  return p_thePolyData;
915 }
916 
922 {
923  // characterize the input perturbation in angle-axis form:
924  Vector3D t_delta = linearTransform.matrix().block<3, 1>(0, 3);
925  Eigen::AngleAxisd angleAxis = Eigen::AngleAxisd(linearTransform.matrix().block<3, 3>(0, 0));
926  double angle = angleAxis.angle();
927 
928  QString qualityText = QString("|t_delta|=%1mm, angle=%2*")
929  .arg(t_delta.length(), 6, 'f', 2)
930  .arg(angle / M_PI * 180.0, 6, 'f', 2);
931 
932  if (t_delta.length() > 20 || fabs(angle) > 10 / 180.0 * M_PI)
933  {
934  reportWarning(qualityText);
935  QString text = QString(
936  "The registration matrix' angle-axis representation shows a large shift. Retry registration.");
937  reportWarning(text);
938  }
939  else
940  {
941  report(qualityText);
942  }
943 }
944 } //namespace cx
vtkSmartPointer< class vtkMatrix4x4 > vtkMatrix4x4Ptr
Definition: cxMathBase.h:58
vtkPolyDataPtr getMovingPoints()
the moving data (one of target or source, depending on inversion)
vtkAbstractTransformPtr nonLinearRegistration(vtkPointsPtr sortedSourcePoints, vtkPointsPtr sortedTargetPoints)
DoubleBoundingBox3D transform(const Transform3D &m, const DoubleBoundingBox3D &bb)
void print(vtkPointsPtr points)
vtkSmartPointer< class vtkPlanes > vtkPlanesPtr
A mesh data set.
Definition: cxMesh.h:61
void performOneRegistration(ContextPtr context, bool linear)
Register the source points to the target point in a single ste.
double mt_distanceDeltaStopThreshold
ReporterPtr reporter()
Definition: cxReporter.cpp:59
vtkSmartPointer< class vtkLandmarkTransform > vtkLandmarkTransformPtr
Transform3D Transform3D
Transform3D is a representation of an affine 3D transform.
vtkSmartPointer< class vtkCellArray > vtkCellArrayPtr
vtkPoints * GetSourceLandmarks()
ContextPtr mLastRun
result from last run of execute()
boost::shared_ptr< class Image > ImagePtr
Definition: cxDicomWidget.h:48
vtkSmartPointer< class vtkFloatArray > vtkFloatArrayPtr
bool mInvertedTransform
the calculated registration goes from target to source instead of source to target ...
double mt_maximumDurationSeconds
vtkSmartPointer< class vtkThinPlateSplineTransform > vtkThinPlateSplineTransformPtr
bool execute(DataPtr source, DataPtr target, QString logPath)
vtkPolyDataPtr mTargetPoints
input: target data
vtkSmartPointer< class vtkIdList > vtkIdListPtr
vtkSmartPointer< class vtkClipPolyData > vtkClipPolyDataPtr
vtkSmartPointer< class vtkTransform > vtkTransformPtr
Definition: cxMathBase.h:62
void printOutResults(QString fileNamePrefix, vtkGeneralTransformPtr myConcatenation)
vtkSmartPointer< class vtkPolyData > vtkPolyDataPtr
Definition: cxProbeSector.h:47
void computeDistances(ContextPtr context)
Compute distances between the two datasets.
boost::shared_ptr< class Data > DataPtr
vtkAbstractTransformPtr linearRegistration(vtkPointsPtr sortedSourcePoints, vtkPointsPtr sortedTargetPoints)
vtkSmartPointer< class vtkMaskPoints > vtkMaskPointsPtr
double getResultLtsRatio(ContextPtr context=ContextPtr())
void reportWarning(QString msg)
Definition: cxLogger.cpp:91
ContextPtr linearRefineAllLTS(ContextPtr context)
SeansVesselReg::ContextPtr splitContext(ContextPtr context)
A volumetric data set.
Definition: cxImage.h:66
double getResultMetric(ContextPtr context=ContextPtr())
vtkSmartPointer< class vtkSortDataArray > vtkSortDataArrayPtr
vtkSmartPointer< class vtkAbstractTransform > vtkAbstractTransformPtr
ContextPtr createContext(DataPtr source, DataPtr target)
vtkPointsPtr createSortedPoints(vtkIdListPtr sortedIDList, vtkPointsPtr unsortedPoints, int numPoints)
Representation of a floating-point bounding box in 3D. The data are stored as {xmin,xmax,ymin,ymax,zmin,zmax}, in order to simplify communication with vtk.
static vtkPolyDataPtr extractPolyData(ImagePtr image, int p_neighborhoodFilterThreshold, double p_BoundingBox[6])
void linearRefine(ContextPtr context)
Eigen::Vector3d Vector3D
Vector3D is a representation of a point or vector in 3D.
Definition: cxVector3D.h:63
void report(QString msg)
Definition: cxLogger.cpp:90
vtkSmartPointer< class vtkDataArray > vtkDataArrayPtr
vtkSmartPointer< class vtkGeneralTransform > vtkGeneralTransformPtr
void checkQuality(Transform3D linearTransform)
boost::shared_ptr< Context > ContextPtr
vtkPointsPtr transformPoints(vtkPointsPtr input, vtkAbstractTransformPtr transform)
boost::shared_ptr< class Mesh > MeshPtr
static vtkPolyDataPtr convertToPolyData(vtkPointsPtr input)
vtkPolyDataPtr crop(vtkPolyDataPtr input, vtkPolyDataPtr fixed, double margin)
Transform3D getLinearResult(ContextPtr context=ContextPtr())
vtkPolyDataPtr getFixedPoints()
the fixed data (one of target or source, depending on inversion)
#define M_PI
vtkSmartPointer< class vtkPoints > vtkPointsPtr
vtkPointsPtr mSourcePoints
input: current source data, modified according to last iteration