X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?a=blobdiff_plain;f=segmentation%2FclitkExtractLymphStation_8.txx;h=d4bbfc389217188c9ba4470d63a56dec39b33a65;hb=595624eb4297e747630105d45017de69733caef2;hp=69e24c92053b5c59d9d772865b0cdc29f3ef02a5;hpb=726fc21726f96f8f32015dda4c3b1efeb7d81851;p=clitk.git diff --git a/segmentation/clitkExtractLymphStation_8.txx b/segmentation/clitkExtractLymphStation_8.txx index 69e24c9..d4bbfc3 100644 --- a/segmentation/clitkExtractLymphStation_8.txx +++ b/segmentation/clitkExtractLymphStation_8.txx @@ -2,6 +2,48 @@ #include #include +//-------------------------------------------------------------------- +template +void +clitk::ExtractLymphStationsFilter:: +ExtractStation_8_SetDefaultValues() +{ + MaskImagePointType p; + p[0] = 15; p[1] = 2; p[2] = 1; + SetEsophagusDiltationForAnt(p); + p[0] = 5; p[1] = 10; p[2] = 1; + SetEsophagusDiltationForRight(p); + SetFuzzyThreshold("8", "Esophagus", 0.5); + SetInjectedThresholdForS8(150); +} +//-------------------------------------------------------------------- + +//-------------------------------------------------------------------- +template +void +clitk::ExtractLymphStationsFilter:: +ExtractStation_8() +{ + if (!CheckForStation("8")) return; + + StartNewStep("Station 8"); + StartSubStep(); + ExtractStation_8_SI_Limits(); // OK, validated + ExtractStation_8_Ant_Limits(); // OK, validated + ExtractStation_8_Left_Sup_Limits(); // OK, validated + ExtractStation_8_Left_Inf_Limits(); // OK, validated + ExtractStation_8_Single_CCL_Limits(); // OK, validated + ExtractStation_8_Remove_Structures(); // OK, validated + + // Store image filenames into AFDB + writeImage(m_ListOfStations["8"], "seg/Station8.mhd"); + GetAFDB()->SetImageFilename("Station8", "seg/Station8.mhd"); + WriteAFDB(); + StopSubStep(); +} +//-------------------------------------------------------------------- + + //-------------------------------------------------------------------- template void @@ -25,69 +67,42 @@ ExtractStation_8_SI_Limits() left; the lower border of the bronchus intermedius on the right" */ - StartNewStep("[Station8] Inf/Sup mediastinum limits with carina/diaphragm junction"); - - // Get Carina Z position - MaskImagePointer Carina = GetAFDB()->template GetImage("Carina"); - clitk::PrintMemory(GetVerboseMemoryFlag(), "after read Carina"); - std::vector centroids; - clitk::ComputeCentroids(Carina, GetBackgroundValue(), centroids); - DD(centroids[1]); - m_CarinaZ = centroids[1][2]; - DD(m_CarinaZ); - // add one slice to include carina ? - m_CarinaZ += m_Mediastinum->GetSpacing()[2]; - DD(m_CarinaZ); - // We dont need Carina structure from now - Carina->Delete(); - clitk::PrintMemory(GetVerboseMemoryFlag(), "after delete Carina"); - - // Get left lower lobe bronchus (L), take the upper border - // Get right bronchus intermedius (RML), take the lower border + StartNewStep("[Station8] Sup/Inf limits with LeftLower/RightMiddle Lobe and diaphragm"); - /* - double m_CarinaZ = GetAFDB()->GetPoint3D("Carina", 2) + - m_Mediastinum->GetSpacing()[2]; // add one slice to include carina - // double GOjunctionZ = GetAFDB()->GetPoint3D("GOjunction", 2); - */ + /* ----------------------------------------------- + NEW SUPERIOR LIMIT = LeftLowerLobeBronchus / + RightMiddleLobeBronchus See FindLineForS7S8Separation + ----------------------------------------------- + */ + ImagePointType A; + ImagePointType B; + FindLineForS7S8Separation(A, B); + + // add one slice to be adjacent to Station7 + B[2] += m_Working_Support->GetSpacing()[2]; + A[2] += m_Working_Support->GetSpacing()[2]; + + // Use the line to remove the inferior part + m_Working_Support = + SliceBySliceSetBackgroundFromSingleLine(m_Working_Support, + GetBackgroundValue(), A, B, 2, 0, true); + + /* ----------------------------------------------- + INFERIOR LIMIT = Diaphragm + ----------------------------------------------- + */ // Found most inferior part of the lung MaskImagePointer Lungs = GetAFDB()->template GetImage("Lungs"); // It should be already croped, so I took the origin and add 10mm above m_DiaphragmInferiorLimit = Lungs->GetOrigin()[2]+10; - DD(m_DiaphragmInferiorLimit); - clitk::PrintMemory(GetVerboseMemoryFlag(), "after read Lung"); - Lungs->Delete(); // we don't need it, release memory - clitk::PrintMemory(GetVerboseMemoryFlag(), "after release Lung"); - - /* Crop support : - Superior limit = carina - Inferior limit = DiaphragmInferiorLimit (old=Gastroesphogeal junction) */ + GetAFDB()->template ReleaseImage("Lungs"); + m_Working_Support = clitk::CropImageAlongOneAxis(m_Working_Support, 2, - m_DiaphragmInferiorLimit, //GOjunctionZ, - m_CarinaZ, true, + m_DiaphragmInferiorLimit, + B[2], true, GetBackgroundValue()); - - // Remove some structures that we know are excluded - MaskImagePointer VertebralBody = - GetAFDB()->template GetImage ("VertebralBody"); - MaskImagePointer Aorta = - GetAFDB()->template GetImage ("Aorta"); - - typedef clitk::BooleanOperatorLabelImageFilter BoolFilterType; - typename BoolFilterType::Pointer boolFilter = BoolFilterType::New(); - boolFilter->InPlaceOn(); - boolFilter->SetInput1(m_Working_Support); - boolFilter->SetInput2(VertebralBody); - boolFilter->SetOperationType(BoolFilterType::AndNot); - boolFilter->Update(); - boolFilter->SetInput1(boolFilter->GetOutput()); - boolFilter->SetInput2(Aorta); - boolFilter->SetOperationType(BoolFilterType::AndNot); - boolFilter->Update(); - m_Working_Support = boolFilter->GetOutput(); - // Done. StopCurrentStep(m_Working_Support); m_ListOfStations["8"] = m_Working_Support; @@ -99,102 +114,127 @@ ExtractStation_8_SI_Limits() template void clitk::ExtractLymphStationsFilter:: -ExtractStation_8_Post_Limits() +ExtractStation_8_Ant_Limits() { + //-------------------------------------------------------------------- + StartNewStep("[Station8] Ant part: not post to Esophagus"); /* - Station 8: paraeosphageal nodes + Consider Esophagus, dilate it and remove ant part. It remains part + on L & R, than can be partly removed by cutting what remains at + right of vertebral body. + */ + + // Get Esophagus + m_Esophagus = GetAFDB()->template GetImage("Esophagus"); + + // In images from the original article, Atlas – UM, the oesophagus + //was included in nodal stations 3p and 8. Having said that, in the + //description for station 8, it indicates that “the delineation of + //station 8 is limited to the soft tissues surrounding the + //oesophagus”. In the recent article, The IASLC Lung Cancer Staging + //Project (J Thorac Oncol 4:5, 568-77), the images drawn by + //Dr. Aletta Frasier exclude this structure. From an oncological + //prospective, the oesophagus should be excluded from these nodal + //stations. + + // Resize Esophagus like current support + m_Esophagus = + clitk::ResizeImageLike(m_Esophagus, m_Working_Support, GetBackgroundValue()); // Needed ? - Anteriorly, it is in contact with Station 7 and the - left main stem bronchus in its superior aspect (Fig. 3C–H) and - with the heart more inferiorly. Posteriorly, Station 8 abuts the - descending aorta and the anterior aspect of the vertebral body - until an imaginary horizontal line running 1 cm posterior to the - anterior border of the vertebral body (Fig. 3C). + // Dilate to keep only not Anterior positions + MaskImagePointType radiusInMM = GetEsophagusDiltationForAnt(); + m_Esophagus = clitk::Dilate(m_Esophagus, + radiusInMM, + GetBackgroundValue(), + GetForegroundValue(), true); + // Keep what is Posterior to Esophagus + typedef clitk::SliceBySliceRelativePositionFilter RelPosFilterType; + typename RelPosFilterType::Pointer relPosFilter = RelPosFilterType::New(); + relPosFilter->VerboseStepFlagOff(); + relPosFilter->WriteStepFlagOff(); + relPosFilter->SetInput(m_Working_Support); + relPosFilter->SetInputObject(m_Esophagus); + relPosFilter->AddOrientationTypeString("PostTo"); + // relPosFilter->InverseOrientationFlagOff(); + relPosFilter->SetDirection(2); // Z axis + relPosFilter->UniqueConnectedComponentBySliceFlagOff(); + relPosFilter->SetIntermediateSpacing(3); + relPosFilter->IntermediateSpacingFlagOn(); + relPosFilter->SetFuzzyThreshold(GetFuzzyThreshold("8", "Esophagus")); + relPosFilter->RemoveObjectFlagOff(); // Do not exclude here because it is dilated + relPosFilter->CombineWithOrFlagOff(); // NO ! + relPosFilter->IgnoreEmptySliceObjectFlagOn(); + relPosFilter->Update(); + m_Working_Support = relPosFilter->GetOutput(); - New classification IASCL 2009 : + // AutoCrop (OR SbS ?) + m_Working_Support = clitk::AutoCrop(m_Working_Support, GetBackgroundValue()); - "Nodes lying adjacent to the wall of the esophagus and to the - right or left of the midline, excluding subcarinal nodes (S7) - Upper" + StopCurrentStep(m_Working_Support); + m_ListOfStations["8"] = m_Working_Support; +} +//-------------------------------------------------------------------- - */ - StartNewStep("[Station8] Post limits with vertebral body"); - MaskImagePointer VertebralBody = - GetAFDB()->template GetImage ("VertebralBody"); +//-------------------------------------------------------------------- +template +void +clitk::ExtractLymphStationsFilter:: +ExtractStation_8_Left_Sup_Limits() +{ + //-------------------------------------------------------------------- + StartNewStep("[Station8] Left limits: remove Left to line from Aorta to PulmonaryTrunk"); - // Consider vertebral body slice by slice - typedef clitk::ExtractSliceFilter ExtractSliceFilterType; - typename ExtractSliceFilterType::Pointer extractSliceFilter = ExtractSliceFilterType::New(); - typedef typename ExtractSliceFilterType::SliceType SliceType; - std::vector vertebralSlices; - extractSliceFilter->SetInput(VertebralBody); - extractSliceFilter->SetDirection(2); - extractSliceFilter->Update(); - extractSliceFilter->GetOutputSlices(vertebralSlices); - - // For each slice, compute the most anterior point - std::map vertebralAntPositionBySlice; - for(uint i=0; i(vertebralSlices[i], - GetBackgroundValue(), - 1, true, p); + /* + We consider a line from Left part of Aorta to left part of + PulmonaryTrunk and remove what is at Left. + */ + + // Load the structures + MaskImagePointer Aorta = GetAFDB()->template GetImage("Aorta"); + MaskImagePointer PulmonaryTrunk = GetAFDB()->template GetImage("PulmonaryTrunk"); + + // Resize like the PT and define the slices + MaskImagePointType min, max; + clitk::GetMinMaxPointPosition(PulmonaryTrunk, min, max); + Aorta = clitk::CropImageAlongOneAxis(Aorta, 2, min[2], max[2], false, GetBackgroundValue()); + std::vector slices_aorta; + clitk::ExtractSlices(Aorta, 2, slices_aorta); + std::vector slices_PT; + clitk::ExtractSlices(PulmonaryTrunk, 2, slices_PT); + + // Find the points at left + std::vector p_A; + std::vector p_B; + MaskImagePointType pA; + MaskImagePointType pB; + for(uint i=0; i(slices_aorta[i], GetBackgroundValue(), 0, false, ps); + clitk::PointsUtils::Convert2DTo3D(ps, Aorta, i, pA); + if (found) { - vertebralAntPositionBySlice[i] = p; + // In PT : generally 2 CCL, we keep the most at left + found = + clitk::FindExtremaPointInAGivenDirection(slices_PT[i], GetBackgroundValue(), 0, false, ps); + clitk::PointsUtils::Convert2DTo3D(ps, PulmonaryTrunk, i, pB); } - else { - // no Foreground in this slice (it appends generally at the - // beginning and the end of the volume). Do nothing in this - // case. + + if (found) { + p_A.push_back(pA); + p_B.push_back(pB); } } + clitk::WriteListOfLandmarks(p_A, "S8-Aorta-Left-points.txt"); + clitk::WriteListOfLandmarks(p_B, "S8-PT-Left-points.txt"); - // Convert 2D points in slice into 3D points - std::vector vertebralAntPositions; - clitk::PointsUtils::Convert2DTo3DList(vertebralAntPositionBySlice, - VertebralBody, - vertebralAntPositions); - - // DEBUG : write list of points - clitk::WriteListOfLandmarks(vertebralAntPositions, - "vertebralMostAntPositions.txt"); - - // Cut support posteriorly 1cm the most anterior point of the - // VertebralBody. Do nothing below and above the VertebralBody. To - // do that compute several region, slice by slice and fill. - MaskImageRegionType region; - MaskImageSizeType size; - MaskImageIndexType start; - size[2] = 1; // a single slice - start[0] = m_Working_Support->GetLargestPossibleRegion().GetIndex()[0]; - size[0] = m_Working_Support->GetLargestPossibleRegion().GetSize()[0]; - for(uint i=0; i IteratorType; - IteratorType iter = - IteratorType(m_Working_Support, m_Working_Support->GetLargestPossibleRegion()); - MaskImageIndexType index; - // Consider some cm posterior to most anterior positions (usually - // 1 cm). - vertebralAntPositions[i][1] += GetDistanceMaxToAnteriorPartOfTheSpine(); - // Get index of this point - m_Working_Support->TransformPhysicalPointToIndex(vertebralAntPositions[i], index); - // Compute region (a single slice) - start[2] = index[2]; - start[1] = m_Working_Support->GetLargestPossibleRegion().GetIndex()[1]+index[1]; - size[1] = m_Working_Support->GetLargestPossibleRegion().GetSize()[1]-start[1]; - region.SetSize(size); - region.SetIndex(start); - // Fill region - if (m_Working_Support->GetLargestPossibleRegion().IsInside(start)) { - itk::ImageRegionIterator it(m_Working_Support, region); - it.GoToBegin(); - while (!it.IsAtEnd()) { - it.Set(GetBackgroundValue()); - ++it; - } - } - } + // Remove part at Left + clitk::SliceBySliceSetBackgroundFromLineSeparation(m_Working_Support, + p_A, p_B, + GetBackgroundValue(), + 0, -10); StopCurrentStep(m_Working_Support); m_ListOfStations["8"] = m_Working_Support; @@ -206,289 +246,104 @@ ExtractStation_8_Post_Limits() template void clitk::ExtractLymphStationsFilter:: -ExtractStation_8_Ant_Limits() +ExtractStation_8_Single_CCL_Limits() { //-------------------------------------------------------------------- - StartNewStep("[Station8] Ant limits with S7 above Carina"); - /* - Anteriorly, it is in contact with Station 7 and the - left main stem bronchus in its superior aspect (Fig. 3C–H) and - with the heart more inferiorly. - - 1) line post wall bronchi (S7), till originRMLB - - LUL bronchus : to detect in trachea. But not needed here ?? - 2) heart ! -> not delineated. - ==> below S7, crop CT not to far away (ant), then try with threshold - - 1) ==> how to share with S7 ? Prepare both support at the same time ! - NEED vector of initial support for each station ? No -> map if it exist before, take it !! - - */ + StartNewStep("[Station8 or 3P] Slice by slice, keep a single CCL (the closest to VertebralBody)"); - // Ant limit from carina (start) to end of S7 = originRMLB - // Get Trachea - MaskImagePointer Trachea = GetAFDB()->template GetImage("Trachea"); - clitk::PrintMemory(GetVerboseMemoryFlag(), "after read Trachea"); - - MaskImagePointer m_Working_Trachea = - clitk::CropImageAbove(Trachea, 2, m_CarinaZ, true, // AutoCrop - GetBackgroundValue()); - clitk::PrintMemory(GetVerboseMemoryFlag(), "after crop"); - - // Seprate into two main bronchi - MaskImagePointer LeftBronchus; - MaskImagePointer RightBronchus; - - // Labelize and consider the two first (main) labels - m_Working_Trachea = Labelize(m_Working_Trachea, 0, true, 1); - clitk::PrintMemory(GetVerboseMemoryFlag(), "after labelize"); - - // 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 - 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; + // Consider slices + std::vector slices; + std::vector slices_vb; + clitk::ExtractSlices(m_Working_Support, 2, slices); + MaskImagePointer VertebralBody = + GetAFDB()->template GetImage ("VertebralBody"); + VertebralBody = clitk::ResizeImageLike(VertebralBody, m_Working_Support, GetBackgroundValue()); + clitk::ExtractSlices(VertebralBody, 2, slices_vb); + + for(uint i=0; i(slices[i], 0, true, 100); + // Compute centroids coordinate + std::vector centroids; + std::vector c; + clitk::ComputeCentroids(slices[i], GetBackgroundValue(), centroids); + clitk::ComputeCentroids(slices_vb[i], GetBackgroundValue(), c); + if ((c.size() > 1) && (centroids.size() > 1)) { + // keep the one which is the closer to vertebralbody centroid + double distance=1000000; + int index=0; + for(uint j=1; j(slices[i], GetBackgroundValue(), + GetForegroundValue(), index, index, true); } - iter.PreviousLine(); - } - if (maxLabel < 2) { - clitkExceptionMacro("First slice form 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 leftLabel; - ImagePixelType rightLabel; - if (C1[0] < C2[0]) { leftLabel = 1; rightLabel = 2; } - else { leftLabel = 2; rightLabel = 1; } - - // Select LeftLabel (set one label to Backgroundvalue) - LeftBronchus = - SetBackground(m_Working_Trachea, m_Working_Trachea, - rightLabel, GetBackgroundValue(), false); - RightBronchus = - SetBackground(m_Working_Trachea, m_Working_Trachea, - leftLabel, GetBackgroundValue(), false); - // Crop images - LeftBronchus = clitk::AutoCrop(LeftBronchus, GetBackgroundValue()); - RightBronchus = clitk::AutoCrop(RightBronchus, GetBackgroundValue()); - - // Insert int AFDB if need after - GetAFDB()->template SetImage ("LeftBronchus", "seg/leftBronchus.mhd", - LeftBronchus, true); - GetAFDB()->template SetImage ("RightBronchus", "seg/rightBronchus.mhd", - RightBronchus, true); - - // Now crop below OriginOfRightMiddleLobeBronchusZ - // It is not done before to keep entire bronchi. + m_Working_Support = clitk::JoinSlices(slices, m_Working_Support, 2); - MaskImagePointer OriginOfRightMiddleLobeBronchus = - GetAFDB()->template GetImage("OriginOfRightMiddleLobeBronchus"); - clitk::PrintMemory(GetVerboseMemoryFlag(), "after read OriginOfRightMiddleLobeBronchus"); - std::vector centroids; - clitk::ComputeCentroids(OriginOfRightMiddleLobeBronchus, GetBackgroundValue(), centroids); - DD(centroids.size()); - DD(centroids[0]); // BG - DD(centroids[1]); - m_OriginOfRightMiddleLobeBronchusZ = centroids[1][2]; - DD(m_OriginOfRightMiddleLobeBronchusZ); - // add one slice to include carina ? - m_OriginOfRightMiddleLobeBronchusZ += LeftBronchus->GetSpacing()[2]; - DD(m_OriginOfRightMiddleLobeBronchusZ); - DD(OriginOfRightMiddleLobeBronchus->GetReferenceCount()); - // We dont need Carina structure from now - OriginOfRightMiddleLobeBronchus->Delete(); - clitk::PrintMemory(GetVerboseMemoryFlag(), "after delete OriginOfRightMiddleLobeBronchus"); - - LeftBronchus = - clitk::CropImageBelow(LeftBronchus, 2, - m_OriginOfRightMiddleLobeBronchusZ, - true, // AutoCrop - GetBackgroundValue()); - RightBronchus = - clitk::CropImageBelow(RightBronchus, 2, - m_OriginOfRightMiddleLobeBronchusZ, - true, // AutoCrop - GetBackgroundValue()); - - // Search for points that are the most left/post/ant and most - // right/post/ant of the left and right bronchus - // 15 = not 15 mm more distance than the middle point. - FindExtremaPointsInBronchus(LeftBronchus, 0, 10, m_RightMostInLeftBronchus, - m_AntMostInLeftBronchus, m_PostMostInLeftBronchus); - FindExtremaPointsInBronchus(RightBronchus, 1, 10, m_LeftMostInRightBronchus, - m_AntMostInRightBronchus, m_PostMostInRightBronchus); - - // DEBUG : write the list of points - ListOfPointsType v; - v.reserve(m_RightMostInLeftBronchus.size()+m_AntMostInLeftBronchus.size()+ - m_PostMostInLeftBronchus.size()); - v.insert(v.end(), m_RightMostInLeftBronchus.begin(), m_RightMostInLeftBronchus.end() ); - v.insert(v.end(), m_AntMostInLeftBronchus.begin(), m_AntMostInLeftBronchus.end() ); - v.insert(v.end(), m_PostMostInLeftBronchus.begin(), m_PostMostInLeftBronchus.end() ); - clitk::WriteListOfLandmarks(v, "LeftBronchusPoints.txt"); - - v.clear(); - v.reserve(m_LeftMostInRightBronchus.size()+m_AntMostInRightBronchus.size()+ - m_PostMostInRightBronchus.size()); - v.insert(v.end(), m_LeftMostInRightBronchus.begin(), m_LeftMostInRightBronchus.end() ); - v.insert(v.end(), m_AntMostInRightBronchus.begin(), m_AntMostInRightBronchus.end() ); - v.insert(v.end(), m_PostMostInRightBronchus.begin(), m_PostMostInRightBronchus.end() ); - clitk::WriteListOfLandmarks(v, "RightBronchusPoints.txt"); - - - // Now uses these points to limit, slice by slice - // line is mainly horizontal, so mainDirection=1 - writeImage(m_Working_Support, "before.mhd"); - clitk::SliceBySliceSetBackgroundFromLineSeparation(m_Working_Support, - m_PostMostInLeftBronchus, - m_PostMostInRightBronchus, - GetBackgroundValue(), 1, 10); - writeImage(m_Working_Support, "after.mhd"); - -HERE - - // Keep main 3D CCL : - m_Working_Support = Labelize(m_Working_Support, 0, false, 10); - m_Working_Support = KeepLabels(m_Working_Support, - GetBackgroundValue(), - GetForegroundValue(), 1, 1, true); - - // Autocrop - m_Working_Support = clitk::AutoCrop(m_Working_Support, GetBackgroundValue()); - - // End of step StopCurrentStep(m_Working_Support); - // m_ListOfStations["8"] = m_Working_Support; - + m_ListOfStations["8"] = m_Working_Support; } +//-------------------------------------------------------------------- + //-------------------------------------------------------------------- template void clitk::ExtractLymphStationsFilter:: -ExtractStation_8_LR_Limits() +ExtractStation_8_Left_Inf_Limits() { - //-------------------------------------------------------------------- - StartNewStep("[Station8] Left and Right limits arround esophagus (below Carina)"); - /* - Consider Esophagus, dilate it and remove ant part. It remains part - on L & R, than can be partly removed by cutting what remains at - right of vertebral body. - */ - - // Get Esophagus - MaskImagePointer Esophagus = GetAFDB()->template GetImage("Esophagus"); - clitk::PrintMemory(GetVerboseMemoryFlag(), "after read Esophagus"); - - // Crop Esophagus : keep only below the OriginOfRightMiddleLobeBronchusZ - Esophagus = - clitk::CropImageAbove(Esophagus, 2, - m_OriginOfRightMiddleLobeBronchusZ, - true, // AutoCrop - GetBackgroundValue()); - - // Dilate to keep only not Anterior positions - MaskImagePointType radiusInMM = GetEsophagusDiltationForAnt(); - Esophagus = EnlargeEsophagusDilatationRadiusInferiorly(Esophagus); - Esophagus = clitk::Dilate(Esophagus, - radiusInMM, - GetBackgroundValue(), - GetForegroundValue(), true); - clitk::PrintMemory(GetVerboseMemoryFlag(), "after dilate Esophagus"); - writeImage(Esophagus, "enlarged-eso.mhd"); - - // Remove Anterior part according to this dilatated esophagus - typedef clitk::SliceBySliceRelativePositionFilter RelPosFilterType; - typename RelPosFilterType::Pointer relPosFilter = RelPosFilterType::New(); - relPosFilter->VerboseStepFlagOff(); - relPosFilter->SetInput(m_Working_Support); - relPosFilter->SetInputObject(Esophagus); - relPosFilter->AddOrientationTypeString("P"); - relPosFilter->InverseOrientationFlagOff(); - relPosFilter->SetDirection(2); // Z axis - relPosFilter->UniqueConnectedComponentBySliceOff(); - relPosFilter->SetIntermediateSpacing(3); - relPosFilter->ResampleBeforeRelativePositionFilterOn(); - relPosFilter->SetFuzzyThreshold(GetFuzzyThresholdForS8()); - relPosFilter->RemoveObjectFlagOff(); - relPosFilter->Update(); - m_Working_Support = relPosFilter->GetOutput(); - clitk::PrintMemory(GetVerboseMemoryFlag(), "after SbS Rel pos Post"); - - // AutoCrop (OR SbS ?) - m_Working_Support = clitk::AutoCrop(m_Working_Support, GetBackgroundValue()); - - writeImage(m_Working_Support, "step1.4.1.mhd"); - - clitk::PrintMemory(GetVerboseMemoryFlag(), "after autocrop"); + StartNewStep("[Station8] Left limits around esophagus with lines from VertebralBody-Aorta-Esophagus"); // Estract slices for current support for slice by slice processing std::vector slices; clitk::ExtractSlices(m_Working_Support, 2, slices); - clitk::PrintMemory(GetVerboseMemoryFlag(), "after support slices"); - + + // Remove what is outside the mediastinum in this enlarged Esophagus -> it allows to select + // 'better' extrema points (not too post). + MaskImagePointer Lungs = GetAFDB()->template GetImage("Lungs"); + clitk::AndNot(m_Esophagus, Lungs, GetBackgroundValue()); + GetAFDB()->template ReleaseImage("Lungs"); + // Estract slices of Esophagus (resize like support before to have the same set of slices) - MaskImagePointer EsophagusForSlice = clitk::ResizeImageLike(Esophagus, m_Working_Support, GetBackgroundValue()); - clitk::PrintMemory(GetVerboseMemoryFlag(), "after Eso resize"); + MaskImagePointer EsophagusForSlice = + clitk::ResizeImageLike(m_Esophagus, m_Working_Support, GetBackgroundValue()); std::vector eso_slices; clitk::ExtractSlices(EsophagusForSlice, 2, eso_slices); - clitk::PrintMemory(GetVerboseMemoryFlag(), "after Eso slices"); // Estract slices of Vertebral (resize like support before to have the same set of slices) MaskImagePointer VertebralBody = GetAFDB()->template GetImage("VertebralBody"); - clitk::PrintMemory(GetVerboseMemoryFlag(), "after Read VertebralBody"); VertebralBody = clitk::ResizeImageLike(VertebralBody, m_Working_Support, GetBackgroundValue()); - clitk::PrintMemory(GetVerboseMemoryFlag(), "after VertebralBody Resize"); + // Remove what is outside the support to not consider what is to + // posterior in the VertebralBody (post the horizontal line) + clitk::And(VertebralBody, m_Working_Support, GetBackgroundValue()); + // writeImage(VertebralBody, "vb.mhd"); std::vector vert_slices; clitk::ExtractSlices(VertebralBody, 2, vert_slices); - clitk::PrintMemory(GetVerboseMemoryFlag(), "after VertebralBody slices"); // Estract slices of Aorta (resize like support before to have the same set of slices) MaskImagePointer Aorta = GetAFDB()->template GetImage("Aorta"); - clitk::PrintMemory(GetVerboseMemoryFlag(), "after Read Aorta"); Aorta = clitk::ResizeImageLike(Aorta, m_Working_Support, GetBackgroundValue()); - clitk::PrintMemory(GetVerboseMemoryFlag(), "after Aorta Resize"); std::vector aorta_slices; clitk::ExtractSlices(Aorta, 2, aorta_slices); - clitk::PrintMemory(GetVerboseMemoryFlag(), "after Aorta slices"); // Extract slices of Mediastinum (resize like support before to have the same set of slices) m_Mediastinum = GetAFDB()->template GetImage("Mediastinum"); - clitk::PrintMemory(GetVerboseMemoryFlag(), "after read Mediastinum"); m_Mediastinum = clitk::ResizeImageLike(m_Mediastinum, m_Working_Support, GetBackgroundValue()); - clitk::PrintMemory(GetVerboseMemoryFlag(), "after resize Mediastinum"); std::vector mediast_slices; clitk::ExtractSlices(m_Mediastinum, 2, mediast_slices); - clitk::PrintMemory(GetVerboseMemoryFlag(), "after Mediastinum slices"); - - writeImage(EsophagusForSlice, "slices_eso.mhd"); - writeImage(VertebralBody, "slices_vert.mhd"); - writeImage(Aorta, "slices_aorta.mhd"); - writeImage(m_Mediastinum, "slices_medias.mhd"); - writeImage(m_Working_Support, "slices_support.mhd"); - // List of points - std::vector p_RightMostAnt; - std::vector p_RightMostPost; - std::vector p_LeftMostAnt; - std::vector p_LeftMostPost; - std::vector p_AllPoints; + std::vector p_MostLeftVertebralBody; + std::vector p_MostRightVertebralBody; + std::vector p_MostLeftAorta; + std::vector p_MostLeftEsophagus; /* In the following, we search for the LeftRight limits. We search @@ -499,140 +354,106 @@ ExtractStation_8_LR_Limits() is concave between Eso/VertebralBody. Esophagus is a bit dilatated. On VertebralBody we go right (or left) until we reach the lung (but no more 20 mm). - */ + */ - // Loop slices + // Temporary 3D point MaskImagePointType p; - MaskImagePointType pp; + + typename MaskSliceType::PointType minSlicePoint; + typename MaskSliceType::PointType maxSlicePoint; + clitk::GetMinMaxPointPosition(vert_slices[0], minSlicePoint, maxSlicePoint); + + // Loop slices for(uint i=0; i(eso_slices[i], GetBackgroundValue(), 0, true, sp_maxRight_Eso); - clitk::FindExtremaPointInAGivenDirection(aorta_slices[i], GetBackgroundValue(), 0, true, sp_maxRight_Aorta); - clitk::PointsUtils::Convert2DTo3D(sp_maxRight_Eso, EsophagusForSlice, i, p); - clitk::PointsUtils::Convert2DTo3D(sp_maxRight_Aorta, Aorta, i, pp); - pp[0] -= 2; // Add a margin of 2 mm to include the 'wall' - p_AllPoints.push_back(p); - p_AllPoints.push_back(pp); - if (p[0] only at most Post part of current - // slice support. First found most ant point in VertebralBody - typedef MaskSliceType SliceType; - typename SliceType::PointType p_slice_ant; - bool found = clitk::FindExtremaPointInAGivenDirection(vert_slices[i], GetBackgroundValue(), 1, true, p_slice_ant); - if (!found) { - // It should not happen ! But sometimes, a contour is missing or - // the VertebralBody is not delineated enough inferiorly ... in - // those cases, we consider the first found slice. - std::cerr << "No foreground pixels in this VertebralBody slices !?? I try with the previous/next slice" << std::endl; - DD(i); - int j=i++; - bool found = false; - while (!found) { - found = clitk::FindExtremaPointInAGivenDirection(vert_slices[j], GetBackgroundValue(), 1, true, p_slice_ant); - //clitkExceptionMacro("No foreground pixels in this VertebralBody slices ??"); - j++; - } - DD(j); - } - p_slice_ant[1] += GetDistanceMaxToAnteriorPartOfTheSpine(); // Consider offset - - // The, find most Right and Left points on that AP position - typename SliceType::IndexType indexR; - typename SliceType::IndexType indexL; - vert_slices[i]->TransformPhysicalPointToIndex(p_slice_ant, indexR); - indexL = indexR; - // Check that is inside the mask - indexR[1] = std::min(indexR[1], (long)vert_slices[i]->GetLargestPossibleRegion().GetSize()[1]-1); - indexL[1] = indexR[1]; - while (vert_slices[i]->GetPixel(indexR) != GetBackgroundValue()) { - indexR[0] --; // Go to the right - } - while (vert_slices[i]->GetPixel(indexL) != GetBackgroundValue()) { - indexL[0] ++; // Go to the left - } - vert_slices[i]->TransformIndexToPhysicalPoint(indexR, sp_maxRight_Vertebra); - clitk::PointsUtils::Convert2DTo3D(sp_maxRight_Vertebra, VertebralBody, i, p); - p_AllPoints.push_back(p); - vert_slices[i]->TransformIndexToPhysicalPoint(indexL, sp_maxLeft_Vertebra); - clitk::PointsUtils::Convert2DTo3D(sp_maxLeft_Vertebra, VertebralBody, i, p); - p_AllPoints.push_back(p); + // Declare all needed 2D points (sp = slice point) + // typename MaskSliceType::PointType sp_MostRightVertebralBody; + typename MaskSliceType::PointType sp_MostLeftVertebralBody; + typename MaskSliceType::PointType sp_MostLeftAorta; + typename MaskSliceType::PointType sp_temp; + typename MaskSliceType::PointType sp_MostLeftEsophagus; + + /* ------------------------------------------------------------------------------------- + Find first point not in mediastinum at LEFT + */ + clitk::FindExtremaPointInAGivenDirection(vert_slices[i], GetBackgroundValue(), + 0, false, sp_MostLeftVertebralBody); + // clitk::PointsUtils::Convert2DTo3D(sp_MostLeftVertebralBody, VertebralBody, i, p); + // DD(p); + + sp_MostLeftVertebralBody = + clitk::FindExtremaPointInAGivenLine(mediast_slices[i], 0, false, + sp_MostLeftVertebralBody, GetBackgroundValue(), 30); + // clitk::PointsUtils::Convert2DTo3D(sp_MostLeftVertebralBody, VertebralBody, i, p); + // DD(p); + + sp_MostLeftVertebralBody[0] += 2; // 2mm margin + // clitk::PointsUtils::Convert2DTo3D(sp_MostLeftVertebralBody, VertebralBody, i, p); + // DD(p); + + // Convert 2D points into 3D + clitk::PointsUtils::Convert2DTo3D(sp_MostLeftVertebralBody, VertebralBody, i, p); + p_MostLeftVertebralBody.push_back(p); + + /* ------------------------------------------------------------------------------------- + Find first point not in mediastinum at RIGHT. Not used yet. + clitk::FindExtremaPointInAGivenDirection(vert_slices[i], GetBackgroundValue(), + 0, true, sp_MostRightVertebralBody); + sp_MostRightVertebralBody = + clitk::FindExtremaPointInAGivenLine(mediast_slices[i], 0, true, + sp_MostRightVertebralBody, GetBackgroundValue(),30); + sp_MostRightVertebralBody[0] -= 2; // 2 mm margin - // Find last point out of the mediastinum on this line, Right : - mediast_slices[i]->TransformPhysicalPointToIndex(sp_maxRight_Vertebra, indexR); - double distance = 0.0; - while (mediast_slices[i]->GetPixel(indexR) != GetBackgroundValue()) { - indexR[0] --; - distance += mediast_slices[i]->GetSpacing()[0]; - } - if (distance < 30) { // Ok in this case, we found limit with lung - mediast_slices[i]->TransformIndexToPhysicalPoint(indexR, sp_maxRight_Vertebra); - clitk::PointsUtils::Convert2DTo3D(sp_maxRight_Vertebra, m_Mediastinum, i, p); - } - else { // in that case, we are probably below the diaphragm, so we - // add aribtrarly few mm - sp_maxRight_Vertebra[0] -= 2; // Leave 2 mm around the VertebralBody - } - p_RightMostPost.push_back(p); - p_AllPoints.push_back(p); - - // Find last point out of the mediastinum on this line, Left : - mediast_slices[i]->TransformPhysicalPointToIndex(sp_maxLeft_Vertebra, indexL); - distance = 0.0; - while (mediast_slices[i]->GetPixel(indexL) != GetBackgroundValue()) { - indexL[0] ++; - distance += mediast_slices[i]->GetSpacing()[0]; + // Convert 2D points into 3D + clitk::PointsUtils::Convert2DTo3D(sp_MostRightVertebralBody, VertebralBody, i, p); + p_MostRightVertebralBody.push_back(p); + */ + + + /* ------------------------------------------------------------------------------------- + Find most Left point in Esophagus + */ + bool found = clitk::FindExtremaPointInAGivenDirection(eso_slices[i], GetBackgroundValue(), 0, false, sp_MostLeftEsophagus); + if (!found) { // No more Esophagus, I remove the previous point + //DD("no eso pop back"); + p_MostLeftVertebralBody.pop_back(); } - if (distance < 30) { // Ok in this case, we found limit with lung - mediast_slices[i]->TransformIndexToPhysicalPoint(indexL, sp_maxLeft_Vertebra); - clitk::PointsUtils::Convert2DTo3D(sp_maxLeft_Vertebra, m_Mediastinum, i, p); + else { + clitk::PointsUtils::Convert2DTo3D(sp_MostLeftEsophagus, EsophagusForSlice, i, p); + p_MostLeftEsophagus.push_back(p); } - else { // in that case, we are probably below the diaphragm, so we - // add aribtrarly few mm - sp_maxLeft_Vertebra[0] += 2; // Leave 2 mm around the VertebralBody + + /* ------------------------------------------------------------------------------------- + Find most Left point in Aorta + */ + if (found) { + clitk::FindExtremaPointInAGivenDirection(aorta_slices[i], GetBackgroundValue(), 0, false, sp_MostLeftAorta); + sp_MostLeftAorta = clitk::FindExtremaPointInAGivenLine(mediast_slices[i], 0, false, sp_MostLeftAorta, GetBackgroundValue(), 10); + typename MaskSliceType::PointType temp=sp_MostLeftEsophagus; + temp[0] -= 10; + if (clitk::IsOnTheSameLineSide(sp_MostLeftAorta, sp_MostLeftVertebralBody, sp_MostLeftEsophagus, temp)) { + // sp_MostLeftAorta is on the same side than temp (at Right) -> ignore Aorta + sp_MostLeftAorta = sp_MostLeftEsophagus; + } + clitk::PointsUtils::Convert2DTo3D(sp_MostLeftAorta, Aorta, i, p); + p_MostLeftAorta.push_back(p); } - p_LeftMostPost.push_back(p); - p_AllPoints.push_back(p); - // -------------------------------------------------------------------------- - // Find the limit on the Left: most left point between Eso and - // Vertebra. (Left is left on screen, coordinate increase) - - // Find left limit of Esophagus - clitk::FindExtremaPointInAGivenDirection(eso_slices[i], GetBackgroundValue(), 0, false, sp_maxLeft_Eso); - clitk::FindExtremaPointInAGivenDirection(aorta_slices[i], GetBackgroundValue(), 0, false, sp_maxLeft_Aorta); - clitk::PointsUtils::Convert2DTo3D(sp_maxLeft_Eso, EsophagusForSlice, i, p); - clitk::PointsUtils::Convert2DTo3D(sp_maxLeft_Aorta, Aorta, i, pp); - p_AllPoints.push_back(p); - pp[0] += 2; // Add a margin of 2 mm to include the 'wall' - p_AllPoints.push_back(pp); - if (p[0]>pp[0]) p_LeftMostAnt.push_back(p); // Insert point most at right - else p_LeftMostAnt.push_back(pp); } // End of slice loop - clitk::WriteListOfLandmarks(p_AllPoints, "LR-Eso-Vert.txt"); + clitk::WriteListOfLandmarks(p_MostLeftVertebralBody, "S8-MostLeft-VB-points.txt"); + // clitk::WriteListOfLandmarks(p_MostRightVertebralBody, "S8-MostRight-VB-points.txt"); + clitk::WriteListOfLandmarks(p_MostLeftAorta, "S8-MostLeft-Aorta-points.txt"); + clitk::WriteListOfLandmarks(p_MostLeftEsophagus, "S8-MostLeft-eso-points.txt"); - // Now uses these points to limit, slice by slice - // Line is mainly vertical, so mainDirection=0 clitk::SliceBySliceSetBackgroundFromLineSeparation(m_Working_Support, - p_RightMostAnt, p_RightMostPost, - GetBackgroundValue(), 0, 10); + p_MostLeftVertebralBody, p_MostLeftAorta, + GetBackgroundValue(), 0, -10); + clitk::SliceBySliceSetBackgroundFromLineSeparation(m_Working_Support, - p_LeftMostAnt, p_LeftMostPost, + p_MostLeftAorta, p_MostLeftEsophagus, GetBackgroundValue(), 0, -10); - // DEBUG + // END + StopCurrentStep(m_Working_Support); m_ListOfStations["8"] = m_Working_Support; return; } @@ -641,123 +462,88 @@ ExtractStation_8_LR_Limits() //-------------------------------------------------------------------- template -typename clitk::ExtractLymphStationsFilter::MaskImagePointer +void clitk::ExtractLymphStationsFilter:: -EnlargeEsophagusDilatationRadiusInferiorly(MaskImagePointer & Esophagus) +ExtractStation_8_Remove_Structures() { - // Check if Esophagus is delineated at least until GOjunction. Now, - // because we use AutoCrop, Origin[2] gives this max inferior - // position. - // double GOjunctionZ = GetAFDB()->GetPoint3D("GOjunction", 2); - - if (Esophagus->GetOrigin()[2] > m_DiaphragmInferiorLimit) { - std::cout << "Warning Esophagus is not delineated until Diaphragm. I mirror-pad it." - << std::endl; - double extraSize = Esophagus->GetOrigin()[2]-m_DiaphragmInferiorLimit; - - // Pad with few more slices - typedef itk::MirrorPadImageFilter PadFilterType; - typename PadFilterType::Pointer padFilter = PadFilterType::New(); - padFilter->SetInput(Esophagus); - MaskImageSizeType b; - b[0] = 0; b[1] = 0; b[2] = (uint)ceil(extraSize/Esophagus->GetSpacing()[2])+1; - padFilter->SetPadLowerBound(b); - padFilter->Update(); - Esophagus = padFilter->GetOutput(); - } - return Esophagus; + //-------------------------------------------------------------------- + Remove_Structures("8", "Aorta"); + Remove_Structures("8", "Esophagus"); + Remove_Structures("8", "VertebralBody"); + + // END + StopCurrentStep(m_Working_Support); + m_ListOfStations["8"] = m_Working_Support; + return; } //-------------------------------------------------------------------- //-------------------------------------------------------------------- -template +template void -clitk::ExtractLymphStationsFilter:: -ExtractStation_8_LR_Limits_old() +clitk::ExtractLymphStationsFilter:: +FindExtremaPointsInBronchus(MaskImagePointer input, + int direction, + double distance_max_from_center_point, + ListOfPointsType & LR, + ListOfPointsType & Ant, + ListOfPointsType & Post) { - /* - Station 8: paraeosphageal nodes - - Laterally, it is within the pleural envelope and again abuts the - descending aorta on the left. Reasonably, the delineation of - Station 8 is limited to the soft tissue surrounding the esophagus - (Fig. 3C–H). - */ - - StartNewStep("[Station8] Right limits (around esophagus)"); - // Get Esophagus - MaskImagePointer Esophagus = GetAFDB()->template GetImage("Esophagus"); - - // Autocrop to get first slice with starting Esophagus - Esophagus = clitk::AutoCrop(Esophagus, GetBackgroundValue()); - - // Dilate - // LR dilatation -> large to keep point inside - // AP dilatation -> few mm - // SI dilatation -> enough to cover Diaphragm (old=GOjunctionZ) - MaskImagePointType radiusInMM = GetEsophagusDiltationForRight(); - Esophagus = EnlargeEsophagusDilatationRadiusInferiorly(Esophagus); - Esophagus = clitk::Dilate(Esophagus, - radiusInMM, - GetBackgroundValue(), - GetForegroundValue(), true); - writeImage(Esophagus, "dilateEso2.mhd"); - - writeImage(m_Working_Support, "before-relpos2.mhd"); - - // Remove Right (Left on the screen) part according to this - // dilatated esophagus - typedef clitk::SliceBySliceRelativePositionFilter RelPosFilterType; - typename RelPosFilterType::Pointer relPosFilter = RelPosFilterType::New(); - relPosFilter->VerboseStepFlagOff(); - relPosFilter->WriteStepFlagOff(); - relPosFilter->SetInput(m_Working_Support); - relPosFilter->SetInputObject(Esophagus); - relPosFilter->AddOrientationTypeString("L"); - relPosFilter->InverseOrientationFlagOn(); // Not Left to - relPosFilter->SetDirection(2); // Z axis - relPosFilter->UniqueConnectedComponentBySliceOff(); // important - relPosFilter->SetIntermediateSpacing(4); - relPosFilter->ResampleBeforeRelativePositionFilterOn(); - relPosFilter->SetFuzzyThreshold(0.9); // remove few part only - relPosFilter->RemoveObjectFlagOff(); - relPosFilter->Update(); - m_Working_Support = relPosFilter->GetOutput(); - - // Get a single 3D CCL - m_Working_Support = Labelize(m_Working_Support, 0, false, 10); - m_Working_Support = KeepLabels(m_Working_Support, - GetBackgroundValue(), - GetForegroundValue(), 1, 1, true); + // Other solution ==> with auto bounding box ! (but pb to prevent to + // be too distant from the center point - /* - // Re-Add post to Esophagus -> sometimes previous relpos remove some - // correct part below esophagus. - MaskImagePointer Esophagus = GetAFDB()->template GetImage("Esophagus"); - EnlargeEsophagusDilatationRadiusInferiorly(Esophagus); - writeImage(Esophagus, "e-again.mhd"); - typedef clitk::SliceBySliceRelativePositionFilter RelPosFilterType; - typename RelPosFilterType::Pointer relPosFilter = RelPosFilterType::New(); - relPosFilter->VerboseStepOff(); - relPosFilter->WriteStepOff(); - relPosFilter->SetInput(m_Working_Support); - relPosFilter->SetInputObject(Esophagus); - relPosFilter->SetOrientationTypeString("P"); - relPosFilter->InverseOrientationFlagOff(); - relPosFilter->SetDirection(2); // Z axis - relPosFilter->UniqueConnectedComponentBySliceOff(); // important - relPosFilter->SetIntermediateSpacing(4); - relPosFilter->ResampleBeforeRelativePositionFilterOn(); - relPosFilter->CombineWithOrFlagOn(); - relPosFilter->SetFuzzyThreshold(0.9); // remove few part only - relPosFilter->RemoveObjectFlagOff(); - relPosFilter->Update(); - m_Working_Support = relPosFilter->GetOutput(); - */ + // Extract slices + std::vector slices; + clitk::ExtractSlices(input, 2, slices); + + // 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); + */ - StopCurrentStep(m_Working_Support); - m_ListOfStations["8"] = m_Working_Support; -} + // ------- 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], + 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); + } + } +} //--------------------------------------------------------------------