]> Creatis software - clitk.git/blob - itk/clitkAddRelativePositionConstraintToLabelImageFilter.txx
6d536186fbf5084da969d0750e05a4cc8cd3c8fb
[clitk.git] / itk / clitkAddRelativePositionConstraintToLabelImageFilter.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 "clitkCommon.h"
21 #include "clitkBooleanOperatorLabelImageFilter.h"
22 #include "clitkAutoCropFilter.h"
23 #include "clitkResampleImageWithOptionsFilter.h"
24 #include "clitkBooleanOperatorLabelImageFilter.h"
25 #include "clitkCropLikeImageFilter.h"
26
27 // itk
28 #include <deque>
29 #include <itkStatisticsLabelMapFilter.h>
30 #include <itkLabelImageToStatisticsLabelMapFilter.h>
31 #include <itkRegionOfInterestImageFilter.h>
32 #include <itkBinaryThresholdImageFilter.h>
33 #include <itkBinaryErodeImageFilter.h>
34 #include <itkBinaryBallStructuringElement.h>
35 #include <itkAddImageFilter.h>
36 #if ITK_VERSION_MAJOR >= 4
37   #include <itkDivideImageFilter.h>
38 #else
39   #include <itkDivideByConstantImageFilter.h>
40 #endif
41
42 // itk [Bloch et al] 
43 #include "RelativePositionPropImageFilter.h"
44
45 //--------------------------------------------------------------------
46 template <class ImageType>
47 clitk::AddRelativePositionConstraintToLabelImageFilter<ImageType>::
48 AddRelativePositionConstraintToLabelImageFilter():
49   clitk::FilterBase(),
50   itk::ImageToImageFilter<ImageType, ImageType>()
51 {
52   this->SetNumberOfRequiredInputs(2);
53   SetFuzzyThreshold(0.6);
54   SetBackgroundValue(0);
55   SetObjectBackgroundValue(0);
56   ClearOrientationType();
57   IntermediateSpacingFlagOn();
58   SetIntermediateSpacing(10);
59   AutoCropFlagOn();
60   InverseOrientationFlagOff();
61   RemoveObjectFlagOn();
62   CombineWithOrFlagOff();
63   VerboseStepFlagOff();
64   WriteStepFlagOff();
65   FuzzyMapOnlyFlagOff();
66   FastFlagOff();
67   SetRadius(2.0);
68 }
69 //--------------------------------------------------------------------
70
71
72 //--------------------------------------------------------------------
73 template <class ImageType>
74 void 
75 clitk::AddRelativePositionConstraintToLabelImageFilter<ImageType>::
76 SetInput(const ImageType * image) 
77 {
78   // Process object is not const-correct so the const casting is required.
79   this->SetNthInput(0, const_cast<ImageType *>(image));
80 }
81 //--------------------------------------------------------------------
82   
83
84 //--------------------------------------------------------------------
85 template <class ImageType>
86 void 
87 clitk::AddRelativePositionConstraintToLabelImageFilter<ImageType>::
88 SetInputObject(const ImageType * image) 
89 {
90   // Process object is not const-correct so the const casting is required.
91   this->SetNthInput(1, const_cast<ImageType *>(image));
92 }
93 //--------------------------------------------------------------------
94   
95
96 //--------------------------------------------------------------------
97 template <class ImageType>
98 void 
99 clitk::AddRelativePositionConstraintToLabelImageFilter<ImageType>::
100 ClearOrientationType() 
101 {
102   m_OrientationTypeString.clear();
103   m_OrientationType.clear();
104   m_Angle1.clear();
105   m_Angle2.clear();
106 }
107 //--------------------------------------------------------------------
108
109
110 //--------------------------------------------------------------------
111 template <class ImageType>
112 int
113 clitk::AddRelativePositionConstraintToLabelImageFilter<ImageType>::
114 GetNumberOfAngles()
115 {
116   return m_OrientationType.size();
117 }
118 //--------------------------------------------------------------------
119
120
121 //--------------------------------------------------------------------
122 template <class ImageType>
123 void 
124 clitk::AddRelativePositionConstraintToLabelImageFilter<ImageType>::
125 AddOrientationTypeString(std::string t) 
126 {
127   m_OrientationTypeString.push_back(t);
128
129   if (t == "LeftTo") { AddOrientationType(LeftTo); return; }
130   if (t == "RightTo") { AddOrientationType(RightTo); return; }
131   if (t == "AntTo") { AddOrientationType(AntTo); return; }
132   if (t == "PostTo") { AddOrientationType(PostTo); return; }
133   if (t == "SupTo") { AddOrientationType(SupTo); return; }
134   if (t == "InfTo") { AddOrientationType(InfTo); return; }
135
136   if (t == "NotLeftTo") { AddOrientationType(LeftTo); InverseOrientationFlagOn(); return; }
137   if (t == "NotRightTo") { AddOrientationType(RightTo); InverseOrientationFlagOn(); return; }
138   if (t == "NotAntTo") { AddOrientationType(AntTo); InverseOrientationFlagOn(); return; }
139   if (t == "NotPostTo") { AddOrientationType(PostTo); InverseOrientationFlagOn(); return; }
140   if (t == "NotSupTo") { AddOrientationType(SupTo); InverseOrientationFlagOn(); return; }
141   if (t == "NotInfTo") { AddOrientationType(InfTo); InverseOrientationFlagOn(); return; }
142
143   if (t == "Angle") return;
144
145   clitkExceptionMacro("Error, you must provide LeftTo,RightTo or AntTo,PostTo or SupTo,InfTo (or NotLeftTo, NotRightTo etc) but you give " << t);
146 }
147 //--------------------------------------------------------------------
148   
149
150 //--------------------------------------------------------------------
151 template <class ImageType>
152 void 
153 clitk::AddRelativePositionConstraintToLabelImageFilter<ImageType>::
154 GenerateOutputInformation() 
155
156   ImagePointer input = dynamic_cast<ImageType*>(itk::ProcessObject::GetInput(0));
157   ImagePointer outputImage = this->GetOutput(0);
158   outputImage->SetRegions(outputImage->GetLargestPossibleRegion());
159 }
160 //--------------------------------------------------------------------
161
162
163 //--------------------------------------------------------------------
164 template <class ImageType>
165 void 
166 clitk::AddRelativePositionConstraintToLabelImageFilter<ImageType>::
167 GenerateInputRequestedRegion() 
168 {
169   // Call default
170   itk::ImageToImageFilter<ImageType, ImageType>::GenerateInputRequestedRegion();
171   // Get input pointers and set requested region to common region
172   ImagePointer input1 = dynamic_cast<ImageType*>(itk::ProcessObject::GetInput(0));
173   ImagePointer input2 = dynamic_cast<ImageType*>(itk::ProcessObject::GetInput(1));
174   input1->SetRequestedRegion(input1->GetLargestPossibleRegion());
175   input2->SetRequestedRegion(input2->GetLargestPossibleRegion());
176 }
177 //--------------------------------------------------------------------
178
179   
180 //--------------------------------------------------------------------
181 template <class ImageType>
182 void 
183 clitk::AddRelativePositionConstraintToLabelImageFilter<ImageType>::
184 AddAnglesInRad(double a, double b) 
185 {
186   m_OrientationTypeString.push_back("Angle");
187   m_OrientationType.push_back(Angle);
188   m_Angle1.push_back(a);
189   m_Angle2.push_back(b);
190 }
191 //--------------------------------------------------------------------
192
193
194 //--------------------------------------------------------------------
195 template <class ImageType>
196 void 
197 clitk::AddRelativePositionConstraintToLabelImageFilter<ImageType>::
198 AddAnglesInDeg(double a, double b) 
199 {
200   AddAnglesInRad(clitk::deg2rad(a), clitk::deg2rad(b));
201 }
202 //--------------------------------------------------------------------
203
204
205 //--------------------------------------------------------------------
206 template <class ImageType>
207 void 
208 clitk::AddRelativePositionConstraintToLabelImageFilter<ImageType>::
209 AddOrientationType(OrientationTypeEnumeration orientation) 
210 {
211   m_OrientationType.push_back(orientation);
212   switch (orientation) {
213   case RightTo:   
214     m_Angle1.push_back(clitk::deg2rad(0));   
215     m_Angle2.push_back(clitk::deg2rad(0));
216     break;
217   case LeftTo:  
218     m_Angle1.push_back(clitk::deg2rad(180)); 
219     m_Angle2.push_back(clitk::deg2rad(0));
220     break;
221   case AntTo:
222     m_Angle1.push_back(clitk::deg2rad(90));
223     m_Angle2.push_back(clitk::deg2rad(0));
224     break;
225   case PostTo:
226     m_Angle1.push_back(clitk::deg2rad(-90)); 
227     m_Angle2.push_back(clitk::deg2rad(0));
228     break;
229   case InfTo:    
230     m_Angle1.push_back(clitk::deg2rad(0));   
231     m_Angle2.push_back(clitk::deg2rad(90));
232     break;
233   case SupTo:    
234     m_Angle1.push_back(clitk::deg2rad(0));   
235     m_Angle2.push_back(clitk::deg2rad(-90));
236     break;
237   case Angle:  break;
238   }
239   /*         A1   A2
240              Left      0    0
241              Right   180    0
242              Ant      90    0
243              Post    -90    0
244              Inf       0   90
245              Sup       0  -90
246   */
247 }
248 //--------------------------------------------------------------------
249
250
251 //--------------------------------------------------------------------
252 template <class ImageType>
253 void 
254 clitk::AddRelativePositionConstraintToLabelImageFilter<ImageType>::
255 PrintOptions() 
256 {
257   DD((int)this->GetBackgroundValue());
258   DD((int)this->GetObjectBackgroundValue());
259   DDV(this->GetOrientationTypeString(), (uint)this->GetNumberOfAngles());
260   DD(this->GetIntermediateSpacingFlag());
261   DD(this->GetIntermediateSpacing());
262   DD(this->GetFuzzyThreshold());
263   DD(this->GetAutoCropFlag());
264   DD(this->GetInverseOrientationFlag());
265   DD(this->GetRemoveObjectFlag());
266   DD(this->GetCombineWithOrFlag());
267 }
268 //--------------------------------------------------------------------
269
270
271 //--------------------------------------------------------------------
272 template <class ImageType>
273 void 
274 clitk::AddRelativePositionConstraintToLabelImageFilter<ImageType>::
275 GenerateData() 
276 {
277   if (GetNumberOfAngles() <1) {
278     clitkExceptionMacro("Add at least one orientation type");
279   }  
280
281   if (GetVerboseOptionFlag()) {
282     for(int i=0; i<GetNumberOfAngles(); i++) {
283         std::cout << "Orientation    \t:" << GetOrientationTypeString(i) << std::endl;
284     }
285     std::cout << "Interm Spacing \t:" << GetIntermediateSpacingFlag() << " " << GetIntermediateSpacing() << "mm" << std::endl;
286     std::cout << "Fuzzy threshold\t:" << GetFuzzyThreshold() << std::endl;
287     std::cout << "AutoCrop       \t:" << GetAutoCropFlag() << std::endl;
288     std::cout << "InverseOrient  \t:" << GetInverseOrientationFlag() << std::endl;
289     std::cout << "RemoveObject   \t:" << GetRemoveObjectFlag() << std::endl;
290     std::cout << "CombineWithOr  \t:" << GetCombineWithOrFlag() << std::endl;
291   }
292
293   // Get input pointer
294   input = dynamic_cast<ImageType*>(itk::ProcessObject::GetInput(0));
295   object = dynamic_cast<ImageType*>(itk::ProcessObject::GetInput(1));
296   static const unsigned int dim = ImageType::ImageDimension;
297
298   // Step 2: object pad to input image -> we want to compute the
299   // relative position for each point belonging to the input image
300   // domain, so we have to extend (pad) the object image to fit the
301   // domain size
302   working_image = object;
303   if (!clitk::HaveSameSizeAndSpacing<ImageType, ImageType>(input, working_image)) {
304     StartNewStep("Pad (resize) object to input size");  
305
306     if (0) { // OLD VERSION (TO REMOVE)
307       StartNewStep("Pad object to image size");  
308       typename ImageType::Pointer output = ImageType::New();
309       SizeType size;
310       for(unsigned int i=0; i<dim; i++) {
311         size[i] = lrint((input->GetLargestPossibleRegion().GetSize()[i]*
312                          input->GetSpacing()[i])/(double)working_image->GetSpacing()[i]);
313       }
314
315       // The index of the input is not necessarily zero, so we have to
316       // take it into account (not done)
317       RegionType region;
318       IndexType index = input->GetLargestPossibleRegion().GetIndex();
319       region.SetSize(size);
320       for(unsigned int i=0; i<dim; i++) {
321         if (index[i] != 0) {
322           std::cerr << "Index diff from zero : " << index << ". not done yet !" << std::endl;
323           exit(0);
324         }
325       }
326       // output->SetLargestPossibleRegion(region);
327       output->SetRegions(region);
328       output->SetSpacing(working_image->GetSpacing());    
329       PointType origin = input->GetOrigin();
330       for(unsigned int i=0; i<dim; i++) {
331         origin[i] = index[i]*input->GetSpacing()[i] + input->GetOrigin()[i];
332       }
333       output->SetOrigin(origin);
334       //    output->SetOrigin(input->GetOrigin());
335
336       output->Allocate();
337       output->FillBuffer(m_BackgroundValue);
338       typename PasteFilterType::Pointer padFilter = PasteFilterType::New();
339       // typename PasteFilterType::InputImageIndexType index;
340       for(unsigned int i=0; i<dim; i++) {
341         index[i] = -index[i]*input->GetSpacing()[i]/(double)working_image->GetSpacing()[i]
342           + lrint((working_image->GetOrigin()[i] - input->GetOrigin()[i])/working_image->GetSpacing()[i]);
343       }
344       padFilter->SetSourceImage(working_image);
345       padFilter->SetDestinationImage(output);
346       padFilter->SetDestinationIndex(index);
347       padFilter->SetSourceRegion(working_image->GetLargestPossibleRegion());
348       padFilter->Update();
349       working_image = padFilter->GetOutput();
350     }
351
352     // Resize object like input
353     working_image = clitk::ResizeImageLike<ImageType>(working_image, input, GetBackgroundValue());
354     StopCurrentStep<ImageType>(working_image);
355   }
356
357   //--------------------------------------------------------------------
358   //--------------------------------------------------------------------
359   // Step 1 : resample
360   if (m_IntermediateSpacingFlag) {
361     StartNewStep("Resample object to intermediate spacing");  
362     typedef clitk::ResampleImageWithOptionsFilter<ImageType> ResampleFilterType;
363     typename ResampleFilterType::Pointer resampleFilter = ResampleFilterType::New();
364     resampleFilter->SetInput(working_image);
365     resampleFilter->SetDefaultPixelValue(0);
366     resampleFilter->SetOutputIsoSpacing(m_IntermediateSpacing);
367     resampleFilter->SetGaussianFilteringEnabled(false);
368     //    resampleFilter->SetVerboseOptions(true);
369     resampleFilter->Update();
370     working_image = resampleFilter->GetOutput();
371     StopCurrentStep<ImageType>(working_image);
372   }
373
374   // Keep object image (with resampline and pad)
375   object_resampled = working_image;
376
377   // Step 3: compute rel pos in object
378   StartNewStep("Relative Position Map");  
379   typedef itk::RelativePositionPropImageFilter<ImageType, FloatImageType> RelPosFilterType;
380   typename RelPosFilterType::Pointer relPosFilter;
381
382   for(int i=0; i<GetNumberOfAngles(); i++) {
383     // Compute fuzzy map
384     relPosFilter = RelPosFilterType::New();
385     relPosFilter->SetFast(GetFastFlag());
386     relPosFilter->SetRadius(GetRadius());
387     relPosFilter->SetInput(working_image);
388     relPosFilter->SetAlpha1(m_Angle1[i]); // xy plane
389     relPosFilter->SetAlpha2(m_Angle2[i]);
390     relPosFilter->SetK1(M_PI/2.0); // Opening parameter, default = pi/2
391
392     // relPosFilter->SetFast(true);
393     // relPosFilter->SetRadius(1); // seems sufficient in this case
394
395     // relPosFilter->SetVerboseProgress(true);
396     relPosFilter->Update();
397     relPos = relPosFilter->GetOutput();
398
399     if (GetNumberOfAngles() != 1) {
400       // Creation of the first m_FuzzyMap
401       if (i==0) {
402         m_FuzzyMap = clitk::NewImageLike<FloatImageType>(relPos, true);
403         m_FuzzyMap->FillBuffer(0.0);
404       }
405       
406       // Add to current fuzzy map
407       typedef itk::AddImageFilter<FloatImageType, FloatImageType, FloatImageType> AddImageFilter;
408       typename AddImageFilter::Pointer addFilter = AddImageFilter::New();
409       addFilter->SetInput1(m_FuzzyMap);
410       addFilter->SetInput2(relPos);
411       addFilter->Update();
412       m_FuzzyMap = addFilter->GetOutput();
413     }
414     else m_FuzzyMap = relPos;
415   }
416
417   // Divide by the number of relpos
418   if (GetNumberOfAngles() != 1) {
419 #if ITK_VERSION_MAJOR >= 4
420     typedef itk::DivideImageFilter<FloatImageType, FloatImageType, FloatImageType> DivideFilter;
421     typename DivideFilter::Pointer divideFilter = DivideFilter::New();
422     divideFilter->SetConstant2(GetNumberOfAngles());
423 #else
424     typedef itk::DivideByConstantImageFilter<FloatImageType, float, FloatImageType> DivideFilter;
425     typename DivideFilter::Pointer divideFilter = DivideFilter::New();
426     divideFilter->SetConstant(GetNumberOfAngles());
427 #endif
428     divideFilter->SetInput(m_FuzzyMap);
429     divideFilter->Update();
430     m_FuzzyMap = divideFilter->GetOutput();
431   }
432
433   relPos = m_FuzzyMap;
434   StopCurrentStep<FloatImageType>(relPos);
435   if (GetFuzzyMapOnlyFlag()) {
436     // If the spacing is used, recompute fuzzy map with the input size/spacing
437     if (m_IntermediateSpacingFlag) {
438       StartNewStep("Resample FuzzyMap to come back to the same sampling than input");
439       typedef clitk::ResampleImageWithOptionsFilter<FloatImageType> ResampleFilterType;
440       typename ResampleFilterType::Pointer resampleFilter = ResampleFilterType::New();
441       resampleFilter->SetDefaultPixelValue(0.0); //Default fuzzymap value FIXME
442       resampleFilter->SetInput(relPos);
443       resampleFilter->SetOutputSpacing(input->GetSpacing());
444       resampleFilter->SetGaussianFilteringEnabled(false);
445       resampleFilter->Update();
446       relPos = m_FuzzyMap = resampleFilter->GetOutput();
447
448       // Need to put exactly the same size
449       if (relPos->GetLargestPossibleRegion() != input->GetLargestPossibleRegion()) {
450         StartNewStep("Pad to get the same size than input");
451         typename FloatImageType::Pointer temp = FloatImageType::New();
452         temp->CopyInformation(input);
453         temp->SetRegions(input->GetLargestPossibleRegion()); // Do not forget !!
454         temp->Allocate();
455         temp->FillBuffer(0.0); // Default fuzzymap value FIXME
456         typename PasteFloatFilterType::Pointer padFilter2 = PasteFloatFilterType::New();
457         padFilter2->SetSourceImage(relPos);
458         padFilter2->SetDestinationImage(temp);
459         padFilter2->SetDestinationIndex(input->GetLargestPossibleRegion().GetIndex());
460         padFilter2->SetSourceRegion(relPos->GetLargestPossibleRegion());
461         padFilter2->Update();
462         relPos = padFilter2->GetOutput();
463         StopCurrentStep<FloatImageType>(relPos);
464         m_FuzzyMap = relPos;
465       }     
466     }
467     else {
468       StopCurrentStep<FloatImageType>(relPos);
469     }
470     return;
471   }
472                
473   //--------------------------------------------------------------------
474   //--------------------------------------------------------------------
475   StartNewStep("Map Threshold");
476   // Step 1: threshold
477   typedef itk::BinaryThresholdImageFilter<FloatImageType, ImageType> BinaryThresholdImageFilterType;
478   typename BinaryThresholdImageFilterType::Pointer thresholdFilter = BinaryThresholdImageFilterType::New();
479   thresholdFilter->SetInput(relPos);
480   thresholdFilter->SetOutsideValue(m_BackgroundValue);
481   thresholdFilter->SetInsideValue(m_BackgroundValue+1);
482   thresholdFilter->SetLowerThreshold(m_FuzzyThreshold);
483   thresholdFilter->Update();
484   working_image = thresholdFilter->GetOutput();
485   StopCurrentStep<ImageType>(working_image);
486
487   //--------------------------------------------------------------------
488   //--------------------------------------------------------------------
489   StartNewStep("Post Processing: erosion with initial mask");
490   // Step 2 : erosion with initial mask to exclude pixels that were
491   // inside the resampled version and outside the original mask
492   typedef itk::BinaryBallStructuringElement<unsigned int, ImageDimension> StructuringElementType; 
493   StructuringElementType kernel;
494   kernel.SetRadius(1);
495   kernel.CreateStructuringElement();
496   typedef itk::BinaryErodeImageFilter<ImageType, ImageType, StructuringElementType> ErodeFilterType;
497   typename ErodeFilterType::Pointer erodeFilter = ErodeFilterType::New();
498   erodeFilter->SetInput(working_image);
499   erodeFilter->SetKernel(kernel);
500   erodeFilter->SetBackgroundValue(m_BackgroundValue);
501   erodeFilter->SetErodeValue(m_BackgroundValue+1);
502   erodeFilter->Update();
503   working_image = erodeFilter->GetOutput();
504   StopCurrentStep<ImageType>(working_image);
505
506   //--------------------------------------------------------------------
507   //--------------------------------------------------------------------
508   // Step 5: resample to initial spacing
509   if (m_IntermediateSpacingFlag) {
510     StartNewStep("Resample to come back to the same sampling than input");
511     typedef clitk::ResampleImageWithOptionsFilter<ImageType> ResampleFilterType;
512     typename ResampleFilterType::Pointer resampleFilter = ResampleFilterType::New();
513     resampleFilter->SetDefaultPixelValue(m_BackgroundValue);
514     resampleFilter->SetInput(working_image);
515     resampleFilter->SetOutputSpacing(input->GetSpacing());
516     resampleFilter->SetGaussianFilteringEnabled(false);
517     // resampleFilter->SetVerboseOptions(true);
518     resampleFilter->Update();
519     working_image = resampleFilter->GetOutput();
520     StopCurrentStep<ImageType>(working_image);
521   }
522
523   //--------------------------------------------------------------------
524   //--------------------------------------------------------------------
525   // Pre Step 6: pad if not the same size : it can occur when downsample and upsample
526   //if (!HaveSameSizeAndSpacing(working_image, input)) {
527   if (working_image->GetLargestPossibleRegion() != input->GetLargestPossibleRegion()) {
528     StartNewStep("Pad to get the same size than input");
529     typename ImageType::Pointer temp = ImageType::New();
530     temp->CopyInformation(input);
531     temp->SetRegions(input->GetLargestPossibleRegion()); // Do not forget !!
532     temp->Allocate();
533     temp->FillBuffer(m_BackgroundValue); 
534     typename PasteFilterType::Pointer padFilter2 = PasteFilterType::New();
535     padFilter2->SetSourceImage(working_image);
536     padFilter2->SetDestinationImage(temp);
537     padFilter2->SetDestinationIndex(input->GetLargestPossibleRegion().GetIndex());
538     padFilter2->SetSourceRegion(working_image->GetLargestPossibleRegion());
539     padFilter2->Update();
540     working_image = padFilter2->GetOutput();
541     StopCurrentStep<ImageType>(working_image);
542   }
543   else {
544     //DD("[debug] Rel Pos : no padding after");
545   }
546
547   //--------------------------------------------------------------------
548   //--------------------------------------------------------------------
549   // Step 6: combine input+thresholded relpos
550   StartNewStep("Combine with initial input (boolean And)");
551   typedef clitk::BooleanOperatorLabelImageFilter<ImageType> BoolFilterType;
552   typename BoolFilterType::Pointer combineFilter = BoolFilterType::New();
553   combineFilter->SetBackgroundValue(m_BackgroundValue);
554   combineFilter->SetBackgroundValue1(m_BackgroundValue);
555   combineFilter->SetBackgroundValue2(m_BackgroundValue);
556   combineFilter->SetForegroundValue(m_BackgroundValue+1);
557   combineFilter->SetInput1(input);
558   combineFilter->SetInput2(working_image);
559   if (GetInverseOrientationFlag())
560     combineFilter->SetOperationType(BoolFilterType::AndNot);
561   else {
562     if (GetCombineWithOrFlag())
563       combineFilter->SetOperationType(BoolFilterType::Or);
564     else
565       combineFilter->SetOperationType(BoolFilterType::And);
566   }
567   combineFilter->InPlaceOff(); // Do not modify initial input (!)
568   combineFilter->Update(); 
569   working_image = combineFilter->GetOutput();
570
571   // Remove (if needed the object from the support)
572   if (GetRemoveObjectFlag()) {
573     combineFilter = BoolFilterType::New();
574     combineFilter->SetInput1(working_image);
575     combineFilter->SetInput2(object);
576     combineFilter->SetOperationType(BoolFilterType::AndNot);
577     combineFilter->InPlaceOn();
578     combineFilter->Update(); 
579     working_image = combineFilter->GetOutput();
580   }
581   // In the other case, we must *add* the initial object to keep it
582   // but not more than the initial support
583   else { 
584     combineFilter = BoolFilterType::New();
585     combineFilter->SetInput1(working_image);
586     combineFilter->SetInput2(object);
587     combineFilter->SetOperationType(BoolFilterType::Or);
588     combineFilter->InPlaceOn();
589     combineFilter->Update(); 
590     working_image = combineFilter->GetOutput(); // not needed because InPlaceOn ?
591     combineFilter = BoolFilterType::New();
592     combineFilter->SetInput1(working_image);
593     combineFilter->SetInput2(input);
594     combineFilter->SetOperationType(BoolFilterType::And);
595     combineFilter->InPlaceOn();
596     combineFilter->Update(); 
597     working_image = combineFilter->GetOutput();
598   }
599
600   StopCurrentStep<ImageType>(working_image);
601
602   //--------------------------------------------------------------------
603   //--------------------------------------------------------------------
604   // Step 7: autocrop
605   if (GetAutoCropFlag()) {
606     StartNewStep("Final AutoCrop");
607     typedef clitk::AutoCropFilter<ImageType> CropFilterType;
608     typename CropFilterType::Pointer cropFilter = CropFilterType::New();
609     cropFilter->SetInput(working_image);
610     cropFilter->ReleaseDataFlagOff();
611     cropFilter->Update();   
612     working_image = cropFilter->GetOutput();
613     StopCurrentStep<ImageType>(working_image);
614   }
615
616   //--------------------------------------------------------------------
617   //--------------------------------------------------------------------
618   
619   // Final Step -> set output
620   this->SetNthOutput(0, working_image);
621   //  this->GraftOutput(working_image);
622 }
623 //--------------------------------------------------------------------
624