X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?a=blobdiff_plain;f=segmentation%2FclitkExtractLymphStation_4RL.txx;h=462ae9d34e142a7d8a40f1ec7168166730dabfce;hb=9a79f8cf7020e0a7ed5b1b97293bfa13a3a27b58;hp=a4478a6c4621a1b69804e9e8a9ef4e732b520ef3;hpb=5ff46b355b778ae675ca60085430c062ea6a3945;p=clitk.git diff --git a/segmentation/clitkExtractLymphStation_4RL.txx b/segmentation/clitkExtractLymphStation_4RL.txx index a4478a6..462ae9d 100644 --- a/segmentation/clitkExtractLymphStation_4RL.txx +++ b/segmentation/clitkExtractLymphStation_4RL.txx @@ -4,9 +4,33 @@ void clitk::ExtractLymphStationsFilter:: ExtractStation_4RL_SI_Limits() { + + /* + 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 + - top of aortic arch + - ends at the upper lobe bronchus or where the right pulmonary artery crosses the midline of the mediastinum */ // Local variables @@ -15,24 +39,21 @@ ExtractStation_4RL_SI_Limits() double m_RightPulmoArteyrCrossesMidMediastinumZPositionInMM; // Get Inputs - m_TopOfAorticArchInMM = GetAFDB()->GetPoint3D("topOfAorticArch", 2); + m_TopOfAorticArchInMM = GetAFDB()->GetPoint3D("TopOfAorticArch", 2); DD(m_TopOfAorticArchInMM); - m_UpperLobeBronchusZPositionInMM = GetAFDB()->GetPoint3D("rightUpperLobeBronchus", 2); + m_UpperLobeBronchusZPositionInMM = GetAFDB()->GetPoint3D("RightUpperLobeBronchus", 2); DD(m_UpperLobeBronchusZPositionInMM); - m_RightPulmoArteyrCrossesMidMediastinumZPositionInMM = GetAFDB()->GetPoint3D("rightPulmoArteryCrossesMidMediastinum", 2); + m_RightPulmoArteyrCrossesMidMediastinumZPositionInMM = GetAFDB()->GetPoint3D("RightPulmoArteryCrossesMidMediastinum", 2); DD(m_RightPulmoArteyrCrossesMidMediastinumZPositionInMM); /* Crop support */ - StartNewStep("Inf/Sup mediastinum limits with aortic arch/upperLBronchus"); double inf = std::max(m_UpperLobeBronchusZPositionInMM, m_RightPulmoArteyrCrossesMidMediastinumZPositionInMM); m_Working_Support = - clitk::CropImageAlongOneAxis(m_Support, 2, + clitk::CropImageAlongOneAxis(m_Mediastinum, 2, inf, m_TopOfAorticArchInMM, true, GetBackgroundValue()); StopCurrentStep(m_Working_Support); - - m_Station4RL = m_Working_Support; } //-------------------------------------------------------------------- @@ -51,50 +72,249 @@ ExtractStation_4RL_LR_Limits() // - very caudal part : right upper lobe pulmonary vein" // AAV ?? - // Constraint at right from the SVC - MaskImagePointer svc = GetAFDB()->template GetImage("SVC"); - typedef clitk::AddRelativePositionConstraintToLabelImageFilter RelPosFilterType; - typename RelPosFilterType::Pointer relPosFilter = RelPosFilterType::New(); - relPosFilter->SetCurrentStepBaseId(this->GetCurrentStepId()); - relPosFilter->VerboseStepOff(); - relPosFilter->WriteStepOff(); - relPosFilter->SetInput(m_Working_Support); - relPosFilter->SetInputObject(svc); - relPosFilter->SetOrientationType(RelPosFilterType::RightTo); - relPosFilter->SetIntermediateSpacing(2); - relPosFilter->SetFuzzyThreshold(0.3); - relPosFilter->Update(); - m_Working_Support = relPosFilter->GetOutput(); - m_Station4RL = m_Working_Support; - // 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 "); - // skeleton ? -> need path description ? follow from slice to slice - // OR CENTROID at each slice ? - - // Crop trachea - // Extract list of slice from trachea - // Loop slice -> Get centroid crop along line (BB limit) -> two supports + /* + 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(m_Trachea, m_Working_Support, GetBackgroundValue()); + clitk::ResizeImageLike(Trachea, m_Working_Support, GetBackgroundValue()); writeImage(crop_trachea, "croptrachea.mhd"); // Extract all the slices - typedef clitk::ExtractSliceFilter ExtractSliceFilterType; - typedef typename ExtractSliceFilterType::SliceType SliceType; - typename ExtractSliceFilterType::Pointer - extractSliceFilter = ExtractSliceFilterType::New(); - extractSliceFilter->SetInput(crop_trachea); - extractSliceFilter->SetDirection(2); - extractSliceFilter->Update(); - std::vector trachea_slices; - extractSliceFilter->GetOutputSlices(trachea_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()); } //-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +template +void +clitk::ExtractLymphStationsFilter:: +ExtractStation_4RL_AP_Limits() +{ + + /* + 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); + + // POST -> horizontal lines bronchus --> points dectection in S7 to store. +} +//-------------------------------------------------------------------- +