From: David Sarrut Date: Wed, 5 Oct 2011 09:04:11 +0000 (+0200) Subject: Station 4RL is not ok X-Git-Tag: v1.3.0~202 X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?a=commitdiff_plain;h=b27eb1982254cc53df1d032413317ce6c7f0556a;p=clitk.git Station 4RL is not ok --- diff --git a/segmentation/clitkExtractLymphStation_4RL.txx b/segmentation/clitkExtractLymphStation_4RL.txx index 462ae9d..1520187 100644 --- a/segmentation/clitkExtractLymphStation_4RL.txx +++ b/segmentation/clitkExtractLymphStation_4RL.txx @@ -1,59 +1,11 @@ + + //-------------------------------------------------------------------- -template +template void -clitk::ExtractLymphStationsFilter:: -ExtractStation_4RL_SI_Limits() +clitk::ExtractLymphStationsFilter:: +ExtractStation_4RL_SetDefaultValues() { - - /* - Station 4R: right lower paratracheal nodes From superior to - inferior, the delineation of Station 4R starts at the top of the - aortic arch (Fig. 2D) and ends at the upper lobe bronchus or where the - right pulmonary artery crosses the midline of the mediastinum - (Fig. 3E,F). On the left side, Station 4R is defined by the midline of - the trachea (Fig. 2D). On the right side, it is contained within the - pleural envelope in the upper part, medial to the superior vena cava - and the arch of the azygos vein in the intermediate section (Fig. 2I - and 3A,B) and the right upper lobe pulmonary vein in its very caudal - part. Anteriorly, it is limited most supe- riorly by the right - brachiocephalic vein (Fig. 2D–H), fol- lowed by the superior vena cava - and the arch or ascending section of the aorta (Figs. 2I and 3A–E). In - between the superior vena cava and the aorta, we recommend delineating - Station 4R so that it extends halfway between the two vessels where it - will contact Station 3A or 6 (Figs. 2H,I and 3A–D). Posteriorly, - Station 4R is defined at its superior extent by an imaginary horizontal - line running along the posterior wall of the trachea - (Fig. 2E). Inferiorly, it remains anterior to the right main stem - bronchus, filling the soft- tissue space between the vessels. - */ - - StartNewStep("[Station 4R]Inf/Sup mediastinum limits with aortic arch/upperLBronchus"); - /* SupInf limits : - - top of aortic arch - - ends at the upper lobe bronchus or where the right pulmonary artery crosses the midline of the mediastinum - */ - - // Local variables - double m_TopOfAorticArchInMM; - double m_UpperLobeBronchusZPositionInMM; - double m_RightPulmoArteyrCrossesMidMediastinumZPositionInMM; - - // Get Inputs - m_TopOfAorticArchInMM = GetAFDB()->GetPoint3D("TopOfAorticArch", 2); - DD(m_TopOfAorticArchInMM); - m_UpperLobeBronchusZPositionInMM = GetAFDB()->GetPoint3D("RightUpperLobeBronchus", 2); - DD(m_UpperLobeBronchusZPositionInMM); - m_RightPulmoArteyrCrossesMidMediastinumZPositionInMM = GetAFDB()->GetPoint3D("RightPulmoArteryCrossesMidMediastinum", 2); - DD(m_RightPulmoArteyrCrossesMidMediastinumZPositionInMM); - - /* Crop support */ - double inf = std::max(m_UpperLobeBronchusZPositionInMM, m_RightPulmoArteyrCrossesMidMediastinumZPositionInMM); - m_Working_Support = - clitk::CropImageAlongOneAxis(m_Mediastinum, 2, - inf, - m_TopOfAorticArchInMM, true, - GetBackgroundValue()); - StopCurrentStep(m_Working_Support); } //-------------------------------------------------------------------- @@ -62,219 +14,41 @@ ExtractStation_4RL_SI_Limits() template void clitk::ExtractLymphStationsFilter:: -ExtractStation_4RL_LR_Limits() -{ - // 4R first - - // Left : midline of the trachea - // Right : "- upper part : contained within the pleural envelope - //- intermediate section : medial to the superior vena cava and the arch of the azygos vein - // - very caudal part : right upper lobe pulmonary vein" - // AAV ?? - - // Left -> midline of the trachea - // slice by slice, find X coord of 2D centroid (?) - // check with previous line in order to not move too fast - - - // ---------------------------------------------------------- - StartNewStep("[Station 4R] Left limits with midline of trachea "); +ExtractStation_4RL() { + if ((!CheckForStation("4R")) && (!CheckForStation("4L"))) return; + + StartNewStep("Stations 4RL"); + StartSubStep(); + + // Get the current support + StartNewStep("[Station 4RL] Get the current 4RL suppport"); + m_ListOfStations["4R"] = m_ListOfSupports["S4R"]; + m_ListOfStations["4L"] = m_ListOfSupports["S4L"]; + StopCurrentStep(m_ListOfStations["4R"]); + + // Generic RelativePosition processes + m_ListOfStations["4R"] = this->ApplyRelativePositionList("Station_4R", m_ListOfStations["4R"]); + m_ListOfStations["4L"] = this->ApplyRelativePositionList("Station_4L", m_ListOfStations["4L"]); + + // Separation Ant/Post + m_Working_Support = m_ListOfStations["4L"]; + ExtractStation_S4L_S5_Limits_Aorta_LeftPulmonaryArtery(10); + m_ListOfStations["4L"] = m_Working_Support; - /* - Two possible approaches - 1) use trachea skeleton (clitkExtractAirwaysTreeInfo) - -> but need to analyse the tree to remove "false" bifurcation - -> need to track from top to bottom, with each bronchus - -> how to stay on the main path ? - - 2) analyse slice by slice the trachea, labelize and take the first - or two first connected components -> find centroids. - -> not really "smooth" when bronchus slicing lead to "splated" region - - ==> we choose 2 - */ - - // Crop the trachea like the current support - MaskImagePointer Trachea = GetAFDB()->template GetImage ("Trachea"); - MaskImagePointer crop_trachea = - clitk::ResizeImageLike(Trachea, m_Working_Support, GetBackgroundValue()); - writeImage(crop_trachea, "croptrachea.mhd"); - - // Extract all the slices - std::vector bronchi_slices; - clitk::ExtractSlices(crop_trachea, 2, bronchi_slices); - - // List of midpoints - std::vector midpoints; - - // Add mid points below carina, from foot to head - for(uint i=0; iGetLargestPossibleRegion().GetIndex(); - for(uint i=0; i<3; i++) { - p[i] += Trachea->GetLargestPossibleRegion().GetSize()[i]; - } - MaskImagePointType q; - Trachea->TransformIndexToPhysicalPoint(p, q); - double maxZ = q[2]; - double m_CarinaZ = GetAFDB()->GetPoint3D("Carina", 2); - MaskImagePointer m_above_carina = - clitk::CropImageAlongOneAxis(Trachea, 2, - m_CarinaZ, - maxZ, true, - GetBackgroundValue()); - writeImage(m_above_carina, "above.mhd"); - - // Extract all the slices - std::vector trachea_slices; - clitk::ExtractSlices(m_above_carina, 2, trachea_slices); - - // Find centroid of the trachea in each slice - std::vector points; - typedef typename MaskSliceType::PointType SlicePointType; - SlicePointType previous; - // Start from patient top (head) - for(uint i=0; i(trachea_slices[i], GetBackgroundValue(), true, 10); - // Get centroid - std::vector c; - clitk::ComputeCentroids(trachea_slices[i], GetBackgroundValue(), c); - // Keep first one (first connected component label) and convert to 3D - MaskImagePointType p; - p[2] = m_above_carina->GetOrigin()[2] + i*m_above_carina->GetSpacing()[2]; - p[0] = c[1][0]; - p[1] = c[1][1]; - midpoints.push_back(p); - } - - // DEBUG POINTS - std::ofstream osp; - openFileForWriting(osp, "mp.txt"); - osp << "LANDMARKS1" << std::endl; - for(uint i=0; i(m_Working_Support); - m_RightSupport = clitk::NewImageLike(m_Working_Support); - - // Loop on current support, slice by slice - typedef itk::ImageSliceIteratorWithIndex SliceIteratorType; - SliceIteratorType iter = SliceIteratorType(m_Working_Support, - m_Working_Support->GetLargestPossibleRegion()); - SliceIteratorType iterL = SliceIteratorType(m_LeftSupport, - m_LeftSupport->GetLargestPossibleRegion()); - SliceIteratorType iterR = SliceIteratorType(m_RightSupport, - m_RightSupport->GetLargestPossibleRegion()); - iter.SetFirstDirection(0); - iter.SetSecondDirection(1); - iter.GoToBegin(); - iterL.SetFirstDirection(0); - iterL.SetSecondDirection(1); - iterL.GoToBegin(); - iterR.SetFirstDirection(0); - iterR.SetSecondDirection(1); - iterR.GoToBegin(); - - int slice=0; - // Assert starting of image has the same Z than first midpoints - while (midpoints[slice][2] != m_Working_Support->GetOrigin()[2]) { - slice++; - if ((uint)slice >= midpoints.size()) { - clitkExceptionMacro("Bug while searching for first midpoint to use"); - } - } - - // Start loop - while (!iter.IsAtEnd()) { - ImageIndexType index; - m_Working_Support->TransformPhysicalPointToIndex(midpoints[slice], index); - while (!iter.IsAtEndOfSlice()) { - // convert into index - while (!iter.IsAtEndOfLine()) { - // if indexcourant (m_LeftSupport, GetBackgroundValue()); - m_RightSupport = clitk::AutoCrop(m_RightSupport, GetBackgroundValue()); - writeImage(m_LeftSupport, "lsac.mhd"); - writeImage(m_RightSupport, "rsac.mhd"); - - StopCurrentStep(m_RightSupport); - - // ------------------------------------------------------------------------- - // Constraint at right from the SVC. Must be after MidTrachea limits - // (if not, bronchus can be split, midposition is false) - StartNewStep("[Station 4R] R limits with SVC "); - MaskImagePointer svc = GetAFDB()->template GetImage("SVC"); - typedef clitk::AddRelativePositionConstraintToLabelImageFilter RelPosFilterType; - typename RelPosFilterType::Pointer relPosFilter = RelPosFilterType::New(); - /* relPosFilter->SetVerboseStep(false); - relPosFilter->SetInput(m_RightSupport); // only right here ... - relPosFilter->SetInputObject(svc); - relPosFilter->SetOrientationType(RelPosFilterType::RightTo); - relPosFilter->SetIntermediateSpacing(2); - relPosFilter->SetFuzzyThreshold(0.3); - relPosFilter->Update(); - m_RightSupport = relPosFilter->GetOutput(); - */ - - /* - ==> TODO RIGHT TO MEDIAL TO SVC : - get centroid, cut in X direction to get medial - - ==> REDO OPERATOR to find extrma points ? - centroid or skeleton ? - - */ - - relPosFilter = RelPosFilterType::New(); - relPosFilter->VerboseStepFlagOff(); - relPosFilter->SetInput(m_RightSupport); // only right here ... - relPosFilter->SetInputObject(svc); - relPosFilter->AddOrientationType(RelPosFilterType::AntTo); - relPosFilter->InverseOrientationFlagOn(); - relPosFilter->SetIntermediateSpacing(2); // this is important to put it low - relPosFilter->SetFuzzyThreshold(0.6); - relPosFilter->Update(); - m_RightSupport = relPosFilter->GetOutput(); - - // AutoCrop - m_RightSupport = clitk::AutoCrop(m_RightSupport, GetBackgroundValue()); + // Keep only one single CCL by slice + StartNewStep("[Station 4L] Keep only one CCL by slice"); + m_ListOfStations["4L"] = SliceBySliceKeepMainCCL(m_ListOfStations["4L"], + GetBackgroundValue(), + GetForegroundValue()); + StopCurrentStep(m_ListOfStations["4L"]); + + // Store image filenames into AFDB + writeImage(m_ListOfStations["4R"], "seg/Station4R.mhd"); + writeImage(m_ListOfStations["4L"], "seg/Station4L.mhd"); + GetAFDB()->SetImageFilename("Station4R", "seg/Station4R.mhd"); + GetAFDB()->SetImageFilename("Station4L", "seg/Station4L.mhd"); + WriteAFDB(); + StopSubStep(); } //-------------------------------------------------------------------- @@ -284,37 +58,82 @@ ExtractStation_4RL_LR_Limits() template void clitk::ExtractLymphStationsFilter:: -ExtractStation_4RL_AP_Limits() +ExtractStation_S4L_S5_Limits_Aorta_LeftPulmonaryArtery(int KeepPoint) { + // ---------------------------------------------------------- + StartNewStep("[Station 4L] Limits between Asc and Desc Aorta, and with LeftPulmonaryArtery "); + + // Separate Aorta into DescendingAorta AscendingAorta + MaskImagePointer AscendingAorta = GetAFDB()->template GetImage("AscendingAorta"); + MaskImagePointer DescendingAorta = GetAFDB()->template GetImage("DescendingAorta"); + + // Crop like support (inferiorly) + m_Working_Support = clitk::AutoCrop(m_Working_Support, GetBackgroundValue()); + AscendingAorta = + clitk::ResizeImageLike(AscendingAorta, m_Working_Support, GetBackgroundValue()); + DescendingAorta = + clitk::ResizeImageLike(DescendingAorta, m_Working_Support, GetBackgroundValue()); + + // Crop superior part (when AscendingAorta and DescendingAorta join) + MaskImagePointType p; + clitk::FindExtremaPointInAGivenDirection(AscendingAorta, + GetBackgroundValue(), 2, false, p); + double max = p[2]+AscendingAorta->GetSpacing()[2]; + AscendingAorta = + clitk::CropImageRemoveGreaterThan(AscendingAorta, 2, max, false, GetBackgroundValue()); + DescendingAorta = + clitk::CropImageRemoveGreaterThan(DescendingAorta, 2, max, false, GetBackgroundValue()); + + // Crop inferior part, where LeftPulmonaryArtery start + MaskImagePointer AscendingAortaCopy = clitk::Clone(AscendingAorta); + MaskImagePointer LeftPulmonaryArtery = GetAFDB()->template GetImage("LeftPulmonaryArtery"); + clitk::FindExtremaPointInAGivenDirection(LeftPulmonaryArtery, + GetBackgroundValue(), 2, false, p); + max = p[2]+LeftPulmonaryArtery->GetSpacing()[2]; + AscendingAorta = + clitk::CropImageRemoveLowerThan(AscendingAorta, 2, max, false, GetBackgroundValue()); + DescendingAorta = + clitk::CropImageRemoveLowerThan(DescendingAorta, 2, max, false, GetBackgroundValue()); + + // Find closest points + std::vector A; + std::vector B; + clitk::SliceBySliceBuildLineSegmentAccordingToMinimalDistanceBetweenStructures(AscendingAorta, + DescendingAorta, + GetBackgroundValue(), + 2, A, B); + // Separate according to AB lines + // clitk::WriteListOfLandmarks(A, "A.txt"); + // clitk::WriteListOfLandmarks(B, "B.txt"); + clitk::SliceBySliceSetBackgroundFromLineSeparation(m_Working_Support, A, B, + GetBackgroundValue(), + 1, KeepPoint); // Keep point along axis 1 + + // Now, same principle between AscendingAorta and LeftPulmonaryArtery + AscendingAorta = + clitk::ResizeImageLike(AscendingAortaCopy, m_Working_Support, GetBackgroundValue()); + LeftPulmonaryArtery = + clitk::ResizeImageLike(LeftPulmonaryArtery, m_Working_Support, GetBackgroundValue()); + AscendingAorta = + clitk::CropImageRemoveGreaterThan(AscendingAorta, 2, max, false, GetBackgroundValue()); + LeftPulmonaryArtery = + clitk::CropImageRemoveGreaterThan(LeftPulmonaryArtery, 2, max, false, GetBackgroundValue()); + A.clear(); + B.clear(); + clitk::SliceBySliceBuildLineSegmentAccordingToMinimalDistanceBetweenStructures(AscendingAorta, + LeftPulmonaryArtery, + GetBackgroundValue(), + 2, A, B); + clitk::SliceBySliceSetBackgroundFromLineSeparation(m_Working_Support, A, B, + GetBackgroundValue(), + 1, KeepPoint); // Keep point along axis 1 - /* - post of S4R - - sup part -> cut line post wall trachea - - inf part (where ???) -> remains anterior to the right main stem bronchus - ==> bo - */ - - // Post (not Ant) to Aorta - MaskImagePointer aorta = GetAFDB()->template GetImage("Aorta"); - // Crop according to current support - aorta = clitk::ResizeImageLike(aorta, m_RightSupport, GetBackgroundValue()); - typedef clitk::AddRelativePositionConstraintToLabelImageFilter RelPosFilterType; - typename RelPosFilterType::Pointer relPosFilter = RelPosFilterType::New(); - relPosFilter = RelPosFilterType::New(); - relPosFilter->VerboseStepFlagOff(); - relPosFilter->SetInput(m_RightSupport); // only right here ... - relPosFilter->SetInputObject(aorta); - relPosFilter->AddOrientationType(RelPosFilterType::PostTo); - // relPosFilter->NotFlagOn(); - relPosFilter->SetIntermediateSpacing(2); // this is important to put it low - relPosFilter->SetFuzzyThreshold(0.6); - relPosFilter->Update(); - m_RightSupport = relPosFilter->GetOutput(); - - m_ListOfStations["4R"] = m_RightSupport; - StopCurrentStep(m_RightSupport); + // AutoCrop + m_Working_Support = clitk::AutoCrop(m_Working_Support, GetBackgroundValue()); - // POST -> horizontal lines bronchus --> points dectection in S7 to store. + // End + StopCurrentStep(m_Working_Support); } //-------------------------------------------------------------------- +