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