From: David Sarrut Date: Fri, 4 Nov 2011 09:27:12 +0000 (+0100) Subject: New way to extract support X-Git-Tag: v1.3.0~174^2~4 X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?a=commitdiff_plain;h=dd3badf7621c63f24a8dcfb831af3dcaf41fbe6c;p=clitk.git New way to extract support --- diff --git a/segmentation/clitkExtractLymphStation_Supports.txx b/segmentation/clitkExtractLymphStation_Supports.txx index 198482c..fa640a2 100644 --- a/segmentation/clitkExtractLymphStation_Supports.txx +++ b/segmentation/clitkExtractLymphStation_Supports.txx @@ -11,91 +11,74 @@ ExtractStationSupports() // Get initial Mediastinum m_Working_Support = m_Mediastinum = this->GetAFDB()->template GetImage("Mediastinum", true); - // Consider sup/inf to Carina - double m_CarinaZ = FindCarina(); - MaskImagePointer m_Support_Superior_to_Carina = - clitk::CropImageRemoveLowerThan(m_Working_Support, 2, - m_CarinaZ, true, GetBackgroundValue()); - MaskImagePointer m_Support_Inferior_to_Carina = - clitk::CropImageRemoveGreaterThan(m_Working_Support, 2, - m_CarinaZ, true, GetBackgroundValue()); - m_ListOfSupports["Support_Superior_to_Carina"] = m_Support_Superior_to_Carina; - m_ListOfSupports["Support_Inferior_to_Carina"] = m_Support_Inferior_to_Carina; - writeImage(m_Support_Inferior_to_Carina, "seg/Support_Inf_Carina.mha"); - this->GetAFDB()->SetImageFilename("Support_Inf_Carina", "seg/Support_Inf_Carina.mha"); - writeImage(m_Support_Superior_to_Carina, "seg/Support_Sup_Carina.mha"); - this->GetAFDB()->SetImageFilename("Support_Sup_Carina", "seg/Support_Sup_Carina.mha"); + // Remove some computed structures + this->GetAFDB()->RemoveTag("CarinaZ"); + this->GetAFDB()->RemoveTag("ApexOfTheChestZ"); + + // Superior and inferior limits. + Support_SI_Limit("inferior", "Sup_to_Carina", "inferior", "Carina", 0); + Support_SI_Limit("superior", "Inf_to_Carina", "inferior", "Carina", m_Working_Support->GetSpacing()[2]); + + // Initialise all others supports + // m_ListOfSupports["S1R"] = m_ListOfSupports["Sup_to_Carina"]; + // m_ListOfSupports["S1L"] = m_ListOfSupports["Sup_to_Carina"]; + // m_ListOfSupports["S2R"] = m_ListOfSupports["Sup_to_Carina"]; + // m_ListOfSupports["S2L"] = m_ListOfSupports["Sup_to_Carina"]; + // m_ListOfSupports["S3A"] = m_ListOfSupports["Sup_to_Carina"]; + // m_ListOfSupports["S3P"] = m_ListOfSupports["Sup_to_Carina"]; + // m_ListOfSupports["S4R"] = m_ListOfSupports["Sup_to_Carina"]; + // m_ListOfSupports["S4L"] = m_ListOfSupports["Sup_to_Carina"]; + // m_ListOfSupports["S5"] = m_Mediastinum; // Not above Carina + // m_ListOfSupports["S6"] = m_Mediastinum; // Not above Carina + + // Read all support limits in a file and apply them + ReadSupportLimits(GetSupportLimitsFilename()); + for(int i=0; iGetSpacing()[2]); + } // S1RL - Support_SupInf_S1RL(); Support_LeftRight_S1R_S1L(); // S2RL - Support_SupInf_S2R_S2L(); Support_LeftRight_S2R_S2L(); // S4RL - Support_SupInf_S4R_S4L(); Support_LeftRight_S4R_S4L(); // Post limits of S1,S2,S4 Support_Post_S1S2S4(); - // S3AP - Support_S3P(); - Support_S3A(); - - // S5, S6 - Support_S5(); - Support_S6(); + // S3P + StartNewStep("[Support] Ant limits of S3P with trachea"); + m_ListOfSupports["S3P"] = LimitsWithTrachea(m_ListOfSupports["S3P"], 1, 0, 10); + + // S3A + StartNewStep("[Support] Ant limits of S3A with trachea"); + m_ListOfSupports["S3A"] = LimitsWithTrachea(m_ListOfSupports["S3A"], 1, 0, -10); + // I will do it later // Below Carina S7,8,9,10 - m_ListOfSupports["S7"] = clitk::Clone(m_Support_Inferior_to_Carina); - m_ListOfSupports["S8"] = clitk::Clone(m_Support_Inferior_to_Carina); - m_ListOfSupports["S9"] = clitk::Clone(m_Support_Inferior_to_Carina); - m_ListOfSupports["S10"] = clitk::Clone(m_Support_Inferior_to_Carina); - m_ListOfSupports["S11"] = clitk::Clone(m_Support_Inferior_to_Carina); + m_ListOfSupports["S7"] = clitk::Clone(m_ListOfSupports["Inf_to_Carina"]); + m_ListOfSupports["S8"] = clitk::Clone(m_ListOfSupports["Inf_to_Carina"]); + m_ListOfSupports["S9"] = clitk::Clone(m_ListOfSupports["Inf_to_Carina"]); + m_ListOfSupports["S10"] = clitk::Clone(m_ListOfSupports["Inf_to_Carina"]); + m_ListOfSupports["S11"] = clitk::Clone(m_ListOfSupports["Inf_to_Carina"]); // Store image filenames into AFDB - writeImage(m_ListOfSupports["S1R"], "seg/Support_S1R.mha"); - this->GetAFDB()->SetImageFilename("Support_S1R", "seg/Support_S1R.mha"); - writeImage(m_ListOfSupports["S1L"], "seg/Support_S1L.mha"); - this->GetAFDB()->SetImageFilename("Support_S1L", "seg/Support_S1L.mha"); - - writeImage(m_ListOfSupports["S2L"], "seg/Support_S2L.mha"); - this->GetAFDB()->SetImageFilename("Support_S2L", "seg/Support_S2L.mha"); - writeImage(m_ListOfSupports["S2R"], "seg/Support_S2R.mha"); - this->GetAFDB()->SetImageFilename("Support_S2R", "seg/Support_S2R.mha"); - - writeImage(m_ListOfSupports["S3P"], "seg/Support_S3P.mha"); - this->GetAFDB()->SetImageFilename("Support_S3P", "seg/Support_S3P.mha"); - writeImage(m_ListOfSupports["S3A"], "seg/Support_S3A.mha"); - this->GetAFDB()->SetImageFilename("Support_S3A", "seg/Support_S3A.mha"); - - writeImage(m_ListOfSupports["S4L"], "seg/Support_S4L.mha"); - this->GetAFDB()->SetImageFilename("Support_S4L", "seg/Support_S4L.mha"); - writeImage(m_ListOfSupports["S4R"], "seg/Support_S4R.mha"); - this->GetAFDB()->SetImageFilename("Support_S4R", "seg/Support_S4R.mha"); - - writeImage(m_ListOfSupports["S5"], "seg/Support_S5.mha"); - this->GetAFDB()->SetImageFilename("Support_S5", "seg/Support_S5.mha"); - writeImage(m_ListOfSupports["S6"], "seg/Support_S6.mha"); - this->GetAFDB()->SetImageFilename("Support_S6", "seg/Support_S6.mha"); - - writeImage(m_ListOfSupports["S7"], "seg/Support_S7.mha"); - this->GetAFDB()->SetImageFilename("Support_S7", "seg/Support_S7.mha"); - - writeImage(m_ListOfSupports["S8"], "seg/Support_S8.mha"); - this->GetAFDB()->SetImageFilename("Support_S8", "seg/Support_S8.mha"); - - writeImage(m_ListOfSupports["S9"], "seg/Support_S9.mha"); - this->GetAFDB()->SetImageFilename("Support_S9", "seg/Support_S9.mha"); - - writeImage(m_ListOfSupports["S10"], "seg/Support_S10.mha"); - this->GetAFDB()->SetImageFilename("Support_S10", "seg/Support_S10.mha"); - - writeImage(m_ListOfSupports["S11"], "seg/Support_S11.mha"); - this->GetAFDB()->SetImageFilename("Support_S11", "seg/Support_S11.mha"); + WriteImageSupport("S1R"); WriteImageSupport("S1L"); + WriteImageSupport("S2R"); WriteImageSupport("S2L"); + WriteImageSupport("S3A"); WriteImageSupport("S3P"); + WriteImageSupport("S4R"); WriteImageSupport("S4L"); + WriteImageSupport("S5"); + WriteImageSupport("S6"); + WriteImageSupport("S7"); + WriteImageSupport("S8"); + WriteImageSupport("S9"); + WriteImageSupport("S10"); + WriteImageSupport("S11"); WriteAFDB(); } //-------------------------------------------------------------------- @@ -105,33 +88,143 @@ ExtractStationSupports() template void clitk::ExtractLymphStationsFilter:: -Support_SupInf_S1RL() +Support_SI_Limit(const std::string station_limit, const std::string station, + const std::string structure_limit, const std::string structure, + const double offset) { - // Step : S1RL - StartNewStep("[Support] Sup-Inf S1RL"); - /* - 2R: Upper border: apex of the right lung and pleural space, and in - the midline, the upper border of the manubrium - - 2L: Upper border: apex of the left lung and pleural space, and in the - midline, the upper border of the manubrium + if (!GetCheckSupportFlag()) + StartNewStep("[Support] "+station_limit+" limit of "+station+" is "+structure_limit+" limit of "+structure); - => apex / manubrium = up Sternum - */ - m_Working_Support = m_ListOfSupports["Support_Superior_to_Carina"]; - MaskImagePointer Sternum = this->GetAFDB()->template GetImage ("Sternum"); - MaskImagePointType p; - p[0] = p[1] = p[2] = 0.0; // to avoid warning - clitk::FindExtremaPointInAGivenDirection(Sternum, GetBackgroundValue(), 2, false, p); - // DD(p); - p[2] += Sternum->GetSpacing()[2]; // add one slice: start just superiorly - MaskImagePointer S1RL = - clitk::CropImageRemoveLowerThan(m_Working_Support, 2, - p[2], true, GetBackgroundValue()); - m_Working_Support = - clitk::CropImageRemoveGreaterThan(m_Working_Support, 2, - p[2], true, GetBackgroundValue()); - m_ListOfSupports["S1RL"] = S1RL; + // Check + if ((station_limit != "superior") && (station_limit != "inferior")) { + clitkExceptionMacro("Error station_limit must be 'inferior' or 'superior', not '"<< station_limit); + } + if ((structure_limit != "superior") && (structure_limit != "inferior")) { + clitkExceptionMacro("Error structure_limit must be 'inferior' or 'superior', not '"<< structure_limit); + } + + // Get current support + if (m_ListOfSupports.find(station) == m_ListOfSupports.end()) { + // std::cerr << "Warning: support " << station << " not initialized" << std::endl; + m_ListOfSupports[station] = m_Mediastinum; + } + m_Working_Support = m_ListOfSupports[station]; + + // Get structure or structureZ + double z; + int found=0; + std::string file; + + // Try to load structure and compute extrema point + if (this->GetAFDB()->TagExist(structure)) { + MaskImagePointer Structure = this->GetAFDB()->template GetImage (structure); + file = this->GetAFDB()->GetTagValue(structure); + MaskImagePointType p; + p[0] = p[1] = p[2] = 0.0; // to avoid warning + if (structure_limit == "superior") + clitk::FindExtremaPointInAGivenDirection(Structure, GetBackgroundValue(), 2, false, p); + else + clitk::FindExtremaPointInAGivenDirection(Structure, GetBackgroundValue(), 2, true, p); + z = p[2]; + found=1; + } + + // Try to load structureZ + if ((found==0) && (this->GetAFDB()->TagExist(structure+"Z"))) { + z = this->GetAFDB()->GetDouble(structure+"Z"); + found=2; + } + + // Try to load structurePoint + if ((found==0) && (this->GetAFDB()->TagExist(structure+"Point"))) { + MaskImagePointType p; + this->GetAFDB()->GetPoint3D(structure+"Point", p); + z = p[2]; + found=3; + } + + // Try to see if it is an already computed support + if (found==0) { + if (m_ListOfSupports.find(structure) != m_ListOfSupports.end()) { + MaskImagePointer Structure = m_ListOfSupports[structure]; + MaskImagePointType p; + if (structure_limit == "superior") + clitk::FindExtremaPointInAGivenDirection(Structure, GetBackgroundValue(), 2, false, p); + else + clitk::FindExtremaPointInAGivenDirection(Structure, GetBackgroundValue(), 2, true, p); + z = p[2]; + found=4; + } + } + + // Try special case : "FindApexOfTheChest" + if (structure == "FindApexOfTheChest") { + z = FindApexOfTheChest(); + found=5; + } + if (structure == "FindInferiorBorderOfAorticArch") { + z = FindInferiorBorderOfAorticArch(); + found=6; + } + if (structure == "FindSuperiorBorderOfAorticArch") { + z = FindSuperiorBorderOfAorticArch(); + found=6; + } + + // If we find anything + if (found == 0) { + std::cerr << "ERROR : I could not find " << structure << " nor " << structure << "Z nor " + << structure << "Point" << std::endl; + exit(EXIT_FAILURE); + } + + // Apply offset + z += offset; + + // Remove Lower or greater + if (station_limit == "inferior") { + m_Working_Support = + clitk::CropImageRemoveLowerThan(m_Working_Support, 2, z, true, GetBackgroundValue()); + } + else { + m_Working_Support = + clitk::CropImageRemoveGreaterThan(m_Working_Support, 2, z, true, GetBackgroundValue()); + } + + // Check: if reference station is given, display information + if (GetCheckSupportFlag()) { + try { + MaskImagePointer Ref = this->GetAFDB()->template GetImage (station+"_Ref"); + MaskImagePointType p_support; + MaskImagePointType p_ref; + if (station_limit == "superior") { + clitk::FindExtremaPointInAGivenDirection(Ref, GetBackgroundValue(), 2, false, p_ref); + clitk::FindExtremaPointInAGivenDirection(m_Working_Support, GetBackgroundValue(), 2, false, p_support); + } + else { + clitk::FindExtremaPointInAGivenDirection(Ref, GetBackgroundValue(), 2, true, p_ref); + clitk::FindExtremaPointInAGivenDirection(m_Working_Support, GetBackgroundValue(), 2, true, p_support); + } + std::ostringstream os; + os << "[Support] \t" << station << "\t" << station_limit << " " + << "Z = " << z << std::setprecision(2) << std::fixed + << "\tSupport = " << p_support[2] + << "\tRef = " << p_ref[2] + << "\tdiff = " << p_support[2]-p_ref[2] << "\t" + << structure << " " << structure_limit; + if (found==1) os << " (S "+file+")"; + if (found==2) os << " (Z)"; + if (found==3) os << " (P)"; + if (found==4) os << " (p)"; + if (found==5) os << " (Apex)"; + if (found==6) os << " (AorticArch)"; + StartNewStep(os.str()); + } catch(clitk::ExceptionObject e) { } + } + + // Set support + m_ListOfSupports[station] = m_Working_Support; + StopCurrentStep(m_Working_Support); } //-------------------------------------------------------------------- @@ -148,7 +241,7 @@ Support_LeftRight_S1R_S1L() std::vector B; // Search for centroid positions of trachea MaskImagePointer Trachea = this->GetAFDB()->template GetImage ("Trachea"); - MaskImagePointer S1RL = m_ListOfSupports["S1RL"]; + MaskImagePointer S1RL = m_ListOfSupports["S1R"]; Trachea = clitk::ResizeImageLike(Trachea, S1RL, GetBackgroundValue()); std::vector slices; clitk::ExtractSlices(Trachea, 2, slices); @@ -172,102 +265,20 @@ Support_LeftRight_S1R_S1L() // Right part clitk::SliceBySliceSetBackgroundFromLineSeparation(S1R, A, B, - GetBackgroundValue(), 0, -10); + GetBackgroundValue(), 0, 10); S1R = clitk::AutoCrop(S1R, GetBackgroundValue()); m_ListOfSupports["S1R"] = S1R; // Left part clitk::SliceBySliceSetBackgroundFromLineSeparation(S1L, A, B, - GetBackgroundValue(), 0, 10); + GetBackgroundValue(), 0, -10); S1L = clitk::AutoCrop(S1L, GetBackgroundValue()); m_ListOfSupports["S1L"] = S1L; + StopCurrentStep(m_ListOfSupports["S1L"]); } //-------------------------------------------------------------------- -//-------------------------------------------------------------------- -template -void -clitk::ExtractLymphStationsFilter:: -Support_SupInf_S2R_S2L() -{ - // Step : S2RL Sup-Inf limits - /* - 2R Lower border: intersection of caudal margin of innominate vein with - the trachea - 2L Lower border: superior border of the aortic arch - */ - StartNewStep("[Support] Sup-Inf S2RL"); - m_Working_Support = m_ListOfSupports["Support_Superior_to_Carina"]; - - // S2R Caudal Margin Of Left BrachiocephalicVein - MaskImagePointer BrachioCephalicVein = this->GetAFDB()->template GetImage("BrachioCephalicVein"); - MaskImagePointType p; - clitk::FindExtremaPointInAGivenDirection(BrachioCephalicVein, GetBackgroundValue(), 2, true, p); - - // I add slightly more than a slice --> NO !! - double CaudalMarginOfLeftBrachiocephalicVeinZ=p[2];//+ 1.1*m_Working_Support->GetSpacing()[2]; - - this->GetAFDB()->SetDouble("CaudalMarginOfLeftBrachiocephalicVeinZ", CaudalMarginOfLeftBrachiocephalicVeinZ); - MaskImagePointer S2R = - clitk::CropImageRemoveLowerThan(m_Working_Support, 2, - CaudalMarginOfLeftBrachiocephalicVeinZ, true, - GetBackgroundValue()); - // S2L : Top Of Aortic Arch - MaskImagePointer Aorta = this->GetAFDB()->template GetImage("Aorta"); - clitk::FindExtremaPointInAGivenDirection(Aorta, GetBackgroundValue(), 2, false, p); - - // Save the TopOfAorticArchZ - this->GetAFDB()->SetDouble("TopOfAorticArchZ", p[2]); - - // I substract slightly more than a slice to respect delineation - double TopOfAorticArchZ=p[2]- 1.1*m_Working_Support->GetSpacing()[2]; - // this->GetAFDB()->SetDouble("TopOfAorticArchZ", TopOfAorticArchZ); - - MaskImagePointer S2L = - clitk::CropImageRemoveLowerThan(m_Working_Support, 2, - TopOfAorticArchZ, true, - GetBackgroundValue()); - - /* - // S2RL: Superior support, I use inferior part of S1RL - MaskImagePointer S1L = m_ListOfSupports["S1L"]; - clitk::FindExtremaPointInAGivenDirection(S1L, GetBackgroundValue(), 2, true, p); - DD(p); - S2L = - clitk::CropImageRemoveGreaterThan(S2L, 2, - p[2], true, - GetBackgroundValue()); - - MaskImagePointer S1R = m_ListOfSupports["S1R"]; - clitk::FindExtremaPointInAGivenDirection(S1R, GetBackgroundValue(), 2, true, p); - DD(p); - S2R = - clitk::CropImageRemoveGreaterThan(S2R, 2, - p[2], true, - GetBackgroundValue()); - */ - - // Superior limits, use Sternum (but not strictly inf to S1RL - MaskImagePointer Sternum = this->GetAFDB()->template GetImage ("Sternum"); - clitk::FindExtremaPointInAGivenDirection(Sternum, GetBackgroundValue(), 2, false, p); - // Add one slice - p[2] = p[2] + m_Working_Support->GetSpacing()[2]; - S2L = - clitk::CropImageRemoveGreaterThan(S2L, 2, - p[2], true, GetBackgroundValue()); - S2R = - clitk::CropImageRemoveGreaterThan(S2R, 2, - p[2], true, GetBackgroundValue()); - - // The is the end - m_ListOfSupports["S2L"] = S2L; - m_ListOfSupports["S2R"] = S2R; -} -//-------------------------------------------------------------------- - - - //-------------------------------------------------------------------- template void @@ -295,71 +306,6 @@ Support_LeftRight_S2R_S2L() //-------------------------------------------------------------------- -//-------------------------------------------------------------------- -template -void -clitk::ExtractLymphStationsFilter:: -Support_SupInf_S4R_S4L() -{ - // --------------------------------------------------------------------------- - /* Step : S4RL Sup-Inf - - start at the end of 2R and 2L - - stop ? - - 4R - Rod says : "The inferior border is at the lower border of the azygous vein." - Rod says : difficulties - (was : "ends at the upper lobe bronchus or where the right pulmonary artery - crosses the midline of the mediastinum ") - - 4L - Rod says : "The lower border is to upper margin of the left main pulmonary artery." - (was LLL bronchus) - */ - StartNewStep("[Support] Sup-Inf limits of 4R/4L"); - - // Start from the support - MaskImagePointer S4RL = clitk::Clone(m_Working_Support); - MaskImagePointer S4R = clitk::Clone(S4RL); - MaskImagePointer S4L = clitk::Clone(S4RL); - - // Keep only what is lower than S2 - MaskImagePointer S2R = m_ListOfSupports["S2R"]; - MaskImagePointer S2L = m_ListOfSupports["S2L"]; - MaskImagePointType p; - // Right part - clitk::FindExtremaPointInAGivenDirection(S2R, GetBackgroundValue(), - 2, true, p); - S4R = clitk::CropImageRemoveGreaterThan(S4R, 2, - p[2], true, GetBackgroundValue()); - // Left part - clitk::FindExtremaPointInAGivenDirection(S2L, GetBackgroundValue(), - 2, true, p); - S4L = clitk::CropImageRemoveGreaterThan(S4L, 2, - p[2], true, GetBackgroundValue()); - - // Get AzygousVein and limit according to LowerBorderAzygousVein - MaskImagePointer LowerBorderAzygousVein - = this->GetAFDB()->template GetImage("LowerBorderAzygousVein"); - std::vector c; - clitk::ComputeCentroids(LowerBorderAzygousVein, GetBackgroundValue(), c); - S4R = clitk::CropImageRemoveLowerThan(S4R, 2, - c[1][2], true, GetBackgroundValue()); - S4R = clitk::AutoCrop(S4R, GetBackgroundValue()); - m_ListOfSupports["S4R"] = S4R; - - - // Limit according to LeftPulmonaryArtery - MaskImagePointer LeftPulmonaryArtery - = this->GetAFDB()->template GetImage("LeftPulmonaryArtery"); - clitk::FindExtremaPointInAGivenDirection(LeftPulmonaryArtery, GetBackgroundValue(), - 2, false, p); - S4L = clitk::CropImageRemoveLowerThan(S4L, 2, - p[2], true, GetBackgroundValue()); - S4L = clitk::AutoCrop(S4L, GetBackgroundValue()); - m_ListOfSupports["S4L"] = S4L; -} -//-------------------------------------------------------------------- - - //-------------------------------------------------------------------- template void @@ -486,111 +432,3 @@ Support_Post_S1S2S4() //-------------------------------------------------------------------- -//-------------------------------------------------------------------- -template -void -clitk::ExtractLymphStationsFilter:: -Support_S3P() -{ - StartNewStep("[Support] Ant limits of S3P and Post limits of S1RL, S2RL, S4RL"); - - // Initial S3P support - MaskImagePointer S3P = clitk::Clone(m_ListOfSupports["Support_Superior_to_Carina"]); - - // Stop at Lung Apex - double m_ApexOfTheChest = FindApexOfTheChest(); - S3P = - clitk::CropImageRemoveGreaterThan(S3P, 2, - m_ApexOfTheChest, true, - GetBackgroundValue()); - // Ant limits with Trachea - S3P = LimitsWithTrachea(S3P, 1, 0, 10); - m_ListOfSupports["S3P"] = S3P; -} -//-------------------------------------------------------------------- - - -//-------------------------------------------------------------------- -template -void -clitk::ExtractLymphStationsFilter:: -Support_S3A() -{ - StartNewStep("[Support] Sup-Inf and Post limits for S3A"); - - // Initial S3A support - MaskImagePointer S3A = clitk::Clone(m_ListOfSupports["Support_Superior_to_Carina"]); - - // Stop at Lung Apex or like S2/S1 (upper border Sternum - manubrium) ? - - //double m_ApexOfTheChest = FindApexOfTheChest(); - - MaskImagePointer Sternum = this->GetAFDB()->template GetImage ("Sternum"); - MaskImagePointType p; - p[0] = p[1] = p[2] = 0.0; // to avoid warning - clitk::FindExtremaPointInAGivenDirection(Sternum, GetBackgroundValue(), 2, false, p); - p[2] += Sternum->GetSpacing()[2]; // we add one slice to stop 3A at the same slice than Sternum stop - S3A = - clitk::CropImageRemoveGreaterThan(S3A, 2, - //m_ApexOfTheChest - p[2], true, - GetBackgroundValue()); - // Ant limits with Trachea - S3A = LimitsWithTrachea(S3A, 1, 0, -10); - m_ListOfSupports["S3A"] = S3A; -} -//-------------------------------------------------------------------- - - -//-------------------------------------------------------------------- -template -void -clitk::ExtractLymphStationsFilter:: -Support_S5() -{ - StartNewStep("[Support] Sup-Inf limits S5 with Aorta and MainPulmonaryArtery"); - - // Initial S5 support - MaskImagePointer S5 = - clitk::Clone(this->GetAFDB()->template GetImage("Mediastinum", true)); - - // Sup limits with Aorta - double sup = FindInferiorBorderOfAorticArch(); - - // Inf limits with "upper rim of the left main pulmonary artery" - // For the moment only, it will change. - MaskImagePointer MainPulmonaryArtery = this->GetAFDB()->template GetImage("MainPulmonaryArtery"); - MaskImagePointType p; - p[0] = p[1] = p[2] = 0.0; // to avoid warning - clitk::FindExtremaPointInAGivenDirection(MainPulmonaryArtery, GetBackgroundValue(), 2, false, p); - p[2] += MainPulmonaryArtery->GetSpacing()[2]; - - // Cut Sup/Inf - S5 = clitk::CropImageAlongOneAxis(S5, 2, p[2], sup, true, GetBackgroundValue()); - - m_ListOfSupports["S5"] = S5; -} -//-------------------------------------------------------------------- - -//-------------------------------------------------------------------- -template -void -clitk::ExtractLymphStationsFilter:: -Support_S6() -{ - StartNewStep("[Support] Sup-Inf limits S6 with aorta"); - - // Initial S6 support like S3A - MaskImagePointer S6 = clitk::Clone(m_ListOfSupports["S3A"]); - - // Inf Sup limits with Aorta - double sup = FindSuperiorBorderOfAorticArch(); - double inf = FindInferiorBorderOfAorticArch(); - - // Cut Sup/Inf - S6 = clitk::CropImageAlongOneAxis(S6, 2, inf, sup, true, GetBackgroundValue()); - - m_ListOfSupports["S6"] = S6; -} -//-------------------------------------------------------------------- - diff --git a/segmentation/clitkExtractLymphStations.cxx b/segmentation/clitkExtractLymphStations.cxx index ec41a4e..25b5289 100644 --- a/segmentation/clitkExtractLymphStations.cxx +++ b/segmentation/clitkExtractLymphStations.cxx @@ -38,6 +38,7 @@ int main(int argc, char * argv[]) filter->Update(); } catch(std::runtime_error e) { std::cout << e.what() << std::endl; + return EXIT_FAILURE; } return EXIT_SUCCESS; diff --git a/segmentation/clitkExtractLymphStations.ggo b/segmentation/clitkExtractLymphStations.ggo index b583e7d..457f64e 100644 --- a/segmentation/clitkExtractLymphStations.ggo +++ b/segmentation/clitkExtractLymphStations.ggo @@ -3,26 +3,30 @@ package "clitkExtractLymphStations" version "1.0" purpose "Extract LymphStations with help of TODO" -option "config" - "Config file" string no -option "imagetypes" - "Display allowed image types" flag off -option "verbose" v "Verbose" flag off -option "verboseStep" - "Verbose each step" flag off -option "writeStep" w "Write image at each step" flag off -option "verboseOption" - "Display options values" flag off -option "verboseWarningOff" - "Do not display warning" flag off -option "verboseMemory" - "Display memory usage" flag off +option "config" - "Config file" string no +option "imagetypes" - "Display allowed image types" flag off +option "verbose" v "Verbose" flag off +option "verboseStep" - "Verbose each step" flag off +option "writeStep" w "Write image at each step" flag off +option "verboseOption" - "Display options values" flag off +option "verboseWarningOff" - "Do not display warning" flag off +option "verboseMemory" - "Display memory usage" flag off section "I/O" -option "afdb" a "Input Anatomical Feature DB" string no -option "afdb_path" p "Input path for image in AFDB" string no -option "input" i "Input filename" string no -option "output" o "Output lungs mask filename" string no +option "afdb" a "Input Anatomical Feature DB" string no +option "afdb_path" p "Input path for image in AFDB" string default="./" no +option "input" i "Input filename" string no +option "support_limits" - "Filename to read the support limits" string yes +option "check_support_limits" - "Display stat on the support limits" flag off +option "output" o "Output lungs mask filename" string no section "Options for all stations" -option "station" - "Force to compute station even if already exist in the DB" string no multiple -option "nosupport" - "Do not recompute the station supports if already available" flag off -option "relpos" - "List of filenames for relativeposition operations" string no multiple +option "force_support" - "Force to compute all supports even if already available" flag off +option "station" - "Force to compute this station even if already exist in the DB" string no multiple +option "relpos" - "List of filenames for relativeposition operations" string no multiple + + # section "Options for Station 3A" # section "Options for Station 2RL" diff --git a/segmentation/clitkExtractLymphStationsFilter.h b/segmentation/clitkExtractLymphStationsFilter.h index b7b8c3b..080bdb7 100644 --- a/segmentation/clitkExtractLymphStationsFilter.h +++ b/segmentation/clitkExtractLymphStationsFilter.h @@ -21,12 +21,31 @@ // clitk #include "clitkStructuresExtractionFilter.h" +#include "clitkLabelImageOverlapMeasureFilter.h" // vtk #include namespace clitk { + class SupportLimitsType { + public: + std::string station_limit; + std::string station; + std::string structure_limit; + std::string structure; + double offset; + void Read(istream & is) { + is >> station_limit; + is >> station; + is >> structure_limit; + is >> structure; + std::string s; + is >> s; + offset = atof(s.c_str()); + } + }; + //-------------------------------------------------------------------- /* Try to extract the LymphStations part of a thorax CT. @@ -106,9 +125,16 @@ namespace clitk { double GetFuzzyThreshold(std::string station, std::string tag); void SetThreshold(std::string station, std::string tag, double value); double GetThreshold(std::string station, std::string tag); - itkGetConstMacro(ComputeStationsSupportsFlag, bool); - itkSetMacro(ComputeStationsSupportsFlag, bool); - itkBooleanMacro(ComputeStationsSupportsFlag); + itkGetConstMacro(ForceSupportsFlag, bool); + itkSetMacro(ForceSupportsFlag, bool); + itkBooleanMacro(ForceSupportsFlag); + + itkGetConstMacro(CheckSupportFlag, bool); + itkSetMacro(CheckSupportFlag, bool); + itkBooleanMacro(CheckSupportFlag); + + itkGetConstMacro(SupportLimitsFilename, std::string); + itkSetMacro(SupportLimitsFilename, std::string); protected: ExtractLymphStationsFilter(); @@ -137,9 +163,18 @@ namespace clitk { MaskImagePixelType m_BackgroundValue; MaskImagePixelType m_ForegroundValue; std::map m_ComputeStationMap; + std::string m_SupportLimitsFilename; + std::vector m_ListOfSupportLimits; bool CheckForStation(std::string station); void Remove_Structures(std::string station, std::string s); + void WriteImageSupport(std::string support); + void WriteImageStation(std::string station); + void ComputeOverlapWithRef(std::string station); + void Support_SI_Limit(const std::string station_limit, const std::string station, + const std::string structure_limit, const std::string structure, + const double offset); + void ReadSupportLimits(std::string filename); // Functions common to several stations double FindCarina(); @@ -159,17 +194,10 @@ namespace clitk { // Station's supports void ExtractStationSupports(); - void Support_SupInf_S1RL(); void Support_LeftRight_S1R_S1L(); - void Support_SupInf_S2R_S2L(); void Support_LeftRight_S2R_S2L(); - void Support_SupInf_S4R_S4L(); void Support_LeftRight_S4R_S4L(); void Support_Post_S1S2S4(); - void Support_S3P(); - void Support_S3A(); - void Support_S5(); - void Support_S6(); MaskImagePointer LimitsWithTrachea(MaskImageType * input, int extremaDirection, int lineDirection, @@ -226,7 +254,8 @@ namespace clitk { // Station 4RL void ExtractStation_4RL_SetDefaultValues(); - void ExtractStation_4RL(); + void ExtractStation_4L(); + void ExtractStation_4R(); void ExtractStation_S4L_S5_Limits_Aorta_LeftPulmonaryArtery(int KeepPoint); // Station 5 @@ -249,7 +278,8 @@ namespace clitk { void ExtractStation_7_Posterior_Limits(); void ExtractStation_7_Remove_Structures(); bool m_S7_UseMostInferiorPartOnlyFlag; - bool m_ComputeStationsSupportsFlag; + bool m_ForceSupportsFlag; + bool m_CheckSupportFlag; MaskImagePointer m_Working_Trachea; MaskImagePointer m_LeftBronchus; MaskImagePointer m_RightBronchus; diff --git a/segmentation/clitkExtractLymphStationsFilter.txx b/segmentation/clitkExtractLymphStationsFilter.txx index 6686923..68b81ee 100644 --- a/segmentation/clitkExtractLymphStationsFilter.txx +++ b/segmentation/clitkExtractLymphStationsFilter.txx @@ -55,7 +55,9 @@ ExtractLymphStationsFilter(): this->SetNumberOfRequiredInputs(1); SetBackgroundValue(0); SetForegroundValue(1); - ComputeStationsSupportsFlagOn(); + ForceSupportsFlagOn(); + SetSupportLimitsFilename("none"); + CheckSupportFlagOff(); // Default values ExtractStation_3P_SetDefaultValues(); @@ -84,34 +86,39 @@ GenerateOutputInformation() { m_Mediastinum = this->GetAFDB()->template GetImage ("Mediastinum"); // Clean some computer landmarks to force the recomputation + // FIXME -> to put elsewhere ? this->GetAFDB()->RemoveTag("AntPostVesselsSeparation"); - // Global supports for stations + // Must I compute the supports ? bool supportsExist = true; - try { - m_ListOfSupports["S1R"] = this->GetAFDB()->template GetImage("Support_S1R"); - m_ListOfSupports["S1L"] = this->GetAFDB()->template GetImage("Support_S1L"); - m_ListOfSupports["S2R"] = this->GetAFDB()->template GetImage("Support_S2R"); - m_ListOfSupports["S2L"] = this->GetAFDB()->template GetImage("Support_S2L"); - m_ListOfSupports["S4R"] = this->GetAFDB()->template GetImage("Support_S4R"); - m_ListOfSupports["S4L"] = this->GetAFDB()->template GetImage("Support_S4L"); - - m_ListOfSupports["S3A"] = this->GetAFDB()->template GetImage("Support_S3A"); - m_ListOfSupports["S3P"] = this->GetAFDB()->template GetImage("Support_S3P"); - m_ListOfSupports["S5"] = this->GetAFDB()->template GetImage("Support_S5"); - m_ListOfSupports["S6"] = this->GetAFDB()->template GetImage("Support_S6"); - m_ListOfSupports["S7"] = this->GetAFDB()->template GetImage("Support_S7"); - m_ListOfSupports["S8"] = this->GetAFDB()->template GetImage("Support_S8"); - m_ListOfSupports["S9"] = this->GetAFDB()->template GetImage("Support_S9"); - m_ListOfSupports["S10"] = this->GetAFDB()->template GetImage("Support_S10"); - m_ListOfSupports["S11"] = this->GetAFDB()->template GetImage("Support_S11"); - } catch(clitk::ExceptionObject o) { - supportsExist = false; + if (!GetForceSupportsFlag()) { + try { + m_ListOfSupports["S1R"] = this->GetAFDB()->template GetImage("Support_S1R"); + m_ListOfSupports["S1L"] = this->GetAFDB()->template GetImage("Support_S1L"); + m_ListOfSupports["S2R"] = this->GetAFDB()->template GetImage("Support_S2R"); + m_ListOfSupports["S2L"] = this->GetAFDB()->template GetImage("Support_S2L"); + m_ListOfSupports["S4R"] = this->GetAFDB()->template GetImage("Support_S4R"); + m_ListOfSupports["S4L"] = this->GetAFDB()->template GetImage("Support_S4L"); + + m_ListOfSupports["S3A"] = this->GetAFDB()->template GetImage("Support_S3A"); + m_ListOfSupports["S3P"] = this->GetAFDB()->template GetImage("Support_S3P"); + m_ListOfSupports["S5"] = this->GetAFDB()->template GetImage("Support_S5"); + m_ListOfSupports["S6"] = this->GetAFDB()->template GetImage("Support_S6"); + m_ListOfSupports["S7"] = this->GetAFDB()->template GetImage("Support_S7"); + m_ListOfSupports["S8"] = this->GetAFDB()->template GetImage("Support_S8"); + m_ListOfSupports["S9"] = this->GetAFDB()->template GetImage("Support_S9"); + m_ListOfSupports["S10"] = this->GetAFDB()->template GetImage("Support_S10"); + m_ListOfSupports["S11"] = this->GetAFDB()->template GetImage("Support_S11"); + } catch(clitk::ExceptionObject o) { + supportsExist = false; + } } - if (!supportsExist || GetComputeStationsSupportsFlag()) { + if (!supportsExist || GetForceSupportsFlag()) { this->StartNewStep("Supports for stations"); this->StartSubStep(); + + // FIXME : why should I remove theses tags ??? this->GetAFDB()->RemoveTag("CarinaZ"); this->GetAFDB()->RemoveTag("ApexOfTheChestZ"); this->GetAFDB()->RemoveTag("ApexOfTheChest"); @@ -130,11 +137,12 @@ GenerateOutputInformation() { ExtractStation_2RL(); ExtractStation_3P(); ExtractStation_3A(); - ExtractStation_4RL(); + ExtractStation_4R(); + ExtractStation_4L(); ExtractStation_5(); ExtractStation_6(); - // ---------- TODO ----------------------- + // ---------- todo ----------------------- // Extract Station8 // ExtractStation_8(); @@ -165,7 +173,7 @@ void clitk::ExtractLymphStationsFilter:: GenerateData() { // Final Step -> graft output (if SetNthOutput => redo) - this->GraftOutput(m_ListOfStations["8"]); + // this->GraftOutput(m_ListOfStations["8"]); } //-------------------------------------------------------------------- @@ -180,25 +188,29 @@ CheckForStation(std::string station) std::string s = "Station"+station; + // Define the starting support + // if (GetComputeStation(station)) { + // std::cout << "Station " << station << " already exists, but re-computation forced." << std::endl; + // } + if (GetComputeStation(station)) { + m_Working_Support = m_Mediastinum = this->GetAFDB()->template GetImage("Mediastinum", true); + return true; + } + else return false; + // else { + // std::cout << "Station " << station << " found. I used it" << std::endl; + // return false; + // } + // Check if station already exist in DB + + // FIXME -> do nothing if not on the command line. Is it what I want ? bool found = false; if (this->GetAFDB()->TagExist(s)) { m_ListOfStations[station] = this->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 = this->GetAFDB()->template GetImage("Mediastinum", true); - return true; - } - else { - std::cout << "Station " << station << " found. I used it" << std::endl; - return false; - } } //-------------------------------------------------------------------- @@ -471,6 +483,8 @@ FindApexOfTheChest() z = this->GetAFDB()->GetDouble("ApexOfTheChestZ"); } catch(clitk::ExceptionObject e) { + + /* //DD("FindApexOfTheChestPosition"); MaskImagePointer Lungs = this->GetAFDB()->template GetImage("Lungs"); MaskImagePointType p; @@ -486,6 +500,23 @@ FindApexOfTheChest() this->GetAFDB()->SetDouble("ApexOfTheChestZ", p[2]); this->WriteAFDB(); z = p[2]; + */ + + // the superior border becomes the more inferior of the two apices + MaskImagePointer RightLung = this->GetAFDB()->template GetImage("RightLung"); + MaskImagePointer LeftLung = this->GetAFDB()->template GetImage("LeftLung"); + MaskImagePointType pr; + MaskImagePointType pl; + clitk::FindExtremaPointInAGivenDirection(RightLung, GetBackgroundValue(), 2, false, pr); + clitk::FindExtremaPointInAGivenDirection(LeftLung, GetBackgroundValue(), 2, false, pl); + // We dont need Lungs structure from now + this->GetAFDB()->template ReleaseImage("RightLung"); + this->GetAFDB()->template ReleaseImage("LeftLung"); + // Put inside the AFDB + if (pr[2] < pl[2]) z = pr[2]; + else z = pl[2]; + this->GetAFDB()->SetDouble("ApexOfTheChestZ", z); + this->WriteAFDB(); } return z; } @@ -1383,6 +1414,65 @@ FindAntPostVessels2() } //-------------------------------------------------------------------- +//-------------------------------------------------------------------- +template +void +clitk::ExtractLymphStationsFilter:: +WriteImageSupport(std::string support) +{ + writeImage(m_ListOfSupports[support], this->GetAFDBPath()+"/"+"seg/Support_"+support+".mha"); + this->GetAFDB()->SetImageFilename("Support_"+support, "seg/Support_"+support+".mha"); +} +//-------------------------------------------------------------------- +//-------------------------------------------------------------------- +template +void +clitk::ExtractLymphStationsFilter:: +WriteImageStation(std::string station) +{ + writeImage(m_ListOfStations[station], GetAFDB()->GetPath()+"/seg/Station"+station+".mha"); + GetAFDB()->SetImageFilename("Station"+station, "seg/Station"+station+".mha"); + WriteAFDB(); +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +template +void +clitk::ExtractLymphStationsFilter:: +ComputeOverlapWithRef(std::string station) +{ + if (GetComputeStation(station)) { + MaskImagePointer ref = this->GetAFDB()->template GetImage ("Station"+station+"_Ref"); + typedef clitk::LabelImageOverlapMeasureFilter FilterType; + typename FilterType::Pointer filter = FilterType::New(); + filter->SetInput(0, m_ListOfStations[station]); + filter->SetInput(1, ref); + filter->Update(); + } +} +//-------------------------------------------------------------------- + +//-------------------------------------------------------------------- +template +void +clitk::ExtractLymphStationsFilter:: +ReadSupportLimits(std::string filename) +{ + m_ListOfSupportLimits.clear(); + ifstream is; + openFileForReading(is, filename); + while (is) { + skipComment(is); + SupportLimitsType s; + s.Read(is); + if (is) m_ListOfSupportLimits.push_back(s); + } +} +//-------------------------------------------------------------------- + #endif //#define CLITKBOOLEANOPERATORLABELIMAGEFILTER_TXX + diff --git a/segmentation/clitkExtractLymphStationsGenericFilter.txx b/segmentation/clitkExtractLymphStationsGenericFilter.txx index a8c3ec1..a27b4a6 100644 --- a/segmentation/clitkExtractLymphStationsGenericFilter.txx +++ b/segmentation/clitkExtractLymphStationsGenericFilter.txx @@ -68,9 +68,10 @@ SetOptionsFromArgsInfoToFilter(FilterType * f) f->SetWriteStepFlag(mArgsInfo.writeStep_flag); f->SetVerboseMemoryFlag(mArgsInfo.verboseMemory_flag); f->SetAFDBFilename(mArgsInfo.afdb_arg); - f->SetAFDBPath(mArgsInfo.afdb_path_arg); - - f->SetComputeStationsSupportsFlag(!mArgsInfo.nosupport_flag); + if (mArgsInfo.afdb_path_given) f->SetAFDBPath(mArgsInfo.afdb_path_arg); + f->SetForceSupportsFlag(mArgsInfo.force_support_flag); + f->SetSupportLimitsFilename(mArgsInfo.support_limits_arg); + f->SetCheckSupportFlag(mArgsInfo.check_support_limits_flag); // Station 8 //f->SetDistanceMaxToAnteriorPartOfTheSpine(mArgsInfo.S8_maxAntSpine_arg);