X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?a=blobdiff_plain;f=segmentation%2FclitkExtractMediastinumFilter.txx;h=7c775468cb16d4b779ab8ab681058d37c50a503f;hb=dad240d633996ba10087d96ece317415086f5a59;hp=b5535cf23af74e19f32275fca7ba5cc89e9fe8b1;hpb=e008d74b0ecdc4ca2eaae8c429901a78f9ef5c31;p=clitk.git diff --git a/segmentation/clitkExtractMediastinumFilter.txx b/segmentation/clitkExtractMediastinumFilter.txx index b5535cf..7c77546 100644 --- a/segmentation/clitkExtractMediastinumFilter.txx +++ b/segmentation/clitkExtractMediastinumFilter.txx @@ -23,26 +23,33 @@ #include "clitkCommon.h" #include "clitkExtractMediastinumFilter.h" #include "clitkAddRelativePositionConstraintToLabelImageFilter.h" -#include "clitkSegmentationFunctions.h" +#include "clitkSliceBySliceRelativePositionFilter.h" +#include "clitkSegmentationUtils.h" +#include "clitkExtractAirwaysTreeInfoFilter.h" +#include "clitkCropLikeImageFilter.h" -// itk +// std #include + +// itk #include "itkStatisticsLabelMapFilter.h" #include "itkLabelImageToStatisticsLabelMapFilter.h" #include "itkRegionOfInterestImageFilter.h" #include "itkBinaryThresholdImageFilter.h" +#include "itkScalarImageKmeansImageFilter.h" // itk ENST #include "RelativePositionPropImageFilter.h" //-------------------------------------------------------------------- -template -clitk::ExtractMediastinumFilter:: +template +clitk::ExtractMediastinumFilter:: ExtractMediastinumFilter(): clitk::FilterBase(), - itk::ImageToImageFilter() + clitk::FilterWithAnatomicalFeatureDatabaseManagement(), + itk::ImageToImageFilter() { - this->SetNumberOfRequiredInputs(3); + this->SetNumberOfRequiredInputs(1); SetBackgroundValuePatient(0); SetBackgroundValueLung(0); @@ -53,30 +60,38 @@ ExtractMediastinumFilter(): SetForegroundValue(1); SetIntermediateSpacing(6); - SetFuzzyThreshold1(0.6); - SetFuzzyThreshold2(0.7); + SetFuzzyThreshold1(0.5); + SetFuzzyThreshold2(0.6); + SetFuzzyThreshold3(0.05); + + SetDistanceMaxToAnteriorPartOfTheSpine(10); + SetOutputMediastinumFilename("mediastinum.mhd"); + + UseBonesOff(); } //-------------------------------------------------------------------- //-------------------------------------------------------------------- -template +template void -clitk::ExtractMediastinumFilter:: -SetInputPatientLabelImage(const TImageType * image, ImagePixelType bg) { - this->SetNthInput(0, const_cast(image)); +clitk::ExtractMediastinumFilter:: +SetInputPatientLabelImage(const MaskImageType * image, MaskImagePixelType bg) +{ + this->SetNthInput(0, const_cast(image)); m_BackgroundValuePatient = bg; } //-------------------------------------------------------------------- //-------------------------------------------------------------------- -template +template void -clitk::ExtractMediastinumFilter:: -SetInputLungLabelImage(const TImageType * image, ImagePixelType bg, - ImagePixelType fgLeft, ImagePixelType fgRight) { - this->SetNthInput(1, const_cast(image)); +clitk::ExtractMediastinumFilter:: +SetInputLungLabelImage(const MaskImageType * image, MaskImagePixelType bg, + MaskImagePixelType fgLeft, MaskImagePixelType fgRight) +{ + this->SetNthInput(1, const_cast(image)); m_BackgroundValueLung = bg; m_ForegroundValueLeftLung = fgLeft; m_ForegroundValueRightLung = fgRight; @@ -85,21 +100,34 @@ SetInputLungLabelImage(const TImageType * image, ImagePixelType bg, //-------------------------------------------------------------------- -template +template void -clitk::ExtractMediastinumFilter:: -SetInputBonesLabelImage(const TImageType * image, ImagePixelType bg) { - this->SetNthInput(2, const_cast(image)); +clitk::ExtractMediastinumFilter:: +SetInputBonesLabelImage(const MaskImageType * image, MaskImagePixelType bg) +{ + this->SetNthInput(2, const_cast(image)); m_BackgroundValueBones = bg; } //-------------------------------------------------------------------- //-------------------------------------------------------------------- -template +template +void +clitk::ExtractMediastinumFilter:: +SetInputTracheaLabelImage(const MaskImageType * image, MaskImagePixelType bg) +{ + this->SetNthInput(3, const_cast(image)); + m_BackgroundValueTrachea = bg; +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +template template void -clitk::ExtractMediastinumFilter:: +clitk::ExtractMediastinumFilter:: SetArgsInfo(ArgsInfoType mArgsInfo) { SetVerboseOption_GGO(mArgsInfo); @@ -107,155 +135,525 @@ SetArgsInfo(ArgsInfoType mArgsInfo) SetWriteStep_GGO(mArgsInfo); SetVerboseWarningOff_GGO(mArgsInfo); - SetBackgroundValuePatient_GGO(mArgsInfo); - SetBackgroundValueLung_GGO(mArgsInfo); - SetBackgroundValueBones_GGO(mArgsInfo); - - SetForegroundValueLeftLung_GGO(mArgsInfo); - SetForegroundValueRightLung_GGO(mArgsInfo); - SetIntermediateSpacing_GGO(mArgsInfo); SetFuzzyThreshold1_GGO(mArgsInfo); SetFuzzyThreshold2_GGO(mArgsInfo); + SetFuzzyThreshold3_GGO(mArgsInfo); + + SetAFDBFilename_GGO(mArgsInfo); + SetDistanceMaxToAnteriorPartOfTheSpine_GGO(mArgsInfo); + SetUseBones_GGO(mArgsInfo); + + SetLowerThreshold_GGO(mArgsInfo); + SetUpperThreshold_GGO(mArgsInfo); } //-------------------------------------------------------------------- //-------------------------------------------------------------------- -template +template void -clitk::ExtractMediastinumFilter:: -GenerateOutputInformation() { - ImagePointer input = dynamic_cast(itk::ProcessObject::GetInput(0)); - ImagePointer outputImage = this->GetOutput(0); - outputImage->SetRegions(outputImage->GetLargestPossibleRegion()); +clitk::ExtractMediastinumFilter:: +GenerateInputRequestedRegion() +{ + //DD("GenerateInputRequestedRegion"); + // Do not call default + // Superclass::GenerateInputRequestedRegion(); + // DD("End GenerateInputRequestedRegion"); } + //-------------------------------------------------------------------- //-------------------------------------------------------------------- -template +template void -clitk::ExtractMediastinumFilter:: -GenerateInputRequestedRegion() { - // Call default - Superclass::GenerateInputRequestedRegion(); - // Get input pointers - ImagePointer patient = dynamic_cast(itk::ProcessObject::GetInput(0)); - ImagePointer lung = dynamic_cast(itk::ProcessObject::GetInput(1)); - ImagePointer bones = dynamic_cast(itk::ProcessObject::GetInput(2)); - - patient->SetRequestedRegion(patient->GetLargestPossibleRegion()); - lung->SetRequestedRegion(lung->GetLargestPossibleRegion()); - bones->SetRequestedRegion(bones->GetLargestPossibleRegion()); +clitk::ExtractMediastinumFilter:: +SetInput(const ImageType * image) +{ + this->SetNthInput(0, const_cast(image)); } //-------------------------------------------------------------------- //-------------------------------------------------------------------- -template +template void -clitk::ExtractMediastinumFilter:: -GenerateData() { +clitk::ExtractMediastinumFilter:: +GenerateOutputInformation() { + // DD("GenerateOutputInformation"); + // Do not call default + // Superclass::GenerateOutputInformation(); + + //-------------------------------------------------------------------- // Get input pointers - ImageConstPointer patient = dynamic_cast(itk::ProcessObject::GetInput(0)); - ImageConstPointer lung = dynamic_cast(itk::ProcessObject::GetInput(1)); - ImageConstPointer bones = dynamic_cast(itk::ProcessObject::GetInput(2)); + LoadAFDB(); + ImageConstPointer input = dynamic_cast(itk::ProcessObject::GetInput(0)); + MaskImagePointer patient = GetAFDB()->template GetImage ("patient"); + MaskImagePointer lung = GetAFDB()->template GetImage ("lungs"); + MaskImagePointer bones = GetAFDB()->template GetImage ("bones"); + MaskImagePointer trachea = GetAFDB()->template GetImage ("trachea"); - // Get output pointer - ImagePointer output; - - // Step 1: patient minus lungs, minus bones - StartNewStep("Patient contours minus lungs and minus bones"); - typedef clitk::BooleanOperatorLabelImageFilter BoolFilterType; + //-------------------------------------------------------------------- + // Step 1: Crop support (patient) to lung extend in RL + StartNewStep("Crop support like lungs along LR"); + typedef clitk::CropLikeImageFilter CropFilterType; + typename CropFilterType::Pointer cropFilter = CropFilterType::New(); + cropFilter->SetInput(patient); + cropFilter->SetCropLikeImage(lung, 0);// Indicate that we only crop in X (Left-Right) axe + cropFilter->Update(); + output = cropFilter->GetOutput(); + this->template StopCurrentStep(output); + + //-------------------------------------------------------------------- + // Step 2: Crop support (previous) to bones extend in AP + if (GetUseBones()) { + StartNewStep("Crop support like bones along AP"); + cropFilter = CropFilterType::New(); + cropFilter->SetInput(output); + cropFilter->SetCropLikeImage(bones, 1);// Indicate that we only crop in Y (Ant-Post) axe + cropFilter->Update(); + output = cropFilter->GetOutput(); + this->template StopCurrentStep(output); + } + + //-------------------------------------------------------------------- + // Step 3: patient minus lungs, minus bones, minus trachea + StartNewStep("Patient contours minus lungs, bones, trachea"); + typedef clitk::BooleanOperatorLabelImageFilter BoolFilterType; typename BoolFilterType::Pointer boolFilter = BoolFilterType::New(); boolFilter->InPlaceOn(); - boolFilter->SetInput1(patient); + boolFilter->SetInput1(output); boolFilter->SetInput2(lung); boolFilter->SetOperationType(BoolFilterType::AndNot); boolFilter->Update(); + if (GetUseBones()) { + boolFilter->SetInput1(boolFilter->GetOutput()); + boolFilter->SetInput2(bones); + boolFilter->SetOperationType(BoolFilterType::AndNot); + boolFilter->Update(); + } boolFilter->SetInput1(boolFilter->GetOutput()); - boolFilter->SetInput2(bones); + boolFilter->SetInput2(trachea); boolFilter->SetOperationType(BoolFilterType::AndNot); boolFilter->Update(); output = boolFilter->GetOutput(); - output = clitk::AutoCrop(output, GetBackgroundValue()); - ////autoCropFilter->GetOutput(); typedef clitk::AutoCropFilter CropFilterType; - //typename CropFilterType::Pointer cropFilter = CropFilterType::New(); - //cropFilter->SetInput(output); - //cropFilter->Update(); - //output = cropFilter->GetOutput(); + // Auto crop to gain support area + output = clitk::AutoCrop(output, GetBackgroundValue()); + this->template StopCurrentStep(output); - this->template StopCurrentStep(output); - - // Step 2: LR limits from lung (need separate lung ?) + //-------------------------------------------------------------------- + // Step 4: LR limits from lung (need separate lung ?) + // Get separate lung images to get only the right and left lung + // (because RelativePositionPropImageFilter only consider fg=1); + // (label must be '1' because right is greater than left). (WE DO + // NOT NEED TO SEPARATE ? ) StartNewStep("Left/Right limits with lungs"); - typedef clitk::AddRelativePositionConstraintToLabelImageFilter RelPosFilterType; + /* + ImagePointer right_lung = clitk::SetBackground(lung, lung, 2, 0); + ImagePointer left_lung = clitk::SetBackground(lung, lung, 1, 0); + writeImage(right_lung, "right.mhd"); + writeImage(left_lung, "left.mhd"); + */ + typedef clitk::AddRelativePositionConstraintToLabelImageFilter RelPosFilterType; typename RelPosFilterType::Pointer relPosFilter = RelPosFilterType::New(); relPosFilter->SetCurrentStepBaseId(this->GetCurrentStepId()); relPosFilter->VerboseStepOff(); relPosFilter->WriteStepOff(); relPosFilter->SetInput(output); + //relPosFilter->SetInputObject(left_lung); relPosFilter->SetInputObject(lung); - relPosFilter->SetOrientationType(RelPosFilterType::LeftTo); + relPosFilter->SetOrientationType(RelPosFilterType::LeftTo); // warning left lung is at right ;) relPosFilter->SetIntermediateSpacing(GetIntermediateSpacing()); relPosFilter->SetFuzzyThreshold(GetFuzzyThreshold1()); relPosFilter->Update(); output = relPosFilter->GetOutput(); + //writeImage(right_lung, "step4-left.mhd"); relPosFilter->SetInput(output); relPosFilter->SetCurrentStepBaseId(this->GetCurrentStepId()); relPosFilter->VerboseStepOff(); relPosFilter->WriteStepOff(); + //relPosFilter->SetInputObject(right_lung); relPosFilter->SetInputObject(lung); relPosFilter->SetOrientationType(RelPosFilterType::RightTo); relPosFilter->SetIntermediateSpacing(GetIntermediateSpacing()); relPosFilter->SetFuzzyThreshold(GetFuzzyThreshold1()); relPosFilter->Update(); output = relPosFilter->GetOutput(); - this->template StopCurrentStep(output); + this->template StopCurrentStep(output); + + //-------------------------------------------------------------------- + // Step 5: AP limits from bones + // Separate the bones in the ant-post middle + MaskImageConstPointer bones_ant; + MaskImageConstPointer bones_post; + MaskImagePointType middle_AntPost__position; + if (GetUseBones()) { + StartNewStep("Ant/Post limits with bones"); + middle_AntPost__position[0] = middle_AntPost__position[2] = 0; + middle_AntPost__position[1] = bones->GetOrigin()[1]+(bones->GetLargestPossibleRegion().GetSize()[1]*bones->GetSpacing()[1])/2.0; + MaskImageIndexType index_bones_middle; + bones->TransformPhysicalPointToIndex(middle_AntPost__position, index_bones_middle); + + // Split bone image first into two parts (ant and post), and crop + // lateraly to get vertebral + typedef itk::RegionOfInterestImageFilter ROIFilterType; + // typedef itk::ExtractImageFilter ROIFilterType; + typename ROIFilterType::Pointer roiFilter = ROIFilterType::New(); + MaskImageRegionType region = bones->GetLargestPossibleRegion(); + MaskImageSizeType size = region.GetSize(); + MaskImageIndexType index = region.GetIndex(); + // ANT part + // crop LR to keep 1/4 center part + index[0] = size[0]/4+size[0]/8; + size[0] = size[0]/4; + // crop AP to keep first (ant) part + size[1] = index_bones_middle[1]; //size[1]/2.0; + region.SetSize(size); + region.SetIndex(index); + roiFilter->SetInput(bones); + roiFilter->SetRegionOfInterest(region); + roiFilter->ReleaseDataFlagOff(); + roiFilter->Update(); + bones_ant = roiFilter->GetOutput(); + writeImage(bones_ant, "b_ant.mhd"); + // POST part + roiFilter = ROIFilterType::New(); + index[1] = bones->GetLargestPossibleRegion().GetIndex()[1] + size[1]-1; + size[1] = bones->GetLargestPossibleRegion().GetSize()[1] - size[1]; + region.SetIndex(index); + region.SetSize(size); + roiFilter->SetInput(bones); + roiFilter->SetRegionOfInterest(region); + roiFilter->ReleaseDataFlagOff(); + roiFilter->Update(); + bones_post = roiFilter->GetOutput(); + writeImage(bones_post, "b_post.mhd"); + + // Go ! + relPosFilter->SetCurrentStepNumber(0); + relPosFilter->ResetPipeline();// = RelPosFilterType::New(); + relPosFilter->SetCurrentStepBaseId(this->GetCurrentStepId()); + relPosFilter->VerboseStepOff(); + relPosFilter->WriteStepOff(); + relPosFilter->SetInput(output); + relPosFilter->SetInputObject(bones_post); + relPosFilter->SetOrientationType(RelPosFilterType::AntTo); + relPosFilter->SetIntermediateSpacing(GetIntermediateSpacing()); + relPosFilter->SetFuzzyThreshold(GetFuzzyThreshold2()); + relPosFilter->Update(); + output = relPosFilter->GetOutput(); + writeImage(output, "post.mhd"); + + relPosFilter->SetInput(relPosFilter->GetOutput()); + relPosFilter->SetCurrentStepBaseId(this->GetCurrentStepId()); + relPosFilter->VerboseStepOff(); + relPosFilter->WriteStepOff(); + relPosFilter->SetInput(output); + relPosFilter->SetInputObject(bones_ant); + relPosFilter->SetOrientationType(RelPosFilterType::PostTo); + relPosFilter->SetIntermediateSpacing(GetIntermediateSpacing()); + relPosFilter->SetFuzzyThreshold(GetFuzzyThreshold2()); + relPosFilter->Update(); + output = relPosFilter->GetOutput(); + this->template StopCurrentStep(output); + } + + //-------------------------------------------------------------------- + // Step 6: Get CCL + StartNewStep("Keep main connected component"); + output = clitk::Labelize(output, GetBackgroundValue(), false, 500); + // output = RemoveLabels(output, BG, param->GetLabelsToRemove()); + output = clitk::KeepLabels(output, GetBackgroundValue(), + GetForegroundValue(), 1, 1, 0); + this->template StopCurrentStep(output); + + //-------------------------------------------------------------------- + // Step 7 : Slice by Slice to optimize posterior part + // Warning slice does not necesseraly correspond between 'output' and 'bones' + typedef clitk::ExtractSliceFilter ExtractSliceFilterType; + typename ExtractSliceFilterType::Pointer extractSliceFilter = ExtractSliceFilterType::New(); + typedef typename ExtractSliceFilterType::SliceType SliceType; + std::vector mSlices; + if (GetUseBones()) { + StartNewStep("Rafine posterior part according to vertebral body"); + extractSliceFilter->SetInput(bones_post); + extractSliceFilter->SetDirection(2); + extractSliceFilter->Update(); + std::vector mVertebralAntPositionBySlice; + extractSliceFilter->GetOutputSlices(mSlices); + for(unsigned int i=0; i(mSlices[i], 0, true, 10); + mSlices[i] = KeepLabels(mSlices[i], + GetBackgroundValue(), + GetForegroundValue(), 1, 2, true); // keep two first + // Find most anterior point (start of the vertebral) + typename itk::ImageRegionIteratorWithIndex + iter(mSlices[i], mSlices[i]->GetLargestPossibleRegion()); + iter.GoToBegin(); + bool stop = false; + while (!stop) { + if (iter.Get() != GetBackgroundValue()) + stop = true; // not foreground because we keep two main label + ++iter; + if (iter.IsAtEnd()) stop = true; + } + if (!iter.IsAtEnd()) { + typename SliceType::PointType p; + mSlices[i]->TransformIndexToPhysicalPoint(iter.GetIndex(),p); + mVertebralAntPositionBySlice.push_back(p[1]); + } + else { + mVertebralAntPositionBySlice.push_back(bones_post->GetOrigin()[1]+(bones->GetLargestPossibleRegion().GetSize()[1]*bones->GetSpacing()[1])); + DD(mVertebralAntPositionBySlice.back()); + DD("ERROR ?? NO FG in bones here ?"); + } + } + + // Cut Post position slice by slice + { + MaskImageRegionType region; + MaskImageSizeType size; + MaskImageIndexType start; + size[2] = 1; + start[0] = output->GetLargestPossibleRegion().GetIndex()[0]; + for(unsigned int i=0; iGetOrigin()[2]+(bones_post->GetLargestPossibleRegion().GetIndex()[2]+i)*bones_post->GetSpacing()[2]; + MaskImageIndexType index; + output->TransformPhysicalPointToIndex(point, index); + // Compute region + start[2] = index[2]; + start[1] = output->GetLargestPossibleRegion().GetIndex()[1]+index[1]; + size[0] = output->GetLargestPossibleRegion().GetSize()[0]; + size[1] = output->GetLargestPossibleRegion().GetSize()[1]-start[1]; + region.SetSize(size); + region.SetIndex(start); + // Fill Region + if (output->GetLargestPossibleRegion().IsInside(start)) { + itk::ImageRegionIteratorWithIndex it(output, region); + it.GoToBegin(); + while (!it.IsAtEnd()) { + it.Set(GetBackgroundValue()); + ++it; + } + } + } + } + this->template StopCurrentStep(output); + } + + //-------------------------------------------------------------------- + // Step 8: Trial segmentation KMeans + if (0) { + StartNewStep("K means"); + // Take input, crop like current mask + typedef CropLikeImageFilter CropLikeFilterType; + typename CropLikeFilterType::Pointer cropLikeFilter = CropLikeFilterType::New(); + cropLikeFilter->SetInput(input); + cropLikeFilter->SetCropLikeImage(output); + cropLikeFilter->Update(); + ImagePointer working_input = cropLikeFilter->GetOutput(); + writeImage(working_input, "crop-input.mhd"); + // Set bG at -1000 + working_input = clitk::SetBackground(working_input, output, GetBackgroundValue(), -1000); + writeImage(working_input, "crop-input2.mhd"); + // Kmeans + typedef itk::ScalarImageKmeansImageFilter KMeansFilterType; + typename KMeansFilterType::Pointer kmeansFilter = KMeansFilterType::New(); + kmeansFilter->SetInput(working_input); + // const unsigned int numberOfInitialClasses = 3; + // const unsigned int useNonContiguousLabels = 0; + kmeansFilter->AddClassWithInitialMean(-1000); + kmeansFilter->AddClassWithInitialMean(30); + kmeansFilter->AddClassWithInitialMean(-40); // ==> I want this one + DD("Go!"); + kmeansFilter->Update(); + DD("End"); + typename KMeansFilterType::ParametersType estimatedMeans = kmeansFilter->GetFinalMeans(); + const unsigned int numberOfClasses = estimatedMeans.Size(); + for ( unsigned int i = 0 ; i < numberOfClasses ; ++i ) { + std::cout << "cluster[" << i << "] "; + std::cout << " estimated mean : " << estimatedMeans[i] << std::endl; + } + MaskImageType::Pointer kmeans = kmeansFilter->GetOutput(); + kmeans = clitk::SetBackground(kmeans, kmeans, + 1, GetBackgroundValue()); + writeImage(kmeans, "kmeans.mhd"); + // Get final results, and remove from current mask + boolFilter = BoolFilterType::New(); + boolFilter->InPlaceOn(); + boolFilter->SetInput1(output); + boolFilter->SetInput2(kmeans); + boolFilter->SetOperationType(BoolFilterType::And); + boolFilter->Update(); + output = boolFilter->GetOutput(); + writeImage(output, "out-kmean.mhd"); + this->template StopCurrentStep(output); + + // TODO -> FillMASK ? + // comment speed ? mask ? 2 class ? + + + //TODO + // Confidence connected ? + + } + + //-------------------------------------------------------------------- + // Step 8: Lower limits from lung (need separate lung ?) + if (1) { + // StartNewStep("Trial : minus segmented struct"); + // MaskImagePointer heart = GetAFDB()->template GetImage ("heart"); + // boolFilter = BoolFilterType::New(); + // boolFilter->InPlaceOn(); + // boolFilter->SetInput1(output); + // boolFilter->SetInput2(heart); + // boolFilter->SetOperationType(BoolFilterType::AndNot); + // boolFilter->Update(); + // output = boolFilter->GetOutput(); // not needed because InPlace + + // Not below the heart + // relPosFilter = RelPosFilterType::New(); + // relPosFilter->SetCurrentStepBaseId(this->GetCurrentStepId()); + // relPosFilter->VerboseStepOff(); + // relPosFilter->WriteStepOff(); + // relPosFilter->SetInput(output); + // relPosFilter->SetInputObject(heart); + // relPosFilter->SetOrientationType(RelPosFilterType::SupTo); + // relPosFilter->SetIntermediateSpacing(GetIntermediateSpacing()); + // relPosFilter->SetFuzzyThreshold(GetFuzzyThreshold3()); + // relPosFilter->Update(); + // output = relPosFilter->GetOutput(); + } + + //-------------------------------------------------------------------- + // Step 8: Lower limits from lung (need separate lung ?) + if (0) { + StartNewStep("Lower limits with lungs"); + // TODO BOFFF ???? + relPosFilter = RelPosFilterType::New(); + relPosFilter->SetCurrentStepBaseId(this->GetCurrentStepId()); + relPosFilter->VerboseStepOff(); + relPosFilter->WriteStepOff(); + relPosFilter->SetInput(output); + // relPosFilter->SetInputObject(left_lung); + relPosFilter->SetInputObject(lung); + relPosFilter->SetOrientationType(RelPosFilterType::SupTo); + relPosFilter->SetIntermediateSpacing(GetIntermediateSpacing()); + relPosFilter->SetFuzzyThreshold(GetFuzzyThreshold3()); + relPosFilter->Update(); + output = relPosFilter->GetOutput(); + this->template StopCurrentStep(output); + } + + //-------------------------------------------------------------------- + // Step 10: Slice by Slice CCL + StartNewStep("Slice by Slice keep only one component"); + typedef clitk::ExtractSliceFilter ExtractSliceFilterType; + // typename ExtractSliceFilterType::Pointer + extractSliceFilter = ExtractSliceFilterType::New(); + extractSliceFilter->SetInput(output); + extractSliceFilter->SetDirection(2); + extractSliceFilter->Update(); + typedef typename ExtractSliceFilterType::SliceType SliceType; + // std::vector + mSlices.clear(); + extractSliceFilter->GetOutputSlices(mSlices); + for(unsigned int i=0; i(mSlices[i], 0, true, 100); + mSlices[i] = KeepLabels(mSlices[i], 0, 1, 1, 1, true); + } + typedef itk::JoinSeriesImageFilter JoinSeriesFilterType; + typename JoinSeriesFilterType::Pointer joinFilter = JoinSeriesFilterType::New(); + joinFilter->SetOrigin(output->GetOrigin()[2]); + joinFilter->SetSpacing(output->GetSpacing()[2]); + for(unsigned int i=0; iPushBackInput(mSlices[i]); + } + joinFilter->Update(); + output = joinFilter->GetOutput(); + this->template StopCurrentStep(output); + + //-------------------------------------------------------------------- + // Step 9: Binarize to remove too high HU + // --> warning CCL slice by slice must be done before + StartNewStep("Remove hypersignal (bones and injected part"); + // Crop initial ct like current support + typedef CropLikeImageFilter CropLikeFilterType; + typename CropLikeFilterType::Pointer cropLikeFilter = CropLikeFilterType::New(); + cropLikeFilter->SetInput(input); + cropLikeFilter->SetCropLikeImage(output); + cropLikeFilter->Update(); + ImagePointer working_input = cropLikeFilter->GetOutput(); + writeImage(working_input, "crop-ct.mhd"); + // Binarize + typedef itk::BinaryThresholdImageFilter InputBinarizeFilterType; + typename InputBinarizeFilterType::Pointer binarizeFilter=InputBinarizeFilterType::New(); + binarizeFilter->SetInput(working_input); + binarizeFilter->SetLowerThreshold(GetLowerThreshold()); + binarizeFilter->SetUpperThreshold(GetUpperThreshold()); + binarizeFilter->SetInsideValue(this->GetBackgroundValue()); // opposite + binarizeFilter->SetOutsideValue(this->GetForegroundValue()); // opposite + binarizeFilter->Update(); + MaskImagePointer working_bin = binarizeFilter->GetOutput(); + writeImage(working_bin, "bin.mhd"); + // Remove from support + boolFilter = BoolFilterType::New(); + boolFilter->InPlaceOn(); + boolFilter->SetInput1(output); + boolFilter->SetInput2(working_bin); + boolFilter->SetOperationType(BoolFilterType::AndNot); + boolFilter->Update(); + output = boolFilter->GetOutput(); + StopCurrentStep(output); + + //-------------------------------------------------------------------- + // Step 10 : AutoCrop + StartNewStep("AutoCrop"); + output = clitk::AutoCrop(output, GetBackgroundValue()); + this->template StopCurrentStep(output); + + // Bones ? pb with RAM ? FillHoles ? + + // how to do with post part ? spine /lung ? + // POST the spine (should be separated from the rest) + /// DO THAT ---->> + // histo Y on the whole bones_post (3D) -> result is the Y center on the spine (?) + // by slice on bones_post + // find the most ant point in the center + // from this point go to post until out of bones. + // + + + // End, set the real size + this->GetOutput(0)->SetRegions(output->GetLargestPossibleRegion()); + this->GetOutput(0)->SetLargestPossibleRegion(output->GetLargestPossibleRegion()); + this->GetOutput(0)->SetRequestedRegion(output->GetLargestPossibleRegion()); + this->GetOutput(0)->SetBufferedRegion(output->GetLargestPossibleRegion()); +} +//-------------------------------------------------------------------- - // Step 3: AP limits from bones - StartNewStep("Ant/Post limits with bones"); - relPosFilter->SetCurrentStepNumber(0); - relPosFilter->ResetPipeline();// = RelPosFilterType::New(); - relPosFilter->SetCurrentStepBaseId(this->GetCurrentStepId()); - relPosFilter->VerboseStepOff(); - relPosFilter->WriteStepOff(); - relPosFilter->SetInput(output); - relPosFilter->SetInputObject(bones); - relPosFilter->SetOrientationType(RelPosFilterType::AntTo); - relPosFilter->SetIntermediateSpacing(GetIntermediateSpacing()); - relPosFilter->SetFuzzyThreshold(GetFuzzyThreshold2()); - relPosFilter->Update(); - relPosFilter->SetInput(relPosFilter->GetOutput()); - relPosFilter->SetCurrentStepBaseId(this->GetCurrentStepId()); - relPosFilter->VerboseStepOff(); - relPosFilter->WriteStepOff(); - relPosFilter->SetInputObject(bones); - relPosFilter->SetOrientationType(RelPosFilterType::PostTo); - relPosFilter->SetIntermediateSpacing(GetIntermediateSpacing()); - relPosFilter->SetFuzzyThreshold(GetFuzzyThreshold2()); - relPosFilter->Update(); - output = relPosFilter->GetOutput(); - this->template StopCurrentStep(output); - - // Get CCL - output = clitk::Labelize(output, GetBackgroundValue(), true, 100); - // output = RemoveLabels(output, BG, param->GetLabelsToRemove()); - output = clitk::KeepLabels(output, GetBackgroundValue(), - GetForegroundValue(), 1, 1, 0); - - output = clitk::AutoCrop(output, GetBackgroundValue()); - // cropFilter = CropFilterType::New(); - //cropFilter->SetInput(output); - //cropFilter->Update(); - //output = cropFilter->GetOutput(); - - // Final Step -> set output - this->SetNthOutput(0, output); +//-------------------------------------------------------------------- +template +void +clitk::ExtractMediastinumFilter:: +GenerateData() +{ + DD("GenerateData"); + this->GraftOutput(output); + // Store image filenames into AFDB + GetAFDB()->SetImageFilename("mediastinum", this->GetOutputMediastinumFilename()); + WriteAFDB(); } //--------------------------------------------------------------------