16 #include <vtkImageImport.h>
17 #include <vtkImageData.h>
18 #include <vtkImageShiftScale.h>
19 #include <ctkPluginContext.h>
20 #include <vtkImplicitModeller.h>
21 #include <vtkContourFilter.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"
55 fast::Reporter::setGlobalReportMethod(fast::Reporter::COUT);
68 return "Airway Segmentation Filter";
73 return "airways_filter";
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>"
87 Vector3D point = spaceProvider->getActiveToolTipPoint(
88 spaceProvider->getD(data));
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);
98 std::cout <<
"the selected seed point is: " << point(0) <<
" " << point(1)
99 <<
" " << point(2) <<
"\n";
106 ImagePtr image = boost::dynamic_pointer_cast<Image>(inputImage);
107 return image->getBaseVtkImageData()->GetDimensions();
110 bool AirwaysFilter::isSeedPointInsideImage(
Vector3D seedPoint,
DataPtr image)
113 std::cout <<
"size of image is: " << size[0] <<
" " << size[1] <<
" "
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]
138 std::string filename = (
patientService()->getActivePatientFolder()
139 +
"/" + inputImage->getFilename()).toStdString();
142 bool useManualSeedPoint = mManualSeedPointOption->getValue();
143 if(useManualSeedPoint)
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.";
164 QString q_filename =
"";
165 QString activePatienFolder =
patientService()->getActivePatientFolder();
166 QString inputImageFileName = mInputImage->getFilename();
167 if(!activePatienFolder.isEmpty())
168 q_filename = activePatienFolder+
"/"+inputImageFileName;
170 q_filename = inputImageFileName;
173 fast::Config::getTestDataPath();
175 fast::Config::setKernelBinaryPath(cacheDir.toStdString());
177 fast::Config::setKernelSourcePath(kernelDir.toStdString());
180 }
catch(fast::Exception& e) {
181 std::string error = e.what();
187 reportError(
"Airway segmentation algorithm threw a unknown exception.");
192 bool doAirwaySegmentation = mAirwaySegmentationOption->getValue();
193 bool doLungSegmentation = mLungSegmentationOption->getValue();
194 bool doVesselSegmentation = mVesselSegmentationOption->getValue();
196 if (doAirwaySegmentation)
198 std::string volumeFilname = q_filename.toStdString();
200 fast::ImageFileImporter::pointer importerPtr = fast::ImageFileImporter::New();
201 importerPtr->setFilename(volumeFilname);
206 if (doLungSegmentation)
208 std::string volumeFilname = q_filename.toStdString();
210 fast::ImageFileImporter::pointer importerPtr = fast::ImageFileImporter::New();
211 importerPtr->setFilename(volumeFilname);
216 if (doVesselSegmentation)
218 std::string volumeFilname = q_filename.toStdString();
220 fast::ImageFileImporter::pointer importerPtr = fast::ImageFileImporter::New();
221 importerPtr->setFilename(volumeFilname);
232 bool useManualSeedPoint = mManualSeedPointOption->getValue();
236 fast::AirwaySegmentation::pointer airwaySegmentationPtr = fast::AirwaySegmentation::New();
238 airwaySegmentationPtr->setInputConnection(importerPtr->getOutputPort());
240 if(useManualSeedPoint) {
241 CX_LOG_INFO() <<
"Using seed point: " << seedPoint.transpose();
242 airwaySegmentationPtr->setSeedPoint(seedPoint(0), seedPoint(1), seedPoint(2));
252 auto segPort = airwaySegmentationPtr->getOutputPort();
255 vtkSmartPointer<fast::VTKImageExporter> vtkExporter = fast::VTKImageExporter::New();
256 vtkExporter->setInputConnection(airwaySegmentationPtr->getOutputPort());
257 vtkExporter->Update();
258 mAirwaySegmentationOutput = vtkExporter->GetOutput();
259 vtkExporter->Delete();
261 auto airwaySegmentationData = segPort->getNextFrame<fast::SpatialDataObject>();
264 fast::CenterlineExtraction::pointer centerline = fast::CenterlineExtraction::New();
265 centerline->setInputData(airwaySegmentationData);
267 vtkSmartPointer<fast::VTKMeshExporter> vtkCenterlineExporter = fast::VTKMeshExporter::New();
268 vtkCenterlineExporter->setInputConnection(centerline->getOutputPort());
269 vtkCenterlineExporter->Update();
270 mAirwayCenterlineOutput = vtkCenterlineExporter->GetOutput();
271 vtkCenterlineExporter->Delete();
273 }
catch(fast::Exception& e) {
274 std::string error = e.what();
276 if(!mManualSeedPointOption->getValue())
277 CX_LOG_ERROR() <<
"Try to set the seed point manually.";
281 }
catch(cl::Error& e) {
286 }
catch (std::exception& e){
291 reportError(
"Airway segmentation algorithm threw a unknown exception.");
303 bool useManualSeedPoint = mManualSeedPointOption->getValue();
306 fast::LungSegmentation::pointer lungSegmentationPtr = fast::LungSegmentation::New();
307 lungSegmentationPtr->setInputConnection(importerPtr->getOutputPort());
309 if(useManualSeedPoint) {
310 CX_LOG_INFO() <<
"Using seed point: " << seedPoint.transpose();
311 lungSegmentationPtr->setAirwaySeedPoint(seedPoint(0), seedPoint(1), seedPoint(2));
320 bool useManualSeedPoint = mManualSeedPointOption->getValue();
323 fast::LungSegmentation::pointer lungSegmentationPtr = fast::LungSegmentation::New();
324 lungSegmentationPtr->setInputConnection(importerPtr->getOutputPort());
326 if(useManualSeedPoint) {
327 CX_LOG_INFO() <<
"Using seed point: " << seedPoint.transpose();
328 lungSegmentationPtr->setAirwaySeedPoint(seedPoint(0), seedPoint(1), seedPoint(2));
337 auto segPortBloodVessels = lungSegmentationPtr->getBloodVesselOutputPort();
340 vtkSmartPointer<fast::VTKImageExporter> vtkBloodVesselExporter = fast::VTKImageExporter::New();
341 vtkBloodVesselExporter->setInputConnection(lungSegmentationPtr->getBloodVesselOutputPort());
342 vtkBloodVesselExporter->Update();
343 mBloodVesselSegmentationOutput = vtkBloodVesselExporter->GetOutput();
344 vtkBloodVesselExporter->Delete();
346 bool generateVesselCenterlines = mVesselCenterlineOption->getValue();
347 if (generateVesselCenterlines)
349 auto bloodVesselSegmentationData = segPortBloodVessels->getNextFrame<fast::SpatialDataObject>();
351 fast::CenterlineExtraction::pointer bloodVesselCenterline = fast::CenterlineExtraction::New();
352 bloodVesselCenterline->setInputData(bloodVesselSegmentationData);
355 vtkSmartPointer<fast::VTKMeshExporter> vtkBloodVesselCenterlineExporter = fast::VTKMeshExporter::New();
356 vtkBloodVesselCenterlineExporter->setInputConnection(bloodVesselCenterline->getOutputPort());
357 vtkBloodVesselCenterlineExporter->Update();
358 mBloodVesselCenterlineOutput = vtkBloodVesselCenterlineExporter->GetOutput();
359 vtkBloodVesselCenterlineExporter->Delete();
362 }
catch(fast::Exception& e) {
363 std::string error = e.what();
365 if(!mManualSeedPointOption->getValue())
366 CX_LOG_ERROR() <<
"Try to set the seed point manually.";
370 }
catch(cl::Error& e) {
375 }
catch (std::exception& e){
381 reportError(
"Vessel segmentation algorithm threw a unknown exception.");
393 vtkSmartPointer<fast::VTKImageExporter> vtkLungExporter = fast::VTKImageExporter::New();
394 vtkLungExporter->setInputConnection(lungSegmentationPtr->getOutputPort(0));
395 vtkLungExporter->Update();
396 mLungSegmentationOutput = vtkLungExporter->GetOutput();
397 vtkLungExporter->Delete();
399 }
catch(fast::Exception& e) {
400 std::string error = e.what();
402 if(!mManualSeedPointOption->getValue())
403 CX_LOG_ERROR() <<
"Try to set the seed point manually.";
407 }
catch(cl::Error& e) {
412 }
catch (std::exception& e){
418 reportError(
"Lung segmentation algorithm threw a unknown exception.");
428 std::cout <<
"POST PROCESS" << std::endl;
430 if(mAirwaySegmentationOption->getValue())
433 mAirwaySegmentationOutput = NULL;
434 mAirwayCenterlineOutput = NULL;
437 if(mLungSegmentationOption->getValue()) {
439 mLungSegmentationOutput = NULL;
442 if(mVesselSegmentationOption->getValue())
445 mBloodVesselSegmentationOutput = NULL;
446 mBloodVesselCenterlineOutput = NULL;
454 if(!mAirwaySegmentationOutput)
458 double threshold = 1;
460 mAirwaySegmentationOutput,
469 QString uidOutput = mInputImage->getUid() + airwaysFilterGetNameSuffixAirways() +
"%1";
470 QString nameOutput = mInputImage->getName() + airwaysFilterGetNameSuffixAirways() +
"%1";
479 contour->get_rMd_History()->setRegistration(mInputImage->get_rMd());
485 QString uid = mInputImage->getUid() + airwaysFilterGetNameSuffixAirways() + airwaysFilterGetNameSuffixCenterline() +
"%1";
486 QString name = mInputImage->getName() + airwaysFilterGetNameSuffixAirways() + airwaysFilterGetNameSuffixCenterline() +
"%1";
489 airwaysCenterline->get_rMd_History()->setParentSpace(mInputImage->getUid());
490 airwaysCenterline->get_rMd_History()->setRegistration(mInputImage->get_rMd());
494 if(mAirwayTubesGenerationOption->getValue())
495 this->createAirwaysFromCenterline();
502 if(!mLungSegmentationOutput)
505 double threshold = 1;
507 mLungSegmentationOutput,
516 QString uidOutput = mInputImage->getUid() + airwaysFilterGetNameSuffixLungs() +
"%1";
517 QString nameOutput = mInputImage->getName() + airwaysFilterGetNameSuffixLungs() +
"%1";
530 contour->get_rMd_History()->setRegistration(mInputImage->get_rMd());
540 if(!mBloodVesselSegmentationOutput)
542 CX_LOG_WARNING() <<
"In AirwaysFilter::postProcessVessels(): No BloodVessel segmentation output created.";
547 double threshold = 1;
549 mBloodVesselSegmentationOutput,
558 QString uidOutput = mInputImage->getUid() + airwaysFilterGetNameSuffixLungVessels() +
"%1";
559 QString nameOutput = mInputImage->getName() + airwaysFilterGetNameSuffixLungVessels() +
"%1";
563 QColor color = QColor(
"blue");
572 contour->get_rMd_History()->setRegistration(mInputImage->get_rMd());
577 bool generateVesselCenterlines = mVesselCenterlineOption->getValue();
578 if (generateVesselCenterlines)
581 QString uid = mInputImage->getUid() + airwaysFilterGetNameSuffixLungVessels() + airwaysFilterGetNameSuffixCenterline() +
"%1";
582 QString name = mInputImage->getName() + airwaysFilterGetNameSuffixLungVessels() + airwaysFilterGetNameSuffixCenterline() +
"%1";
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");
589 mOutputTypes[5]->setValue(bloodVesselsCenterline->getUid());
592 bool generateVesselVolume = mVesselVolumeOption->getValue();
593 if (generateVesselVolume)
596 QString uidVolume = mInputImage->getUid() + airwaysFilterGetNameSuffixLungVessels() + airwaysFilterGetNameSuffixVolume() +
"%1";
597 QString nameVolume = mInputImage->getName() + airwaysFilterGetNameSuffixLungVessels() + airwaysFilterGetNameSuffixVolume() +
"%1";
599 uidVolume, nameVolume,
600 mBloodVesselSegmentationOutput, mInputImage);
601 outputVolume->mergevtkSettingsIntosscTransform();
609 void AirwaysFilter::createAirwaysFromCenterline()
613 airwaysFromCLPtr->processCenterline(mAirwayCenterlineOutput);
614 airwaysFromCLPtr->setSegmentedVolume(mAirwaySegmentationOutput);
617 QString uidMesh = mInputImage->getUid() + airwaysFilterGetNameSuffixAirways() + airwaysFilterGetNameSuffixTubes() +
"%1";
618 QString nameMesh = mInputImage->getName() + airwaysFilterGetNameSuffixAirways() + airwaysFilterGetNameSuffixTubes() +
"%1";
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));
627 if(mColoredAirwaysOption->getValue())
628 this->createColoredAirways();
631 QString uidCenterline = mInputImage->getUid() + airwaysFilterGetNameSuffixAirways() + airwaysFilterGetNameSuffixTubes() + airwaysFilterGetNameSuffixCenterline() +
"%1";
632 QString nameCenterline = mInputImage->getName() + airwaysFilterGetNameSuffixAirways() + airwaysFilterGetNameSuffixTubes() + airwaysFilterGetNameSuffixCenterline() +
"%1";
635 centerline->get_rMd_History()->setParentSpace(mInputImage->getUid());
636 centerline->get_rMd_History()->setRegistration(mInputImage->get_rMd());
641 void AirwaysFilter::createColoredAirways()
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;
652 MeshPtr coloredMesh = coloringFilter->execute(mesh, globaleVariance, localeVariance, smoothingIterations);
674 temp->setValueName(
"Input");
675 temp->setHelp(
"Select input to run airway segmentation on.");
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.")));
691 foreach(
auto pair, valueHelpPairs)
694 tempMeshStringAdapter->setValueName(pair.first);
695 tempMeshStringAdapter->setHelp(pair.second);
700 tempVolumeStringAdapter->setValueName(
"Blood Vessels Volume");
701 tempVolumeStringAdapter->setHelp(
"Volume of segmented blood vessels in the lungs.");
707 mAirwaySegmentationOption->setValue(airwaySegmentation);
712 mColoredAirwaysOption->setValue(coloringAirways);
717 mVesselSegmentationOption->setValue(vesselSegmentation);
720 BoolPropertyPtr AirwaysFilter::getManualSeedPointOption(QDomElement root)
723 "Use manual seed point",
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.",
729 return mManualSeedPointOption;
733 BoolPropertyPtr AirwaysFilter::getAirwaySegmentationOption(QDomElement root)
736 "Airway segmentation",
738 "Selecting this option will segment airways",
740 return mAirwaySegmentationOption;
743 BoolPropertyPtr AirwaysFilter::getAirwayTubesGenerationOption(QDomElement root)
746 "Airway tubes generation",
748 "Selecting this option will generate artificial airway tubes for virtual bronchoscopy",
750 return mAirwayTubesGenerationOption;
754 BoolPropertyPtr AirwaysFilter::getColoredAirwaysOption(QDomElement root)
757 "Add color specter to airway tubes",
759 "Selecting this option will add a random color specter to the airway tubes using the filter Color Variation",
761 return mColoredAirwaysOption;
765 BoolPropertyPtr AirwaysFilter::getLungSegmentationOption(QDomElement root)
770 "Selecting this option will segment the two lung sacs",
772 return mLungSegmentationOption;
775 BoolPropertyPtr AirwaysFilter::getVesselSegmentationOption(QDomElement root)
778 "Vessel segmentation",
780 "Selecting this option will segment the blood vessels in the lungs",
782 return mVesselSegmentationOption;
785 BoolPropertyPtr AirwaysFilter::getVesselCenterlineOption(QDomElement root)
790 "Selecting this option will generate centerlines of the seegmented blood vessels",
792 return mVesselCenterlineOption;
801 "Selecting this option will generate binary volume of the seegmented blood vessels",
803 return mVesselVolumeOption;