SetEsophagusDiltationForAnt(p);
p[0] = 5; p[1] = 10; p[2] = 1;
SetEsophagusDiltationForRight(p);
- SetFuzzyThresholdForS8(0.5);
+ SetFuzzyThreshold("8", "Esophagus", 0.5);
+ SetInjectedThresholdForS8(150);
}
//--------------------------------------------------------------------
// Get Carina Z position
MaskImagePointer Carina = GetAFDB()->template GetImage<MaskImageType>("Carina");
- // CHANGE TO -> OriginOfRightMiddleLobeBronchus ???
-
std::vector<MaskImagePointType> centroids;
clitk::ComputeCentroids<MaskImageType>(Carina, GetBackgroundValue(), centroids);
m_CarinaZ = centroids[1][2];
+ // DD(m_CarinaZ);
// add one slice to include carina ?
m_CarinaZ += m_Mediastinum->GetSpacing()[2];
// We dont need Carina structure from now
Carina->Delete();
GetAFDB()->SetDouble("CarinaZ", m_CarinaZ);
- // Get left lower lobe bronchus (L), take the upper border
- // Get right bronchus intermedius (RML), take the lower border
-
- /*
- double m_CarinaZ = GetAFDB()->GetPoint3D("Carina", 2) +
- m_Mediastinum->GetSpacing()[2]; // add one slice to include carina
- // double GOjunctionZ = GetAFDB()->GetPoint3D("GOjunction", 2);
- */
-
// Found most inferior part of the lung
MaskImagePointer Lungs = GetAFDB()->template GetImage<MaskImageType>("Lungs");
// It should be already croped, so I took the origin and add 10mm above
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();
+ boolFilter->Update();
+ /*
+
+ DO NOT REMOVE AORTA YET (LATER)
+
+ boolFilter->SetInput1(boolFilter->GetOutput());
+ boolFilter->SetInput2(Aorta);
+ boolFilter->SetOperationType(BoolFilterType::AndNot);
+ boolFilter->Update();
+ */
m_Working_Support = boolFilter->GetOutput();
// Done.
// Convert 2D points in slice into 3D points
std::vector<MaskImagePointType> vertebralAntPositions;
- clitk::PointsUtils<MaskImageType>::Convert2DTo3DList(vertebralAntPositionBySlice,
- VertebralBody,
- vertebralAntPositions);
+ clitk::PointsUtils<MaskImageType>::Convert2DMapTo3DList(vertebralAntPositionBySlice,
+ VertebralBody,
+ vertebralAntPositions);
// DEBUG : write list of points
clitk::WriteListOfLandmarks<MaskImageType>(vertebralAntPositions,
- "vertebralMostAntPositions.txt");
+ "S8-vertebralMostAntPositions-points.txt");
// Cut support posteriorly 1cm the most anterior point of the
// VertebralBody. Do nothing below and above the VertebralBody. To
template <class ImageType>
void
clitk::ExtractLymphStationsFilter<ImageType>::
-ExtractStation_8_Ant_Limits()
+ExtractStation_8_Ant_Sup_Limits()
{
//--------------------------------------------------------------------
StartNewStep("[Station8] Ant limits with S7 above Carina");
MaskImagePointer Trachea = GetAFDB()->template GetImage<MaskImageType>("Trachea");
MaskImagePointer m_Working_Trachea =
- clitk::CropImageAbove<MaskImageType>(Trachea, 2, m_CarinaZ, true, // AutoCrop
+ clitk::CropImageRemoveGreaterThan<MaskImageType>(Trachea, 2, m_CarinaZ, true, // AutoCrop
GetBackgroundValue());
// Seprate into two main bronchi
- MaskImagePointer LeftBronchus;
MaskImagePointer RightBronchus;
+ MaskImagePointer LeftBronchus;
// Labelize and consider the two first (main) labels
m_Working_Trachea = Labelize<MaskImageType>(m_Working_Trachea, 0, true, 1);
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; }
+ ImagePixelType rightLabel;
+ ImagePixelType leftLabel;
+ if (C1[0] < C2[0]) { rightLabel = 1; leftLabel = 2; }
+ else { rightLabel = 2; leftLabel = 1; }
// Select LeftLabel (set one label to Backgroundvalue)
- LeftBronchus =
+ RightBronchus =
+ clitk::Binarize<MaskImageType>(m_Working_Trachea, rightLabel, rightLabel,
+ GetBackgroundValue(), GetForegroundValue());
+ /*
SetBackground<MaskImageType, MaskImageType>(m_Working_Trachea, m_Working_Trachea,
- rightLabel, GetBackgroundValue(), false);
- RightBronchus =
+ leftLabel, GetBackgroundValue(), false);
+ */
+ LeftBronchus = clitk::Binarize<MaskImageType>(m_Working_Trachea, leftLabel, leftLabel,
+ GetBackgroundValue(), GetForegroundValue());
+ /*
SetBackground<MaskImageType, MaskImageType>(m_Working_Trachea, m_Working_Trachea,
- leftLabel, GetBackgroundValue(), false);
+ rightLabel, GetBackgroundValue(), false);
+ */
+
// Crop images
- LeftBronchus = clitk::AutoCrop<MaskImageType>(LeftBronchus, GetBackgroundValue());
RightBronchus = clitk::AutoCrop<MaskImageType>(RightBronchus, GetBackgroundValue());
+ LeftBronchus = clitk::AutoCrop<MaskImageType>(LeftBronchus, GetBackgroundValue());
// Insert int AFDB if need after
- GetAFDB()->template SetImage <MaskImageType>("LeftBronchus", "seg/leftBronchus.mhd",
- LeftBronchus, true);
GetAFDB()->template SetImage <MaskImageType>("RightBronchus", "seg/rightBronchus.mhd",
RightBronchus, true);
+ GetAFDB()->template SetImage <MaskImageType>("LeftBronchus", "seg/leftBronchus.mhd",
+ LeftBronchus, true);
// Now crop below OriginOfRightMiddleLobeBronchusZ
// It is not done before to keep entire bronchi.
clitk::ComputeCentroids<MaskImageType>(OriginOfRightMiddleLobeBronchus, GetBackgroundValue(), centroids);
m_OriginOfRightMiddleLobeBronchusZ = centroids[1][2];
// add one slice to include carina ?
- m_OriginOfRightMiddleLobeBronchusZ += LeftBronchus->GetSpacing()[2];
+ m_OriginOfRightMiddleLobeBronchusZ += RightBronchus->GetSpacing()[2];
// We dont need Carina structure from now
OriginOfRightMiddleLobeBronchus->Delete();
- LeftBronchus =
- clitk::CropImageBelow<MaskImageType>(LeftBronchus, 2,
+ RightBronchus =
+ clitk::CropImageRemoveLowerThan<MaskImageType>(RightBronchus, 2,
m_OriginOfRightMiddleLobeBronchusZ,
true, // AutoCrop
GetBackgroundValue());
- RightBronchus =
- clitk::CropImageBelow<MaskImageType>(RightBronchus, 2,
+ LeftBronchus =
+ clitk::CropImageRemoveLowerThan<MaskImageType>(LeftBronchus, 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,
+ FindExtremaPointsInBronchus(RightBronchus, 0, 10, m_LeftMostInRightBronchus,
m_AntMostInRightBronchus, m_PostMostInRightBronchus);
+ FindExtremaPointsInBronchus(LeftBronchus, 1, 10, m_RightMostInLeftBronchus,
+ m_AntMostInLeftBronchus, m_PostMostInLeftBronchus);
+
// DEBUG : write the list of points
ListOfPointsType v;
+ 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<MaskImageType>(v, "S8-RightBronchus-points.txt");
+
+ v.clear();
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<MaskImageType>(v, "LeftBronchusPoints.txt");
+ clitk::WriteListOfLandmarks<MaskImageType>(v, "S8-LeftBronchus-points.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.reserve(m_PostMostInLeftBronchus.size()+m_PostMostInRightBronchus.size());
+ v.insert(v.end(), m_PostMostInLeftBronchus.begin(), m_PostMostInLeftBronchus.end() );
v.insert(v.end(), m_PostMostInRightBronchus.begin(), m_PostMostInRightBronchus.end() );
- clitk::WriteListOfLandmarks<MaskImageType>(v, "RightBronchusPoints.txt");
+ clitk::WriteListOfLandmarks<MaskImageType>(v, "S8-RightLeftBronchus-points.txt");
// Now uses these points to limit, slice by slice
// line is mainly horizontal, so mainDirection=1
- writeImage<MaskImageType>(m_Working_Support, "before.mhd");
clitk::SliceBySliceSetBackgroundFromLineSeparation<MaskImageType>(m_Working_Support,
- m_PostMostInLeftBronchus,
m_PostMostInRightBronchus,
+ m_PostMostInLeftBronchus,
GetBackgroundValue(), 1, 10);
- writeImage<MaskImageType>(m_Working_Support, "after.mhd");
// Keep main 3D CCL :
m_Working_Support = Labelize<MaskImageType>(m_Working_Support, 0, false, 10);
template <class ImageType>
void
clitk::ExtractLymphStationsFilter<ImageType>::
-ExtractStation_8_LR_Limits()
+ExtractStation_8_Ant_Inf_Limits()
{
//--------------------------------------------------------------------
- StartNewStep("[Station8] Ant part (not post to Esophagus)");
+ StartNewStep("[Station8] Ant part: not post to Esophagus");
/*
Consider Esophagus, dilate it and remove ant part. It remains part
on L & R, than can be partly removed by cutting what remains at
*/
// Get Esophagus
- MaskImagePointer Esophagus = GetAFDB()->template GetImage<MaskImageType>("Esophagus");
+ m_Esophagus = GetAFDB()->template GetImage<MaskImageType>("Esophagus");
clitk::PrintMemory(GetVerboseMemoryFlag(), "after read Esophagus");
// In images from the original article, Atlas – UM, the oesophagus
//Dr. Aletta Frasier exclude this structure. From an oncological
//prospective, the oesophagus should be excluded from these nodal
//stations.
- typedef clitk::BooleanOperatorLabelImageFilter<MaskImageType> BoolFilterType;
- typename BoolFilterType::Pointer boolFilter = BoolFilterType::New();
- boolFilter->InPlaceOn();
- boolFilter->SetInput1(m_Working_Support);
- boolFilter->SetInput2(Esophagus);
- boolFilter->SetOperationType(BoolFilterType::AndNot);
- boolFilter->Update();
- m_Working_Support = boolFilter->GetOutput();
+
+ /* NOT YET !! DO IT LATER
+
+ typedef clitk::BooleanOperatorLabelImageFilter<MaskImageType> BoolFilterType;
+ typename BoolFilterType::Pointer boolFilter = BoolFilterType::New();
+ boolFilter->InPlaceOn();
+ boolFilter->SetInput1(m_Working_Support);
+ boolFilter->SetInput2(m_Esophagus);
+ boolFilter->SetOperationType(BoolFilterType::AndNot);
+ boolFilter->Update();
+ m_Working_Support = boolFilter->GetOutput();
+
+ */
// Crop Esophagus : keep only below the OriginOfRightMiddleLobeBronchusZ
- Esophagus =
- clitk::CropImageAbove<MaskImageType>(Esophagus, 2,
+ m_Esophagus =
+ clitk::CropImageRemoveGreaterThan<MaskImageType>(m_Esophagus, 2,
m_OriginOfRightMiddleLobeBronchusZ,
true, // AutoCrop
GetBackgroundValue());
// Dilate to keep only not Anterior positions
MaskImagePointType radiusInMM = GetEsophagusDiltationForAnt();
- Esophagus = EnlargeEsophagusDilatationRadiusInferiorly(Esophagus);
- Esophagus = clitk::Dilate<MaskImageType>(Esophagus,
- radiusInMM,
- GetBackgroundValue(),
- GetForegroundValue(), true);
- writeImage<MaskImageType>(Esophagus, "enlarged-eso.mhd");
+
+ // m_Esophagus = EnlargeEsophagusDilatationRadiusInferiorly(m_Esophagus);
+
+ m_Esophagus = clitk::Dilate<MaskImageType>(m_Esophagus,
+ radiusInMM,
+ GetBackgroundValue(),
+ GetForegroundValue(), true);
// Remove Anterior part according to this dilatated esophagus. Note:
// because we crop Esophagus with ORML, the support will also be
typedef clitk::SliceBySliceRelativePositionFilter<MaskImageType> RelPosFilterType;
typename RelPosFilterType::Pointer relPosFilter = RelPosFilterType::New();
relPosFilter->VerboseStepFlagOff();
+ relPosFilter->WriteStepFlagOff();
relPosFilter->SetInput(m_Working_Support);
- relPosFilter->SetInputObject(Esophagus);
- relPosFilter->AddOrientationTypeString("P");
- relPosFilter->InverseOrientationFlagOff();
+ relPosFilter->SetInputObject(m_Esophagus);
+ relPosFilter->AddOrientationTypeString("PostTo");
+ // relPosFilter->InverseOrientationFlagOff();
relPosFilter->SetDirection(2); // Z axis
relPosFilter->UniqueConnectedComponentBySliceOff();
relPosFilter->SetIntermediateSpacing(3);
- relPosFilter->ResampleBeforeRelativePositionFilterOn();
- relPosFilter->SetFuzzyThreshold(GetFuzzyThresholdForS8());
+ 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();
m_Working_Support = clitk::AutoCrop<MaskImageType>(m_Working_Support, GetBackgroundValue());
StopCurrentStep<MaskImageType>(m_Working_Support);
+ m_ListOfStations["8"] = m_Working_Support;
+}
+//--------------------------------------------------------------------
+
+
+//--------------------------------------------------------------------
+template <class ImageType>
+void
+clitk::ExtractLymphStationsFilter<ImageType>::
+ExtractStation_8_Ant_Injected_Limits()
+{
+
+ //--------------------------------------------------------------------
+ StartNewStep("[Station8] Ant part (remove high density, injected part)");
+
+ // Consider initial image, crop to current support
+ ImagePointer working_input =
+ clitk::ResizeImageLike<ImageType>(m_Input,
+ m_Working_Support,
+ (short)GetBackgroundValue());
+
+ // Threshold
+ typedef itk::BinaryThresholdImageFilter<ImageType, MaskImageType> BinarizeFilterType;
+ typename BinarizeFilterType::Pointer binarizeFilter = BinarizeFilterType::New();
+ binarizeFilter->SetInput(working_input);
+ binarizeFilter->SetLowerThreshold(GetInjectedThresholdForS8());
+ binarizeFilter->SetInsideValue(GetForegroundValue());
+ binarizeFilter->SetOutsideValue(GetBackgroundValue());
+ binarizeFilter->Update();
+ MaskImagePointer injected = binarizeFilter->GetOutput();
+
+ // Combine with current support
+ clitk::AndNot<MaskImageType>(m_Working_Support, injected, GetBackgroundValue());
+
+ StopCurrentStep<MaskImageType>(m_Working_Support);
+ m_ListOfStations["8"] = m_Working_Support;
+}
+//--------------------------------------------------------------------
+
+
+
+//--------------------------------------------------------------------
+template <class ImageType>
+void
+clitk::ExtractLymphStationsFilter<ImageType>::
+ExtractStation_8_LR_1_Limits()
+{
+ //--------------------------------------------------------------------
+ StartNewStep("[Station8] Left and Right (from Carina to PulmonaryTrunk): Right to LeftPulmonaryArtery");
+
+ /*
+ We remove LeftPulmonaryArtery structure and what is at Left to
+ this structure.
+ */
+ MaskImagePointer LeftPulmonaryArtery = GetAFDB()->template GetImage<MaskImageType>("LeftPulmonaryArtery");
+
+ // Relative Position : not at Left
+ typedef clitk::AddRelativePositionConstraintToLabelImageFilter<MaskImageType> RelPosFilterType;
+ typename RelPosFilterType::Pointer relPosFilter = RelPosFilterType::New();
+ relPosFilter->VerboseStepFlagOff();
+ relPosFilter->WriteStepFlagOff();
+ relPosFilter->SetBackgroundValue(GetBackgroundValue());
+ relPosFilter->SetInput(m_Working_Support);
+ relPosFilter->SetInputObject(LeftPulmonaryArtery);
+ relPosFilter->RemoveObjectFlagOn(); // remove the object too
+ relPosFilter->AddOrientationTypeString("L");
+ relPosFilter->InverseOrientationFlagOn(); // Not at Left
+ relPosFilter->SetIntermediateSpacing(3);
+ relPosFilter->IntermediateSpacingFlagOn();
+ relPosFilter->SetFuzzyThreshold(0.7);
+ relPosFilter->AutoCropFlagOn();
+ relPosFilter->Update();
+ m_Working_Support = relPosFilter->GetOutput();
+
+ // Release LeftPulmonaryArtery
+ GetAFDB()->template ReleaseImage<MaskImageType>("LeftPulmonaryArtery");
+
+ StopCurrentStep<MaskImageType>(m_Working_Support);
+ m_ListOfStations["8"] = m_Working_Support;
+}
+//--------------------------------------------------------------------
+
+
+//--------------------------------------------------------------------
+template <class ImageType>
+void
+clitk::ExtractLymphStationsFilter<ImageType>::
+ExtractStation_8_LR_2_Limits()
+{
+ //--------------------------------------------------------------------
+ StartNewStep("[Station8] Left and Right (from PulmTrunk to OriginMiddleLobeBronchus) Right to line from Aorta to PulmonaryTrunk");
+
+ /*
+ 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<MaskImageType>("Aorta");
+ MaskImagePointer PulmonaryTrunk = GetAFDB()->template GetImage<MaskImageType>("PulmonaryTrunk");
+
+ // Resize like the PT and define the slices
+ MaskImagePointType min, max;
+ clitk::GetMinMaxPointPosition<MaskImageType>(PulmonaryTrunk, min, max);
+ Aorta = clitk::CropImageAlongOneAxis<MaskImageType>(Aorta, 2, min[2], max[2], false, GetBackgroundValue());
+ std::vector<MaskSlicePointer> slices_aorta;
+ clitk::ExtractSlices<MaskImageType>(Aorta, 2, slices_aorta);
+ std::vector<MaskSlicePointer> slices_PT;
+ clitk::ExtractSlices<MaskImageType>(PulmonaryTrunk, 2, slices_PT);
+
+ // Find the points at left
+ std::vector<MaskImagePointType> p_A;
+ std::vector<MaskImagePointType> p_B;
+ MaskImagePointType pA;
+ MaskImagePointType pB;
+ for(uint i=0; i<slices_PT.size(); i++) {
+ typename MaskSliceType::PointType ps;
+ // In Aorta (assume a single CCL)
+ bool found =
+ clitk::FindExtremaPointInAGivenDirection<MaskSliceType>(slices_aorta[i], GetBackgroundValue(), 0, false, ps);
+ clitk::PointsUtils<MaskImageType>::Convert2DTo3D(ps, Aorta, i, pA);
+
+ if (found) {
+ // In PT : generally 2 CCL, we keep the most at left
+ found =
+ clitk::FindExtremaPointInAGivenDirection<MaskSliceType>(slices_PT[i], GetBackgroundValue(), 0, false, ps);
+ clitk::PointsUtils<MaskImageType>::Convert2DTo3D(ps, PulmonaryTrunk, i, pB);
+ }
+
+ if (found) {
+ p_A.push_back(pA);
+ p_B.push_back(pB);
+ }
+ }
+ clitk::WriteListOfLandmarks<MaskImageType>(p_A, "S8-Aorta-Left-points.txt");
+ clitk::WriteListOfLandmarks<MaskImageType>(p_B, "S8-PT-Left-points.txt");
+
+ // Remove part at Left
+ clitk::SliceBySliceSetBackgroundFromLineSeparation<MaskImageType>(m_Working_Support,
+ p_A, p_B,
+ GetBackgroundValue(),
+ 0, -10);
+
+ StopCurrentStep<MaskImageType>(m_Working_Support);
+ m_ListOfStations["8"] = m_Working_Support;
+}
+//--------------------------------------------------------------------
+
+
+//--------------------------------------------------------------------
+template <class ImageType>
+void
+clitk::ExtractLymphStationsFilter<ImageType>::
+ExtractStation_8_Single_CCL_Limits()
+{
+ //--------------------------------------------------------------------
+ StartNewStep("[Station8 or 3P] Slice by slice, keep a single CCL (the closest to VertebralBody)");
+
+ // Consider slices
+ std::vector<typename MaskSliceType::Pointer> slices;
+ std::vector<typename MaskSliceType::Pointer> slices_vb;
+ clitk::ExtractSlices<MaskImageType>(m_Working_Support, 2, slices);
+ MaskImagePointer VertebralBody =
+ GetAFDB()->template GetImage <MaskImageType>("VertebralBody");
+ VertebralBody = clitk::ResizeImageLike<MaskImageType>(VertebralBody, m_Working_Support, GetBackgroundValue());
+ clitk::ExtractSlices<MaskImageType>(VertebralBody, 2, slices_vb);
+
+ for(uint i=0; i<slices.size(); i++) {
+ // Decompose in labels
+ slices[i] = Labelize<MaskSliceType>(slices[i], 0, true, 100);
+ // Compute centroids coordinate
+ std::vector<typename MaskSliceType::PointType> centroids;
+ std::vector<typename MaskSliceType::PointType> c;
+ clitk::ComputeCentroids<MaskSliceType>(slices[i], GetBackgroundValue(), centroids);
+ clitk::ComputeCentroids<MaskSliceType>(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<centroids.size(); j++) {
+ double d = centroids[j].EuclideanDistanceTo(c[1]);
+ if (d<distance) {
+ distance = d;
+ index = j;
+ }
+ }
+ // remove all others label
+ slices[i] = KeepLabels<MaskSliceType>(slices[i], GetBackgroundValue(),
+ GetForegroundValue(), index, index, true);
+ }
+ }
+ m_Working_Support = clitk::JoinSlices<MaskImageType>(slices, m_Working_Support, 2);
+
+ StopCurrentStep<MaskImageType>(m_Working_Support);
+ m_ListOfStations["8"] = m_Working_Support;
+}
+//--------------------------------------------------------------------
+
+
+//--------------------------------------------------------------------
+template <class ImageType>
+void
+clitk::ExtractLymphStationsFilter<ImageType>::
+ExtractStation_8_LR_Limits_old2()
+{
+
//--------------------------------------------------------------------
StartNewStep("[Station8] Left and Right limits arround esophagus (below Carina)");
std::vector<typename MaskSliceType::Pointer> slices;
clitk::ExtractSlices<MaskImageType>(m_Working_Support, 2, slices);
+ // Dilate the Esophagus to consider a margins around
+ MaskImagePointType radiusInMM = GetEsophagusDiltationForAnt();
+ m_Esophagus = clitk::Dilate<MaskImageType>(m_Esophagus,
+ radiusInMM,
+ GetBackgroundValue(),
+ GetForegroundValue(), true);
+
+ // 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<MaskImageType>("Lungs");
+ clitk::AndNot<MaskImageType>(m_Esophagus, Lungs, GetBackgroundValue());
+ GetAFDB()->template ReleaseImage<MaskImageType>("Lungs");
+
// Estract slices of Esophagus (resize like support before to have the same set of slices)
- MaskImagePointer EsophagusForSlice = clitk::ResizeImageLike<MaskImageType>(Esophagus, m_Working_Support, GetBackgroundValue());
+ MaskImagePointer EsophagusForSlice = clitk::ResizeImageLike<MaskImageType>(m_Esophagus, m_Working_Support, GetBackgroundValue());
+
std::vector<typename MaskSliceType::Pointer> eso_slices;
clitk::ExtractSlices<MaskImageType>(EsophagusForSlice, 2, eso_slices);
std::vector<MaskImagePointType> p_LeftMostAnt;
std::vector<MaskImagePointType> p_LeftMostPost;
std::vector<MaskImagePointType> p_AllPoints;
+ std::vector<MaskImagePointType> p_LeftAorta;
+ std::vector<MaskImagePointType> p_LeftEso;
/*
In the following, we search for the LeftRight limits. We search
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
MaskImagePointType p;
p_LeftMostPost.push_back(p);
p_AllPoints.push_back(p);
+ // Find Eso slice centroid and do not consider what is post to
+ // this centroid.
+ std::vector<typename MaskSliceType::PointType> c;
+ clitk::ComputeCentroids<MaskSliceType>(eso_slices[i], GetBackgroundValue(), c);
+ if (c.size() >1) {
+ eso_slices[i] =
+ clitk::CropImageRemoveGreaterThan<MaskSliceType>(eso_slices[i], 1, c[1][1], false, GetBackgroundValue());
+ eso_slices[i] =
+ clitk::ResizeImageLike<MaskSliceType>(eso_slices[i], aorta_slices[i], GetBackgroundValue());
+ // writeImage<MaskSliceType>(eso_slices[i], "eso-slice-"+toString(i)+".mhd");
+ }
+
// Find right limit of Esophagus and Aorta
- clitk::FindExtremaPointInAGivenDirection<MaskSliceType>(eso_slices[i], GetBackgroundValue(), 0, true, sp_maxRight_Eso);
- bool f = clitk::FindExtremaPointInAGivenDirection<MaskSliceType>(aorta_slices[i], GetBackgroundValue(), 0, true, sp_maxRight_Aorta);
+ bool f =
+ clitk::FindExtremaPointInAGivenDirection<MaskSliceType>(eso_slices[i], GetBackgroundValue(),
+ 0, true, sp_maxRight_Eso);
+ f = f &&
+ clitk::FindExtremaPointInAGivenDirection<MaskSliceType>(aorta_slices[i], GetBackgroundValue(),
+ 0, true, sp_maxRight_Aorta);
clitk::PointsUtils<MaskImageType>::Convert2DTo3D(sp_maxRight_Eso, EsophagusForSlice, i, p);
clitk::PointsUtils<MaskImageType>::Convert2DTo3D(sp_maxRight_Aorta, Aorta, i, pp);
pp[0] -= 2; // Add a margin of 2 mm to include the Aorta 'wall'
if (s>0) p_RightMostAnt.push_back(p);
else p_RightMostAnt.push_back(pp);
}
- else {
- p_RightMostAnt.push_back(p);
+ else { // No more Esophagus in this slice : do nothing
+ // p_RightMostAnt.push_back(p);
+ p_RightMostPost.pop_back();
}
// --------------------------------------------------------------------------
// Find the limit on the Left: most left point between Eso and
- // Vertebra. (Left is left on screen, coordinate increase)
+ // Eso. (Left is left on screen, coordinate increase)
// Find left limit of Esophagus
clitk::FindExtremaPointInAGivenDirection<MaskSliceType>(eso_slices[i], GetBackgroundValue(), 0, false, sp_maxLeft_Eso);
MaskImagePointType B = p;
MaskImagePointType C = pp;
double s = (B[0] - A[0]) * (C[1] - A[1]) - (B[1] - A[1]) * (C[0] - A[0]);
- if (s<0) p_LeftMostAnt.push_back(p); // Insert point most at Left
- else p_LeftMostAnt.push_back(pp);
+ if (s<0) {
+ p_LeftMostAnt.push_back(p); // Insert point most at Left, Eso
+ }
+ else {
+ // in this case -> two lines !
+ p_LeftMostAnt.push_back(pp); // Insert point most at Left, Aorta (Vert to Aorta)
+ // but also consider Aorta to Eso
+ p_LeftAorta.push_back(pp);
+ p_LeftEso.push_back(p);
+ }
}
- else {
- p_LeftMostAnt.push_back(p);
+ else { // No more Esophagus in this slice : do nothing
+ p_LeftMostPost.pop_back();
+ //p_LeftMostAnt.push_back(p);
}
} // End of slice loop
- clitk::WriteListOfLandmarks<MaskImageType>(p_AllPoints, "LR-Eso-Vert.txt");
+ clitk::WriteListOfLandmarks<MaskImageType>(p_AllPoints, "S8-LR-Eso-Vert.txt");
+ clitk::WriteListOfLandmarks<MaskImageType>(p_LeftEso, "S8-Left-Eso.txt");
+ clitk::WriteListOfLandmarks<MaskImageType>(p_LeftAorta, "S8-Left-Aorta.txt");
// Now uses these points to limit, slice by slice
// Line is mainly vertical, so mainDirection=0
clitk::SliceBySliceSetBackgroundFromLineSeparation<MaskImageType>(m_Working_Support,
p_LeftMostAnt, p_LeftMostPost,
GetBackgroundValue(), 0, -10);
+ clitk::SliceBySliceSetBackgroundFromLineSeparation<MaskImageType>(m_Working_Support,
+ p_LeftEso,p_LeftAorta,
+ GetBackgroundValue(), 0, -10);
+ // END
+ StopCurrentStep<MaskImageType>(m_Working_Support);
+ m_ListOfStations["8"] = m_Working_Support;
+ return;
+}
+//--------------------------------------------------------------------
+
+
+//--------------------------------------------------------------------
+template <class ImageType>
+void
+clitk::ExtractLymphStationsFilter<ImageType>::
+ExtractStation_8_LR_Limits()
+{
+
+ //--------------------------------------------------------------------
+ StartNewStep("[Station8] Left and Right limits arround esophagus with lines from VertebralBody-Aorta-Esophagus");
+
+ // Estract slices for current support for slice by slice processing
+ std::vector<typename MaskSliceType::Pointer> slices;
+ clitk::ExtractSlices<MaskImageType>(m_Working_Support, 2, slices);
+
+ // Dilate the Esophagus to consider a margins around
+ MaskImagePointType radiusInMM = GetEsophagusDiltationForAnt();
+ m_Esophagus = clitk::Dilate<MaskImageType>(m_Esophagus, radiusInMM,
+ GetBackgroundValue(), GetForegroundValue(), true);
+ // m_Esophagus = EnlargeEsophagusDilatationRadiusInferiorly(m_Esophagus);
+
+ // 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<MaskImageType>("Lungs");
+ clitk::AndNot<MaskImageType>(m_Esophagus, Lungs, GetBackgroundValue());
+ GetAFDB()->template ReleaseImage<MaskImageType>("Lungs");
+
+ // Estract slices of Esophagus (resize like support before to have the same set of slices)
+ MaskImagePointer EsophagusForSlice = clitk::ResizeImageLike<MaskImageType>(m_Esophagus, m_Working_Support, GetBackgroundValue());
+ std::vector<typename MaskSliceType::Pointer> eso_slices;
+ clitk::ExtractSlices<MaskImageType>(EsophagusForSlice, 2, eso_slices);
+
+ // Estract slices of Vertebral (resize like support before to have the same set of slices)
+ MaskImagePointer VertebralBody = GetAFDB()->template GetImage<MaskImageType>("VertebralBody");
+ VertebralBody = clitk::ResizeImageLike<MaskImageType>(VertebralBody, m_Working_Support, GetBackgroundValue());
+ std::vector<typename MaskSliceType::Pointer> vert_slices;
+ clitk::ExtractSlices<MaskImageType>(VertebralBody, 2, vert_slices);
+
+ // Estract slices of Aorta (resize like support before to have the same set of slices)
+ MaskImagePointer Aorta = GetAFDB()->template GetImage<MaskImageType>("Aorta");
+ Aorta = clitk::ResizeImageLike<MaskImageType>(Aorta, m_Working_Support, GetBackgroundValue());
+ std::vector<typename MaskSliceType::Pointer> aorta_slices;
+ clitk::ExtractSlices<MaskImageType>(Aorta, 2, aorta_slices);
+
+ // Extract slices of Mediastinum (resize like support before to have the same set of slices)
+ m_Mediastinum = GetAFDB()->template GetImage<MaskImageType>("Mediastinum");
+ m_Mediastinum = clitk::ResizeImageLike<MaskImageType>(m_Mediastinum, m_Working_Support, GetBackgroundValue());
+ std::vector<typename MaskSliceType::Pointer> mediast_slices;
+ clitk::ExtractSlices<MaskImageType>(m_Mediastinum, 2, mediast_slices);
+
+ // List of points
+ std::vector<MaskImagePointType> p_MostLeftVertebralBody;
+ std::vector<MaskImagePointType> p_MostRightVertebralBody;
+ std::vector<MaskImagePointType> p_MostLeftAorta;
+ std::vector<MaskImagePointType> p_MostLeftEsophagus;
+
+ /*
+ In the following, we search for the LeftRight limits. We search
+ for the most Right points in Esophagus and in VertebralBody and
+ consider a line between those to most right points. All points in
+ the support which are most right to this line are discarded. Same
+ for the left part. The underlying assumption is that the support
+ 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).
+ */
+
+ // Temporary 3D point
+ MaskImagePointType p;
+
+ // Loop slices
+ for(uint i=0; i<slices.size() ; i++) {
+ // 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;
+
+ // Right is at left on screen, coordinate decrease
+ // Left is at right on screen, coordinate increase
+
+ /* -------------------------------------------------------------------------------------
+ Find most Left point in VertebralBody. Consider only the
+ horizontal line which is 'DistanceMaxToAnteriorPartOfTheSpine'
+ away from the most ant point.
+ */
+ typename MaskSliceType::PointType sp_MostAntVertebralBody;
+ bool found = false;
+ int j=i;
+ while (!found) {
+ found = clitk::FindExtremaPointInAGivenDirection<MaskSliceType>(vert_slices[j], GetBackgroundValue(), 1, true, sp_MostAntVertebralBody);
+ 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;
+ j++;
+ }
+ }
+ sp_MostAntVertebralBody[1] += GetDistanceMaxToAnteriorPartOfTheSpine(); // Consider offset
+
+ // Crop the vertebralbody below this most post line
+ vert_slices[j] =
+ clitk::CropImageRemoveGreaterThan<MaskSliceType>(vert_slices[j], 1, sp_MostAntVertebralBody[1], false, GetBackgroundValue());
+ vert_slices[j] =
+ clitk::ResizeImageLike<MaskSliceType>(vert_slices[j], aorta_slices[i], GetBackgroundValue());
+ // writeImage<MaskSliceType>(vert_slices[i], "vert-slice-"+toString(i)+".mhd");
+
+ // Find first point not in mediastinum
+ clitk::FindExtremaPointInAGivenDirection<MaskSliceType>(vert_slices[j], GetBackgroundValue(), 0, false, sp_MostLeftVertebralBody);
+ sp_MostLeftVertebralBody = clitk::FindExtremaPointInAGivenLine<MaskSliceType>(mediast_slices[i], 0, false, sp_MostLeftVertebralBody, GetBackgroundValue(), 30);
+ sp_MostLeftVertebralBody[0] += 2; // 2mm margin
+ clitk::FindExtremaPointInAGivenDirection<MaskSliceType>(vert_slices[j], GetBackgroundValue(), 0, true, sp_MostRightVertebralBody);
+ sp_MostRightVertebralBody = clitk::FindExtremaPointInAGivenLine<MaskSliceType>(mediast_slices[i], 0, true, sp_MostRightVertebralBody, GetBackgroundValue(),30);
+ sp_MostRightVertebralBody[0] -= 2; // 2 mm margin
+
+ // Convert 2D points into 3D
+ clitk::PointsUtils<MaskImageType>::Convert2DTo3D(sp_MostRightVertebralBody, VertebralBody, i, p);
+ p_MostRightVertebralBody.push_back(p);
+ clitk::PointsUtils<MaskImageType>::Convert2DTo3D(sp_MostLeftVertebralBody, VertebralBody, i, p);
+ p_MostLeftVertebralBody.push_back(p);
+
+ /* -------------------------------------------------------------------------------------
+ Find most Left point in Esophagus
+ */
+ found = clitk::FindExtremaPointInAGivenDirection<MaskSliceType>(eso_slices[i], GetBackgroundValue(), 0, false, sp_MostLeftEsophagus);
+ if (!found) { // No more Esophagus, I remove the previous point
+
+ // if (p_MostLeftEsophagus.size() < 1) {
+ p_MostLeftVertebralBody.pop_back();
+ // }
+ // else {
+ // // Consider the previous point
+ // p = p_MostLeftEsophagus.back();
+ // p_MostLeftEsophagus.push_back(p);
+ // sp_MostLeftEsophagus = sp_temp; // Retrieve previous 2D position
+ // found = true;
+ // }
+ }
+ else {
+ clitk::PointsUtils<MaskImageType>::Convert2DTo3D(sp_MostLeftEsophagus, EsophagusForSlice, i, p);
+ p_MostLeftEsophagus.push_back(p);
+ // sp_temp = sp_MostLeftEsophagus; // Store previous 2D position
+ }
+
+ /* -------------------------------------------------------------------------------------
+ Find most Left point in Aorta
+ */
+ if (found) {
+ clitk::FindExtremaPointInAGivenDirection<MaskSliceType>(aorta_slices[i], GetBackgroundValue(), 0, false, sp_MostLeftAorta);
+ sp_MostLeftAorta = clitk::FindExtremaPointInAGivenLine<MaskSliceType>(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<MaskImageType>::Convert2DTo3D(sp_MostLeftAorta, Aorta, i, p);
+ p_MostLeftAorta.push_back(p);
+ }
+
+ } // End of slice loop
+
+ clitk::WriteListOfLandmarks<MaskImageType>(p_MostLeftVertebralBody, "S8-MostLeft-VB-points.txt");
+ clitk::WriteListOfLandmarks<MaskImageType>(p_MostRightVertebralBody, "S8-MostRight-VB-points.txt");
+ clitk::WriteListOfLandmarks<MaskImageType>(p_MostLeftAorta, "S8-MostLeft-Aorta-points.txt");
+ clitk::WriteListOfLandmarks<MaskImageType>(p_MostLeftEsophagus, "S8-MostLeft-eso-points.txt");
+
+ clitk::SliceBySliceSetBackgroundFromLineSeparation<MaskImageType>(m_Working_Support,
+ p_MostLeftVertebralBody, p_MostLeftAorta,
+ GetBackgroundValue(), 0, -10);
+
+ clitk::SliceBySliceSetBackgroundFromLineSeparation<MaskImageType>(m_Working_Support,
+ p_MostLeftAorta, p_MostLeftEsophagus,
+ GetBackgroundValue(), 0, -10);
+
+ // END
+ StopCurrentStep<MaskImageType>(m_Working_Support);
+ m_ListOfStations["8"] = m_Working_Support;
+ return;
+}
+//--------------------------------------------------------------------
+
+
+//--------------------------------------------------------------------
+template <class ImageType>
+void
+clitk::ExtractLymphStationsFilter<ImageType>::
+ExtractStation_8_Remove_Structures()
+{
+
+ //--------------------------------------------------------------------
+ StartNewStep("[Station8] remove some structures");
+
+ Remove_Structures("8", "Aorta");
+ Remove_Structures("8", "Esophagus");
+
// END
StopCurrentStep<MaskImageType>(m_Working_Support);
m_ListOfStations["8"] = m_Working_Support;
clitk::ExtractLymphStationsFilter<ImageType>::
EnlargeEsophagusDilatationRadiusInferiorly(MaskImagePointer & Esophagus)
{
- // Check if Esophagus is delineated at least until GOjunction. Now,
+ // Check if Esophagus is delineated at least until Diaphragm. Now,
// because we use AutoCrop, Origin[2] gives this max inferior
// position.
- // double GOjunctionZ = GetAFDB()->GetPoint3D("GOjunction", 2);
+
+ DD("BUGGY DONT USE");
+ exit(0);
if (Esophagus->GetOrigin()[2] > m_DiaphragmInferiorLimit) {
+ // crop first slice without mask
+ MaskImagePointType pt;
+ clitk::FindExtremaPointInAGivenDirection<MaskImageType>(Esophagus, GetBackgroundValue(), 2, true, pt);
+ DD(pt);
+ Esophagus =
+ clitk::CropImageRemoveLowerThan<MaskImageType>(Esophagus, 2,
+ pt[2],
+ false, // AutoCrop
+ GetBackgroundValue());
+ writeImage<MaskImageType>(Esophagus, "crop-eso.mhd");
+
std::cout << "Warning Esophagus is not delineated until Diaphragm. I mirror-pad it."
<< std::endl;
double extraSize = Esophagus->GetOrigin()[2]-m_DiaphragmInferiorLimit;
relPosFilter->WriteStepFlagOff();
relPosFilter->SetInput(m_Working_Support);
relPosFilter->SetInputObject(Esophagus);
- relPosFilter->AddOrientationTypeString("L");
- relPosFilter->InverseOrientationFlagOn(); // Not Left to
+ relPosFilter->AddOrientationTypeString("NotLeftTo");
+ // relPosFilter->InverseOrientationFlagOn(); // Not Left to
relPosFilter->SetDirection(2); // Z axis
relPosFilter->UniqueConnectedComponentBySliceOff(); // important
relPosFilter->SetIntermediateSpacing(4);
- relPosFilter->ResampleBeforeRelativePositionFilterOn();
+ relPosFilter->IntermediateSpacingFlagOn();
relPosFilter->SetFuzzyThreshold(0.9); // remove few part only
relPosFilter->RemoveObjectFlagOff();
relPosFilter->Update();
relPosFilter->SetDirection(2); // Z axis
relPosFilter->UniqueConnectedComponentBySliceOff(); // important
relPosFilter->SetIntermediateSpacing(4);
- relPosFilter->ResampleBeforeRelativePositionFilterOn();
+ relPosFilter->IntermediateSpacingFlagOn();
relPosFilter->CombineWithOrFlagOn();
relPosFilter->SetFuzzyThreshold(0.9); // remove few part only
relPosFilter->RemoveObjectFlagOff();
m_ListOfStations["8"] = m_Working_Support;
}
//--------------------------------------------------------------------
+
+
+//--------------------------------------------------------------------
+template <class TImageType>
+void
+clitk::ExtractLymphStationsFilter<TImageType>::
+FindExtremaPointsInBronchus(MaskImagePointer input,
+ int direction,
+ double distance_max_from_center_point,
+ ListOfPointsType & LR,
+ ListOfPointsType & Ant,
+ ListOfPointsType & Post)
+{
+
+ // Other solution ==> with auto bounding box ! (but pb to prevent to
+ // be too distant from the center point
+
+ // Extract slices
+ std::vector<typename MaskSliceType::Pointer> slices;
+ clitk::ExtractSlices<MaskImageType>(input, 2, slices);
+
+ // Loop on slices
+ bool found;
+ for(uint i=0; i<slices.size(); i++) {
+ /*
+ // Keep main CCL
+ slices[i] = Labelize<MaskSliceType>(slices[i], 0, true, 10);
+ slices[i] = KeepLabels<MaskSliceType>(slices[i],
+ GetBackgroundValue(),
+ GetForegroundValue(), 1, 1, true);
+ */
+
+ // ------- Find rightmost or leftmost point -------
+ MaskSliceType::PointType LRMost;
+ found =
+ clitk::FindExtremaPointInAGivenDirection<MaskSliceType>(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<MaskSliceType>(slices[i],
+ GetBackgroundValue(),
+ 1, false, LRMost,
+ distance_max_from_center_point,
+ postMost);
+ // ------- Find antmost point -------
+ MaskSliceType::PointType antMost;
+ found =
+ clitk::FindExtremaPointInAGivenDirection<MaskSliceType>(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<MaskImageType>::Convert2DTo3D(LRMost, input, i, p);
+ LR.push_back(p);
+ clitk::PointsUtils<MaskImageType>::Convert2DTo3D(antMost, input, i, p);
+ Ant.push_back(p);
+ clitk::PointsUtils<MaskImageType>::Convert2DTo3D(postMost, input, i, p);
+ Post.push_back(p);
+ }
+ }
+}
+//--------------------------------------------------------------------