]> Creatis software - clitk.git/blob - segmentation/clitkExtractLymphStation_3P.txx
merge cvs -> git
[clitk.git] / segmentation / clitkExtractLymphStation_3P.txx
1
2 //--------------------------------------------------------------------
3 template <class ImageType>
4 void 
5 clitk::ExtractLymphStationsFilter<ImageType>::
6 ExtractStation_3P_SetDefaultValues()
7 {
8 }
9 //--------------------------------------------------------------------
10
11
12 //--------------------------------------------------------------------
13 template <class ImageType>
14 void 
15 clitk::ExtractLymphStationsFilter<ImageType>::
16 ExtractStation_3P_SI_Limits() 
17 {
18   /*
19     Apex of the chest & Carina.
20   */
21   StartNewStep("[Station 3P] Inf/Sup limits with apex of the chest and carina");
22
23   // Get Carina position (has been determined in Station8)
24   m_CarinaZ = GetAFDB()->GetDouble("CarinaZ");
25   
26   // Get Apex of the Chest. The "lungs" structure is autocroped so we
27   // consider the most superior point.
28   MaskImagePointer Lungs = GetAFDB()->template GetImage<MaskImageType>("Lungs");
29   MaskImageIndexType index = Lungs->GetLargestPossibleRegion().GetIndex();
30   index += Lungs->GetLargestPossibleRegion().GetSize();
31   MaskImagePointType p;
32   Lungs->TransformIndexToPhysicalPoint(index, p);
33   p[2] -= 5; // 5 mm below because the autocrop is slightly above the apex
34   double m_ApexOfTheChest = p[2];
35
36   /* Crop support :
37      Superior limit = carina
38      Inferior limit = Apex of the chest */
39   m_Working_Support = 
40     clitk::CropImageAlongOneAxis<MaskImageType>(m_Working_Support, 2, 
41                                                 m_CarinaZ,
42                                                 m_ApexOfTheChest, true,
43                                                 GetBackgroundValue());
44
45   StopCurrentStep<MaskImageType>(m_Working_Support);
46   m_ListOfStations["3P"] = m_Working_Support;
47 }
48 //--------------------------------------------------------------------
49
50
51 //--------------------------------------------------------------------
52 template <class ImageType>
53 void 
54 clitk::ExtractLymphStationsFilter<ImageType>::
55 ExtractStation_3P_Remove_Structures() 
56 {
57   /*
58     3 - (sup) remove Aorta, VB, subcl
59     not LR subcl ! -> a séparer LR ?
60     (inf) remove Eso, Aorta, Azygousvein
61   */
62
63   StartNewStep("[Station 3P] Remove some structures.");
64
65   Remove_Structures("3P", "Aorta");
66   Remove_Structures("3P", "VertebralBody");
67   Remove_Structures("3P", "SubclavianArtery");
68   Remove_Structures("3P", "Esophagus");
69   Remove_Structures("3P", "Azygousvein");
70   Remove_Structures("3P", "Thyroid");
71   Remove_Structures("3P", "VertebralArtery");
72
73   StopCurrentStep<MaskImageType>(m_Working_Support);
74   m_ListOfStations["3P"] = m_Working_Support;
75 }
76 //--------------------------------------------------------------------
77
78
79 //--------------------------------------------------------------------
80 template <class ImageType>
81 void 
82 clitk::ExtractLymphStationsFilter<ImageType>::
83 ExtractStation_3P_Ant_Limits() 
84 {
85   /*
86     Ant Post limit : 
87
88     Anteriorly, it is in contact with the posterior aspect of Stations
89     1–2 superiorly (Fig. 2A–C) and with Stations 4R and 4L inferiorly
90     (Fig. 2D–I and 3A–C). The anterior limit of Station 3P is kept
91     posterior to the trachea, which is defined by an imaginary
92     horizontal line running along the posterior wall of the trachea
93     (Fig. 2B,E, red line). Posteriorly, it is delineated along the
94     anterior and lateral borders of the vertebral body until an
95     imaginary horizontal line running 1 cm posteriorly to the
96     anterior border of the vertebral body (Fig. 2D).
97
98     1 - post to the trachea : define an imaginary line just post the
99     Trachea and remove what is anterior. 
100
101   */
102   StartNewStep("[Station 3P] Ant limits with Trachea ");
103
104   // Load Trachea
105   MaskImagePointer Trachea = GetAFDB()->template GetImage<MaskImageType>("Trachea");
106   
107   // Crop like current support (need by SliceBySliceSetBackgroundFromLineSeparation after)
108   Trachea = 
109     clitk::ResizeImageLike<MaskImageType>(Trachea, m_Working_Support, GetBackgroundValue());
110   
111   // Slice by slice, determine the most post point of the trachea (A)
112   // and consider a second point on the same horizontal line (B)
113   std::vector<MaskImagePointType> p_A;
114   std::vector<MaskImagePointType> p_B;
115   std::vector<typename MaskSliceType::Pointer> slices;
116   clitk::ExtractSlices<MaskImageType>(Trachea, 2, slices);
117   MaskImagePointType p;
118   typename MaskSliceType::PointType sp;
119   for(uint i=0; i<slices.size(); i++) {
120     // First only consider the main CCL (trachea, not bronchus)
121     slices[i] = Labelize<MaskSliceType>(slices[i], 0, true, 100);
122     slices[i] = KeepLabels<MaskSliceType>(slices[i], GetBackgroundValue(), 
123                                           GetForegroundValue(), 1, 1, true);
124     // Find most posterior point
125     clitk::FindExtremaPointInAGivenDirection<MaskSliceType>(slices[i], GetBackgroundValue(), 
126                                                             1, false, sp);
127     clitk::PointsUtils<MaskImageType>::Convert2DTo3D(sp, Trachea, i, p);
128     p_A.push_back(p);
129     p[0] -= 20;
130     p_B.push_back(p);
131   }
132   clitk::WriteListOfLandmarks<MaskImageType>(p_A, "trachea-post.txt");
133
134   // Remove Ant part above those lines
135   clitk::SliceBySliceSetBackgroundFromLineSeparation<MaskImageType>(m_Working_Support, 
136                                                                     p_A, p_B,
137                                                                     GetBackgroundValue(), 
138                                                                     1, 10);
139   // End, release memory
140   GetAFDB()->template ReleaseImage<MaskImageType>("Trachea");
141   StopCurrentStep<MaskImageType>(m_Working_Support);
142   m_ListOfStations["3P"] = m_Working_Support;
143 }
144 //--------------------------------------------------------------------
145
146
147 //--------------------------------------------------------------------
148 template <class ImageType>
149 void 
150 clitk::ExtractLymphStationsFilter<ImageType>::
151 ExtractStation_3P_Post_Limits() 
152 {
153   /*
154     Ant Post limit : 
155
156     Anteriorly, it is in contact with the posterior aspect of Stations
157     1–2 superiorly (Fig. 2A–C) and with Stations 4R and 4L inferiorly
158     (Fig. 2D–I and 3A–C). The anterior limit of Station 3P is kept
159     posterior to the trachea, which is defined by an imaginary
160     horizontal line running along the posterior wall of the trachea
161     (Fig. 2B,E, red line). Posteriorly, it is delineated along the
162     anterior and lateral borders of the vertebral body until an
163     imaginary horizontal line running 1 cm posteriorly to the
164     anterior border of the vertebral body (Fig. 2D).
165
166     2 - post to the trachea : define an imaginary line just post the
167     Trachea and remove what is anterior. 
168
169   */
170   StartNewStep("[Station 3P] Post limits with VertebralBody ");
171
172   // Load VertebralBody
173   MaskImagePointer VertebralBody = GetAFDB()->template GetImage<MaskImageType>("VertebralBody");
174   
175   // Crop like current support (need by SliceBySliceSetBackgroundFromLineSeparation after)
176   VertebralBody = clitk::ResizeImageLike<MaskImageType>(VertebralBody, m_Working_Support, GetBackgroundValue());
177   
178   writeImage<MaskImageType>(VertebralBody, "vb.mhd");
179   
180   // Compute VertebralBody most Ant position (again because slices
181   // changes). Slice by slice, determine the most post point of the
182   // trachea (A) and consider a second point on the same horizontal
183   // line (B)
184   std::vector<MaskImagePointType> p_A;
185   std::vector<MaskImagePointType> p_B;
186   std::vector<typename MaskSliceType::Pointer> slices;
187   clitk::ExtractSlices<MaskImageType>(VertebralBody, 2, slices);
188   MaskImagePointType p;
189   typename MaskSliceType::PointType sp;
190   for(uint i=0; i<slices.size(); i++) {
191     // Find most anterior point
192     bool found = clitk::FindExtremaPointInAGivenDirection<MaskSliceType>(slices[i], GetBackgroundValue(), 
193                                                                          1, true, sp);
194     
195     // If the VertebralBody stop superiorly before the end of
196     // m_Working_Support, we consider the same previous point.
197     if (!found) {
198       p = p_A.back();
199       p[2] += VertebralBody->GetSpacing()[2];
200       p_A.push_back(p);
201       p = p_B.back();
202       p[2] += VertebralBody->GetSpacing()[2];
203       p_B.push_back(p);
204     }
205     else {
206       clitk::PointsUtils<MaskImageType>::Convert2DTo3D(sp, VertebralBody, i, p);
207       p[1] += 10; // Consider 10 mm more post
208       p_A.push_back(p);
209       p[0] -= 20;
210       p_B.push_back(p);
211     }
212   }
213   clitk::WriteListOfLandmarks<MaskImageType>(p_A, "vb-ant.txt");
214   
215
216   // Remove Ant part above those lines
217   clitk::SliceBySliceSetBackgroundFromLineSeparation<MaskImageType>(m_Working_Support, 
218                                                                     p_A, p_B,
219                                                                     GetBackgroundValue(), 
220                                                                     1, -10);
221   writeImage<MaskImageType>(m_Working_Support, "a.mhd");
222
223   StopCurrentStep<MaskImageType>(m_Working_Support);
224   m_ListOfStations["3P"] = m_Working_Support;
225 }
226 //--------------------------------------------------------------------
227
228
229 //--------------------------------------------------------------------
230 template <class ImageType>
231 void 
232 clitk::ExtractLymphStationsFilter<ImageType>::
233 ExtractStation_3P_LR_sup_Limits() 
234 {
235   /*
236     "On the right side, the limit is defined by the air–soft-tissue
237     interface. On the left side, it is defined by the air–tissue
238     interface superiorly (Fig. 2A–C) and the aorta inferiorly
239     (Figs. 2D–I and 3A–C)."
240
241     sup : 
242     Resizelike support : Trachea, SubclavianArtery
243     Trachea, slice by slice, get centroid trachea
244     SubclavianArtery, slice by slice, CCL
245     prendre la 1ère à L et R, not at Left
246     
247   */
248   StartNewStep("[Station 3P] Left/Right limits (superior part) ");
249
250   // Load structures
251   MaskImagePointer Trachea = GetAFDB()->template GetImage<MaskImageType>("Trachea");
252   MaskImagePointer SubclavianArtery = GetAFDB()->template GetImage<MaskImageType>("SubclavianArtery");
253   
254   // Crop like current support
255   Trachea = clitk::ResizeImageLike<MaskImageType>(Trachea, m_Working_Support, GetBackgroundValue());
256   SubclavianArtery = clitk::ResizeImageLike<MaskImageType>(SubclavianArtery, m_Working_Support, GetBackgroundValue());
257   
258   writeImage<MaskImageType>(Trachea, "tr.mhd");
259   writeImage<MaskImageType>(SubclavianArtery, "sca.mhd");
260   
261   // Get list of slices
262   std::vector<MaskSlicePointer> slices_support;
263   std::vector<MaskSlicePointer> slices_trachea;
264   std::vector<MaskSlicePointer> slices_subclavianartery;
265   clitk::ExtractSlices<MaskImageType>(m_Working_Support, 2, slices_support);
266   clitk::ExtractSlices<MaskImageType>(Trachea, 2, slices_trachea);
267   clitk::ExtractSlices<MaskImageType>(SubclavianArtery, 2, slices_subclavianartery);
268
269   // Loop on slices
270   std::vector<MaskImagePointType> points;
271   MaskImagePointType p;
272   for(uint i=0; i<slices_support.size(); i++) {
273     // Get Trachea centroid
274     std::vector<typename MaskSliceType::PointType> centroids;
275     typename MaskSliceType::PointType c;
276     ComputeCentroids<MaskSliceType>(slices_trachea[i], GetBackgroundValue(), centroids);
277     c = centroids[1];
278
279     // [debug] Store point
280     clitk::PointsUtils<MaskImageType>::Convert2DTo3D(centroids[1], Trachea, i, p);
281     points.push_back(p);
282     
283     // Get Right and Left CCL in SubclavianArtery
284     slices_subclavianartery[i] = Labelize<MaskSliceType>(slices_subclavianartery[i], 0, true, 10);
285     ComputeCentroids<MaskSliceType>(slices_subclavianartery[i], GetBackgroundValue(), centroids);
286
287     if (centroids.size() > 1) {
288       // Determine the one at Right/Left -> first after Trachea
289       // centroid 
290       typename MaskSliceType::PointType right;
291       typename MaskSliceType::PointType left;
292       int label_right=-1;
293       int label_left=-1;
294       right[0] = c[0]-100;
295       left[0] = c[0]+100;
296       for(uint j=1; j<centroids.size(); j++) {
297         if (centroids[j][0] < c[0]) { // At Right of Trachea centroid
298           if (centroids[j][0] >= right[0]) {
299             right = centroids[j];
300             label_right = j;
301           }
302         }
303         if (centroids[j][0] > c[0]) { // At Left of Trachea centroid
304           if (centroids[j][0] <= left[0]) {
305             left = centroids[j];
306             label_left = j;
307           }
308         }
309       }
310
311       if (label_right != -1) {
312     
313         // Debug points
314         clitk::PointsUtils<MaskImageType>::Convert2DTo3D(centroids[label_right], SubclavianArtery, i, p);
315         points.push_back(p);
316
317         // Set Background and ForegroundValue according to label_right
318         MaskSlicePointer object = 
319           clitk::Binarize<MaskSliceType>(slices_subclavianartery[i], label_right, label_right, 
320                                          GetBackgroundValue(), GetForegroundValue());
321       
322         // Relative Position : not at Right
323         typedef clitk::AddRelativePositionConstraintToLabelImageFilter<MaskSliceType> RelPosFilterType;
324         typename RelPosFilterType::Pointer relPosFilter = RelPosFilterType::New();
325         relPosFilter->VerboseStepFlagOff();
326         relPosFilter->WriteStepFlagOff();
327         relPosFilter->SetBackgroundValue(GetBackgroundValue());
328         relPosFilter->SetInput(slices_support[i]); 
329         relPosFilter->SetInputObject(object); 
330         relPosFilter->AddOrientationTypeString("R");
331         relPosFilter->SetInverseOrientationFlag(true);
332         //      relPosFilter->SetIntermediateSpacing(3);
333         relPosFilter->SetIntermediateSpacingFlag(false);
334         relPosFilter->SetFuzzyThreshold(0.7);
335         relPosFilter->AutoCropFlagOff(); // important ! because we join the slices after this loop
336         relPosFilter->Update();
337         slices_support[i] = relPosFilter->GetOutput();
338
339         // Relative Position : not Anterior
340         relPosFilter = RelPosFilterType::New();
341         relPosFilter->VerboseStepFlagOff();
342         relPosFilter->WriteStepFlagOff();
343         relPosFilter->SetBackgroundValue(GetBackgroundValue());
344         relPosFilter->SetInput(slices_support[i]); 
345         relPosFilter->SetInputObject(object); 
346         relPosFilter->AddOrientationTypeString("A");
347         relPosFilter->SetInverseOrientationFlag(true);
348         //      relPosFilter->SetIntermediateSpacing(3);
349         relPosFilter->SetIntermediateSpacingFlag(false);
350         relPosFilter->SetFuzzyThreshold(0.7);
351         relPosFilter->AutoCropFlagOff(); // important ! because we join the slices after this loop
352         relPosFilter->Update();
353         slices_support[i] = relPosFilter->GetOutput();
354
355       } // End RelativePosition for Right
356
357
358       if (label_left != -1) {
359     
360         // Debug points
361         clitk::PointsUtils<MaskImageType>::Convert2DTo3D(centroids[label_left], SubclavianArtery, i, p);
362         points.push_back(p);
363
364         // Set Background and ForegroundValue according to label_right
365         MaskSlicePointer object = 
366           clitk::Binarize<MaskSliceType>(slices_subclavianartery[i], label_left, label_left, 
367                                          GetBackgroundValue(), GetForegroundValue());
368       
369         // Relative Position : not at Right
370         typedef clitk::AddRelativePositionConstraintToLabelImageFilter<MaskSliceType> RelPosFilterType;
371         typename RelPosFilterType::Pointer relPosFilter = RelPosFilterType::New();
372         relPosFilter->VerboseStepFlagOff();
373         relPosFilter->WriteStepFlagOff();
374         relPosFilter->SetBackgroundValue(GetBackgroundValue());
375         relPosFilter->SetInput(slices_support[i]); 
376         relPosFilter->SetInputObject(object); 
377         relPosFilter->AddOrientationTypeString("L");
378         relPosFilter->SetInverseOrientationFlag(true);
379         //      relPosFilter->SetIntermediateSpacing(3);
380         relPosFilter->SetIntermediateSpacingFlag(false);
381         relPosFilter->SetFuzzyThreshold(0.7);
382         relPosFilter->AutoCropFlagOff(); // important ! because we join the slices after this loop
383         relPosFilter->Update();
384         slices_support[i] = relPosFilter->GetOutput();
385
386         // Relative Position : not Anterior
387         relPosFilter = RelPosFilterType::New();
388         relPosFilter->VerboseStepFlagOff();
389         relPosFilter->WriteStepFlagOff();
390         relPosFilter->SetBackgroundValue(GetBackgroundValue());
391         relPosFilter->SetInput(slices_support[i]); 
392         relPosFilter->SetInputObject(object); 
393         relPosFilter->AddOrientationTypeString("A");
394         relPosFilter->SetInverseOrientationFlag(true);
395         //      relPosFilter->SetIntermediateSpacing(3);
396         relPosFilter->SetIntermediateSpacingFlag(false);
397         relPosFilter->SetFuzzyThreshold(0.7);
398         relPosFilter->AutoCropFlagOff(); // important ! because we join the slices after this loop
399         relPosFilter->Update();
400         slices_support[i] = relPosFilter->GetOutput();
401
402       }
403
404     
405     } // if centroids.size > 1
406   } // End loop slices
407
408   // Joint slices
409   m_Working_Support = clitk::JoinSlices<MaskImageType>(slices_support, m_Working_Support, 2);
410
411   // Save list points
412   clitk::WriteListOfLandmarks<MaskImageType>(points, "subcl-lr.txt");
413
414
415   StopCurrentStep<MaskImageType>(m_Working_Support);
416   m_ListOfStations["3P"] = m_Working_Support;
417 }
418 //--------------------------------------------------------------------
419
420 //--------------------------------------------------------------------
421 template <class ImageType>
422 void 
423 clitk::ExtractLymphStationsFilter<ImageType>::
424 ExtractStation_3P_LR_sup_Limits_2() 
425 {
426   /*
427     Use VertebralArtery to limit.
428     
429
430   StartNewStep("[Station 3P] Left/Right limits with VertebralArtery");
431
432   // Load structures
433   MaskImagePointer VertebralArtery = GetAFDB()->template GetImage<MaskImageType>("VertebralArtery");
434
435   clitk::AndNot<MaskImageType>(m_Working_Support, VertebralArtery);
436
437   StopCurrentStep<MaskImageType>(m_Working_Support);
438   m_ListOfStations["3P"] = m_Working_Support;
439   */
440 }
441 //--------------------------------------------------------------------
442
443 //--------------------------------------------------------------------
444 template <class ImageType>
445 void 
446 clitk::ExtractLymphStationsFilter<ImageType>::
447 ExtractStation_3P_LR_inf_Limits() 
448 {
449   /*
450     "On the right side, the limit is defined by the air–soft-tissue
451     interface. On the left side, it is defined by the air–tissue
452     interface superiorly (Fig. 2A–C) and the aorta inferiorly
453     (Figs. 2D–I and 3A–C)."
454
455     inf : not Right to Azygousvein    
456   */
457   StartNewStep("[Station 3P] Left/Right limits (inferior part) with Azygousvein and Aorta");
458
459   // Load structures
460   MaskImagePointer AzygousVein = GetAFDB()->template GetImage<MaskImageType>("AzygousVein");
461   MaskImagePointer Aorta = GetAFDB()->template GetImage<MaskImageType>("Aorta");
462
463   typedef clitk::AddRelativePositionConstraintToLabelImageFilter<MaskImageType> RelPosFilterType;
464   typename RelPosFilterType::Pointer relPosFilter = RelPosFilterType::New();
465   relPosFilter->VerboseStepFlagOff();
466   relPosFilter->WriteStepFlagOff();
467   relPosFilter->SetBackgroundValue(GetBackgroundValue());
468   relPosFilter->SetInput(m_Working_Support); 
469   relPosFilter->SetInputObject(AzygousVein); 
470   relPosFilter->AddOrientationTypeString("R");
471   relPosFilter->SetInverseOrientationFlag(true);
472   //      relPosFilter->SetIntermediateSpacing(3);
473   relPosFilter->SetIntermediateSpacingFlag(false);
474   relPosFilter->SetFuzzyThreshold(0.7);
475   relPosFilter->AutoCropFlagOn();
476   relPosFilter->Update();
477   m_Working_Support = relPosFilter->GetOutput();
478
479   writeImage<MaskImageType>(m_Working_Support, "before-L-aorta.mhd");
480   relPosFilter->SetInput(m_Working_Support); 
481   relPosFilter->SetInputObject(Aorta); 
482   relPosFilter->AddOrientationTypeString("L");
483   relPosFilter->SetInverseOrientationFlag(true);
484   //      relPosFilter->SetIntermediateSpacing(3);
485   relPosFilter->SetIntermediateSpacingFlag(false);
486   relPosFilter->SetFuzzyThreshold(0.7);
487   relPosFilter->AutoCropFlagOn();
488   relPosFilter->Update();
489   m_Working_Support = relPosFilter->GetOutput();
490   writeImage<MaskImageType>(m_Working_Support, "after-L-aorta.mhd");
491
492   StopCurrentStep<MaskImageType>(m_Working_Support);
493   m_ListOfStations["3P"] = m_Working_Support;
494 }
495 //--------------------------------------------------------------------