]> Creatis software - clitk.git/blob - segmentation/clitkExtractLymphStation_8.txx
motion masks with and without bands
[clitk.git] / segmentation / clitkExtractLymphStation_8.txx
1
2 #include <itkBinaryDilateImageFilter.h>
3 #include <itkMirrorPadImageFilter.h>
4
5 //--------------------------------------------------------------------
6 template <class ImageType>
7 void 
8 clitk::ExtractLymphStationsFilter<ImageType>::
9 ExtractStation_8_SetDefaultValues()
10 {
11   MaskImagePointType p;
12   p[0] = 15; p[1] = 2; p[2] = 1;
13   SetEsophagusDiltationForAnt(p);
14   p[0] = 5; p[1] = 10; p[2] = 1;
15   SetEsophagusDiltationForRight(p);
16   SetFuzzyThreshold("8", "Esophagus", 0.5);
17   SetInjectedThresholdForS8(150);
18 }
19 //--------------------------------------------------------------------
20
21 //--------------------------------------------------------------------
22 template <class TImageType>
23 void 
24 clitk::ExtractLymphStationsFilter<TImageType>::
25 ExtractStation_8() 
26 {
27   if (!CheckForStation("8")) return;
28
29   StartNewStep("Station 8");
30   StartSubStep();   
31   ExtractStation_8_SI_Limits();         // OK, validated
32   ExtractStation_8_Ant_Limits();        // OK, validated
33   ExtractStation_8_Left_Sup_Limits();   // OK, validated
34   ExtractStation_8_Left_Inf_Limits();   // OK, validated
35   ExtractStation_8_Single_CCL_Limits(); // OK, validated
36   ExtractStation_8_Remove_Structures(); // OK, validated
37   
38   // Store image filenames into AFDB 
39   writeImage<MaskImageType>(m_ListOfStations["8"], "seg/Station8.mhd");
40   GetAFDB()->SetImageFilename("Station8", "seg/Station8.mhd");  
41   WriteAFDB();
42   StopSubStep();
43 }
44 //--------------------------------------------------------------------
45
46
47 //--------------------------------------------------------------------
48 template <class ImageType>
49 void 
50 clitk::ExtractLymphStationsFilter<ImageType>::
51 ExtractStation_8_SI_Limits() 
52 {
53   /*
54     Station 8: paraeosphageal nodes
55     
56     "Superiorly, Station 8 begins at the level of the carina and,
57     therefore, abuts Station 3P (Fig. 3C). Inferiorly, the lower limit
58     of Station 8 was not specified in the Mountain and Dresler
59     classification (1). We delineate this volume until it reaches the
60     gastroesphogeal junction. "
61     
62     => new classification IASCL 2009: 
63
64     "Lower border: the diaphragm"
65     
66     "Upper border: the upper border of the lower lobe bronchus on the
67     left; the lower border of the bronchus intermedius on the right"
68
69   */
70   StartNewStep("[Station8] Sup/Inf limits with LeftLower/RightMiddle Lobe and diaphragm");
71
72   /* -----------------------------------------------
73      NEW SUPERIOR LIMIT = LeftLowerLobeBronchus /
74      RightMiddleLobeBronchus See FindLineForS7S8Separation
75      -----------------------------------------------
76   */
77   ImagePointType A;
78   ImagePointType B;
79   FindLineForS7S8Separation(A, B);
80
81   // add one slice to be adjacent to Station7
82   B[2] += m_Working_Support->GetSpacing()[2];
83   A[2] += m_Working_Support->GetSpacing()[2];
84
85   // Use the line to remove the inferior part
86   m_Working_Support =
87     SliceBySliceSetBackgroundFromSingleLine<MaskImageType>(m_Working_Support, 
88                                                            GetBackgroundValue(), A, B, 2, 0, true);
89   
90   /* -----------------------------------------------
91      INFERIOR LIMIT = Diaphragm
92      -----------------------------------------------
93   */  
94
95   // Found most inferior part of the lung
96   MaskImagePointer Lungs = GetAFDB()->template GetImage<MaskImageType>("Lungs");
97   // It should be already croped, so I took the origin and add 10mm above 
98   m_DiaphragmInferiorLimit = Lungs->GetOrigin()[2]+10;
99   GetAFDB()->template ReleaseImage<MaskImageType>("Lungs");
100
101   m_Working_Support = 
102     clitk::CropImageAlongOneAxis<MaskImageType>(m_Working_Support, 2, 
103                                                 m_DiaphragmInferiorLimit,
104                                                 B[2], true,
105                                                 GetBackgroundValue());
106   // Done.
107   StopCurrentStep<MaskImageType>(m_Working_Support);
108   m_ListOfStations["8"] = m_Working_Support;
109 }
110 //--------------------------------------------------------------------
111
112
113 //--------------------------------------------------------------------
114 template <class ImageType>
115 void 
116 clitk::ExtractLymphStationsFilter<ImageType>::
117 ExtractStation_8_Ant_Limits() 
118 {
119   //--------------------------------------------------------------------
120   StartNewStep("[Station8] Ant part: not post to Esophagus");
121   /*
122     Consider Esophagus, dilate it and remove ant part. It remains part
123     on L & R, than can be partly removed by cutting what remains at
124     right of vertebral body.
125   */
126   
127   // Get Esophagus
128   m_Esophagus = GetAFDB()->template GetImage<MaskImageType>("Esophagus");
129
130   // In images from the original article, Atlas – UM, the oesophagus
131   //was included in nodal stations 3p and 8.  Having said that, in the
132   //description for station 8, it indicates that “the delineation of
133   //station 8 is limited to the soft tissues surrounding the
134   //oesophagus”.  In the recent article, The IASLC Lung Cancer Staging
135   //Project (J Thorac Oncol 4:5, 568-77), the images drawn by
136   //Dr. Aletta Frasier exclude this structure.  From an oncological
137   //prospective, the oesophagus should be excluded from these nodal
138   //stations.
139
140   // Resize Esophagus like current support
141   m_Esophagus = 
142     clitk::ResizeImageLike<MaskImageType>(m_Esophagus, m_Working_Support, GetBackgroundValue()); // Needed ?
143
144   // Dilate to keep only not Anterior positions
145   MaskImagePointType radiusInMM = GetEsophagusDiltationForAnt();
146   m_Esophagus = clitk::Dilate<MaskImageType>(m_Esophagus, 
147                                              radiusInMM, 
148                                              GetBackgroundValue(), 
149                                              GetForegroundValue(), true);
150   // Keep what is Posterior to Esophagus
151   typedef clitk::SliceBySliceRelativePositionFilter<MaskImageType> RelPosFilterType;
152   typename RelPosFilterType::Pointer relPosFilter = RelPosFilterType::New();
153   relPosFilter->VerboseStepFlagOff();
154   relPosFilter->WriteStepFlagOff();
155   relPosFilter->SetInput(m_Working_Support);
156   relPosFilter->SetInputObject(m_Esophagus);
157   relPosFilter->AddOrientationTypeString("PostTo");
158   //  relPosFilter->InverseOrientationFlagOff();
159   relPosFilter->SetDirection(2); // Z axis
160   relPosFilter->UniqueConnectedComponentBySliceFlagOff();
161   relPosFilter->SetIntermediateSpacing(3);
162   relPosFilter->IntermediateSpacingFlagOn();
163   relPosFilter->SetFuzzyThreshold(GetFuzzyThreshold("8", "Esophagus"));
164   relPosFilter->RemoveObjectFlagOff(); // Do not exclude here because it is dilated
165   relPosFilter->CombineWithOrFlagOff(); // NO !
166   relPosFilter->IgnoreEmptySliceObjectFlagOn();
167   relPosFilter->Update();
168   m_Working_Support = relPosFilter->GetOutput();
169
170   // AutoCrop (OR SbS ?)
171   m_Working_Support = clitk::AutoCrop<MaskImageType>(m_Working_Support, GetBackgroundValue()); 
172
173   StopCurrentStep<MaskImageType>(m_Working_Support);
174   m_ListOfStations["8"] = m_Working_Support;
175 }
176 //--------------------------------------------------------------------
177
178
179 //--------------------------------------------------------------------
180 template <class ImageType>
181 void 
182 clitk::ExtractLymphStationsFilter<ImageType>::
183 ExtractStation_8_Left_Sup_Limits() 
184 {
185   //--------------------------------------------------------------------
186   StartNewStep("[Station8] Left limits: remove Left to line from Aorta to PulmonaryTrunk");
187
188   /*
189     We consider a line from Left part of Aorta to left part of
190     PulmonaryTrunk and remove what is at Left.
191   */
192     
193   // Load the structures
194   MaskImagePointer Aorta = GetAFDB()->template GetImage<MaskImageType>("Aorta");
195   MaskImagePointer PulmonaryTrunk = GetAFDB()->template GetImage<MaskImageType>("PulmonaryTrunk");
196   
197   // Resize like the PT and define the slices
198   MaskImagePointType min, max;
199   clitk::GetMinMaxPointPosition<MaskImageType>(PulmonaryTrunk, min, max);
200   Aorta = clitk::CropImageAlongOneAxis<MaskImageType>(Aorta, 2, min[2], max[2], false, GetBackgroundValue());
201   std::vector<MaskSlicePointer> slices_aorta;
202   clitk::ExtractSlices<MaskImageType>(Aorta, 2, slices_aorta);
203   std::vector<MaskSlicePointer> slices_PT;
204   clitk::ExtractSlices<MaskImageType>(PulmonaryTrunk, 2, slices_PT);
205   
206   // Find the points at left
207   std::vector<MaskImagePointType> p_A;
208   std::vector<MaskImagePointType> p_B;
209   MaskImagePointType pA;
210   MaskImagePointType pB;
211   for(uint i=0; i<slices_PT.size(); i++) {    
212     typename MaskSliceType::PointType ps;
213     // In Aorta (assume a single CCL)
214     bool found = 
215       clitk::FindExtremaPointInAGivenDirection<MaskSliceType>(slices_aorta[i], GetBackgroundValue(), 0, false, ps);
216     clitk::PointsUtils<MaskImageType>::Convert2DTo3D(ps, Aorta, i, pA);
217     
218     if (found) {
219       // In PT : generally 2 CCL, we keep the most at left
220       found = 
221         clitk::FindExtremaPointInAGivenDirection<MaskSliceType>(slices_PT[i], GetBackgroundValue(), 0, false, ps);
222       clitk::PointsUtils<MaskImageType>::Convert2DTo3D(ps, PulmonaryTrunk, i, pB);
223     }
224     
225     if (found) {
226       p_A.push_back(pA);
227       p_B.push_back(pB);
228     }
229   }
230   clitk::WriteListOfLandmarks<MaskImageType>(p_A, "S8-Aorta-Left-points.txt");
231   clitk::WriteListOfLandmarks<MaskImageType>(p_B, "S8-PT-Left-points.txt");
232
233   // Remove part at Left  
234   clitk::SliceBySliceSetBackgroundFromLineSeparation<MaskImageType>(m_Working_Support, 
235                                                                     p_A, p_B,
236                                                                     GetBackgroundValue(), 
237                                                                     0, -10);
238
239   StopCurrentStep<MaskImageType>(m_Working_Support);
240   m_ListOfStations["8"] = m_Working_Support;
241 }
242 //--------------------------------------------------------------------
243
244
245 //--------------------------------------------------------------------
246 template <class ImageType>
247 void 
248 clitk::ExtractLymphStationsFilter<ImageType>::
249 ExtractStation_8_Single_CCL_Limits() 
250 {
251   //--------------------------------------------------------------------
252   StartNewStep("[Station8 or 3P] Slice by slice, keep a single CCL (the closest to VertebralBody)");
253
254   // Consider slices
255   std::vector<typename MaskSliceType::Pointer> slices;
256   std::vector<typename MaskSliceType::Pointer> slices_vb;
257   clitk::ExtractSlices<MaskImageType>(m_Working_Support, 2, slices);
258   MaskImagePointer VertebralBody = 
259     GetAFDB()->template GetImage <MaskImageType>("VertebralBody");  
260   VertebralBody = clitk::ResizeImageLike<MaskImageType>(VertebralBody, m_Working_Support, GetBackgroundValue());
261   clitk::ExtractSlices<MaskImageType>(VertebralBody, 2, slices_vb);
262
263   for(uint i=0; i<slices.size(); i++) {
264     // Decompose in labels
265     slices[i] = Labelize<MaskSliceType>(slices[i], 0, true, 100);
266     // Compute centroids coordinate
267     std::vector<typename MaskSliceType::PointType> centroids;
268     std::vector<typename MaskSliceType::PointType> c;
269     clitk::ComputeCentroids<MaskSliceType>(slices[i], GetBackgroundValue(), centroids);
270     clitk::ComputeCentroids<MaskSliceType>(slices_vb[i], GetBackgroundValue(), c);
271     if ((c.size() > 1) && (centroids.size() > 1)) {
272       // keep the one which is the closer to vertebralbody centroid
273       double distance=1000000;
274       int index=0;
275       for(uint j=1; j<centroids.size(); j++) {
276         double d = centroids[j].EuclideanDistanceTo(c[1]);
277         if (d<distance) {
278           distance = d;
279           index = j;
280         }
281       }
282       // remove all others label
283       slices[i] = KeepLabels<MaskSliceType>(slices[i], GetBackgroundValue(), 
284                                             GetForegroundValue(), index, index, true);
285     }
286   }
287   m_Working_Support = clitk::JoinSlices<MaskImageType>(slices, m_Working_Support, 2);
288   
289   StopCurrentStep<MaskImageType>(m_Working_Support);
290   m_ListOfStations["8"] = m_Working_Support;  
291 }
292 //--------------------------------------------------------------------
293
294
295 //--------------------------------------------------------------------
296 template <class ImageType>
297 void 
298 clitk::ExtractLymphStationsFilter<ImageType>::
299 ExtractStation_8_Left_Inf_Limits() 
300 {
301   //--------------------------------------------------------------------
302   StartNewStep("[Station8] Left limits around esophagus with lines from VertebralBody-Aorta-Esophagus");
303
304   // Estract slices for current support for slice by slice processing
305   std::vector<typename MaskSliceType::Pointer> slices;
306   clitk::ExtractSlices<MaskImageType>(m_Working_Support, 2, slices);
307
308   // Remove what is outside the mediastinum in this enlarged Esophagus -> it allows to select
309   // 'better' extrema points (not too post).
310   MaskImagePointer Lungs = GetAFDB()->template GetImage<MaskImageType>("Lungs");
311   clitk::AndNot<MaskImageType>(m_Esophagus, Lungs, GetBackgroundValue());
312   GetAFDB()->template ReleaseImage<MaskImageType>("Lungs");
313
314   // Estract slices of Esophagus (resize like support before to have the same set of slices)
315   MaskImagePointer EsophagusForSlice = 
316     clitk::ResizeImageLike<MaskImageType>(m_Esophagus, m_Working_Support, GetBackgroundValue());
317   std::vector<typename MaskSliceType::Pointer> eso_slices;
318   clitk::ExtractSlices<MaskImageType>(EsophagusForSlice, 2, eso_slices);
319
320   // Estract slices of Vertebral (resize like support before to have the same set of slices)
321   MaskImagePointer VertebralBody = GetAFDB()->template GetImage<MaskImageType>("VertebralBody");
322   VertebralBody = clitk::ResizeImageLike<MaskImageType>(VertebralBody, m_Working_Support, GetBackgroundValue());
323   // Remove what is outside the support to not consider what is to
324   // posterior in the VertebralBody (post the horizontal line)
325   clitk::And<MaskImageType>(VertebralBody, m_Working_Support, GetBackgroundValue());
326   // writeImage<MaskImageType>(VertebralBody, "vb.mhd");
327   std::vector<typename MaskSliceType::Pointer> vert_slices;
328   clitk::ExtractSlices<MaskImageType>(VertebralBody, 2, vert_slices);
329
330   // Estract slices of Aorta (resize like support before to have the same set of slices)
331   MaskImagePointer Aorta = GetAFDB()->template GetImage<MaskImageType>("Aorta");
332   Aorta = clitk::ResizeImageLike<MaskImageType>(Aorta, m_Working_Support, GetBackgroundValue());
333   std::vector<typename MaskSliceType::Pointer> aorta_slices;
334   clitk::ExtractSlices<MaskImageType>(Aorta, 2, aorta_slices);
335
336   // Extract slices of Mediastinum (resize like support before to have the same set of slices)
337   m_Mediastinum = GetAFDB()->template GetImage<MaskImageType>("Mediastinum");
338   m_Mediastinum = clitk::ResizeImageLike<MaskImageType>(m_Mediastinum, m_Working_Support, GetBackgroundValue());
339   std::vector<typename MaskSliceType::Pointer> mediast_slices;
340   clitk::ExtractSlices<MaskImageType>(m_Mediastinum, 2, mediast_slices);
341
342   // List of points
343   std::vector<MaskImagePointType> p_MostLeftVertebralBody;
344   std::vector<MaskImagePointType> p_MostRightVertebralBody;
345   std::vector<MaskImagePointType> p_MostLeftAorta;
346   std::vector<MaskImagePointType> p_MostLeftEsophagus;
347
348   /*
349     In the following, we search for the LeftRight limits.  We search
350     for the most Right points in Esophagus and in VertebralBody and
351     consider a line between those to most right points. All points in
352     the support which are most right to this line are discarded. Same
353     for the left part. The underlying assumption is that the support
354     is concave between Eso/VertebralBody. Esophagus is a bit
355     dilatated. On VertebralBody we go right (or left) until we reach
356     the lung (but no more 20 mm).
357   */
358
359   // Temporary 3D point
360   MaskImagePointType p;
361
362   typename MaskSliceType::PointType minSlicePoint;
363   typename MaskSliceType::PointType maxSlicePoint;
364   clitk::GetMinMaxPointPosition<MaskSliceType>(vert_slices[0], minSlicePoint, maxSlicePoint);
365
366   // Loop slices
367   for(uint i=0; i<slices.size() ; i++) {
368     // Declare all needed 2D points (sp = slice point)
369     //    typename MaskSliceType::PointType sp_MostRightVertebralBody;
370     typename MaskSliceType::PointType sp_MostLeftVertebralBody;
371     typename MaskSliceType::PointType sp_MostLeftAorta;
372     typename MaskSliceType::PointType sp_temp;
373     typename MaskSliceType::PointType sp_MostLeftEsophagus;
374
375     /* -------------------------------------------------------------------------------------
376         Find first point not in mediastinum at LEFT
377     */
378     clitk::FindExtremaPointInAGivenDirection<MaskSliceType>(vert_slices[i], GetBackgroundValue(), 
379                                                             0, false, sp_MostLeftVertebralBody);
380     // clitk::PointsUtils<MaskImageType>::Convert2DTo3D(sp_MostLeftVertebralBody, VertebralBody, i, p);
381     // DD(p);
382
383     sp_MostLeftVertebralBody = 
384       clitk::FindExtremaPointInAGivenLine<MaskSliceType>(mediast_slices[i], 0, false, 
385                                                          sp_MostLeftVertebralBody, GetBackgroundValue(), 30);
386     // clitk::PointsUtils<MaskImageType>::Convert2DTo3D(sp_MostLeftVertebralBody, VertebralBody, i, p);
387     // DD(p);
388
389     sp_MostLeftVertebralBody[0] += 2; // 2mm margin
390     // clitk::PointsUtils<MaskImageType>::Convert2DTo3D(sp_MostLeftVertebralBody, VertebralBody, i, p);
391     // DD(p);
392
393     // Convert 2D points into 3D
394     clitk::PointsUtils<MaskImageType>::Convert2DTo3D(sp_MostLeftVertebralBody, VertebralBody, i, p);
395     p_MostLeftVertebralBody.push_back(p);
396
397     /* -------------------------------------------------------------------------------------
398        Find first point not in mediastinum at RIGHT. Not used yet.
399     clitk::FindExtremaPointInAGivenDirection<MaskSliceType>(vert_slices[i], GetBackgroundValue(), 
400                                                             0, true, sp_MostRightVertebralBody);
401     sp_MostRightVertebralBody = 
402       clitk::FindExtremaPointInAGivenLine<MaskSliceType>(mediast_slices[i], 0, true, 
403                                                          sp_MostRightVertebralBody, GetBackgroundValue(),30);
404     sp_MostRightVertebralBody[0] -= 2; // 2 mm margin
405     
406     // Convert 2D points into 3D
407     clitk::PointsUtils<MaskImageType>::Convert2DTo3D(sp_MostRightVertebralBody, VertebralBody, i, p);
408     p_MostRightVertebralBody.push_back(p);
409     */
410
411
412     /* -------------------------------------------------------------------------------------
413        Find most Left point in Esophagus
414      */
415     bool found = clitk::FindExtremaPointInAGivenDirection<MaskSliceType>(eso_slices[i], GetBackgroundValue(), 0, false, sp_MostLeftEsophagus);
416     if (!found) { // No more Esophagus, I remove the previous point
417       //DD("no eso pop back");
418       p_MostLeftVertebralBody.pop_back();
419     }
420     else {
421       clitk::PointsUtils<MaskImageType>::Convert2DTo3D(sp_MostLeftEsophagus, EsophagusForSlice, i, p);
422       p_MostLeftEsophagus.push_back(p);
423     }
424       
425     /* -------------------------------------------------------------------------------------
426        Find most Left point in Aorta 
427     */
428     if (found) {
429       clitk::FindExtremaPointInAGivenDirection<MaskSliceType>(aorta_slices[i], GetBackgroundValue(), 0, false, sp_MostLeftAorta);
430       sp_MostLeftAorta = clitk::FindExtremaPointInAGivenLine<MaskSliceType>(mediast_slices[i], 0, false, sp_MostLeftAorta, GetBackgroundValue(), 10);
431       typename MaskSliceType::PointType temp=sp_MostLeftEsophagus;
432       temp[0] -= 10;
433       if (clitk::IsOnTheSameLineSide(sp_MostLeftAorta, sp_MostLeftVertebralBody, sp_MostLeftEsophagus, temp)) { 
434         // sp_MostLeftAorta is on the same side than temp (at Right) -> ignore Aorta
435         sp_MostLeftAorta = sp_MostLeftEsophagus;
436       }
437       clitk::PointsUtils<MaskImageType>::Convert2DTo3D(sp_MostLeftAorta, Aorta, i, p);
438       p_MostLeftAorta.push_back(p);
439     }
440
441   } // End of slice loop
442   
443   clitk::WriteListOfLandmarks<MaskImageType>(p_MostLeftVertebralBody, "S8-MostLeft-VB-points.txt");
444   //  clitk::WriteListOfLandmarks<MaskImageType>(p_MostRightVertebralBody, "S8-MostRight-VB-points.txt");
445   clitk::WriteListOfLandmarks<MaskImageType>(p_MostLeftAorta, "S8-MostLeft-Aorta-points.txt");
446   clitk::WriteListOfLandmarks<MaskImageType>(p_MostLeftEsophagus, "S8-MostLeft-eso-points.txt");
447
448   clitk::SliceBySliceSetBackgroundFromLineSeparation<MaskImageType>(m_Working_Support, 
449                                                                     p_MostLeftVertebralBody, p_MostLeftAorta,
450                                                                     GetBackgroundValue(), 0, -10);
451
452   clitk::SliceBySliceSetBackgroundFromLineSeparation<MaskImageType>(m_Working_Support, 
453                                                                     p_MostLeftAorta, p_MostLeftEsophagus,
454                                                                     GetBackgroundValue(), 0, -10);
455   // END
456   StopCurrentStep<MaskImageType>(m_Working_Support);
457   m_ListOfStations["8"] = m_Working_Support;
458   return;
459 }
460 //--------------------------------------------------------------------
461
462
463 //--------------------------------------------------------------------
464 template <class ImageType>
465 void 
466 clitk::ExtractLymphStationsFilter<ImageType>::
467 ExtractStation_8_Remove_Structures()
468 {
469   //--------------------------------------------------------------------
470   Remove_Structures("8", "Aorta");
471   Remove_Structures("8", "Esophagus");
472   Remove_Structures("8", "VertebralBody");  
473
474   // END
475   StopCurrentStep<MaskImageType>(m_Working_Support);
476   m_ListOfStations["8"] = m_Working_Support;
477   return;
478 }
479 //--------------------------------------------------------------------
480
481
482 //--------------------------------------------------------------------
483 template <class TImageType>
484 void 
485 clitk::ExtractLymphStationsFilter<TImageType>::
486 FindExtremaPointsInBronchus(MaskImagePointer input, 
487                             int direction,
488                             double distance_max_from_center_point, 
489                             ListOfPointsType & LR, 
490                             ListOfPointsType & Ant, 
491                             ListOfPointsType & Post)
492 {
493
494   // Other solution ==> with auto bounding box ! (but pb to prevent to
495   // be too distant from the center point
496
497   // Extract slices
498   std::vector<typename MaskSliceType::Pointer> slices;
499   clitk::ExtractSlices<MaskImageType>(input, 2, slices);
500   
501   // Loop on slices
502   bool found;
503   for(uint i=0; i<slices.size(); i++) {
504     /*
505     // Keep main CCL
506     slices[i] = Labelize<MaskSliceType>(slices[i], 0, true, 10);
507     slices[i] = KeepLabels<MaskSliceType>(slices[i], 
508     GetBackgroundValue(), 
509     GetForegroundValue(), 1, 1, true);
510     */
511
512     // ------- Find rightmost or leftmost point  ------- 
513     MaskSliceType::PointType LRMost;
514     found = 
515       clitk::FindExtremaPointInAGivenDirection<MaskSliceType>(slices[i], 
516                                                               GetBackgroundValue(), 
517                                                               0, // axis XY
518                                                               (direction==0?false:true),  // right or left according to direction
519                                                               LRMost);
520     // ------- Find postmost point  ------- 
521     MaskSliceType::PointType postMost;
522     found = 
523       clitk::FindExtremaPointInAGivenDirection<MaskSliceType>(slices[i], 
524                                                               GetBackgroundValue(), 
525                                                               1, false, LRMost, 
526                                                               distance_max_from_center_point, 
527                                                               postMost);
528     // ------- Find antmost point  ------- 
529     MaskSliceType::PointType antMost;
530     found = 
531       clitk::FindExtremaPointInAGivenDirection<MaskSliceType>(slices[i], 
532                                                               GetBackgroundValue(), 
533                                                               1, true, LRMost, 
534                                                               distance_max_from_center_point, 
535                                                               antMost);
536     // Only add point if found
537     if (found)  {
538       // ------- Convert 2D to 3D points --------
539       MaskImageType::PointType p;
540       clitk::PointsUtils<MaskImageType>::Convert2DTo3D(LRMost, input, i, p);
541       LR.push_back(p); 
542       clitk::PointsUtils<MaskImageType>::Convert2DTo3D(antMost, input, i, p);
543       Ant.push_back(p);
544       clitk::PointsUtils<MaskImageType>::Convert2DTo3D(postMost, input, i, p);
545       Post.push_back(p);
546     }
547   }
548
549 //--------------------------------------------------------------------