X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?a=blobdiff_plain;f=segmentation%2FclitkExtractLungFilter.txx;h=3de027cc3b8210d0dbbac0e5d2a24d1a4aa02cfa;hb=44ebb81a500e42cf19964d209e14a59812a0dd4d;hp=3bb57b8ffb0cf290dc18c3fe2892fc84ebe52696;hpb=6e16222234a90c6079a8f4696c92de7349a496bb;p=clitk.git diff --git a/segmentation/clitkExtractLungFilter.txx b/segmentation/clitkExtractLungFilter.txx index 3bb57b8..3de027c 100644 --- a/segmentation/clitkExtractLungFilter.txx +++ b/segmentation/clitkExtractLungFilter.txx @@ -32,7 +32,8 @@ #include "itkOtsuThresholdImageFilter.h" #include "itkBinaryThinningImageFilter3D.h" #include "itkImageIteratorWithIndex.h" - +#include "itkBinaryMorphologicalOpeningImageFilter.h" +#include "itkBinaryMorphologicalClosingImageFilter.h" //-------------------------------------------------------------------- template @@ -83,8 +84,9 @@ ExtractLungFilter(): p3->UseLastKeepOff(); SetLabelizeParameters3(p3); - // Step 5 : find bronchial bifurcations - FindBronchialBifurcationsOn(); + // Step 5 + FinalOpenCloseOff(); + SetFinalOpenCloseRadius(1); } //-------------------------------------------------------------------- @@ -156,6 +158,9 @@ SetArgsInfo(ArgsInfoType mArgsInfo) SetRadiusForTrachea_GGO(mArgsInfo); SetLabelizeParameters3_GGO(mArgsInfo); + + SetFinalOpenCloseRadius_GGO(mArgsInfo); + SetFinalOpenClose_GGO(mArgsInfo); } //-------------------------------------------------------------------- @@ -167,7 +172,6 @@ clitk::ExtractLungFilter:: GenerateOutputInformation() { Superclass::GenerateOutputInformation(); - //this->GetOutput(0)->SetRequestedRegion(this->GetOutput(0)->GetLargestPossibleRegion()); // Get input pointers patient = dynamic_cast(itk::ProcessObject::GetInput(1)); @@ -175,25 +179,23 @@ GenerateOutputInformation() // Check image if (!HaveSameSizeAndSpacing(input, patient)) { - this->SetLastError("* ERROR * the images (input and patient mask) must have the same size & spacing"); - return; + clitkExceptionMacro("the 'input' and 'patient' masks must have the same size & spacing."); } //-------------------------------------------------------------------- //-------------------------------------------------------------------- - StartNewStepOrStop("Set background to initial image"); + StartNewStep("Set background to initial image"); working_input = SetBackground (input, patient, GetPatientMaskBackgroundValue(), -1000); StopCurrentStep(working_input); //-------------------------------------------------------------------- //-------------------------------------------------------------------- - StartNewStepOrStop("Remove Air"); + StartNewStep("Remove Air"); // Check threshold if (m_UseLowerThreshold) { if (m_LowerThreshold > m_UpperThreshold) { - this->SetLastError("ERROR: lower threshold cannot be greater than upper threshold."); - return; + clitkExceptionMacro("lower threshold cannot be greater than upper threshold."); } } // Threshold to get air @@ -230,12 +232,12 @@ GenerateOutputInformation() //-------------------------------------------------------------------- //-------------------------------------------------------------------- - StartNewStepOrStop("Search for the trachea"); + StartNewStep("Search for the trachea"); SearchForTrachea(); //-------------------------------------------------------------------- //-------------------------------------------------------------------- - StartNewStepOrStop("Extract the lung with Otsu filter"); + StartNewStep("Extract the lung with Otsu filter"); // Automated Otsu thresholding and relabeling typedef itk::OtsuThresholdImageFilter OtsuThresholdImageFilterType; typename OtsuThresholdImageFilterType::Pointer otsuFilter=OtsuThresholdImageFilterType::New(); @@ -251,7 +253,7 @@ GenerateOutputInformation() //-------------------------------------------------------------------- //-------------------------------------------------------------------- - StartNewStepOrStop("Select labels"); + StartNewStep("Select labels"); // Keep right labels working_image = LabelizeAndSelectLabels (working_image, @@ -267,7 +269,7 @@ GenerateOutputInformation() //-------------------------------------------------------------------- //-------------------------------------------------------------------- if (m_Seeds.size() != 0) { // if ==0 ->no trachea found - StartNewStepOrStop("Remove the trachea"); + StartNewStep("Remove the trachea"); // Set the trachea working_image = SetBackground (working_image, trachea_tmp, 1, -1); @@ -314,7 +316,7 @@ GenerateOutputInformation() typedef clitk::AutoCropFilter CropFilterType; typename CropFilterType::Pointer cropFilter = CropFilterType::New(); if (m_Seeds.size() != 0) { // if ==0 ->no trachea found - StartNewStepOrStop("Croping trachea"); + StartNewStep("Croping trachea"); cropFilter->SetInput(trachea_tmp); cropFilter->Update(); // Needed typedef itk::CastImageFilter CastImageFilterType; @@ -327,7 +329,7 @@ GenerateOutputInformation() //-------------------------------------------------------------------- //-------------------------------------------------------------------- - StartNewStepOrStop("Croping lung"); + StartNewStep("Croping lung"); typename CropFilterType::Pointer cropFilter2 = CropFilterType::New(); // Needed to reset pipeline cropFilter2->SetInput(working_image); cropFilter2->Update(); @@ -336,7 +338,38 @@ GenerateOutputInformation() //-------------------------------------------------------------------- //-------------------------------------------------------------------- - StartNewStepOrStop("Separate Left/Right lungs"); + // Final OpenClose + if (GetFinalOpenClose()) { + StartNewStep("Open/Close"); + + // Structuring element + typedef itk::BinaryBallStructuringElement KernelType; + KernelType structuringElement; + structuringElement.SetRadius(GetFinalOpenCloseRadius()); + structuringElement.CreateStructuringElement(); + + // Open + typedef itk::BinaryMorphologicalOpeningImageFilter OpenFilterType; + typename OpenFilterType::Pointer openFilter = OpenFilterType::New(); + openFilter->SetInput(working_image); + openFilter->SetBackgroundValue(GetBackgroundValue()); + openFilter->SetForegroundValue(GetForegroundValue()); + openFilter->SetKernel(structuringElement); + + // Close + typedef itk::BinaryMorphologicalClosingImageFilter CloseFilterType; + typename CloseFilterType::Pointer closeFilter = CloseFilterType::New(); + closeFilter->SetInput(openFilter->GetOutput()); + closeFilter->SetSafeBorder(true); + closeFilter->SetForegroundValue(GetForegroundValue()); + closeFilter->SetKernel(structuringElement); + closeFilter->Update(); + working_image = closeFilter->GetOutput(); + } + + //-------------------------------------------------------------------- + //-------------------------------------------------------------------- + StartNewStep("Separate Left/Right lungs"); // Initial label working_image = Labelize(working_image, GetBackgroundValue(), @@ -384,7 +417,7 @@ GenerateOutputInformation() StopCurrentStep (working_image); // Final Cast - StartNewStepOrStop("Final cast"); + StartNewStep("Cast the lung mask"); typedef itk::CastImageFilter CastImageFilterType; typename CastImageFilterType::Pointer caster= CastImageFilterType::New(); caster->SetInput(working_image); @@ -394,67 +427,7 @@ GenerateOutputInformation() // Update output info this->GetOutput(0)->SetRegions(output->GetLargestPossibleRegion()); - // Try to extract bifurcation in the trachea (bronchi) - // STILL EXPERIMENTAL - if (m_Seeds.size() != 0) { // if ==0 ->no trachea found - if (GetFindBronchialBifurcations()) { - StartNewStepOrStop("Find bronchial bifurcations"); - // Step 1 : extract skeleton - // Define the thinning filter - typedef itk::BinaryThinningImageFilter3D ThinningFilterType; - typename ThinningFilterType::Pointer thinningFilter = ThinningFilterType::New(); - thinningFilter->SetInput(trachea); - thinningFilter->Update(); - typename MaskImageType::Pointer skeleton = thinningFilter->GetOutput(); - writeImage(skeleton, "skeleton.mhd"); - - // Step 2 : tracking - DD("tracking"); - - // Step 2.1 : find first point for tracking - typedef itk::ImageRegionConstIteratorWithIndex IteratorType; - IteratorType it(skeleton, skeleton->GetLargestPossibleRegion()); - it.GoToReverseBegin(); - while ((!it.IsAtEnd()) && (it.Get() == GetBackgroundValue())) { - --it; - } - if (it.IsAtEnd()) { - this->SetLastError("ERROR: first point in the skeleton not found ! Abort"); - return; - } - DD(skeleton->GetLargestPossibleRegion().GetIndex()); - typename MaskImageType::IndexType index = it.GetIndex(); - DD(index); - - // Step 2.2 : initialize neighborhooditerator - typedef itk::NeighborhoodIterator NeighborhoodIteratorType; - typename NeighborhoodIteratorType::SizeType radius; - radius.Fill(1); - NeighborhoodIteratorType nit(radius, skeleton, skeleton->GetLargestPossibleRegion()); - DD(nit.GetSize()); - DD(nit.Size()); - - // Find first label number (must be different from BG and FG) - typename MaskImageType::PixelType label = GetForegroundValue()+1; - while ((label == GetBackgroundValue()) || (label == GetForegroundValue())) { label++; } - DD(label); - - // Track from the first point - std::vector listOfBifurcations; - TrackFromThisIndex(listOfBifurcations, skeleton, index, label); - DD("end track"); - DD(listOfBifurcations.size()); - writeImage(skeleton, "skeleton2.mhd"); - - for(unsigned int i=0; iTransformIndexToPhysicalPoint(listOfBifurcations[i].index, p); - DD(p); - } - - } - } } //-------------------------------------------------------------------- @@ -465,77 +438,12 @@ void clitk::ExtractLungFilter:: GenerateData() { - // Do not put some "startnewstep" here, because the object if - // modified and the filter's pipeline it do two times. But it is - // required to quit if MustStop was set before. - if (GetMustStop()) return; - - // If everything goes well, set the output + // Set the output this->GraftOutput(output); // not SetNthOutput } //-------------------------------------------------------------------- -//-------------------------------------------------------------------- -template -void -clitk::ExtractLungFilter:: -TrackFromThisIndex(std::vector & listOfBifurcations, - MaskImagePointer skeleton, - MaskImageIndexType index, - MaskImagePixelType label) -{ - DD("TrackFromThisIndex"); - DD(index); - DD((int)label); - // Create NeighborhoodIterator - typedef itk::NeighborhoodIterator NeighborhoodIteratorType; - typename NeighborhoodIteratorType::SizeType radius; - radius.Fill(1); - NeighborhoodIteratorType nit(radius, skeleton, skeleton->GetLargestPossibleRegion()); - - // Track - std::vector listOfTrackedPoint; - bool stop = false; - while (!stop) { - nit.SetLocation(index); - // DD((int)nit.GetCenterPixel()); - nit.SetCenterPixel(label); - listOfTrackedPoint.clear(); - for(unsigned int i=0; i 2) { - std::cerr << "too much bifurcation points ... ?" << std::endl; - exit(0); - } - // Else this it the end of the tracking - } - stop = true; - } - } -} -//-------------------------------------------------------------------- - - //-------------------------------------------------------------------- template bool @@ -615,17 +523,14 @@ TracheaRegionGrowing() f->Update(); // take first (main) connected component - writeImage(f->GetOutput(), "t1.mhd"); trachea_tmp = Labelize(f->GetOutput(), GetBackgroundValue(), true, GetMinimalComponentSize()); - writeImage(trachea_tmp, "t2.mhd"); trachea_tmp = KeepLabels(trachea_tmp, GetBackgroundValue(), GetForegroundValue(), 1, 1, false); - writeImage(trachea_tmp, "t3.mhd"); } //-------------------------------------------------------------------- @@ -671,8 +576,8 @@ SearchForTrachea() stop = SearchForTracheaSeed(skip); if (stop) { TracheaRegionGrowing(); - volume = ComputeTracheaVolume(); // assume mm3 - if ((volume > 10000) && (volume < 55000 )) { // it is ok + volume = ComputeTracheaVolume()/1000; // assume mm3, so divide by 1000 to get cc + if ((volume > 10) && (volume < 55 )) { // it is ok // Typical volume 22.59 cm 3 (± 7.69 cm 3 ) [ Leader 2004 ] if (GetVerboseStep()) { std::cout << "\t Found trachea with volume " << volume << " cc." << std::endl;