X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?a=blobdiff_plain;f=segmentation%2FclitkExtractLymphStation_2RL.txx;h=7332dee29921c804c621c161e44127f17bbdc66c;hb=e3dfdd2305abb337638468aaca3d9b20718b5026;hp=542540fb9511ef4ba338ed83e6abb352a317c031;hpb=aced463099d763ade982dfc8425b23ecd6784ccd;p=clitk.git diff --git a/segmentation/clitkExtractLymphStation_2RL.txx b/segmentation/clitkExtractLymphStation_2RL.txx index 542540f..7332dee 100644 --- a/segmentation/clitkExtractLymphStation_2RL.txx +++ b/segmentation/clitkExtractLymphStation_2RL.txx @@ -11,286 +11,58 @@ // itk #include -//-------------------------------------------------------------------- -template -class comparePointsX { -public: - bool operator() (PointType i, PointType j) { return (i[0] -class comparePointsWithAngle { -public: - bool operator() (PairType i, PairType j) { return (i.second < j.second); } -}; -//-------------------------------------------------------------------- - - -//-------------------------------------------------------------------- -template -void HypercubeCorners(std::vector > & out) { - std::vector > previous; - HypercubeCorners(previous); - out.resize(previous.size()*2); - for(uint i=0; i p; - if (i -void HypercubeCorners<1>(std::vector > & out) { - out.resize(2); - out[0][0] = 0; - out[1][0] = 1; -} -//-------------------------------------------------------------------- - - -//-------------------------------------------------------------------- -template -void ComputeImageBoundariesCoordinates(typename ImageType::Pointer image, - std::vector & bounds) -{ - // Get image max/min coordinates - const uint dim=ImageType::ImageDimension; - typedef typename ImageType::PointType PointType; - typedef typename ImageType::IndexType IndexType; - PointType min_c, max_c; - IndexType min_i, max_i; - min_i = image->GetLargestPossibleRegion().GetIndex(); - for(uint i=0; iGetLargestPossibleRegion().GetSize()[i] + min_i[i]; - image->TransformIndexToPhysicalPoint(min_i, min_c); - image->TransformIndexToPhysicalPoint(max_i, max_c); - - // Get corners coordinates - HypercubeCorners(bounds); - for(uint i=0; i void clitk::ExtractLymphStationsFilter:: ExtractStation_2RL_SetDefaultValues() { - SetFuzzyThreshold("2RL", "CommonCarotidArtery", 0.7); - SetFuzzyThreshold("2RL", "BrachioCephalicTrunk", 0.7); - SetFuzzyThreshold("2RL", "BrachioCephalicVein", 0.3); - SetFuzzyThreshold("2RL", "Aorta", 0.7); - SetFuzzyThreshold("2RL", "SubclavianArteryRight", 0.5); - SetFuzzyThreshold("2RL", "SubclavianArteryLeft", 0.8); } //-------------------------------------------------------------------- //-------------------------------------------------------------------- -template +template void -clitk::ExtractLymphStationsFilter:: -ExtractStation_2RL_SI_Limits() +clitk::ExtractLymphStationsFilter:: +ExtractStation_2RL() { - // Apex of the chest or Sternum & Carina. - StartNewStep("[Station 2RL] Inf/Sup limits with Sternum and TopOfAorticArch/CaudalMarginOfLeftBrachiocephalicVein"); - - /* Rod says: "For the inferior border, unlike in Atlas – UM, there - is now a difference between 2R and 2L. 2R stops at the - intersection of the caudal margin of the innominate vein with the - trachea. 2L extends less inferiorly to the superior border of the - aortic arch." */ - - /* Get TopOfAorticArch and CaudalMarginOfLeftBrachiocephalicVein - - TopOfAorticArch -> can be obtain from Aorta -> most sup part. - - CaudalMarginOfLeftBrachiocephalicVein -> must inf part of BrachicephalicVein - */ - MaskImagePointer Aorta = GetAFDB()->template GetImage("Aorta"); - MaskImagePointType p = Aorta->GetOrigin(); // initialise to avoid warning - clitk::FindExtremaPointInAGivenDirection(Aorta, GetBackgroundValue(), 2, false, p); - double TopOfAorticArchZ=p[2]; - GetAFDB()->SetDouble("TopOfAorticArchZ", TopOfAorticArchZ); - - MaskImagePointer BrachioCephalicVein = GetAFDB()->template GetImage("BrachioCephalicVein"); - clitk::FindExtremaPointInAGivenDirection(BrachioCephalicVein, GetBackgroundValue(), 2, true, p); - double CaudalMarginOfLeftBrachiocephalicVeinZ=p[2]; - GetAFDB()->SetDouble("CaudalMarginOfLeftBrachiocephalicVeinZ", CaudalMarginOfLeftBrachiocephalicVeinZ); - - // First, cut on the most inferior part. Add one slice because this - // inf slice should not be included. - double inf = std::min(CaudalMarginOfLeftBrachiocephalicVeinZ, TopOfAorticArchZ) + m_Working_Support->GetSpacing()[2]; + if ((!CheckForStation("2R")) && (!CheckForStation("2L"))) return; - // Get Sternum and search for the upper position - MaskImagePointer Sternum = GetAFDB()->template GetImage("Sternum"); + StartNewStep("Stations 2RL"); + StartSubStep(); - // Search most sup point - clitk::FindExtremaPointInAGivenDirection(Sternum, GetBackgroundValue(), 2, false, p); - double m_SternumZ = p[2]; - // +Sternum->GetSpacing()[2]; // One more slice, because it is below this point // NOT HERE ?? WHY DIFFERENT FROM 3A ?? - - //* Crop support : - m_Working_Support = - clitk::CropImageAlongOneAxis(m_Working_Support, 2, - inf, m_SternumZ, true, - GetBackgroundValue()); - - StopCurrentStep(m_Working_Support); - m_ListOfStations["2R"] = m_Working_Support; - m_ListOfStations["2L"] = m_Working_Support; -} -//-------------------------------------------------------------------- - - -//-------------------------------------------------------------------- -template -void -clitk::ExtractLymphStationsFilter:: -ExtractStation_2RL_Ant_Limits() -{ - // ----------------------------------------------------- - /* Rod says: "The anterior border, as with the Atlas – UM, is - posterior to the vessels (right subclavian vein, left - brachiocephalic vein, right brachiocephalic vein, left subclavian - artery, left common carotid artery and brachiocephalic trunk). - These vessels are not included in the nodal station. The anterior - border is drawn to the midpoint of the vessel and an imaginary - line joins the middle of these vessels. Between the vessels, - station 2 is in contact with station 3a." */ - - // ----------------------------------------------------- - StartNewStep("[Station 2RL] Ant limits with CommonCarotidArtery"); - - // Get CommonCarotidArtery - MaskImagePointer CommonCarotidArtery = GetAFDB()->template GetImage("CommonCarotidArtery"); - - // Remove Ant to CommonCarotidArtery - typedef SliceBySliceRelativePositionFilter SliceRelPosFilterType; - typename SliceRelPosFilterType::Pointer sliceRelPosFilter = SliceRelPosFilterType::New(); - sliceRelPosFilter->VerboseStepFlagOff(); - sliceRelPosFilter->WriteStepFlagOff(); - sliceRelPosFilter->SetInput(m_Working_Support); - sliceRelPosFilter->SetInputObject(CommonCarotidArtery); - sliceRelPosFilter->SetDirection(2); - sliceRelPosFilter->SetFuzzyThreshold(GetFuzzyThreshold("2RL", "CommonCarotidArtery")); - sliceRelPosFilter->AddOrientationTypeString("NotAntTo"); - sliceRelPosFilter->IntermediateSpacingFlagOn(); - sliceRelPosFilter->SetIntermediateSpacing(2); - sliceRelPosFilter->UniqueConnectedComponentBySliceOff(); - sliceRelPosFilter->UseASingleObjectConnectedComponentBySliceFlagOff(); - sliceRelPosFilter->AutoCropFlagOn(); - sliceRelPosFilter->IgnoreEmptySliceObjectFlagOn(); - sliceRelPosFilter->RemoveObjectFlagOff(); - sliceRelPosFilter->Update(); - m_Working_Support = sliceRelPosFilter->GetOutput(); - - // End - StopCurrentStep(m_Working_Support); + // Get the current support + StartNewStep("[Station 2RL] Get the current 2RL suppport"); + m_ListOfStations["2R"] = m_ListOfSupports["S2R"]; + m_ListOfStations["2L"] = m_ListOfSupports["S2L"]; + StopCurrentStep(m_ListOfStations["2R"]); + + // Do the same limits for R & L + m_Working_Support = m_ListOfStations["2R"]; + ExtractStation_2RL_Ant_Limits("2R"); + ExtractStation_2RL_Remove_Structures(" 2R"); m_ListOfStations["2R"] = m_Working_Support; - m_ListOfStations["2L"] = m_Working_Support; - - // ----------------------------------------------------- - // Remove Ant to H line from the Ant most part of the - // CommonCarotidArtery until we reach the first slice of - // BrachioCephalicTrunk - StartNewStep("[Station 2RL] Ant limits with CommonCarotidArtery, H line"); - - // First, find the first slice of BrachioCephalicTrunk - MaskImagePointer BrachioCephalicTrunk = GetAFDB()->template GetImage("BrachioCephalicTrunk"); - MaskImagePointType p = BrachioCephalicTrunk->GetOrigin(); // initialise to avoid warning - clitk::FindExtremaPointInAGivenDirection(BrachioCephalicTrunk, GetBackgroundValue(), 2, false, p); - double TopOfBrachioCephalicTrunkZ=p[2] + BrachioCephalicTrunk->GetSpacing()[2]; // Add one slice - - // Remove CommonCarotidArtery below this point - CommonCarotidArtery = clitk::CropImageRemoveLowerThan(CommonCarotidArtery, 2, TopOfBrachioCephalicTrunkZ, true, GetBackgroundValue()); - // Find most Ant points - std::vector ccaAntPositionA; - std::vector ccaAntPositionB; - clitk::SliceBySliceBuildLineSegmentAccordingToExtremaPosition(CommonCarotidArtery, - GetBackgroundValue(), 2, - 1, true, // Ant - 0, // Horizontal line - -3, // margin - ccaAntPositionA, - ccaAntPositionB); - // Cut ant to this line - clitk::SliceBySliceSetBackgroundFromLineSeparation(m_Working_Support, - ccaAntPositionA, - ccaAntPositionB, - GetBackgroundValue(), 1, 10); - - // End - StopCurrentStep(m_Working_Support); - m_ListOfStations["2R"] = m_Working_Support; + m_Working_Support = m_ListOfStations["2L"]; + ExtractStation_2RL_Ant_Limits("2L"); + ExtractStation_2RL_Remove_Structures(" 2L"); m_ListOfStations["2L"] = m_Working_Support; - // ----------------------------------------------------- - // Ant limit with the BrachioCephalicTrunk - StartNewStep("[Station 2RL] Ant limits with BrachioCephalicTrunk line"); - - // Remove Ant to BrachioCephalicTrunk - m_Working_Support = - clitk::SliceBySliceRelativePosition(m_Working_Support, BrachioCephalicTrunk, 2, - GetFuzzyThreshold("2RL", "BrachioCephalicTrunk"), "NotAntTo", false, 2, true, false); - // End - StopCurrentStep(m_Working_Support); - m_ListOfStations["2R"] = m_Working_Support; - m_ListOfStations["2L"] = m_Working_Support; + // Remove superior part to BrachioCephalicVein (used then by RelPos) + ExtractStation_2RL_Cut_BrachioCephalicVein_superiorly_when_it_split(); - // ----------------------------------------------------- - // Ant limit with the BrachioCephalicTrunk H line - StartNewStep("[Station 2RL] Ant limits with BrachioCephalicTrunk, Horizontal line"); + // Generic RelativePosition processes + m_ListOfStations["2R"] = this->ApplyRelativePositionList("Station_2R", m_ListOfStations["2R"]); + m_ListOfStations["2L"] = this->ApplyRelativePositionList("Station_2L", m_ListOfStations["2L"]); - // Find most Ant points - std::vector bctAntPositionA; - std::vector bctAntPositionB; - clitk::SliceBySliceBuildLineSegmentAccordingToExtremaPosition(BrachioCephalicTrunk, - GetBackgroundValue(), 2, - 1, true, // Ant - 0, // Horizontal line - -1, // margin - bctAntPositionA, - bctAntPositionB); - // Cut ant to this line - clitk::SliceBySliceSetBackgroundFromLineSeparation(m_Working_Support, - bctAntPositionA, - bctAntPositionB, - GetBackgroundValue(), 1, 10); - // End - StopCurrentStep(m_Working_Support); - m_ListOfStations["2R"] = m_Working_Support; - m_ListOfStations["2L"] = m_Working_Support; - - // ----------------------------------------------------- - // Ant limit with the BrachioCephalicVein - StartNewStep("[Station 2RL] Ant limits with BrachioCephalicVein"); - - // Remove Ant to BrachioCephalicVein - MaskImagePointer BrachioCephalicVein = GetAFDB()->template GetImage("BrachioCephalicVein"); - m_Working_Support = - clitk::SliceBySliceRelativePosition(m_Working_Support, BrachioCephalicVein, 2, - GetFuzzyThreshold("2RL", "BrachioCephalicVein"), "NotAntTo", false, 2, true, false); - // End - StopCurrentStep(m_Working_Support); - m_ListOfStations["2R"] = m_Working_Support; - m_ListOfStations["2L"] = m_Working_Support; + // Store image filenames into AFDB + writeImage(m_ListOfStations["2R"], "seg/Station2R.mhd"); + writeImage(m_ListOfStations["2L"], "seg/Station2L.mhd"); + GetAFDB()->SetImageFilename("Station2R", "seg/Station2R.mhd"); + GetAFDB()->SetImageFilename("Station2L", "seg/Station2L.mhd"); + WriteAFDB(); + StopSubStep(); } //-------------------------------------------------------------------- @@ -299,299 +71,22 @@ ExtractStation_2RL_Ant_Limits() template void clitk::ExtractLymphStationsFilter:: -ExtractStation_2RL_Ant_Limits2() +ExtractStation_2RL_Ant_Limits(std::string s) { // ----------------------------------------------------- - /* Rod says: "The anterior border, as with the Atlas – UM, is - posterior to the vessels (right subclavian vein, left - brachiocephalic vein, right brachiocephalic vein, left subclavian - artery, left common carotid artery and brachiocephalic trunk). - These vessels are not included in the nodal station. The anterior - border is drawn to the midpoint of the vessel and an imaginary - line joins the middle of these vessels. Between the vessels, - station 2 is in contact with station 3a." */ - - // ----------------------------------------------------- - StartNewStep("[Station 2RL] Ant limits with vessels centroids"); - - /* Here, we consider the vessels form a kind of anterior barrier. We - link all vessels centroids and remove what is post to it. - - select the list of structure - vessel1 = BrachioCephalicTrunk - vessel2 = BrachioCephalicVein (warning several CCL, keep most at Right) - vessel3 = CommonCarotidArtery - vessel4 = SubclavianArtery - other = Thyroid - other = Aorta - - crop images as needed - - slice by slice, choose the CCL and extract centroids - - slice by slice, sort according to polar angle wrt Trachea centroid. - - slice by slice, link centroids and close contour - - remove outside this contour - - merge with support - */ - - // Read structures - MaskImagePointer BrachioCephalicTrunk = GetAFDB()->template GetImage("BrachioCephalicTrunk"); - MaskImagePointer BrachioCephalicVein = GetAFDB()->template GetImage("BrachioCephalicVein"); - MaskImagePointer CommonCarotidArtery = GetAFDB()->template GetImage("CommonCarotidArtery"); - MaskImagePointer SubclavianArtery = GetAFDB()->template GetImage("SubclavianArtery"); - MaskImagePointer Thyroid = GetAFDB()->template GetImage("Thyroid"); - MaskImagePointer Aorta = GetAFDB()->template GetImage("Aorta"); - MaskImagePointer Trachea = GetAFDB()->template GetImage("Trachea"); + StartNewStep("[Station "+s+"] Ant limits with vessels centroids"); - // Resize all structures like support - BrachioCephalicTrunk = - clitk::ResizeImageLike(BrachioCephalicTrunk, m_Working_Support, GetBackgroundValue()); - CommonCarotidArtery = - clitk::ResizeImageLike(CommonCarotidArtery, m_Working_Support, GetBackgroundValue()); - SubclavianArtery = - clitk::ResizeImageLike(SubclavianArtery, m_Working_Support, GetBackgroundValue()); - Thyroid = - clitk::ResizeImageLike(Thyroid, m_Working_Support, GetBackgroundValue()); - Aorta = - clitk::ResizeImageLike(Aorta, m_Working_Support, GetBackgroundValue()); - BrachioCephalicVein = - clitk::ResizeImageLike(BrachioCephalicVein, m_Working_Support, GetBackgroundValue()); - Trachea = - clitk::ResizeImageLike(Trachea, m_Working_Support, GetBackgroundValue()); - - // Extract slices - std::vector slices_BrachioCephalicTrunk; - clitk::ExtractSlices(BrachioCephalicTrunk, 2, slices_BrachioCephalicTrunk); - std::vector slices_BrachioCephalicVein; - clitk::ExtractSlices(BrachioCephalicVein, 2, slices_BrachioCephalicVein); - std::vector slices_CommonCarotidArtery; - clitk::ExtractSlices(CommonCarotidArtery, 2, slices_CommonCarotidArtery); - std::vector slices_SubclavianArtery; - clitk::ExtractSlices(SubclavianArtery, 2, slices_SubclavianArtery); - std::vector slices_Thyroid; - clitk::ExtractSlices(Thyroid, 2, slices_Thyroid); - std::vector slices_Aorta; - clitk::ExtractSlices(Aorta, 2, slices_Aorta); - std::vector slices_Trachea; - clitk::ExtractSlices(Trachea, 2, slices_Trachea); - uint n= slices_BrachioCephalicTrunk.size(); - - // Get the boundaries of one slice - std::vector bounds; - ComputeImageBoundariesCoordinates(slices_BrachioCephalicTrunk[0], bounds); - - // For all slices, for all structures, find the centroid and build the contour - // List of 3D points (for debug) - std::vector p3D; - - vtkSmartPointer append = vtkSmartPointer::New(); - for(uint i=0; i(slices_CommonCarotidArtery[i], - GetBackgroundValue(), true, 1); - slices_SubclavianArtery[i] = Labelize(slices_SubclavianArtery[i], - GetBackgroundValue(), true, 1); - slices_BrachioCephalicTrunk[i] = Labelize(slices_BrachioCephalicTrunk[i], - GetBackgroundValue(), true, 1); - slices_BrachioCephalicVein[i] = Labelize(slices_BrachioCephalicVein[i], - GetBackgroundValue(), true, 1); - slices_Thyroid[i] = Labelize(slices_Thyroid[i], - GetBackgroundValue(), true, 1); - slices_Aorta[i] = Labelize(slices_Aorta[i], - GetBackgroundValue(), true, 1); - - // Search centroids - std::vector points2D; - std::vector centroids1; - std::vector centroids2; - std::vector centroids3; - std::vector centroids4; - std::vector centroids5; - std::vector centroids6; - ComputeCentroids(slices_CommonCarotidArtery[i], GetBackgroundValue(), centroids1); - ComputeCentroids(slices_SubclavianArtery[i], GetBackgroundValue(), centroids2); - ComputeCentroids(slices_BrachioCephalicTrunk[i], GetBackgroundValue(), centroids3); - ComputeCentroids(slices_Thyroid[i], GetBackgroundValue(), centroids4); - ComputeCentroids(slices_Aorta[i], GetBackgroundValue(), centroids5); - ComputeCentroids(slices_BrachioCephalicVein[i], GetBackgroundValue(), centroids6); - - // BrachioCephalicVein -> when it is separated into two CCL, we - // only consider the most at Right one - if (centroids6.size() > 2) { - if (centroids6[1][0] < centroids6[2][0]) centroids6.erase(centroids6.begin()+2); - else centroids6.erase(centroids6.begin()+1); - } - - // BrachioCephalicVein -> when SubclavianArtery has 2 CCL - // (BrachioCephalicTrunk is divided) -> forget BrachioCephalicVein - if ((centroids3.size() ==1) && (centroids2.size() > 2)) { - centroids6.clear(); - } - - for(uint j=1; j centroids_trachea; - ComputeCentroids(slices_Trachea[i], GetBackgroundValue(), centroids_trachea); - typedef std::pair PointAngleType; - std::vector angles; - for(uint j=0; j0) angle = atan(y/x); - if ((x<0) && (y>=0)) angle = atan(y/x)+M_PI; - if ((x<0) && (y<0)) angle = atan(y/x)-M_PI; - if (x==0) { - if (y>0) angle = M_PI/2.0; - if (y<0) angle = -M_PI/2.0; - if (y==0) angle = 0; - } - angle = clitk::rad2deg(angle); - // Angle is [-180;180] wrt the X axis. We change the X axis to - // be the vertical line, because we want to sort from Right to - // Left from Post to Ant. - if (angle>0) - angle = (270-angle); - if (angle<0) { - angle = -angle-90; - if (angle<0) angle = 360-angle; - } - PointAngleType a; - a.first = points2D[j]; - a.second = angle; - angles.push_back(a); - } - - // Do nothing if less than 2 points --> n - if (points2D.size() < 3) { //continue; - continue; - } - - // Sort points2D according to polar angles - std::sort(angles.begin(), angles.end(), comparePointsWithAngle()); - for(uint j=0; j toadd; - uint index = 0; - double dmax = 5; - while (indexdmax) { - - MaskSlicePointType b; - b[0] = a[0]+(c[0]-a[0])/2.0; - b[1] = a[1]+(c[1]-a[1])/2.0; - - // Compute distance to trachea centroid - MaskSlicePointType m = centroids_trachea[1]; - double da = m.EuclideanDistanceTo(a); - double db = m.EuclideanDistanceTo(b); - //double dc = m.EuclideanDistanceTo(c); - - // Mean distance, find point on the line from trachea centroid - // to b - double alpha = (da+db)/2.0; - MaskSlicePointType v; - double n = sqrt( pow(b[0]-m[0], 2) + pow(b[1]-m[1], 2)); - v[0] = (b[0]-m[0])/n; - v[1] = (b[1]-m[1])/n; - MaskSlicePointType r; - r[0] = m[0]+alpha*v[0]; - r[1] = m[1]+alpha*v[1]; - points2D.insert(points2D.begin()+index+1, r); - } - else { - index++; - } - } - // DDV(points2D, points2D.size()); - - // Add some points to close the contour - // - H line towards Right - MaskSlicePointType p = points2D[0]; - p[0] = bounds[0][0]; - points2D.insert(points2D.begin(), p); - // - corner Right/Post - p = bounds[0]; - points2D.insert(points2D.begin(), p); - // - H line towards Left - p = points2D.back(); - p[0] = bounds[2][0]; - points2D.push_back(p); - // - corner Right/Post - p = bounds[2]; - points2D.push_back(p); - // Close contour with the first point - points2D.push_back(points2D[0]); - // DDV(points2D, points2D.size()); - - // Build 3D points from the 2D points - std::vector points3D; - clitk::PointsUtils::Convert2DListTo3DList(points2D, i, m_Working_Support, points3D); - for(uint x=0; x mesh = Build3DMeshFrom2DContour(points3D); - append->AddInput(mesh); - } - - // DEBUG: write points3D - clitk::WriteListOfLandmarks(p3D, "vessels-centroids.txt"); - - // Build the final 3D mesh form the list 2D mesh - append->Update(); - vtkSmartPointer mesh = append->GetOutput(); - - // Debug, write the mesh - /* - vtkSmartPointer w = vtkSmartPointer::New(); - w->SetInput(mesh); - w->SetFileName("bidon.vtk"); - w->Write(); - */ - - // Compute a single binary 3D image from the list of contours - clitk::MeshToBinaryImageFilter::Pointer filter = - clitk::MeshToBinaryImageFilter::New(); - filter->SetMesh(mesh); - filter->SetLikeImage(m_Working_Support); - filter->Update(); - MaskImagePointer binarizedContour = filter->GetOutput(); - - // Inverse binary mask if needed. We test a point that we know must be in FG. If it is not, inverse - ImagePointType p = p3D[2]; // This is the first centroid of the first slice - p[1] += 50; // 50 mm Post from this point must be kept - ImageIndexType index; - binarizedContour->TransformPhysicalPointToIndex(p, index); - bool isInside = (binarizedContour->GetPixel(index) != GetBackgroundValue()); - + // WARNING, as I used "And" after, empty slice in binarizedContour + // lead to remove part of the support, although we want to keep + // unchanged. So we decide to ResizeImageLike but pad with + // ForegroundValue instead of BG + + // Get or compute the binary mask that separate Ant/Post part + // according to vessels + MaskImagePointer binarizedContour = FindAntPostVessels2(); + binarizedContour = clitk::ResizeImageLike(binarizedContour, + m_Working_Support, + GetForegroundValue()); // remove from support typedef clitk::BooleanOperatorLabelImageFilter BoolFilterType; typename BoolFilterType::Pointer boolFilter = BoolFilterType::New(); @@ -600,17 +95,12 @@ ExtractStation_2RL_Ant_Limits2() boolFilter->SetInput2(binarizedContour); boolFilter->SetBackgroundValue1(GetBackgroundValue()); boolFilter->SetBackgroundValue2(GetBackgroundValue()); - if (isInside) - boolFilter->SetOperationType(BoolFilterType::And); - else - boolFilter->SetOperationType(BoolFilterType::AndNot); + boolFilter->SetOperationType(BoolFilterType::And); boolFilter->Update(); m_Working_Support = boolFilter->GetOutput(); - + // End StopCurrentStep(m_Working_Support); - m_ListOfStations["2R"] = m_Working_Support; - m_ListOfStations["2L"] = m_Working_Support; } //-------------------------------------------------------------------- @@ -619,35 +109,43 @@ ExtractStation_2RL_Ant_Limits2() template void clitk::ExtractLymphStationsFilter:: -ExtractStation_2RL_Post_Limits() +ExtractStation_2RL_Cut_BrachioCephalicVein_superiorly_when_it_split() { - StartNewStep("[Station 2RL] Post limits with post wall of Trachea"); - - // Get Trachea - MaskImagePointer Trachea = GetAFDB()->template GetImage("Trachea"); + // ----------------------------------------------------- + StartNewStep("[Station 2RL] Cut BrachioCephalicVein superiorly (when it split)"); - // Resize like the current support (to have the same number of slices) - Trachea = clitk::ResizeImageLike(Trachea, m_Working_Support, GetBackgroundValue()); + // Get BrachioCephalicVein + MaskImagePointer BrachioCephalicVein = GetAFDB()->template GetImage("BrachioCephalicVein"); + + // Remove the part superior to the slice where BrachioCephalicVein + // divide in two CCL + std::vector BCV_slices; + clitk::ExtractSlices(BrachioCephalicVein, 2, BCV_slices); + bool stop = false; + uint i=0; + while (!stop) { + // Count the number of CCL + int nb; + clitk::LabelizeAndCountNumberOfObjects(BCV_slices[i], GetBackgroundValue(), true, 1, nb); + if (nb>1) stop = true; + i++; + } + // Convert slice into coordinate + MaskImagePointType p; + MaskImageIndexType index; + index[0] = index[1] = 0; + index[2] = i; + BrachioCephalicVein->TransformIndexToPhysicalPoint(index, p); + BrachioCephalicVein = + clitk::CropImageRemoveGreaterThan(BrachioCephalicVein, 2, + p[2], true, + GetBackgroundValue()); - // Find extrema post positions - std::vector tracheaPostPositionsA; - std::vector tracheaPostPositionsB; - clitk::SliceBySliceBuildLineSegmentAccordingToExtremaPosition(Trachea, - GetBackgroundValue(), 2, - 1, false, // Post - 0, // Horizontal line - 1, - tracheaPostPositionsA, - tracheaPostPositionsB); - // Cut post to this line - clitk::SliceBySliceSetBackgroundFromLineSeparation(m_Working_Support, - tracheaPostPositionsA, - tracheaPostPositionsB, - GetBackgroundValue(), 1, -10); - // END - StopCurrentStep(m_Working_Support); - m_ListOfStations["2R"] = m_Working_Support; - m_ListOfStations["2L"] = m_Working_Support; + // Now, insert this image in the AFDB (but do not store on disk) + GetAFDB()->template SetImage("BrachioCephalicVein_ForS2RL", "bidon", + BrachioCephalicVein, false); + // End + StopCurrentStep(BrachioCephalicVein); } //-------------------------------------------------------------------- @@ -681,173 +179,18 @@ Build3DMeshFrom2DContour(const std::vector & points) template void clitk::ExtractLymphStationsFilter:: -ExtractStation_2RL_LR_Limits() +ExtractStation_2RL_Remove_Structures(std::string s) { - // --------------------------------------------------------------------------- - StartNewStep("[Station 2RL] Left/Right limits with Aorta"); - MaskImagePointer Aorta = GetAFDB()->template GetImage("Aorta"); - // DD(GetFuzzyThreshold("2RL", "BrachioCephalicVein")); - m_Working_Support = - clitk::SliceBySliceRelativePosition(m_Working_Support, Aorta, 2, - GetFuzzyThreshold("2RL", "Aorta"), - "RightTo", false, 2, true, false); - // END - StopCurrentStep(m_Working_Support); - m_ListOfStations["2R"] = m_Working_Support; - m_ListOfStations["2L"] = m_Working_Support; - - // --------------------------------------------------------------------------- - StartNewStep("[Station 2RL] Left/Right limits with SubclavianArtery (Right)"); - - // SliceBySliceRelativePosition + select CCL most at Right - MaskImagePointer SubclavianArtery = GetAFDB()->template GetImage("SubclavianArtery"); - typedef SliceBySliceRelativePositionFilter SliceRelPosFilterType; - typename SliceRelPosFilterType::Pointer sliceRelPosFilter = SliceRelPosFilterType::New(); - sliceRelPosFilter->VerboseStepFlagOff(); - sliceRelPosFilter->WriteStepFlagOff(); - sliceRelPosFilter->SetInput(m_Working_Support); - sliceRelPosFilter->SetInputObject(SubclavianArtery); - sliceRelPosFilter->SetDirection(2); - sliceRelPosFilter->SetFuzzyThreshold(GetFuzzyThreshold("2RL", "SubclavianArteryRight")); - sliceRelPosFilter->AddOrientationTypeString("NotRightTo"); - sliceRelPosFilter->IntermediateSpacingFlagOn(); - sliceRelPosFilter->SetIntermediateSpacing(2); - sliceRelPosFilter->UniqueConnectedComponentBySliceOff(); - sliceRelPosFilter->UseASingleObjectConnectedComponentBySliceFlagOff(); - - sliceRelPosFilter->CCLSelectionFlagOn(); // select one CCL by slice - sliceRelPosFilter->SetCCLSelectionDimension(0); // select according to X (0) axis - sliceRelPosFilter->SetCCLSelectionDirection(-1); // select most at Right - sliceRelPosFilter->CCLSelectionIgnoreSingleCCLFlagOn(); // ignore if only one CCL - - sliceRelPosFilter->AutoCropFlagOn(); - sliceRelPosFilter->IgnoreEmptySliceObjectFlagOn(); - sliceRelPosFilter->RemoveObjectFlagOff(); - sliceRelPosFilter->Update(); - m_Working_Support = sliceRelPosFilter->GetOutput(); - - // END - StopCurrentStep(m_Working_Support); - m_ListOfStations["2R"] = m_Working_Support; - m_ListOfStations["2L"] = m_Working_Support; - - - // --------------------------------------------------------------------------- - StartNewStep("[Station 2RL] Left/Right limits with SubclavianArtery (Left)"); - - // SliceBySliceRelativePosition + select CCL most at Right - sliceRelPosFilter = SliceRelPosFilterType::New(); - sliceRelPosFilter->VerboseStepFlagOff(); - sliceRelPosFilter->WriteStepFlagOff(); - sliceRelPosFilter->SetInput(m_Working_Support); - sliceRelPosFilter->SetInputObject(SubclavianArtery); - sliceRelPosFilter->SetDirection(2); - sliceRelPosFilter->SetFuzzyThreshold(GetFuzzyThreshold("2RL", "SubclavianArteryLeft")); - sliceRelPosFilter->AddOrientationTypeString("NotLeftTo"); - sliceRelPosFilter->IntermediateSpacingFlagOn(); - sliceRelPosFilter->SetIntermediateSpacing(2); - sliceRelPosFilter->UniqueConnectedComponentBySliceOff(); - sliceRelPosFilter->UseASingleObjectConnectedComponentBySliceFlagOff(); - - sliceRelPosFilter->CCLSelectionFlagOn(); // select one CCL by slice - sliceRelPosFilter->SetCCLSelectionDimension(0); // select according to X (0) axis - sliceRelPosFilter->SetCCLSelectionDirection(+1); // select most at Left - sliceRelPosFilter->CCLSelectionIgnoreSingleCCLFlagOff(); // do not ignore if only one CCL - - sliceRelPosFilter->AutoCropFlagOn(); - sliceRelPosFilter->IgnoreEmptySliceObjectFlagOn(); - sliceRelPosFilter->RemoveObjectFlagOff(); - sliceRelPosFilter->Update(); - m_Working_Support = sliceRelPosFilter->GetOutput(); - - // END - StopCurrentStep(m_Working_Support); - m_ListOfStations["2R"] = m_Working_Support; - m_ListOfStations["2L"] = m_Working_Support; -} -//-------------------------------------------------------------------- - -//-------------------------------------------------------------------- -template -void -clitk::ExtractLymphStationsFilter:: -ExtractStation_2RL_Remove_Structures() -{ - Remove_Structures("2RL", "BrachioCephalicVein"); - Remove_Structures("2RL", "CommonCarotidArtery"); - Remove_Structures("2RL", "SubclavianArtery"); - Remove_Structures("2RL", "Thyroid"); - Remove_Structures("2RL", "Aorta"); - - // END - StopCurrentStep(m_Working_Support); - m_ListOfStations["2R"] = m_Working_Support; - m_ListOfStations["2L"] = m_Working_Support; + // m_Working_Support must be set + Remove_Structures(s, "BrachioCephalicVein"); + Remove_Structures(s, "BrachioCephalicArtery"); + Remove_Structures(s, "LeftCommonCarotidArtery"); + Remove_Structures(s, "RightCommonCarotidArtery"); + Remove_Structures(s, "LeftSubclavianArtery"); + Remove_Structures(s, "RightSubclavianArtery"); + Remove_Structures(s, "Thyroid"); + Remove_Structures(s, "Aorta"); } //-------------------------------------------------------------------- -//-------------------------------------------------------------------- -template -void -clitk::ExtractLymphStationsFilter:: -ExtractStation_2RL_SeparateRL() -{ - // --------------------------------------------------------------------------- - StartNewStep("[Station 2RL] Separate 2R/2L according to Trachea"); - - /*Rod says: - - "For station 2 there is a shift, dividing 2R from 2L, from midline - to the left paratracheal border." - - Algo: - - Consider Trachea SliceBySlice - - find extrema at Left - - add margins towards Right - - remove what is at Left of this line - */ - - // Get Trachea - MaskImagePointer Trachea = GetAFDB()->template GetImage("Trachea"); - - // Resize like the current support (to have the same number of slices) - Trachea = clitk::ResizeImageLike(Trachea, m_Working_Support, GetBackgroundValue()); - - // Find extrema post positions - std::vector tracheaLeftPositionsA; - std::vector tracheaLeftPositionsB; - clitk::SliceBySliceBuildLineSegmentAccordingToExtremaPosition(Trachea, - GetBackgroundValue(), 2, - 0, false, // Left - 1, // Vertical line - 1, // margins - tracheaLeftPositionsA, - tracheaLeftPositionsB); - // Copy support for R and L - typedef itk::ImageDuplicator DuplicatorType; - DuplicatorType::Pointer duplicator = DuplicatorType::New(); - duplicator->SetInputImage(m_Working_Support); - duplicator->Update(); - MaskImageType::Pointer m_Working_Support2 = duplicator->GetOutput(); - - // Cut post to this line for Right part - clitk::SliceBySliceSetBackgroundFromLineSeparation(m_Working_Support, - tracheaLeftPositionsA, - tracheaLeftPositionsB, - GetBackgroundValue(), 0, -10); - writeImage(m_Working_Support, "R.mhd"); - - // Cut post to this line for Left part - clitk::SliceBySliceSetBackgroundFromLineSeparation(m_Working_Support2, - tracheaLeftPositionsA, - tracheaLeftPositionsB, - GetBackgroundValue(), 0, +10); - writeImage(m_Working_Support2, "L.mhd"); - - // END - StopCurrentStep(m_Working_Support); - m_ListOfStations["2R"] = m_Working_Support; - m_ListOfStations["2L"] = m_Working_Support2; -} -//--------------------------------------------------------------------