CustusX  2023.01.05-dev+develop.0da12
An IGT application
cxAirwaysFilterService.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 
12 #include "cxAirwaysFilterService.h"
13 
14 #include <QTimer>
15 
16 #include <vtkImageImport.h>
17 #include <vtkImageData.h>
18 #include <vtkImageShiftScale.h>
19 #include <ctkPluginContext.h>
20 #include <vtkImplicitModeller.h>
21 #include <vtkContourFilter.h>
22 #include "cxBranchList.h"
25 #include "cxColorVariationFilter.h"
26 #include "cxVolumeHelpers.h"
27 
28 #include "cxTime.h"
29 #include "cxTypeConversions.h"
30 #include "cxLogger.h"
32 #include "cxDoubleProperty.h"
33 #include "cxContourFilter.h"
34 #include "cxImage.h"
35 #include "cxDataLocations.h"
37 #include "vtkForwardDeclarations.h"
39 #include "cxVisServices.h"
40 #include "cxUtilHelpers.h"
41 #include "FAST/Algorithms/LungSegmentation/LungSegmentation.hpp"
42 #include "FAST/Algorithms/AirwaySegmentation/AirwaySegmentation.hpp"
43 #include "FAST/Algorithms/CenterlineExtraction/CenterlineExtraction.hpp"
44 #include "FAST/Importers/ImageFileImporter.hpp"
45 #include "FAST/Exporters/VTKImageExporter.hpp"
46 #include "FAST/Exporters/VTKMeshExporter.hpp"
47 #include "FAST/Data/Segmentation.hpp"
48 #include "FAST/SceneGraph.hpp"
49 
50 namespace cx {
51 
53  FilterImpl(services)
54 {
55  fast::Reporter::setGlobalReportMethod(fast::Reporter::COUT);
56  //Need to create OpenGL context of fast in main thread, this is done in the constructor of DeviceManger
57  //This hack sometimes cause CTK plugin start/stop to fail - if needed it must be solved in another way
58  //fast::ImageFileImporter::pointer importer = fast::ImageFileImporter::New();
59  //Q_UNUSED(importer)
60 }
61 
62 
64 }
65 
66 QString AirwaysFilter::getName() const
67 {
68  return "Airway Segmentation Filter";
69 }
70 
71 QString AirwaysFilter::getType() const
72 {
73  return "airways_filter";
74 }
75 
76 QString AirwaysFilter::getHelp() const
77 {
78  return "<html>"
79  "<h3>Airway Segmentation.</h3>"
80  "<p><i>Extracts airways and blood vessels, including centerlines, and lungs from a CT volume. If method fails, try to crop volume. </br>Algorithm written by Erik Smistad.</i></p>"
81  "</html>";
82 }
83 
84 Vector3D AirwaysFilter::getSeedPointFromTool(SpaceProviderPtr spaceProvider, DataPtr data)
85 {
86  // Retrieve position of tooltip and use it as seed point
87  Vector3D point = spaceProvider->getActiveToolTipPoint(
88  spaceProvider->getD(data));
89 
90  // Have to multiply by the inverse of the spacing to get the voxel position
91  ImagePtr image = boost::dynamic_pointer_cast<Image>(data);
92  double spacingX, spacingY, spacingZ;
93  image->getBaseVtkImageData()->GetSpacing(spacingX, spacingY, spacingZ);
94  point(0) = point(0) * (1.0 / spacingX);
95  point(1) = point(1) * (1.0 / spacingY);
96  point(2) = point(2) * (1.0 / spacingZ);
97 
98  std::cout << "the selected seed point is: " << point(0) << " " << point(1)
99  << " " << point(2) << "\n";
100 
101  return point;
102 }
103 
104 int * getImageSize(DataPtr inputImage)
105 {
106  ImagePtr image = boost::dynamic_pointer_cast<Image>(inputImage);
107  return image->getBaseVtkImageData()->GetDimensions();
108 }
109 
110 bool AirwaysFilter::isSeedPointInsideImage(Vector3D seedPoint, DataPtr image)
111 {
112  int * size = getImageSize(image);
113  std::cout << "size of image is: " << size[0] << " " << size[1] << " "
114  << size[2] << "\n";
115  int x = (int) seedPoint(0);
116  int y = (int) seedPoint(1);
117  int z = (int) seedPoint(2);
118  bool result = x >= 0 && y >= 0 && z >= 0 && x < size[0] && y < size[1]
119  && z < size[2];
120  return result;
121 }
122 
124 {
125  DataPtr inputImage = mInputTypes[0].get()->getData();
126  if (!inputImage)
127  {
128  CX_LOG_ERROR() << "No input data selected";
129  return false;
130  }
131 
132  if (inputImage->getType() != Image::getTypeName())
133  {
134  CX_LOG_ERROR() << "Input data has to be an image";
135  return false;
136  }
137 
138  std::string filename = (patientService()->getActivePatientFolder()
139  + "/" + inputImage->getFilename()).toStdString();
140 
141  // only check seed point inside image if use seed point is checked
142  bool useManualSeedPoint = mManualSeedPointOption->getValue();
143  if(useManualSeedPoint)
144  {
145  seedPoint = getSeedPointFromTool(mServices->spaceProvider(), inputImage);
146  if(!isSeedPointInsideImage(seedPoint, inputImage)) {
147  CX_LOG_ERROR() << "Seed point is not inside image. Use cursor to set seed point inside trachea in the CT image.";
148  return false;
149  }
150  }
151  mInputImage = patientService()->getData<Image>(inputImage->getUid());
152 
153  return true;
154 }
155 
157 {
158 
159  CX_LOG_INFO() << "EXECUTING AIRWAYS FILTER";
160  // Check if pre process went ok:
161  if(!mInputImage)
162  return false;
163 
164  QString q_filename = "";
165  QString activePatienFolder = patientService()->getActivePatientFolder();
166  QString inputImageFileName = mInputImage->getFilename();
167  if(!activePatienFolder.isEmpty())
168  q_filename = activePatienFolder+"/"+inputImageFileName;
169  else
170  q_filename = inputImageFileName;
171 
172  try {
173  fast::Config::getTestDataPath(); // needed for initialization
174  QString cacheDir = cx::DataLocations::getCachePath();
175  fast::Config::setKernelBinaryPath(cacheDir.toStdString());
176  QString kernelDir = cx::DataLocations::findConfigFolder("/FAST", FAST_SOURCE_DIR);
177  fast::Config::setKernelSourcePath(kernelDir.toStdString());
178 
179 
180  } catch(fast::Exception& e) {
181  std::string error = e.what();
182  reportError("fast::Exception: "+qstring_cast(error));
183 
184  return false;
185 
186  } catch (...){
187  reportError("Airway segmentation algorithm threw a unknown exception.");
188 
189  return false;
190  }
191 
192  bool doAirwaySegmentation = mAirwaySegmentationOption->getValue();
193  bool doLungSegmentation = mLungSegmentationOption->getValue();
194  bool doVesselSegmentation = mVesselSegmentationOption->getValue();
195 
196  if (doAirwaySegmentation)
197  {
198  std::string volumeFilname = q_filename.toStdString();
199  // Import image data from disk
200  fast::ImageFileImporter::pointer importerPtr = fast::ImageFileImporter::New();//TODO: This line cause an exception
201  importerPtr->setFilename(volumeFilname);
202 
203  segmentAirways(importerPtr);
204  }
205 
206  if (doLungSegmentation)
207  {
208  std::string volumeFilname = q_filename.toStdString();
209  // Import image data from disk
210  fast::ImageFileImporter::pointer importerPtr = fast::ImageFileImporter::New();
211  importerPtr->setFilename(volumeFilname);
212 
213  segmentLungs(importerPtr);
214  }
215 
216  if (doVesselSegmentation)
217  {
218  std::string volumeFilname = q_filename.toStdString();
219  // Import image data from disk
220  fast::ImageFileImporter::pointer importerPtr = fast::ImageFileImporter::New();
221  importerPtr->setFilename(volumeFilname);
222 
223  segmentVessels(importerPtr);
224  }
225 
226  return true;
227 }
228 
229 void AirwaysFilter::segmentAirways(fast::ImageFileImporter::pointer importerPtr)
230 {
231 
232  bool useManualSeedPoint = mManualSeedPointOption->getValue();
233 
234 
235  // Do segmentation
236  fast::AirwaySegmentation::pointer airwaySegmentationPtr = fast::AirwaySegmentation::New();
237 
238  airwaySegmentationPtr->setInputConnection(importerPtr->getOutputPort());
239 
240  if(useManualSeedPoint) {
241  CX_LOG_INFO() << "Using seed point: " << seedPoint.transpose();
242  airwaySegmentationPtr->setSeedPoint(seedPoint(0), seedPoint(1), seedPoint(2));
243  }
244 
245  extractAirways(airwaySegmentationPtr);
246 }
247 
248 bool AirwaysFilter::extractAirways(fast::AirwaySegmentation::pointer airwaySegmentationPtr)
249 {
250 
251  try{
252  auto segPort = airwaySegmentationPtr->getOutputPort();
253 
254  // Convert fast segmentation data to VTK data which CX can use
255  vtkSmartPointer<fast::VTKImageExporter> vtkExporter = fast::VTKImageExporter::New();
256  vtkExporter->setInputConnection(airwaySegmentationPtr->getOutputPort());
257  vtkExporter->Update();
258  mAirwaySegmentationOutput = vtkExporter->GetOutput();
259  vtkExporter->Delete();
260 
261  auto airwaySegmentationData = segPort->getNextFrame<fast::SpatialDataObject>();
262 
263  // Extract centerline
264  fast::CenterlineExtraction::pointer centerline = fast::CenterlineExtraction::New();
265  centerline->setInputData(airwaySegmentationData);
266  // Get centerline
267  vtkSmartPointer<fast::VTKMeshExporter> vtkCenterlineExporter = fast::VTKMeshExporter::New();
268  vtkCenterlineExporter->setInputConnection(centerline->getOutputPort());
269  vtkCenterlineExporter->Update();
270  mAirwayCenterlineOutput = vtkCenterlineExporter->GetOutput();
271  vtkCenterlineExporter->Delete();
272 
273 } catch(fast::Exception& e) {
274  std::string error = e.what();
275  reportError("fast::Exception: "+qstring_cast(error));
276  if(!mManualSeedPointOption->getValue())
277  CX_LOG_ERROR() << "Try to set the seed point manually.";
278 
279  return false;
280 
281 } catch(cl::Error& e) {
282  reportError("cl::Error:"+qstring_cast(e.what()));
283 
284  return false;
285 
286 } catch (std::exception& e){
287  reportError("std::exception:"+qstring_cast(e.what()));
288  return false;
289 
290 } catch (...){
291  reportError("Airway segmentation algorithm threw a unknown exception.");
292 
293  return false;
294 }
295 
296  return true;
297 
298 }
299 
300 void AirwaysFilter::segmentLungs(fast::ImageFileImporter::pointer importerPtr)
301 {
302 
303  bool useManualSeedPoint = mManualSeedPointOption->getValue();
304 
305  // Do segmentation
306  fast::LungSegmentation::pointer lungSegmentationPtr = fast::LungSegmentation::New();
307  lungSegmentationPtr->setInputConnection(importerPtr->getOutputPort());
308 
309  if(useManualSeedPoint) {
310  CX_LOG_INFO() << "Using seed point: " << seedPoint.transpose();
311  lungSegmentationPtr->setAirwaySeedPoint(seedPoint(0), seedPoint(1), seedPoint(2));
312  }
313 
314  extractLungs(lungSegmentationPtr);
315 }
316 
317 void AirwaysFilter::segmentVessels(fast::ImageFileImporter::pointer importerPtr)
318 {
319 
320  bool useManualSeedPoint = mManualSeedPointOption->getValue();
321 
322  // Do segmentation
323  fast::LungSegmentation::pointer lungSegmentationPtr = fast::LungSegmentation::New();
324  lungSegmentationPtr->setInputConnection(importerPtr->getOutputPort());
325 
326  if(useManualSeedPoint) {
327  CX_LOG_INFO() << "Using seed point: " << seedPoint.transpose();
328  lungSegmentationPtr->setAirwaySeedPoint(seedPoint(0), seedPoint(1), seedPoint(2));
329  }
330 
331  extractBloodVessels(lungSegmentationPtr);
332 }
333 
334 bool AirwaysFilter::extractBloodVessels(fast::LungSegmentation::pointer lungSegmentationPtr)
335 {
336  try{
337  auto segPortBloodVessels = lungSegmentationPtr->getBloodVesselOutputPort();
338 
339  // Convert fast segmentation data to VTK data which CX can use
340  vtkSmartPointer<fast::VTKImageExporter> vtkBloodVesselExporter = fast::VTKImageExporter::New();
341  vtkBloodVesselExporter->setInputConnection(lungSegmentationPtr->getBloodVesselOutputPort());
342  vtkBloodVesselExporter->Update();
343  mBloodVesselSegmentationOutput = vtkBloodVesselExporter->GetOutput();
344  vtkBloodVesselExporter->Delete();
345 
346  bool generateVesselCenterlines = mVesselCenterlineOption->getValue();
347  if (generateVesselCenterlines)
348  {
349  auto bloodVesselSegmentationData = segPortBloodVessels->getNextFrame<fast::SpatialDataObject>();
350  // Extract centerline
351  fast::CenterlineExtraction::pointer bloodVesselCenterline = fast::CenterlineExtraction::New();
352  bloodVesselCenterline->setInputData(bloodVesselSegmentationData);
353 
354  // Get centerline
355  vtkSmartPointer<fast::VTKMeshExporter> vtkBloodVesselCenterlineExporter = fast::VTKMeshExporter::New();
356  vtkBloodVesselCenterlineExporter->setInputConnection(bloodVesselCenterline->getOutputPort());
357  vtkBloodVesselCenterlineExporter->Update();
358  mBloodVesselCenterlineOutput = vtkBloodVesselCenterlineExporter->GetOutput();
359  vtkBloodVesselCenterlineExporter->Delete();
360  }
361 
362 } catch(fast::Exception& e) {
363  std::string error = e.what();
364  reportError("In vessel segmentation fast::Exception: "+qstring_cast(error));
365  if(!mManualSeedPointOption->getValue())
366  CX_LOG_ERROR() << "Try to set the seed point manually.";
367 
368  return false;
369 
370 } catch(cl::Error& e) {
371  reportError("In vessel segmentation cl::Error:"+qstring_cast(e.what()));
372 
373  return false;
374 
375 } catch (std::exception& e){
376  reportError("In vessel segmentation std::exception:"+qstring_cast(e.what()));
377 
378  return false;
379 
380 } catch (...){
381  reportError("Vessel segmentation algorithm threw a unknown exception.");
382 
383  return false;
384 }
385 
386  return true;
387 }
388 
389 bool AirwaysFilter::extractLungs(fast::LungSegmentation::pointer lungSegmentationPtr)
390 {
391  try{
392  // Convert fast segmentation data to VTK data which CX can use
393  vtkSmartPointer<fast::VTKImageExporter> vtkLungExporter = fast::VTKImageExporter::New();
394  vtkLungExporter->setInputConnection(lungSegmentationPtr->getOutputPort(0));
395  vtkLungExporter->Update();
396  mLungSegmentationOutput = vtkLungExporter->GetOutput();
397  vtkLungExporter->Delete();
398 
399 } catch(fast::Exception& e) {
400  std::string error = e.what();
401  reportError("In lung segmentation fast::Exception: "+qstring_cast(error));
402  if(!mManualSeedPointOption->getValue())
403  CX_LOG_ERROR() << "Try to set the seed point manually.";
404 
405  return false;
406 
407 } catch(cl::Error& e) {
408  reportError("In lung segmentation cl::Error:"+qstring_cast(e.what()));
409 
410  return false;
411 
412 } catch (std::exception& e){
413  reportError("In lung segmentation std::exception:"+qstring_cast(e.what()));
414 
415  return false;
416 
417 } catch (...){
418  reportError("Lung segmentation algorithm threw a unknown exception.");
419 
420  return false;
421 }
422 
423  return true;
424 }
425 
427 {
428  std::cout << "POST PROCESS" << std::endl;
429 
430  if(mAirwaySegmentationOption->getValue())
431  {
433  mAirwaySegmentationOutput = NULL; //To avoid publishing old results if next segmentation fails
434  mAirwayCenterlineOutput = NULL;
435  }
436 
437  if(mLungSegmentationOption->getValue()) {
439  mLungSegmentationOutput = NULL; //To avoid publishing old results if next segmentation fails
440  }
441 
442  if(mVesselSegmentationOption->getValue())
443  {
445  mBloodVesselSegmentationOutput = NULL; //To avoid publishing old results if next segmentation fails
446  mBloodVesselCenterlineOutput = NULL;
447  }
448 
449  return true;
450 }
451 
453 {
454  if(!mAirwaySegmentationOutput)
455  return false;
456 
457  // Make contour of segmented volume
458  double threshold = 1;
460  mAirwaySegmentationOutput,
461  threshold,
462  false, // reduce resolution
463  true, // smoothing
464  true, // keep topology
465  0 // target decimation
466  );
467 
468  //Create temporary ImagePtr for correct output name from contour filter
469  QString uidOutput = mInputImage->getUid() + airwaysFilterGetNameSuffixAirways() + "%1";
470  QString nameOutput = mInputImage->getName() + airwaysFilterGetNameSuffixAirways() + "%1";
471  ImagePtr outputImage = patientService()->createSpecificData<Image>(uidOutput, nameOutput);
472  // Add contour internally to cx
474  patientService(),
475  rawContour,
476  outputImage,
477  QColor("green")
478  );
479  contour->get_rMd_History()->setRegistration(mInputImage->get_rMd());
480 
481  // Set output
482  mOutputTypes[1]->setValue(contour->getUid());
483 
484  // Centerline
485  QString uid = mInputImage->getUid() + airwaysFilterGetNameSuffixAirways() + airwaysFilterGetNameSuffixCenterline() + "%1";
486  QString name = mInputImage->getName() + airwaysFilterGetNameSuffixAirways() + airwaysFilterGetNameSuffixCenterline() + "%1";
487  MeshPtr airwaysCenterline = patientService()->createSpecificData<Mesh>(uid, name);
488  airwaysCenterline->setVtkPolyData(mAirwayCenterlineOutput);
489  airwaysCenterline->get_rMd_History()->setParentSpace(mInputImage->getUid());
490  airwaysCenterline->get_rMd_History()->setRegistration(mInputImage->get_rMd());
491  patientService()->insertData(airwaysCenterline);
492  mOutputTypes[0]->setValue(airwaysCenterline->getUid());
493 
494  if(mAirwayTubesGenerationOption->getValue())
495  this->createAirwaysFromCenterline();
496 
497  return true;
498 }
499 
501 {
502  if(!mLungSegmentationOutput)
503  return false;
504 
505  double threshold = 1;
507  mLungSegmentationOutput,
508  threshold,
509  false, // reduce resolution
510  true, // smoothing
511  true, // keep topology
512  0 // target decimation
513  );
514 
515  //Create temporary ImagePtr for correct output name from contour filter
516  QString uidOutput = mInputImage->getUid() + airwaysFilterGetNameSuffixLungs() + "%1";
517  QString nameOutput = mInputImage->getName() + airwaysFilterGetNameSuffixLungs() + "%1";
518  ImagePtr outputImage = patientService()->createSpecificData<Image>(uidOutput, nameOutput);
519 
520  //Add contour internally to cx
521  QColor color("red");
522  color.setAlpha(100);
524  patientService(),
525  rawContour,
526  outputImage,
527  color
528  );
529 
530  contour->get_rMd_History()->setRegistration(mInputImage->get_rMd());
531 
532  // Set output
533  mOutputTypes[4]->setValue(contour->getUid());
534 
535  return true;
536 }
537 
539 {
540  if(!mBloodVesselSegmentationOutput)
541  {
542  CX_LOG_WARNING() << "In AirwaysFilter::postProcessVessels(): No BloodVessel segmentation output created.";
543  return false;
544  }
545 
546  // Make contour of segmented volume
547  double threshold = 1;
549  mBloodVesselSegmentationOutput,
550  threshold,
551  false, // reduce resolution
552  true, // smoothing
553  true, // keep topology
554  0 // target decimation
555  );
556 
557  //Create temporary ImagePtr for correct output name from contour filter
558  QString uidOutput = mInputImage->getUid() + airwaysFilterGetNameSuffixLungVessels() + "%1";
559  QString nameOutput = mInputImage->getName() + airwaysFilterGetNameSuffixLungVessels() + "%1";
560  ImagePtr outputImage = patientService()->createSpecificData<Image>(uidOutput, nameOutput);
561 
562  // Add contour internally to cx(
563  QColor color = QColor("blue");
564  color.setAlpha(255);
565 
567  patientService(),
568  rawContour,
569  outputImage,
570  color
571  );
572  contour->get_rMd_History()->setRegistration(mInputImage->get_rMd());
573 
574  // Set output
575  mOutputTypes[6]->setValue(contour->getUid());
576 
577  bool generateVesselCenterlines = mVesselCenterlineOption->getValue();
578  if (generateVesselCenterlines)
579  {
580  // Centerline
581  QString uid = mInputImage->getUid() + airwaysFilterGetNameSuffixLungVessels() + airwaysFilterGetNameSuffixCenterline() + "%1";
582  QString name = mInputImage->getName() + airwaysFilterGetNameSuffixLungVessels() + airwaysFilterGetNameSuffixCenterline() + "%1";
583  MeshPtr bloodVesselsCenterline = patientService()->createSpecificData<Mesh>(uid, name);
584  bloodVesselsCenterline->setVtkPolyData(mBloodVesselCenterlineOutput);
585  bloodVesselsCenterline->get_rMd_History()->setParentSpace(mInputImage->getUid());
586  bloodVesselsCenterline->get_rMd_History()->setRegistration(mInputImage->get_rMd());
587  bloodVesselsCenterline->setColor("blue");
588  patientService()->insertData(bloodVesselsCenterline);
589  mOutputTypes[5]->setValue(bloodVesselsCenterline->getUid());
590  }
591 
592  bool generateVesselVolume = mVesselVolumeOption->getValue();
593  if (generateVesselVolume)
594  {
595  //Create segmented volume output
596  QString uidVolume = mInputImage->getUid() + airwaysFilterGetNameSuffixLungVessels() + airwaysFilterGetNameSuffixVolume() + "%1";
597  QString nameVolume = mInputImage->getName() + airwaysFilterGetNameSuffixLungVessels() + airwaysFilterGetNameSuffixVolume() + "%1";
598  ImagePtr outputVolume = createDerivedImage( mServices->patient(),
599  uidVolume, nameVolume,
600  mBloodVesselSegmentationOutput, mInputImage);
601  outputVolume->mergevtkSettingsIntosscTransform();
602  patientService()->insertData(outputVolume);
603  mOutputTypes[7]->setValue(outputVolume->getUid());
604  }
605 
606  return true;
607 }
608 
609 void AirwaysFilter::createAirwaysFromCenterline()
610 {
612 
613  airwaysFromCLPtr->processCenterline(mAirwayCenterlineOutput);
614  airwaysFromCLPtr->setSegmentedVolume(mAirwaySegmentationOutput);
615 
616  // Create the mesh object from the airway walls
617  QString uidMesh = mInputImage->getUid() + airwaysFilterGetNameSuffixAirways() + airwaysFilterGetNameSuffixTubes() + "%1";
618  QString nameMesh = mInputImage->getName() + airwaysFilterGetNameSuffixAirways() + airwaysFilterGetNameSuffixTubes() + "%1";
619  MeshPtr airwayWalls = patientService()->createSpecificData<Mesh>(uidMesh, nameMesh);
620  airwayWalls->setVtkPolyData(airwaysFromCLPtr->generateTubes(0, true));
621  airwayWalls->get_rMd_History()->setParentSpace(mInputImage->getUid());
622  airwayWalls->get_rMd_History()->setRegistration(mInputImage->get_rMd());
623  airwayWalls->setColor(QColor(253, 173, 136, 255));
624  patientService()->insertData(airwayWalls);
625  mOutputTypes[3]->setValue(airwayWalls->getUid());
626 
627  if(mColoredAirwaysOption->getValue())
628  this->createColoredAirways();
629 
630  //insert filtered centerline from airwaysFromCenterline
631  QString uidCenterline = mInputImage->getUid() + airwaysFilterGetNameSuffixAirways() + airwaysFilterGetNameSuffixTubes() + airwaysFilterGetNameSuffixCenterline() + "%1";
632  QString nameCenterline = mInputImage->getName() + airwaysFilterGetNameSuffixAirways() + airwaysFilterGetNameSuffixTubes() + airwaysFilterGetNameSuffixCenterline() + "%1";
633  MeshPtr centerline = patientService()->createSpecificData<Mesh>(uidCenterline, nameCenterline);
634  centerline->setVtkPolyData(airwaysFromCLPtr->getVTKPoints());
635  centerline->get_rMd_History()->setParentSpace(mInputImage->getUid());
636  centerline->get_rMd_History()->setRegistration(mInputImage->get_rMd());
637  patientService()->insertData(centerline);
638  mOutputTypes[2]->setValue(centerline->getUid());
639 }
640 
641 void AirwaysFilter::createColoredAirways()
642 {
643  if(mOutputTypes[3]->getValue().isEmpty())
644  return;
645 
647  MeshPtr mesh = boost::dynamic_pointer_cast<StringPropertySelectMesh>(mOutputTypes[3])->getMesh();
648  double globaleVariance = 50.0;
649  double localeVariance = 5.0;
650  int smoothingIterations = 5;
651 
652  MeshPtr coloredMesh = coloringFilter->execute(mesh, globaleVariance, localeVariance, smoothingIterations);
653  if(coloredMesh)
654  mOutputTypes[3]->setValue(coloredMesh->getUid());
655 }
656 
658 {
659  mOptionsAdapters.push_back(this->getManualSeedPointOption(mOptions));
660  mOptionsAdapters.push_back(this->getAirwaySegmentationOption(mOptions));
661  mOptionsAdapters.push_back(this->getAirwayTubesGenerationOption(mOptions));
662  mOptionsAdapters.push_back(this->getColoredAirwaysOption(mOptions));
663  mOptionsAdapters.push_back(this->getLungSegmentationOption(mOptions));
664  mOptionsAdapters.push_back(this->getVesselSegmentationOption(mOptions));
665  mOptionsAdapters.push_back(this->getVesselCenterlineOption(mOptions));
666  mOptionsAdapters.push_back(this->getVesselVolumeOption(mOptions));
667 }
668 
670 {
672 
674  temp->setValueName("Input");
675  temp->setHelp("Select input to run airway segmentation on.");
676  mInputTypes.push_back(temp);
677 }
678 
680 {
681  StringPropertySelectMeshPtr tempMeshStringAdapter;
682  std::vector<std::pair<QString, QString>> valueHelpPairs;
683  valueHelpPairs.push_back(std::make_pair(tr("Airway Centerline"), tr("Generated centerline mesh (vtk-format).")));
684  valueHelpPairs.push_back(std::make_pair(tr("Airway Segmentation Mesh"), tr("Generated surface of the airway segmentation volume.")));
685  valueHelpPairs.push_back(std::make_pair(tr("Tube Airway Centerline"), tr("Smoothed centerline.")));
686  valueHelpPairs.push_back(std::make_pair(tr("Tube Airway Tubes Mesh"), tr("Tubes based on the smoothed centerline")));
687  valueHelpPairs.push_back(std::make_pair(tr("Lung Segmentation Mesh"), tr("Generated surface of the lung segmentation volume.")));
688  valueHelpPairs.push_back(std::make_pair(tr("Blood Vessel Centerlines"), tr("Segmented blood vessel centerlines.")));
689  valueHelpPairs.push_back(std::make_pair(tr("Blood Vessels Mesh"), tr("Segmented blood vessels in the lungs.")));
690 
691  foreach(auto pair, valueHelpPairs)
692  {
693  tempMeshStringAdapter = StringPropertySelectMesh::New(patientService());
694  tempMeshStringAdapter->setValueName(pair.first);
695  tempMeshStringAdapter->setHelp(pair.second);
696  mOutputTypes.push_back(tempMeshStringAdapter);
697  }
698 
700  tempVolumeStringAdapter->setValueName("Blood Vessels Volume");
701  tempVolumeStringAdapter->setHelp("Volume of segmented blood vessels in the lungs.");
702  mOutputTypes.push_back(tempVolumeStringAdapter);
703 }
704 
705 void AirwaysFilter::setAirwaySegmentation(bool airwaySegmentation)
706 {
707  mAirwaySegmentationOption->setValue(airwaySegmentation);
708 }
709 
710 void AirwaysFilter::setColoringAirways(bool coloringAirways)
711 {
712  mColoredAirwaysOption->setValue(coloringAirways);
713 }
714 
715 void AirwaysFilter::setVesselSegmentation(bool vesselSegmentation)
716 {
717  mVesselSegmentationOption->setValue(vesselSegmentation);
718 }
719 
720 BoolPropertyPtr AirwaysFilter::getManualSeedPointOption(QDomElement root)
721 {
722  mManualSeedPointOption = BoolProperty::initialize(
723  "Use manual seed point",
724  "",
725  "If the automatic seed point detection algorithm fails you can use cursor to set the seed point "
726  "inside trachea of the patient. "
727  "Then tick this checkbox to use the manual seed point in the airways filter.",
728  false, root);
729  return mManualSeedPointOption;
730 
731 }
732 
733 BoolPropertyPtr AirwaysFilter::getAirwaySegmentationOption(QDomElement root)
734 {
735  mAirwaySegmentationOption = BoolProperty::initialize(
736  "Airway segmentation",
737  "",
738  "Selecting this option will segment airways",
739  true, root);
740  return mAirwaySegmentationOption;
741 }
742 
743 BoolPropertyPtr AirwaysFilter::getAirwayTubesGenerationOption(QDomElement root)
744 {
745  mAirwayTubesGenerationOption = BoolProperty::initialize(
746  "Airway tubes generation",
747  "",
748  "Selecting this option will generate artificial airway tubes for virtual bronchoscopy",
749  true, root);
750  return mAirwayTubesGenerationOption;
751 
752 }
753 
754 BoolPropertyPtr AirwaysFilter::getColoredAirwaysOption(QDomElement root)
755 {
756  mColoredAirwaysOption = BoolProperty::initialize(
757  "Add color specter to airway tubes",
758  "",
759  "Selecting this option will add a random color specter to the airway tubes using the filter Color Variation",
760  true, root);
761  return mColoredAirwaysOption;
762 
763 }
764 
765 BoolPropertyPtr AirwaysFilter::getLungSegmentationOption(QDomElement root)
766 {
767  mLungSegmentationOption = BoolProperty::initialize(
768  "Lung segmentation",
769  "",
770  "Selecting this option will segment the two lung sacs",
771  false, root);
772  return mLungSegmentationOption;
773 }
774 
775 BoolPropertyPtr AirwaysFilter::getVesselSegmentationOption(QDomElement root)
776 {
777  mVesselSegmentationOption = BoolProperty::initialize(
778  "Vessel segmentation",
779  "",
780  "Selecting this option will segment the blood vessels in the lungs",
781  false, root);
782  return mVesselSegmentationOption;
783 }
784 
785 BoolPropertyPtr AirwaysFilter::getVesselCenterlineOption(QDomElement root)
786 {
787  mVesselCenterlineOption = BoolProperty::initialize(
788  "Vessel centerline",
789  "",
790  "Selecting this option will generate centerlines of the seegmented blood vessels",
791  false, root);
792  return mVesselCenterlineOption;
793 
794 }
795 
796 BoolPropertyPtr AirwaysFilter::getVesselVolumeOption(QDomElement root)
797 {
798  mVesselVolumeOption = BoolProperty::initialize(
799  "Vessel volume",
800  "",
801  "Selecting this option will generate binary volume of the seegmented blood vessels",
802  false, root);
803  return mVesselVolumeOption;
804 }
805 
806 } /* namespace cx */
807 
boost::shared_ptr< class SpaceProvider > SpaceProviderPtr
void setVesselSegmentation(bool vesselSegmentation)
QString qstring_cast(const T &val)
boost::shared_ptr< AirwaysFromCenterline > AirwaysFromCenterlinePtr
boost::shared_ptr< ColorVariationFilter > ColorVariationFilterPtr
static BoolPropertyPtr initialize(const QString &uid, QString name, QString help, bool value, QDomNode root=QDomNode())
std::vector< SelectDataStringPropertyBasePtr > mInputTypes
Definition: cxFilterImpl.h:73
void reportError(QString msg)
Definition: cxLogger.cpp:71
A mesh data set.
Definition: cxMesh.h:45
void setAirwaySegmentation(bool airwaySegmentation)
boost::shared_ptr< class VisServices > VisServicesPtr
Definition: cxMainWindow.h:40
#define CX_LOG_INFO
Definition: cxLogger.h:96
void segmentAirways(fast::ImageFileImporter::pointer importerPtr)
boost::shared_ptr< class Image > ImagePtr
Definition: cxDicomWidget.h:27
void segmentLungs(fast::ImageFileImporter::pointer importerPtr)
virtual vtkImageDataPtr getBaseVtkImageData()
Definition: cxImage.cpp:335
virtual void createOutputTypes()
AirwaysFilter(VisServicesPtr services)
std::vector< PropertyPtr > mOptionsAdapters
Definition: cxFilterImpl.h:75
boost::shared_ptr< class Data > DataPtr
static QString findConfigFolder(QString pathRelativeToConfigRoot, QString alternativeAbsolutePath="")
VisServicesPtr mServices
Definition: cxFilterImpl.h:82
ImagePtr createDerivedImage(PatientModelServicePtr dataManager, QString uid, QString name, vtkImageDataPtr raw, ImagePtr parent)
bool extractAirways(fast::AirwaySegmentation::pointer airwaySegmentationPtr)
boost::shared_ptr< class SelectDataStringPropertyBase > SelectDataStringPropertyBasePtr
PatientModelServicePtr patientService()
virtual bool execute()
static QString getCachePath()
return path to a folder that is used during execution, will be cleared at start and stop...
void setVtkPolyData(const vtkPolyDataPtr &polyData)
Definition: cxMesh.cpp:92
#define CX_LOG_ERROR
Definition: cxLogger.h:99
A volumetric data set.
Definition: cxImage.h:45
int * getImageSize(DataPtr inputImage)
static QString getTypeName()
Definition: cxImage.h:126
QDomElement mOptions
Definition: cxFilterImpl.h:76
virtual QString getType() const
boost::shared_ptr< class StringPropertySelectImage > StringPropertySelectImagePtr
vtkSmartPointer< vtkPolyData > vtkPolyDataPtr
Eigen::Vector3d Vector3D
Vector3D is a representation of a point or vector in 3D.
Definition: cxVector3D.h:42
std::vector< SelectDataStringPropertyBasePtr > mOutputTypes
Definition: cxFilterImpl.h:74
bool extractBloodVessels(fast::LungSegmentation::pointer lungSegmentationPtr)
bool extractLungs(fast::LungSegmentation::pointer lungSegmentationPtr)
#define CX_LOG_WARNING
Definition: cxLogger.h:98
static StringPropertySelectMeshPtr New(PatientModelServicePtr patientModelService)
virtual bool postProcess()
static StringPropertySelectImagePtr New(PatientModelServicePtr patientModelService)
boost::shared_ptr< class BoolProperty > BoolPropertyPtr
boost::shared_ptr< class Mesh > MeshPtr
void setColoringAirways(bool coloringAirways)
boost::shared_ptr< class StringPropertySelectMesh > StringPropertySelectMeshPtr
virtual QString getName() const
virtual QString getHelp() const
void segmentVessels(fast::ImageFileImporter::pointer importerPtr)
Namespace for all CustusX production code.