X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?a=blobdiff_plain;f=segmentation%2FclitkExtractLymphStationsFilter.txx;h=58f2991d348426b184c92a37c6c7baf93848399a;hb=278bf98285ad8ed820e52f1fa3c9c37873040c9d;hp=2172dae21b215823d61f01f88b8fb49a4cbe6a98;hpb=726fc21726f96f8f32015dda4c3b1efeb7d81851;p=clitk.git diff --git a/segmentation/clitkExtractLymphStationsFilter.txx b/segmentation/clitkExtractLymphStationsFilter.txx index 2172dae..58f2991 100644 --- a/segmentation/clitkExtractLymphStationsFilter.txx +++ b/segmentation/clitkExtractLymphStationsFilter.txx @@ -52,18 +52,12 @@ ExtractLymphStationsFilter(): SetBackgroundValue(0); SetForegroundValue(1); - // Station 8 - SetDistanceMaxToAnteriorPartOfTheSpine(10); - MaskImagePointType p; - p[0] = 15; p[1] = 2; p[2] = 1; - SetEsophagusDiltationForAnt(p); - p[0] = 5; p[1] = 10; p[2] = 1; - SetEsophagusDiltationForRight(p); - SetFuzzyThresholdForS8(0.5); - - // Station 7 - SetFuzzyThreshold(0.5); - SetStation7Filename("station7.mhd"); + // Default values + ExtractStation_8_SetDefaultValues(); + ExtractStation_3P_SetDefaultValues(); + ExtractStation_2RL_SetDefaultValues(); + ExtractStation_3A_SetDefaultValues(); + ExtractStation_7_SetDefaultValues(); } //-------------------------------------------------------------------- @@ -78,48 +72,51 @@ GenerateOutputInformation() { m_Input = dynamic_cast(itk::ProcessObject::GetInput(0)); m_Mediastinum = GetAFDB()->template GetImage ("Mediastinum"); + // Global supports for stations + StartNewStep("Supports for stations"); + StartSubStep(); + ExtractStationSupports(); + StopSubStep(); + // Extract Station8 StartNewStep("Station 8"); StartSubStep(); ExtractStation_8(); StopSubStep(); - // Compute some interesting points in trachea - // ( ALTERNATIVE -> SKELETON ANALYSIS ? - // Pb : not sufficient for mostXX points ... ) + // Extract Station3P + StartNewStep("Station 3P"); + StartSubStep(); + ExtractStation_3P(); + StopSubStep(); - /* ==> todo (but why ???) - ComputeTracheaCentroidsAboveCarina(); - ComputeBronchusExtremaPointsBelowCarina(); + // Extract Station2RL + /* + StartNewStep("Station 2RL"); + StartSubStep(); + ExtractStation_2RL(); + StopSubStep(); */ - if (0) { // temporary suppress - // Extract Station7 - StartNewStep("Station 7"); - StartSubStep(); - ExtractStation_7(); - StopSubStep(); + // Extract Station3A + StartNewStep("Station 3A"); + StartSubStep(); + ExtractStation_3A(); + StopSubStep(); + + // Extract Station7 + StartNewStep("Station 7"); + StartSubStep(); + ExtractStation_7(); + StopSubStep(); + if (0) { // temporary suppress // Extract Station4RL StartNewStep("Station 4RL"); StartSubStep(); //ExtractStation_4RL(); StopSubStep(); } - - - // - // typedef clitk::BooleanOperatorLabelImageFilter BFilter; - //BFilter::Pointer merge = BFilter::New(); - // writeImage(m_Output, "ouput.mhd"); - //writeImage(m_Working_Support, "ws.mhd"); - /*merge->SetInput1(m_Station7); - merge->SetInput2(m_Station4RL); // support - merge->SetOperationType(BFilter::AndNot); CHANGE OPERATOR - merge->SetForegroundValue(4); - merge->Update(); - m_Output = merge->GetOutput(); - */ } //-------------------------------------------------------------------- @@ -129,7 +126,7 @@ template void clitk::ExtractLymphStationsFilter:: GenerateInputRequestedRegion() { - DD("GenerateInputRequestedRegion (nothing?)"); + //DD("GenerateInputRequestedRegion (nothing?)"); } //-------------------------------------------------------------------- @@ -139,8 +136,6 @@ template void clitk::ExtractLymphStationsFilter:: GenerateData() { - DD("GenerateData, graft output"); - // Final Step -> graft output (if SetNthOutput => redo) this->GraftOutput(m_ListOfStations["8"]); } @@ -149,23 +144,98 @@ GenerateData() { //-------------------------------------------------------------------- template -void +bool +clitk::ExtractLymphStationsFilter:: +CheckForStation(std::string station) +{ + // Compute Station name + std::string s = "Station"+station; + + + // Check if station already exist in DB + bool found = false; + if (GetAFDB()->TagExist(s)) { + m_ListOfStations[station] = GetAFDB()->template GetImage(s); + found = true; + } + + // Define the starting support + if (found && GetComputeStation(station)) { + std::cout << "Station " << station << " already exists, but re-computation forced." << std::endl; + } + if (!found || GetComputeStation(station)) { + m_Working_Support = m_Mediastinum = GetAFDB()->template GetImage("Mediastinum", true); + return true; + } + else { + std::cout << "Station " << station << " found. I used it" << std::endl; + return false; + } +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +template +bool +clitk::ExtractLymphStationsFilter:: +GetComputeStation(std::string station) +{ + return (m_ComputeStationMap.find(station) != m_ComputeStationMap.end()); +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +template +void clitk::ExtractLymphStationsFilter:: -ExtractStation_8() { +AddComputeStation(std::string station) +{ + m_ComputeStationMap[station] = true; +} +//-------------------------------------------------------------------- - // Check if m_ListOfStations["8"] exist. If yes -> use it as initial - // support instead of m_Mediastinum - if (m_ListOfStations["8"]) { - DD("Station 8 support already exist -> use it"); - m_Working_Support = m_ListOfStations["8"]; + +//-------------------------------------------------------------------- +template +void +clitk::ExtractLymphStationsFilter:: +ExtractStation_3P() +{ + if (CheckForStation("3P")) { + ExtractStation_3P_SI_Limits(); + ExtractStation_3P_Ant_Limits(); + ExtractStation_3P_Post_Limits(); + ExtractStation_3P_LR_sup_Limits(); + // ExtractStation_3P_LR_sup_Limits_2(); + ExtractStation_3P_LR_inf_Limits(); + ExtractStation_8_Single_CCL_Limits(); // YES 8 ! + ExtractStation_3P_Remove_Structures(); // after CCL + // Store image filenames into AFDB + writeImage(m_ListOfStations["3P"], "seg/Station3P.mhd"); + GetAFDB()->SetImageFilename("Station3P", "seg/Station3P.mhd"); + WriteAFDB(); } - else m_Working_Support = m_Mediastinum; +} +//-------------------------------------------------------------------- - ExtractStation_8_SI_Limits(); - ExtractStation_8_Post_Limits(); - ExtractStation_8_Ant_Limits(); - ExtractStation_8_LR_Limits(); - // ExtractStation_8_LR_Limits(); + +//-------------------------------------------------------------------- +template +void +clitk::ExtractLymphStationsFilter:: +ExtractStation_3A() +{ + if (CheckForStation("3A")) { + ExtractStation_3A_SI_Limits(); + ExtractStation_3A_Ant_Limits(); + ExtractStation_3A_Post_Limits(); + // Store image filenames into AFDB + writeImage(m_ListOfStations["3A"], "seg/Station3A.mhd"); + GetAFDB()->SetImageFilename("Station3A", "seg/Station3A.mhd"); + WriteAFDB(); + } } //-------------------------------------------------------------------- @@ -174,15 +244,24 @@ ExtractStation_8() { template void clitk::ExtractLymphStationsFilter:: -ExtractStation_7() { - if (m_ListOfStations["7"]) { - DD("Station 7 support already exist -> use it"); - m_Working_Support = m_ListOfStations["7"]; +ExtractStation_2RL() +{ + if (CheckForStation("2RL")) { + ExtractStation_2RL_SI_Limits(); + ExtractStation_2RL_Post_Limits(); + ExtractStation_2RL_Ant_Limits2(); + ExtractStation_2RL_Ant_Limits(); + ExtractStation_2RL_LR_Limits(); + ExtractStation_2RL_Remove_Structures(); + ExtractStation_2RL_SeparateRL(); + + // Store image filenames into AFDB + writeImage(m_ListOfStations["2R"], "seg/Station2R.mhd"); + writeImage(m_ListOfStations["2L"], "seg/Station2L.mhd"); + GetAFDB()->SetImageFilename("Station2R", "seg/Station2R.mhd"); + GetAFDB()->SetImageFilename("Station2L", "seg/Station2L.mhd"); + WriteAFDB(); } - else m_Working_Support = m_Mediastinum; - ExtractStation_7_SI_Limits(); - ExtractStation_7_RL_Limits(); - ExtractStation_7_Posterior_Limits(); } //-------------------------------------------------------------------- @@ -192,6 +271,8 @@ template void clitk::ExtractLymphStationsFilter:: ExtractStation_4RL() { + DD("TODO"); + exit(0); /* WARNING ONLY 4R FIRST !!! (not same inf limits) */ @@ -202,73 +283,221 @@ ExtractStation_4RL() { //-------------------------------------------------------------------- +//-------------------------------------------------------------------- +template +void +clitk::ExtractLymphStationsFilter:: +Remove_Structures(std::string station, std::string s) +{ + try { + StartNewStep("[Station"+station+"] Remove "+s); + MaskImagePointer Structure = GetAFDB()->template GetImage(s); + clitk::AndNot(m_Working_Support, Structure, GetBackgroundValue()); + } + catch(clitk::ExceptionObject e) { + std::cout << s << " not found, skip." << std::endl; + } +} +//-------------------------------------------------------------------- + + //-------------------------------------------------------------------- template void clitk::ExtractLymphStationsFilter:: -FindExtremaPointsInBronchus(MaskImagePointer input, - int direction, - double distance_max_from_center_point, - ListOfPointsType & LR, - ListOfPointsType & Ant, - ListOfPointsType & Post) +SetFuzzyThreshold(std::string station, std::string tag, double value) { + m_FuzzyThreshold[station][tag] = value; +} +//-------------------------------------------------------------------- - // Other solution ==> with auto bounding box ! (but pb to prevent to - // be too distant from the center point - // Extract slices - std::vector slices; - clitk::ExtractSlices(input, 2, slices); +//-------------------------------------------------------------------- +template +double +clitk::ExtractLymphStationsFilter:: +GetFuzzyThreshold(std::string station, std::string tag) +{ + if (m_FuzzyThreshold.find(station) == m_FuzzyThreshold.end()) { + clitkExceptionMacro("Could not find options for station "+station+" in the list (while searching for tag "+tag+")."); + return 0.0; + } + + if (m_FuzzyThreshold[station].find(tag) == m_FuzzyThreshold[station].end()) { + clitkExceptionMacro("Could not find options "+tag+" in the list of FuzzyThreshold for station "+station+"."); + return 0.0; + } - // Loop on slices - bool found; - for(uint i=0; i(slices[i], 0, true, 10); - slices[i] = KeepLabels(slices[i], - GetBackgroundValue(), - GetForegroundValue(), 1, 1, true); - */ + return m_FuzzyThreshold[station][tag]; +} +//-------------------------------------------------------------------- - // ------- Find rightmost or leftmost point ------- - MaskSliceType::PointType LRMost; - found = - clitk::FindExtremaPointInAGivenDirection(slices[i], - GetBackgroundValue(), - 0, // axis XY - (direction==0?false:true), // right or left according to direction - LRMost); - // ------- Find postmost point ------- - MaskSliceType::PointType postMost; - found = - clitk::FindExtremaPointInAGivenDirection(slices[i], - GetBackgroundValue(), - 1, false, LRMost, - distance_max_from_center_point, - postMost); - // ------- Find antmost point ------- - MaskSliceType::PointType antMost; - found = - clitk::FindExtremaPointInAGivenDirection(slices[i], + +//-------------------------------------------------------------------- +template +void +clitk::ExtractLymphStationsFilter:: +FindLineForS7S8Separation(MaskImagePointType & A, MaskImagePointType & B) +{ + // Create line from A to B with + // A = upper border of LLL at left + // B = lower border of bronchus intermedius (BI) or RightMiddleLobeBronchus + + try { + GetAFDB()->GetPoint3D("LineForS7S8Separation_Begin", A); + GetAFDB()->GetPoint3D("LineForS7S8Separation_End", B); + } + catch(clitk::ExceptionObject & o) { + + DD("FindLineForS7S8Separation"); + // Load LeftLowerLobeBronchus and get centroid point + MaskImagePointer LeftLowerLobeBronchus = + GetAFDB()->template GetImage ("LeftLowerLobeBronchus"); + std::vector c; + clitk::ComputeCentroids(LeftLowerLobeBronchus, GetBackgroundValue(), c); + A = c[1]; + + // Load RightMiddleLobeBronchus and get superior point (not centroid here) + MaskImagePointer RightMiddleLobeBronchus = + GetAFDB()->template GetImage ("RightMiddleLobeBronchus"); + bool b = FindExtremaPointInAGivenDirection(RightMiddleLobeBronchus, GetBackgroundValue(), - 1, true, LRMost, - distance_max_from_center_point, - antMost); - // Only add point if found - if (found) { - // ------- Convert 2D to 3D points -------- - MaskImageType::PointType p; - clitk::PointsUtils::Convert2DTo3D(LRMost, input, i, p); - LR.push_back(p); - clitk::PointsUtils::Convert2DTo3D(antMost, input, i, p); - Ant.push_back(p); - clitk::PointsUtils::Convert2DTo3D(postMost, input, i, p); - Post.push_back(p); + 2, false, B); + if (!b) { + clitkExceptionMacro("Error while searching most superior point in RightMiddleLobeBronchus. Abort"); + } + + // Insert into the DB + GetAFDB()->SetPoint3D("LineForS7S8Separation_Begin", A); + GetAFDB()->SetPoint3D("LineForS7S8Separation_End", B); + } +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +template +double +clitk::ExtractLymphStationsFilter:: +FindCarinaSlicePosition() +{ + double z; + try { + z = GetAFDB()->GetDouble("CarinaZ"); + } + catch(clitk::ExceptionObject e) { + DD("FindCarinaSlicePosition"); + // Get Carina + MaskImagePointer Carina = GetAFDB()->template GetImage("Carina"); + + // Get Centroid and Z value + std::vector centroids; + clitk::ComputeCentroids(Carina, GetBackgroundValue(), centroids); + + // We dont need Carina structure from now + Carina->Delete(); + + // Put inside the AFDB + GetAFDB()->SetPoint3D("CarinaPoint", centroids[1]); + GetAFDB()->SetDouble("CarinaZ", centroids[1][2]); + WriteAFDB(); + z = centroids[1][2]; + } + return z; +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +template +void +clitk::ExtractLymphStationsFilter:: +FindLeftAndRightBronchi() +{ + try { + m_RightBronchus = GetAFDB()->template GetImage ("RightBronchus"); + m_LeftBronchus = GetAFDB()->template GetImage ("LeftBronchus"); + } + catch(clitk::ExceptionObject & o) { + + DD("FindLeftAndRightBronchi"); + // The goal is to separate the trachea inferiorly to the carina into + // a Left and Right bronchus. + + // Get the trachea + MaskImagePointer Trachea = GetAFDB()->template GetImage("Trachea"); + + // Get the Carina position + m_CarinaZ = FindCarinaSlicePosition(); + + // Consider only inferiorly to the Carina + MaskImagePointer m_Working_Trachea = + clitk::CropImageRemoveGreaterThan(Trachea, 2, m_CarinaZ, true, // AutoCrop + GetBackgroundValue()); + + // Labelize the trachea + m_Working_Trachea = Labelize(m_Working_Trachea, 0, true, 1); + + // Carina position must at the first slice that separate the two + // main bronchus (not superiorly). We thus first check that the + // upper slice is composed of at least two labels + MaskImagePointer RightBronchus; + MaskImagePointer LeftBronchus; + typedef itk::ImageSliceIteratorWithIndex SliceIteratorType; + SliceIteratorType iter(m_Working_Trachea, m_Working_Trachea->GetLargestPossibleRegion()); + iter.SetFirstDirection(0); + iter.SetSecondDirection(1); + iter.GoToReverseBegin(); // Start from the end (because image is IS not SI) + int maxLabel=0; + while (!iter.IsAtReverseEndOfSlice()) { + while (!iter.IsAtReverseEndOfLine()) { + if (iter.Get() > maxLabel) maxLabel = iter.Get(); + --iter; + } + iter.PreviousLine(); } + if (maxLabel < 2) { + clitkExceptionMacro("First slice from Carina does not seems to seperate the two main bronchus. Abort"); + } + + // Compute 3D centroids of both parts to identify the left from the + // right bronchus + std::vector c; + clitk::ComputeCentroids(m_Working_Trachea, GetBackgroundValue(), c); + ImagePointType C1 = c[1]; + ImagePointType C2 = c[2]; + + ImagePixelType rightLabel; + ImagePixelType leftLabel; + if (C1[0] < C2[0]) { rightLabel = 1; leftLabel = 2; } + else { rightLabel = 2; leftLabel = 1; } + + // Select LeftLabel (set one label to Backgroundvalue) + RightBronchus = + clitk::Binarize(m_Working_Trachea, rightLabel, rightLabel, + GetBackgroundValue(), GetForegroundValue()); + /* + SetBackground(m_Working_Trachea, m_Working_Trachea, + leftLabel, GetBackgroundValue(), false); + */ + LeftBronchus = clitk::Binarize(m_Working_Trachea, leftLabel, leftLabel, + GetBackgroundValue(), GetForegroundValue()); + /* + SetBackground(m_Working_Trachea, m_Working_Trachea, + rightLabel, GetBackgroundValue(), false); + */ + + // Crop images + RightBronchus = clitk::AutoCrop(RightBronchus, GetBackgroundValue()); + LeftBronchus = clitk::AutoCrop(LeftBronchus, GetBackgroundValue()); + + // Insert int AFDB if need after + GetAFDB()->template SetImage ("RightBronchus", "seg/rightBronchus.mhd", + RightBronchus, true); + GetAFDB()->template SetImage ("LeftBronchus", "seg/leftBronchus.mhd", + LeftBronchus, true); } -} +} //-------------------------------------------------------------------- #endif //#define CLITKBOOLEANOPERATORLABELIMAGEFILTER_TXX