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