]> Creatis software - clitk.git/blob - itk/clitkSegmentationUtils.txx
Fix for bug #274: move ExtractSlices definition in .h
[clitk.git] / itk / clitkSegmentationUtils.txx
1 /*=========================================================================
2   Program:   vv                     http://www.creatis.insa-lyon.fr/rio/vv
3
4   Authors belong to: 
5   - University of LYON              http://www.universite-lyon.fr/
6   - Léon Bérard cancer center       http://www.centreleonberard.fr
7   - CREATIS CNRS laboratory         http://www.creatis.insa-lyon.fr
8
9   This software is distributed WITHOUT ANY WARRANTY; without even
10   the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
11   PURPOSE.  See the copyright notices for more information.
12
13   It is distributed under dual licence
14
15   - BSD        See included LICENSE.txt file
16   - CeCILL-B   http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
17   ======================================================================-====*/
18
19 // clitk
20 #include "clitkSetBackgroundImageFilter.h"
21 #include "clitkSliceBySliceRelativePositionFilter.h"
22 #include "clitkCropLikeImageFilter.h"
23 #include "clitkMemoryUsage.h"
24
25 // itk
26 #include <itkConnectedComponentImageFilter.h>
27 #include <itkRelabelComponentImageFilter.h>
28 #include <itkBinaryThresholdImageFilter.h>
29 #include <itkPasteImageFilter.h>
30 #include <itkStatisticsLabelMapFilter.h>
31 #include <itkBinaryBallStructuringElement.h>
32 #include <itkBinaryDilateImageFilter.h>
33 #include <itkConstantPadImageFilter.h>
34 #include <itkImageSliceIteratorWithIndex.h>
35 #include <itkBinaryMorphologicalOpeningImageFilter.h>
36 #include <itkImageDuplicator.h>
37
38 namespace clitk {
39
40   //--------------------------------------------------------------------
41   template<class ImageType>
42   void ComputeBBFromImageRegion(const ImageType * image, 
43                                 typename ImageType::RegionType region,
44                                 typename itk::BoundingBox<unsigned long, 
45                                 ImageType::ImageDimension>::Pointer bb) {
46     typedef typename ImageType::IndexType IndexType;
47     IndexType firstIndex;
48     IndexType lastIndex;
49     for(unsigned int i=0; i<image->GetImageDimension(); i++) {
50       firstIndex[i] = region.GetIndex()[i];
51       lastIndex[i] = firstIndex[i]+region.GetSize()[i];
52     }
53
54     typedef itk::BoundingBox<unsigned long, 
55                              ImageType::ImageDimension> BBType;
56     typedef typename BBType::PointType PointType;
57     PointType lastPoint;
58     PointType firstPoint;
59     image->TransformIndexToPhysicalPoint(firstIndex, firstPoint);
60     image->TransformIndexToPhysicalPoint(lastIndex, lastPoint);
61
62     bb->SetMaximum(lastPoint);
63     bb->SetMinimum(firstPoint);
64   }
65   //--------------------------------------------------------------------
66
67
68   //--------------------------------------------------------------------
69   template<int Dimension>
70   void ComputeBBIntersection(typename itk::BoundingBox<unsigned long, Dimension>::Pointer bbo, 
71                              typename itk::BoundingBox<unsigned long, Dimension>::Pointer bbi1, 
72                              typename itk::BoundingBox<unsigned long, Dimension>::Pointer bbi2) {
73
74     typedef itk::BoundingBox<unsigned long, Dimension> BBType;
75     typedef typename BBType::PointType PointType;
76     PointType lastPoint;
77     PointType firstPoint;
78
79     for(unsigned int i=0; i<Dimension; i++) {
80       firstPoint[i] = std::max(bbi1->GetMinimum()[i], 
81                                bbi2->GetMinimum()[i]);
82       lastPoint[i] = std::min(bbi1->GetMaximum()[i], 
83                               bbi2->GetMaximum()[i]);
84     }
85
86     bbo->SetMaximum(lastPoint);
87     bbo->SetMinimum(firstPoint);
88   }
89   //--------------------------------------------------------------------
90
91
92   //--------------------------------------------------------------------
93   template<class ImageType>
94   void ComputeRegionFromBB(const ImageType * image, 
95                            const typename itk::BoundingBox<unsigned long, 
96                                                            ImageType::ImageDimension>::Pointer bb, 
97                            typename ImageType::RegionType & region) {
98     // Types
99     typedef typename ImageType::IndexType  IndexType;
100     typedef typename ImageType::PointType  PointType;
101     typedef typename ImageType::RegionType RegionType;
102     typedef typename ImageType::SizeType   SizeType;
103
104     // Region starting point
105     IndexType regionStart;
106     PointType start = bb->GetMinimum();
107     image->TransformPhysicalPointToIndex(start, regionStart);
108     
109     // Region size
110     SizeType regionSize;
111     PointType maxs = bb->GetMaximum();
112     PointType mins = bb->GetMinimum();
113     for(unsigned int i=0; i<ImageType::ImageDimension; i++) {
114       regionSize[i] = lrint((maxs[i] - mins[i])/image->GetSpacing()[i]);
115     }
116    
117     // Create region
118     region.SetIndex(regionStart);
119     region.SetSize(regionSize);
120   }
121   //--------------------------------------------------------------------
122
123   //--------------------------------------------------------------------
124   template<class ImageType, class TMaskImageType>
125   typename ImageType::Pointer
126   SetBackground(const ImageType * input, 
127                 const TMaskImageType * mask, 
128                 typename TMaskImageType::PixelType maskBG,
129                 typename ImageType::PixelType outValue, 
130                 bool inPlace) {
131     typedef SetBackgroundImageFilter<ImageType, TMaskImageType, ImageType> 
132       SetBackgroundImageFilterType;
133     typename SetBackgroundImageFilterType::Pointer setBackgroundFilter 
134       = SetBackgroundImageFilterType::New();
135     //  if (inPlace) setBackgroundFilter->ReleaseDataFlagOn(); // No seg fault
136     setBackgroundFilter->SetInPlace(inPlace); // This is important to keep memory low
137     setBackgroundFilter->SetInput(input);
138     setBackgroundFilter->SetInput2(mask);
139     setBackgroundFilter->SetMaskValue(maskBG);
140     setBackgroundFilter->SetOutsideValue(outValue);
141     setBackgroundFilter->Update();
142     return setBackgroundFilter->GetOutput();
143   }
144   //--------------------------------------------------------------------
145
146
147   //--------------------------------------------------------------------
148   template<class ImageType>
149   int GetNumberOfConnectedComponentLabels(const ImageType * input, 
150                                           typename ImageType::PixelType BG, 
151                                           bool isFullyConnected) {
152     // Connected Component label 
153     typedef itk::ConnectedComponentImageFilter<ImageType, ImageType> ConnectFilterType;
154     typename ConnectFilterType::Pointer connectFilter = ConnectFilterType::New();
155     connectFilter->SetInput(input);
156     connectFilter->SetBackgroundValue(BG);
157     connectFilter->SetFullyConnected(isFullyConnected);
158     connectFilter->Update();
159   
160     // Return result
161     return connectFilter->GetObjectCount();
162   }
163   //--------------------------------------------------------------------
164
165   //--------------------------------------------------------------------
166   /*
167     Warning : in this cas, we consider outputType like inputType, not
168     InternalImageType. Be sure it fits.
169   */
170   template<class ImageType>
171   typename ImageType::Pointer
172   Labelize(const ImageType * input, 
173            typename ImageType::PixelType BG, 
174            bool isFullyConnected, 
175            int minimalComponentSize) {
176     // InternalImageType for storing large number of component
177     typedef itk::Image<int, ImageType::ImageDimension> InternalImageType;
178   
179     // Connected Component label 
180     typedef itk::ConnectedComponentImageFilter<ImageType, InternalImageType> ConnectFilterType;
181     typename ConnectFilterType::Pointer connectFilter = ConnectFilterType::New();
182     //  connectFilter->ReleaseDataFlagOn(); 
183     connectFilter->SetInput(input);
184     connectFilter->SetBackgroundValue(BG);
185     connectFilter->SetFullyConnected(isFullyConnected);
186   
187     // Sort by size and remove too small area.
188     typedef itk::RelabelComponentImageFilter<InternalImageType, ImageType> RelabelFilterType;
189     typename RelabelFilterType::Pointer relabelFilter = RelabelFilterType::New();
190     //  relabelFilter->ReleaseDataFlagOn(); // if yes, fail when ExplosionControlledThresholdConnectedImageFilter ???
191     relabelFilter->SetInput(connectFilter->GetOutput());
192     relabelFilter->SetMinimumObjectSize(minimalComponentSize);
193     relabelFilter->Update();
194
195     // Return result
196     typename ImageType::Pointer output = relabelFilter->GetOutput();
197     return output;
198   }
199   //--------------------------------------------------------------------
200
201
202   //--------------------------------------------------------------------
203   /*
204     Warning : in this cas, we consider outputType like inputType, not
205     InternalImageType. Be sure it fits.
206   */
207   template<class ImageType>
208   typename ImageType::Pointer
209   LabelizeAndCountNumberOfObjects(const ImageType * input, 
210                                   typename ImageType::PixelType BG, 
211                                   bool isFullyConnected, 
212                                   int minimalComponentSize, 
213                                   int & nb) {
214     // InternalImageType for storing large number of component
215     typedef itk::Image<int, ImageType::ImageDimension> InternalImageType;
216   
217     // Connected Component label 
218     typedef itk::ConnectedComponentImageFilter<ImageType, InternalImageType> ConnectFilterType;
219     typename ConnectFilterType::Pointer connectFilter = ConnectFilterType::New();
220     //  connectFilter->ReleaseDataFlagOn(); 
221     connectFilter->SetInput(input);
222     connectFilter->SetBackgroundValue(BG);
223     connectFilter->SetFullyConnected(isFullyConnected);
224   
225     // Sort by size and remove too small area.
226     typedef itk::RelabelComponentImageFilter<InternalImageType, ImageType> RelabelFilterType;
227     typename RelabelFilterType::Pointer relabelFilter = RelabelFilterType::New();
228     //  relabelFilter->ReleaseDataFlagOn(); // if yes, fail when ExplosionControlledThresholdConnectedImageFilter ???
229     relabelFilter->SetInput(connectFilter->GetOutput());
230     relabelFilter->SetMinimumObjectSize(minimalComponentSize);
231     relabelFilter->Update();
232
233     nb = relabelFilter->GetNumberOfObjects();
234     // DD(relabelFilter->GetOriginalNumberOfObjects());
235     // DD(relabelFilter->GetSizeOfObjectsInPhysicalUnits()[0]);
236
237     // Return result
238     typename ImageType::Pointer output = relabelFilter->GetOutput();
239     return output;
240   }
241   //--------------------------------------------------------------------
242
243
244
245   //--------------------------------------------------------------------
246   template<class ImageType>
247   typename ImageType::Pointer
248   RemoveLabels(const ImageType * input, 
249                typename ImageType::PixelType BG,
250                std::vector<typename ImageType::PixelType> & labelsToRemove) {
251     assert(labelsToRemove.size() != 0);
252     typename ImageType::Pointer working_image;// = input;
253     for (unsigned int i=0; i <labelsToRemove.size(); i++) {
254       typedef SetBackgroundImageFilter<ImageType, ImageType> SetBackgroundImageFilterType;
255       typename SetBackgroundImageFilterType::Pointer setBackgroundFilter = SetBackgroundImageFilterType::New();
256       setBackgroundFilter->SetInput(input);
257       setBackgroundFilter->SetInput2(input);
258       setBackgroundFilter->SetMaskValue(labelsToRemove[i]);
259       setBackgroundFilter->SetOutsideValue(BG);
260       setBackgroundFilter->Update();
261       working_image = setBackgroundFilter->GetOutput();
262     }
263     return working_image;
264   }
265   //--------------------------------------------------------------------
266
267
268   //--------------------------------------------------------------------
269   template<class ImageType>
270   typename ImageType::Pointer
271   KeepLabels(const ImageType * input, 
272              typename ImageType::PixelType BG, 
273              typename ImageType::PixelType FG, 
274              typename ImageType::PixelType firstKeep, 
275              typename ImageType::PixelType lastKeep, 
276              bool useLastKeep) {
277     typedef itk::BinaryThresholdImageFilter<ImageType, ImageType> BinarizeFilterType; 
278     typename BinarizeFilterType::Pointer binarizeFilter = BinarizeFilterType::New();
279     binarizeFilter->SetInput(input);
280     binarizeFilter->SetLowerThreshold(firstKeep);
281     if (useLastKeep) binarizeFilter->SetUpperThreshold(lastKeep);
282     binarizeFilter->SetInsideValue(FG);
283     binarizeFilter->SetOutsideValue(BG);
284     binarizeFilter->Update();
285     return binarizeFilter->GetOutput();
286   }
287   //--------------------------------------------------------------------
288
289
290   //--------------------------------------------------------------------
291   template<class ImageType>
292   typename ImageType::Pointer
293   LabelizeAndSelectLabels(const ImageType * input,
294                           typename ImageType::PixelType BG, 
295                           typename ImageType::PixelType FG, 
296                           bool isFullyConnected,
297                           int minimalComponentSize,
298                           LabelizeParameters<typename ImageType::PixelType> * param)
299   {
300     typename ImageType::Pointer working_image;
301     working_image = Labelize<ImageType>(input, BG, isFullyConnected, minimalComponentSize);
302     if (param->GetLabelsToRemove().size() != 0)
303       working_image = RemoveLabels<ImageType>(working_image, BG, param->GetLabelsToRemove());
304     working_image = KeepLabels<ImageType>(working_image, 
305                                           BG, FG, 
306                                           param->GetFirstKeep(), 
307                                           param->GetLastKeep(), 
308                                           param->GetUseLastKeep());
309     return working_image;
310   }
311   //--------------------------------------------------------------------
312
313
314   //--------------------------------------------------------------------
315   template<class ImageType>
316   typename ImageType::Pointer
317   ResizeImageLike(const ImageType * input,                       
318                   const itk::ImageBase<ImageType::ImageDimension> * like, 
319                   typename ImageType::PixelType backgroundValue) 
320   {
321     typedef CropLikeImageFilter<ImageType> CropFilterType;
322     typename CropFilterType::Pointer cropFilter = CropFilterType::New();
323     cropFilter->SetInput(input);
324     cropFilter->SetCropLikeImage(like);
325     cropFilter->SetBackgroundValue(backgroundValue);
326     cropFilter->Update();
327     return cropFilter->GetOutput();  
328   }
329   //--------------------------------------------------------------------
330
331
332   //--------------------------------------------------------------------
333   template<class MaskImageType>
334   typename MaskImageType::Pointer
335   SliceBySliceRelativePosition(const MaskImageType * input,
336                                const MaskImageType * object,
337                                int direction, 
338                                double threshold, 
339                                std::string orientation, 
340                                bool uniqueConnectedComponent, 
341                                double spacing, 
342                                bool autocropFlag, 
343                                bool singleObjectCCL) 
344   {
345     typedef SliceBySliceRelativePositionFilter<MaskImageType> SliceRelPosFilterType;
346     typename SliceRelPosFilterType::Pointer sliceRelPosFilter = SliceRelPosFilterType::New();
347     sliceRelPosFilter->VerboseStepFlagOff();
348     sliceRelPosFilter->WriteStepFlagOff();
349     sliceRelPosFilter->SetInput(input);
350     sliceRelPosFilter->SetInputObject(object);
351     sliceRelPosFilter->SetDirection(direction);
352     sliceRelPosFilter->SetFuzzyThreshold(threshold);
353     sliceRelPosFilter->AddOrientationTypeString(orientation);
354     sliceRelPosFilter->SetIntermediateSpacingFlag((spacing != -1));
355     sliceRelPosFilter->SetIntermediateSpacing(spacing);
356     sliceRelPosFilter->SetUniqueConnectedComponentBySlice(uniqueConnectedComponent);
357     sliceRelPosFilter->SetUseASingleObjectConnectedComponentBySliceFlag(singleObjectCCL);
358     //    sliceRelPosFilter->SetInverseOrientationFlag(inverseflag); 
359     sliceRelPosFilter->SetAutoCropFlag(autocropFlag); 
360     sliceRelPosFilter->IgnoreEmptySliceObjectFlagOn();
361     sliceRelPosFilter->Update();
362     return sliceRelPosFilter->GetOutput();
363   }
364   //--------------------------------------------------------------------
365
366   //--------------------------------------------------------------------
367   template<class ImageType>
368   bool
369   FindExtremaPointInAGivenDirection(const ImageType * input, 
370                                     typename ImageType::PixelType bg, 
371                                     int direction, bool opposite, 
372                                     typename ImageType::PointType & point)
373   {
374     typename ImageType::PointType dummy;
375     return FindExtremaPointInAGivenDirection(input, bg, direction, 
376                                              opposite, dummy, 0, point);
377   }
378   //--------------------------------------------------------------------
379
380   //--------------------------------------------------------------------
381   template<class ImageType>
382   bool
383   FindExtremaPointInAGivenDirection(const ImageType * input, 
384                                     typename ImageType::PixelType bg, 
385                                     int direction, bool opposite, 
386                                     typename ImageType::PointType refpoint,
387                                     double distanceMax, 
388                                     typename ImageType::PointType & point)
389   {
390     /*
391       loop over input pixels, store the index in the fg that is max
392       according to the given direction. 
393     */    
394     typedef itk::ImageRegionConstIteratorWithIndex<ImageType> IteratorType;
395     IteratorType iter(input, input->GetLargestPossibleRegion());
396     iter.GoToBegin();
397     typename ImageType::IndexType max = input->GetLargestPossibleRegion().GetIndex();
398     if (opposite) max = max+input->GetLargestPossibleRegion().GetSize();
399     bool found=false;
400     while (!iter.IsAtEnd()) {
401       if (iter.Get() != bg) {
402         bool test = iter.GetIndex()[direction] >  max[direction];
403         if (opposite) test = !test;
404         if (test) {
405           typename ImageType::PointType p;
406           input->TransformIndexToPhysicalPoint(iter.GetIndex(), p);
407           if ((distanceMax==0) || (p.EuclideanDistanceTo(refpoint) < distanceMax)) {
408             max = iter.GetIndex();
409             found = true;
410           }
411         }
412       }
413       ++iter;
414     }
415     if (!found) return false;
416     input->TransformIndexToPhysicalPoint(max, point);
417     return true;
418   }
419   //--------------------------------------------------------------------
420
421
422   //--------------------------------------------------------------------
423   template<class ImageType>
424   typename ImageType::Pointer
425   CropImageRemoveGreaterThan(const ImageType * image, 
426                  int dim, double min, bool autoCrop,
427                  typename ImageType::PixelType BG) 
428   {
429     return CropImageAlongOneAxis<ImageType>(image, dim, 
430                                             image->GetOrigin()[dim], 
431                                             min,
432                                             autoCrop, BG);
433   }
434   //--------------------------------------------------------------------
435
436
437   //--------------------------------------------------------------------
438   template<class ImageType>
439   typename ImageType::Pointer
440   CropImageRemoveLowerThan(const ImageType * image, 
441                  int dim, double max, bool autoCrop,
442                  typename ImageType::PixelType BG) 
443   {
444     typename ImageType::PointType p;
445     image->TransformIndexToPhysicalPoint(image->GetLargestPossibleRegion().GetIndex()+
446                                          image->GetLargestPossibleRegion().GetSize(), p);
447     return CropImageAlongOneAxis<ImageType>(image, dim, max, p[dim], autoCrop, BG);
448   }
449   //--------------------------------------------------------------------
450
451
452   //--------------------------------------------------------------------
453   template<class ImageType>
454   typename ImageType::Pointer
455   CropImageAlongOneAxis(const ImageType * image, 
456                         int dim, double min, double max, 
457                         bool autoCrop, typename ImageType::PixelType BG) 
458   {
459     // Compute region size
460     typename ImageType::RegionType region;
461     typename ImageType::SizeType size = image->GetLargestPossibleRegion().GetSize();
462     typename ImageType::PointType p = image->GetOrigin();
463     p[dim] = min;
464     typename ImageType::IndexType start;
465     image->TransformPhysicalPointToIndex(p, start);
466     p[dim] = max;
467     typename ImageType::IndexType end;
468     image->TransformPhysicalPointToIndex(p, end);
469     size[dim] = abs(end[dim]-start[dim]);
470     region.SetIndex(start);
471     region.SetSize(size);
472   
473     // Perform Crop
474     typedef itk::RegionOfInterestImageFilter<ImageType, ImageType> CropFilterType;
475     typename CropFilterType::Pointer cropFilter = CropFilterType::New();
476     cropFilter->SetInput(image);
477     cropFilter->SetRegionOfInterest(region);
478     cropFilter->Update();
479     typename ImageType::Pointer result = cropFilter->GetOutput();
480   
481     // Auto Crop
482     if (autoCrop) {
483       result = AutoCrop<ImageType>(result, BG);
484     }
485     return result;
486   }
487   //--------------------------------------------------------------------
488
489
490   //--------------------------------------------------------------------
491   template<class ImageType>
492   void
493   ComputeCentroids(const ImageType * image, 
494                    typename ImageType::PixelType BG, 
495                    std::vector<typename ImageType::PointType> & centroids) 
496   {
497     typedef long LabelType;
498     static const unsigned int Dim = ImageType::ImageDimension;
499     typedef itk::ShapeLabelObject< LabelType, Dim > LabelObjectType;
500     typedef itk::LabelMap< LabelObjectType > LabelMapType;
501     typedef itk::LabelImageToLabelMapFilter<ImageType, LabelMapType> ImageToMapFilterType;
502     typename ImageToMapFilterType::Pointer imageToLabelFilter = ImageToMapFilterType::New(); 
503     typedef itk::ShapeLabelMapFilter<LabelMapType, ImageType> ShapeFilterType; 
504     typename ShapeFilterType::Pointer statFilter = ShapeFilterType::New();
505     imageToLabelFilter->SetBackgroundValue(BG);
506     imageToLabelFilter->SetInput(image);
507     statFilter->SetInput(imageToLabelFilter->GetOutput());
508     statFilter->Update();
509     typename LabelMapType::Pointer labelMap = statFilter->GetOutput();
510
511     centroids.clear();
512     typename ImageType::PointType dummy;
513     centroids.push_back(dummy); // label 0 -> no centroid, use dummy point for BG 
514     //DS FIXME (not useful ! to change ..)
515     for(uint i=0; i<labelMap->GetNumberOfLabelObjects(); i++) {
516       int label = labelMap->GetLabels()[i];
517       centroids.push_back(labelMap->GetLabelObject(label)->GetCentroid());
518     } 
519   }
520   //--------------------------------------------------------------------
521
522
523   //--------------------------------------------------------------------
524   template<class ImageType, class LabelType>
525   typename itk::LabelMap< itk::ShapeLabelObject<LabelType, ImageType::ImageDimension> >::Pointer
526   ComputeLabelMap(const ImageType * image, 
527                   typename ImageType::PixelType BG, 
528                   bool computePerimeterFlag) 
529   {
530     static const unsigned int Dim = ImageType::ImageDimension;
531     typedef itk::ShapeLabelObject< LabelType, Dim > LabelObjectType;
532     typedef itk::LabelMap< LabelObjectType > LabelMapType;
533     typedef itk::LabelImageToLabelMapFilter<ImageType, LabelMapType> ImageToMapFilterType;
534     typename ImageToMapFilterType::Pointer imageToLabelFilter = ImageToMapFilterType::New(); 
535     typedef itk::ShapeLabelMapFilter<LabelMapType, ImageType> ShapeFilterType; 
536     typename ShapeFilterType::Pointer statFilter = ShapeFilterType::New();
537     imageToLabelFilter->SetBackgroundValue(BG);
538     imageToLabelFilter->SetInput(image);
539     statFilter->SetInput(imageToLabelFilter->GetOutput());
540     statFilter->SetComputePerimeter(computePerimeterFlag);
541     statFilter->Update();
542     return statFilter->GetOutput();
543   }
544   //--------------------------------------------------------------------
545
546
547   //--------------------------------------------------------------------
548   template<class ImageType>
549   void
550   ComputeCentroids2(const ImageType * image, 
551                    typename ImageType::PixelType BG, 
552                    std::vector<typename ImageType::PointType> & centroids) 
553   {
554     typedef long LabelType;
555     static const unsigned int Dim = ImageType::ImageDimension;
556     typedef itk::ShapeLabelObject< LabelType, Dim > LabelObjectType;
557     typedef itk::LabelMap< LabelObjectType > LabelMapType;
558     typedef itk::LabelImageToLabelMapFilter<ImageType, LabelMapType> ImageToMapFilterType;
559     typename ImageToMapFilterType::Pointer imageToLabelFilter = ImageToMapFilterType::New(); 
560     typedef itk::ShapeLabelMapFilter<LabelMapType, ImageType> ShapeFilterType; 
561     typename ShapeFilterType::Pointer statFilter = ShapeFilterType::New();
562     imageToLabelFilter->SetBackgroundValue(BG);
563     imageToLabelFilter->SetInput(image);
564     statFilter->SetInput(imageToLabelFilter->GetOutput());
565     statFilter->Update();
566     typename LabelMapType::Pointer labelMap = statFilter->GetOutput();
567
568     centroids.clear();
569     typename ImageType::PointType dummy;
570     centroids.push_back(dummy); // label 0 -> no centroid, use dummy point
571     for(uint i=1; i<labelMap->GetNumberOfLabelObjects()+1; i++) {
572       centroids.push_back(labelMap->GetLabelObject(i)->GetCentroid());
573     } 
574     
575     for(uint i=1; i<labelMap->GetNumberOfLabelObjects()+1; i++) {
576       DD(labelMap->GetLabelObject(i)->GetBinaryPrincipalAxes());
577       DD(labelMap->GetLabelObject(i)->GetBinaryFlatness());
578       DD(labelMap->GetLabelObject(i)->GetRoundness ());      
579
580       // search for the point on the boundary alog PA
581
582     }
583
584   }
585   //--------------------------------------------------------------------
586
587
588   //--------------------------------------------------------------------
589   template<class ImageType>
590   void
591   PointsUtils<ImageType>::Convert2DTo3D(const PointType2D & p2D, 
592                                         const ImageType * image, 
593                                         const int slice, 
594                                         PointType3D & p3D)  
595   {
596     IndexType3D index3D;
597     index3D[0] = index3D[1] = 0;
598     index3D[2] = image->GetLargestPossibleRegion().GetIndex()[2]+slice;
599     image->TransformIndexToPhysicalPoint(index3D, p3D);
600     p3D[0] = p2D[0]; 
601     p3D[1] = p2D[1];
602     //  p3D[2] = p[2];//(image->GetLargestPossibleRegion().GetIndex()[2]+slice)*image->GetSpacing()[2] 
603     //    + image->GetOrigin()[2];
604   }
605   //--------------------------------------------------------------------
606
607
608   //--------------------------------------------------------------------
609   template<class ImageType>
610   void 
611   PointsUtils<ImageType>::Convert2DMapTo3DList(const MapPoint2DType & map, 
612                                             const ImageType * image, 
613                                             VectorPoint3DType & list)
614   {
615     typename MapPoint2DType::const_iterator iter = map.begin();
616     while (iter != map.end()) {
617       PointType3D p;
618       Convert2DTo3D(iter->second, image, iter->first, p);
619       list.push_back(p);
620       ++iter;
621     }
622   }
623   //--------------------------------------------------------------------
624
625
626   //--------------------------------------------------------------------
627   template<class ImageType>
628   void 
629   PointsUtils<ImageType>::Convert2DListTo3DList(const VectorPoint2DType & p2D, 
630                                                 int slice,
631                                                 const ImageType * image, 
632                                                 VectorPoint3DType & list) 
633   {
634     for(uint i=0; i<p2D.size(); i++) {
635       PointType3D p;
636       Convert2DTo3D(p2D[i], image, slice, p);
637       list.push_back(p);
638     }
639   }
640   //--------------------------------------------------------------------
641
642
643   //--------------------------------------------------------------------
644   template<class ImageType>
645   void 
646   WriteListOfLandmarks(std::vector<typename ImageType::PointType> points, 
647                        std::string filename)
648   {
649     std::ofstream os; 
650     openFileForWriting(os, filename); 
651     os << "LANDMARKS1" << std::endl;  
652     for(uint i=0; i<points.size(); i++) {
653       const typename ImageType::PointType & p = points[i];
654       // Write it in the file
655       os << i << " " << p[0] << " " << p[1] << " " << p[2] << " 0 0 " << std::endl;
656     }
657     os.close();
658   }
659   //--------------------------------------------------------------------
660
661
662   //--------------------------------------------------------------------
663   template<class ImageType>
664   typename ImageType::Pointer 
665   Dilate(const ImageType * image, double radiusInMM,               
666          typename ImageType::PixelType BG,
667          typename ImageType::PixelType FG,  
668          bool extendSupport)
669   {
670     typename ImageType::SizeType r;
671     for(uint i=0; i<ImageType::ImageDimension; i++) 
672       r[i] = (uint)lrint(radiusInMM/image->GetSpacing()[i]);
673     return Dilate<ImageType>(image, r, BG, FG, extendSupport);
674   }
675   //--------------------------------------------------------------------
676
677
678   //--------------------------------------------------------------------
679   template<class ImageType>
680   typename ImageType::Pointer 
681   Dilate(const ImageType * image, typename ImageType::PointType radiusInMM, 
682          typename ImageType::PixelType BG, 
683          typename ImageType::PixelType FG, 
684          bool extendSupport)
685   {
686     typename ImageType::SizeType r;
687     for(uint i=0; i<ImageType::ImageDimension; i++) 
688       r[i] = (uint)lrint(radiusInMM[i]/image->GetSpacing()[i]);
689     return Dilate<ImageType>(image, r, BG, FG, extendSupport);
690   }
691   //--------------------------------------------------------------------
692
693
694   //--------------------------------------------------------------------
695   template<class ImageType>
696   typename ImageType::Pointer 
697   Dilate(const ImageType * image, typename ImageType::SizeType radius, 
698          typename ImageType::PixelType BG, 
699          typename ImageType::PixelType FG, 
700          bool extendSupport)
701   {
702     // Create kernel for dilatation
703     typedef itk::BinaryBallStructuringElement<typename ImageType::PixelType, 
704                                               ImageType::ImageDimension> KernelType;
705     KernelType structuringElement;
706     structuringElement.SetRadius(radius);
707     structuringElement.CreateStructuringElement();
708
709     typename ImageType::Pointer output;
710     if (extendSupport) {
711       typedef itk::ConstantPadImageFilter<ImageType, ImageType> PadFilterType;
712       typename PadFilterType::Pointer padFilter = PadFilterType::New();
713       padFilter->SetInput(image);
714       typename ImageType::SizeType lower;
715       typename ImageType::SizeType upper;
716       for(uint i=0; i<3; i++) {
717         lower[i] = upper[i] = 2*(radius[i]+1);
718       }
719       padFilter->SetPadLowerBound(lower);
720       padFilter->SetPadUpperBound(upper);
721       padFilter->Update();
722       output = padFilter->GetOutput();
723     }
724
725     // Dilate  filter
726     typedef itk::BinaryDilateImageFilter<ImageType, ImageType , KernelType> DilateFilterType;
727     typename DilateFilterType::Pointer dilateFilter = DilateFilterType::New();
728     dilateFilter->SetBackgroundValue(BG);
729     dilateFilter->SetForegroundValue(FG);
730     dilateFilter->SetBoundaryToForeground(false);
731     dilateFilter->SetKernel(structuringElement);
732     dilateFilter->SetInput(output);
733     dilateFilter->Update();
734     return dilateFilter->GetOutput();
735   }
736   //--------------------------------------------------------------------
737
738
739   //--------------------------------------------------------------------
740   template<class ImageType>
741   typename ImageType::Pointer 
742   Opening(const ImageType * image, typename ImageType::SizeType radius,
743          typename ImageType::PixelType BG,
744          typename ImageType::PixelType FG)
745   {
746     // Kernel 
747     typedef itk::BinaryBallStructuringElement<typename ImageType::PixelType, 
748                                               ImageType::ImageDimension> KernelType;    
749     KernelType structuringElement;
750     structuringElement.SetRadius(radius);
751     structuringElement.CreateStructuringElement();
752     
753     // Filter
754     typedef itk::BinaryMorphologicalOpeningImageFilter<ImageType, ImageType , KernelType> OpeningFilterType;
755     typename OpeningFilterType::Pointer open = OpeningFilterType::New();
756     open->SetInput(image);
757     open->SetBackgroundValue(BG);
758     open->SetForegroundValue(FG);
759     open->SetKernel(structuringElement);
760     open->Update();
761     return open->GetOutput();
762   }
763   //--------------------------------------------------------------------
764
765
766
767   //--------------------------------------------------------------------
768   template<class ValueType, class VectorType>
769   void ConvertOption(std::string optionName, uint given, 
770                      ValueType * values, VectorType & p, 
771                      uint dim, bool required) 
772   {
773     if (required && (given == 0)) {
774       clitkExceptionMacro("The option --" << optionName << " must be set and have 1 or " 
775                           << dim << " values.");
776     }
777     if (given == 1) {
778       for(uint i=0; i<dim; i++) p[i] = values[0];
779       return;
780     }
781     if (given == dim) {
782       for(uint i=0; i<dim; i++) p[i] = values[i];
783       return;
784     }
785     if (given == 0) return;
786     clitkExceptionMacro("The option --" << optionName << " must have 1 or " 
787                         << dim << " values.");
788   }
789   //--------------------------------------------------------------------
790
791
792   //--------------------------------------------------------------------
793   /*
794     http://www.gamedev.net/community/forums/topic.asp?topic_id=542870
795     Assuming the points are (Ax,Ay) (Bx,By) and (Cx,Cy), you need to compute:
796     (Bx - Ax) * (Cy - Ay) - (By - Ay) * (Cx - Ax)
797     This will equal zero if the point C is on the line formed by
798     points A and B, and will have a different sign depending on the
799     side. Which side this is depends on the orientation of your (x,y)
800     coordinates, but you can plug test values for A,B and C into this
801     formula to determine whether negative values are to the left or to
802     the right.
803     => to accelerate, start with formula, when change sign -> stop and fill
804
805     offsetToKeep = is used to determine which side of the line we
806     keep. The point along the mainDirection but 'offsetToKeep' mm away
807     is kept.
808   
809   */
810   template<class ImageType>
811   void 
812   SliceBySliceSetBackgroundFromLineSeparation(ImageType * input, 
813                                               std::vector<typename ImageType::PointType> & lA, 
814                                               std::vector<typename ImageType::PointType> & lB, 
815                                               typename ImageType::PixelType BG, 
816                                               int mainDirection, 
817                                               double offsetToKeep)
818   {
819     typedef itk::ImageSliceIteratorWithIndex<ImageType> SliceIteratorType;
820     SliceIteratorType siter = SliceIteratorType(input, 
821                                                 input->GetLargestPossibleRegion());
822     siter.SetFirstDirection(0);
823     siter.SetSecondDirection(1);
824     siter.GoToBegin();
825     uint i=0;
826     typename ImageType::PointType A;
827     typename ImageType::PointType B;
828     typename ImageType::PointType C;
829     assert(lA.size() == lB.size());
830     while ((i<lA.size()) && (!siter.IsAtEnd())) {
831       // Check that the current slice correspond to the current point
832       input->TransformIndexToPhysicalPoint(siter.GetIndex(), C);
833       // DD(C);
834       // DD(i);
835       // DD(lA[i]);
836       if ((fabs(C[2] - lA[i][2]))>0.01) { // is !equal with a tolerance of 0.01 mm
837       }
838       else {
839         // Define A,B,C points
840         A = lA[i];
841         B = lB[i];
842         C = A;
843         // DD(A);
844         // DD(B);
845         // DD(C);
846       
847         // Check that the line is not a point (A=B)
848         bool p = (A[0] == B[0]) && (A[1] == B[1]);
849       
850         if (!p) {
851           C[mainDirection] += offsetToKeep; // I know I must keep this point
852           double s = (B[0] - A[0]) * (C[1] - A[1]) - (B[1] - A[1]) * (C[0] - A[0]);
853           bool isPositive = s<0;
854           while (!siter.IsAtEndOfSlice()) {
855             while (!siter.IsAtEndOfLine()) {
856               // Very slow, I know ... but image should be very small
857               input->TransformIndexToPhysicalPoint(siter.GetIndex(), C);
858               double s = (B[0] - A[0]) * (C[1] - A[1]) - (B[1] - A[1]) * (C[0] - A[0]);
859               if (s == 0) siter.Set(BG); // on the line, we decide to remove
860               if (isPositive) {
861                 if (s > 0) siter.Set(BG);
862               }
863               else {
864                 if (s < 0) siter.Set(BG); 
865               }
866               ++siter;
867             }
868             siter.NextLine();
869           } // end loop slice
870         }      
871
872         ++i;
873       } // End of current slice
874       siter.NextSlice();
875     }
876   }                                                   
877   //--------------------------------------------------------------------
878
879   //--------------------------------------------------------------------
880   template<class ImageType>
881   void 
882   AndNot(ImageType * input, 
883          const ImageType * object, 
884          typename ImageType::PixelType BG)
885   {
886     typename ImageType::Pointer o;
887     bool resized=false;
888     if (!clitk::HaveSameSizeAndSpacing<ImageType, ImageType>(input, object)) {
889       o = clitk::ResizeImageLike<ImageType>(object, input, BG);
890       resized = true;
891     }
892
893     typedef clitk::BooleanOperatorLabelImageFilter<ImageType> BoolFilterType;
894     typename BoolFilterType::Pointer boolFilter = BoolFilterType::New(); 
895     boolFilter->InPlaceOn();
896     boolFilter->SetInput1(input);
897     if (resized) boolFilter->SetInput2(o);  
898     else boolFilter->SetInput2(object);
899     boolFilter->SetBackgroundValue1(BG);
900     boolFilter->SetBackgroundValue2(BG);
901     boolFilter->SetOperationType(BoolFilterType::AndNot);
902     boolFilter->Update();
903   }
904   //--------------------------------------------------------------------
905
906
907   //--------------------------------------------------------------------
908   template<class ImageType>
909   typename ImageType::Pointer
910   Binarize(const ImageType * input, 
911            typename ImageType::PixelType lower, 
912            typename ImageType::PixelType upper, 
913            typename ImageType::PixelType BG,
914            typename ImageType::PixelType FG) 
915   {
916     typedef itk::BinaryThresholdImageFilter<ImageType, ImageType> BinaryThresholdFilterType;
917     typename BinaryThresholdFilterType::Pointer binarizeFilter = BinaryThresholdFilterType::New();
918     binarizeFilter->SetInput(input);
919     binarizeFilter->InPlaceOff();
920     binarizeFilter->SetLowerThreshold(lower);
921     binarizeFilter->SetUpperThreshold(upper);
922     binarizeFilter->SetInsideValue(FG);
923     binarizeFilter->SetOutsideValue(BG);
924     binarizeFilter->Update();
925     return binarizeFilter->GetOutput();
926   }
927   //--------------------------------------------------------------------
928
929
930   //--------------------------------------------------------------------
931   template<class ImageType>
932   void
933   GetMinMaxPointPosition(const ImageType * input, 
934                          typename ImageType::PointType & min,
935                          typename ImageType::PointType & max) 
936   {
937     typename ImageType::IndexType index = input->GetLargestPossibleRegion().GetIndex();
938     input->TransformIndexToPhysicalPoint(index, min);
939     index = index+input->GetLargestPossibleRegion().GetSize();
940     input->TransformIndexToPhysicalPoint(index, max);
941   }
942   //--------------------------------------------------------------------
943
944
945   //--------------------------------------------------------------------
946   template<class ImageType>
947   typename ImageType::PointType
948   FindExtremaPointInAGivenLine(const ImageType * input, 
949                                int dimension, 
950                                bool inverse, 
951                                typename ImageType::PointType p, 
952                                typename ImageType::PixelType BG, 
953                                double distanceMax) 
954   {
955     // Which direction ?  Increasing or decreasing.
956     int d=1;
957     if (inverse) d=-1;
958   
959     // Transform to pixel index
960     typename ImageType::IndexType index;
961     input->TransformPhysicalPointToIndex(p, index);
962
963     // Loop while inside the mask;
964     while (input->GetPixel(index) != BG) {
965       index[dimension] += d;
966     }
967
968     // Transform back to Physical Units
969     typename ImageType::PointType result;
970     input->TransformIndexToPhysicalPoint(index, result);
971
972     // Check that is is not too far away
973     double distance = p.EuclideanDistanceTo(result);
974     if (distance > distanceMax) {
975       result = p; // Get back to initial value
976     }
977
978     return result;
979   }
980   //--------------------------------------------------------------------
981
982
983   //--------------------------------------------------------------------
984   template<class PointType>
985   bool
986   IsOnTheSameLineSide(PointType C, PointType A, PointType B, PointType like) 
987   {
988     // Look at the position of point 'like' according to the AB line
989     double s = (B[0] - A[0]) * (like[1] - A[1]) - (B[1] - A[1]) * (like[0] - A[0]);
990     bool negative = s<0;
991   
992     // Look the C position
993     s = (B[0] - A[0]) * (C[1] - A[1]) - (B[1] - A[1]) * (C[0] - A[0]);
994
995     if (negative && (s<=0)) return true;
996     if (!negative && (s>=0)) return true;
997     return false;
998   }
999   //--------------------------------------------------------------------
1000
1001
1002   //--------------------------------------------------------------------
1003   /* Consider an input object, for each slice, find the extrema
1004      position according to a given direction and build a line segment
1005      passing throught this point in a given direction.  Output is a
1006      vector of line (from point A to B), for each slice;
1007    */
1008   template<class ImageType>
1009   void 
1010   SliceBySliceBuildLineSegmentAccordingToExtremaPosition(const ImageType * input, 
1011                                                          typename ImageType::PixelType BG, 
1012                                                          int sliceDimension, 
1013                                                          int extremaDirection, 
1014                                                          bool extremaOppositeFlag, 
1015                                                          int lineDirection,
1016                                                          double margin,
1017                                                          std::vector<typename ImageType::PointType> & A, 
1018                                                          std::vector<typename ImageType::PointType> & B)
1019   {
1020     // Type of a slice
1021     typedef typename itk::Image<typename ImageType::PixelType, ImageType::ImageDimension-1> SliceType;
1022     
1023     // Build the list of slices
1024     std::vector<typename SliceType::Pointer> slices;
1025     clitk::ExtractSlices<ImageType>(input, sliceDimension, slices);
1026
1027     // Build the list of 2D points
1028     std::map<int, typename SliceType::PointType> position2D;
1029     for(uint i=0; i<slices.size(); i++) {
1030       typename SliceType::PointType p;
1031       bool found = 
1032         clitk::FindExtremaPointInAGivenDirection<SliceType>(slices[i], BG, 
1033                                                             extremaDirection, extremaOppositeFlag, p);
1034       if (found) {
1035         position2D[i] = p;
1036       }    
1037     }
1038     
1039     // Convert 2D points in slice into 3D points
1040     clitk::PointsUtils<ImageType>::Convert2DMapTo3DList(position2D, input, A);
1041     
1042     // Create additional point just right to the previous ones, on the
1043     // given lineDirection, in order to create a horizontal/vertical line.
1044     for(uint i=0; i<A.size(); i++) {
1045       typename ImageType::PointType p = A[i];
1046       p[lineDirection] += 10;
1047       B.push_back(p);
1048       // Margins ?
1049       A[i][1] += margin;
1050       B[i][1] += margin;
1051     }
1052
1053   }
1054   //--------------------------------------------------------------------
1055
1056
1057   //--------------------------------------------------------------------
1058   template<class ImageType>
1059   typename ImageType::Pointer
1060   SliceBySliceKeepMainCCL(const ImageType * input, 
1061                           typename ImageType::PixelType BG,
1062                           typename ImageType::PixelType FG)  {
1063     
1064     // Extract slices
1065     const int d = ImageType::ImageDimension-1;
1066     typedef typename itk::Image<typename ImageType::PixelType, d> SliceType;
1067     std::vector<typename SliceType::Pointer> slices;
1068     clitk::ExtractSlices<ImageType>(input, d, slices);
1069     
1070     // Labelize and keep the main one
1071     std::vector<typename SliceType::Pointer> o;
1072     for(uint i=0; i<slices.size(); i++) {
1073       o.push_back(clitk::Labelize<SliceType>(slices[i], BG, false, 1));
1074       o[i] = clitk::KeepLabels<SliceType>(o[i], BG, FG, 1, 1, true);
1075     }
1076     
1077     // Join slices
1078     typename ImageType::Pointer output;
1079     output = clitk::JoinSlices<ImageType>(o, input, d);
1080     return output;
1081   }
1082   //--------------------------------------------------------------------
1083
1084
1085   //--------------------------------------------------------------------
1086   template<class ImageType>
1087   typename ImageType::Pointer
1088   Clone(const ImageType * input) {
1089     typedef itk::ImageDuplicator<ImageType> DuplicatorType;
1090     typename DuplicatorType::Pointer duplicator = DuplicatorType::New();
1091     duplicator->SetInputImage(input);
1092     duplicator->Update();
1093     return duplicator->GetOutput();
1094   }
1095   //--------------------------------------------------------------------
1096
1097
1098 } // end of namespace
1099