]> Creatis software - clitk.git/blob - tools/clitkAffineTransformGenericFilter.txx
Merge branch 'master' of git.creatis.insa-lyon.fr:clitk
[clitk.git] / tools / clitkAffineTransformGenericFilter.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 #ifndef clitkAffineTransformGenericFilter_txx
19 #define clitkAffineTransformGenericFilter_txx
20
21 #include <sstream>
22 #include <istream>
23 #include <iterator>
24 #include <itkCenteredEuler3DTransform.h>
25
26 namespace clitk
27 {
28
29   //-----------------------------------------------------------
30   // Constructor
31   //-----------------------------------------------------------
32   template<class args_info_type>
33   AffineTransformGenericFilter<args_info_type>::AffineTransformGenericFilter()
34   {
35     m_Verbose=false;
36     m_InputFileName="";
37   }
38   //-------------------------------------------------------------------
39  
40
41   //-----------------------------------------------------------
42   // Update
43   //-----------------------------------------------------------
44   template<class args_info_type>
45   void AffineTransformGenericFilter<args_info_type>::Update()
46   {
47     // Read the Dimension and PixelType
48     int Dimension, Components;
49     std::string PixelType;
50     ReadImageDimensionAndPixelType(m_InputFileName, Dimension, PixelType, Components);
51
52     // Call UpdateWithDim
53     if(Dimension==2) UpdateWithDim<2>(PixelType, Components);
54     else 
55     if(Dimension==3) UpdateWithDim<3>(PixelType, Components);
56     else if (Dimension==4)UpdateWithDim<4>(PixelType, Components);
57     else {
58       std::cout<<"Error, Only for 2, 3 or 4  Dimensions!!!"<<std::endl ;
59       return;
60     }
61   }
62   //-------------------------------------------------------------------
63  
64
65   //-------------------------------------------------------------------
66   // Update with the number of dimensions
67   //-------------------------------------------------------------------
68   template<class args_info_type>
69   template<unsigned int Dimension>
70   void
71   AffineTransformGenericFilter<args_info_type>::UpdateWithDim(std::string PixelType, int Components)
72   {
73     if (m_Verbose) std::cout << "Image was detected to be "<<Dimension<<"D and "<<Components<<" component(s) of "<<  PixelType<<"..."<<std::endl;
74
75     if (Components==1) {
76       if(PixelType == "short") {
77         if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and signed short..." << std::endl;
78         UpdateWithDimAndPixelType<Dimension, signed short>();
79       }
80       //    else if(PixelType == "unsigned_short"){
81       //       if (m_Verbose) std::cout  << "Launching filter in "<< Dimension <<"D and unsigned_short..." << std::endl;
82       //       UpdateWithDimAndPixelType<Dimension, unsigned short>();
83       //     }
84
85       else if (PixelType == "unsigned_char") {
86         if (m_Verbose) std::cout  << "Launching filter in "<< Dimension <<"D and unsigned_char..." << std::endl;
87         UpdateWithDimAndPixelType<Dimension, unsigned char>();
88       }
89
90       //     else if (PixelType == "char"){
91       //       if (m_Verbose) std::cout  << "Launching filter in "<< Dimension <<"D and signed_char..." << std::endl;
92       //       UpdateWithDimAndPixelType<Dimension, signed char>();
93       //     }
94       else {
95         if (m_Verbose) std::cout  << "Launching filter in "<< Dimension <<"D and float..." << std::endl;
96         UpdateWithDimAndPixelType<Dimension, float>();
97       }
98     }
99
100     else if (Components==3) {
101       if (m_Verbose) std::cout  << "Launching transform in "<< Dimension <<"D and 3D float (DVF)" << std::endl;
102       UpdateWithDimAndVectorType<Dimension, itk::Vector<float, Dimension> >();
103     }
104
105     else std::cerr<<"Number of components is "<<Components<<", not supported!"<<std::endl;
106
107   }
108   //-------------------------------------------------------------------
109  
110
111   //-------------------------------------------------------------------
112   // Update with the number of dimensions and the pixeltype
113   //-------------------------------------------------------------------
114   template<class args_info_type>
115   template <unsigned int Dimension, class  PixelType>
116   void
117   AffineTransformGenericFilter<args_info_type>::UpdateWithDimAndPixelType()
118   {
119
120     // ImageTypes
121     typedef itk::Image<PixelType, Dimension> InputImageType;
122     typedef itk::Image<PixelType, Dimension> OutputImageType;
123
124     // Read the input
125     typedef itk::ImageFileReader<InputImageType> InputReaderType;
126     typename InputReaderType::Pointer reader = InputReaderType::New();
127     reader->SetFileName( m_InputFileName);
128     reader->Update();
129     typename InputImageType::Pointer input= reader->GetOutput();
130
131     //Filter
132     typedef  itk::ResampleImageFilter< InputImageType,OutputImageType >  ResampleFilterType;
133     typename ResampleFilterType::Pointer resampler = ResampleFilterType::New();
134
135     // Matrix
136     typename itk::Matrix<double, Dimension+1, Dimension+1> matrix;
137     if (m_ArgsInfo.rotate_given || m_ArgsInfo.translate_given)
138       {
139         if (m_ArgsInfo.matrix_given)
140           {
141             std::cerr << "You must use either rotate/translate or matrix options" << std::cout;
142             return;
143           }
144         itk::Array<double> transformParameters(2 * Dimension);
145         transformParameters.Fill(0.0);
146         if (m_ArgsInfo.rotate_given)
147           {
148             if (Dimension == 2)
149               transformParameters[0] = m_ArgsInfo.rotate_arg[0];
150             else
151               for (unsigned int i = 0; i < 3; i++)
152                 transformParameters[i] = m_ArgsInfo.rotate_arg[i];
153           }
154         if (m_ArgsInfo.translate_given)
155           {
156             int pos = 3;
157             if (Dimension == 2)
158               pos = 1;
159             for (unsigned int i = 0; i < Dimension && i < 3; i++)
160               transformParameters[pos++] = m_ArgsInfo.translate_arg[i];
161           }
162         if (Dimension == 4)
163           {
164             matrix.SetIdentity();
165             itk::Matrix<double, 4, 4> tmp = GetForwardAffineMatrix3D(transformParameters);
166             for (unsigned int i = 0; i < 3; ++i)
167               for (unsigned int j = 0; j < 3; ++j)
168                 matrix[i][j] = tmp[i][j];
169             for (unsigned int i = 0; i < 3; ++i)
170               matrix[i][4] = tmp[i][3];
171           }
172         else
173           matrix = GetForwardAffineMatrix<Dimension>(transformParameters);
174       }
175     else
176       {
177         if (m_ArgsInfo.matrix_given)
178           {
179             matrix= clitk::ReadMatrix<Dimension>(m_ArgsInfo.matrix_arg);
180             if (m_Verbose) std::cout << "Reading the matrix..." << std::endl;
181           }
182         else {
183           if (m_ArgsInfo.elastix_given) {
184             matrix = createMatrixFromElastixFile<Dimension,PixelType>(m_ArgsInfo.elastix_arg);
185           }
186           else 
187             matrix.SetIdentity();
188         }
189       }
190     if (m_Verbose)
191       std::cout << "Using the following matrix:" << std::endl
192                 << matrix << std::endl;
193     typename itk::Matrix<double, Dimension, Dimension> rotationMatrix = clitk::GetRotationalPartMatrix(matrix);
194     typename itk::Vector<double, Dimension> translationPart = clitk::GetTranslationPartMatrix(matrix);
195
196     // Transform
197     typedef itk::AffineTransform<double, Dimension> AffineTransformType;
198     typename AffineTransformType::Pointer affineTransform=AffineTransformType::New();
199     affineTransform->SetMatrix(rotationMatrix);
200     affineTransform->SetTranslation(translationPart);
201
202     // Interp
203     typedef clitk::GenericInterpolator<args_info_type, InputImageType, double> GenericInterpolatorType;
204     typename GenericInterpolatorType::Pointer genericInterpolator=GenericInterpolatorType::New();
205     genericInterpolator->SetArgsInfo(m_ArgsInfo);
206
207     // Properties
208     if (m_ArgsInfo.like_given) {
209       typename InputReaderType::Pointer likeReader=InputReaderType::New();
210       likeReader->SetFileName(m_ArgsInfo.like_arg);
211       likeReader->Update();
212       resampler->SetOutputParametersFromImage(likeReader->GetOutput());
213     } else if(m_ArgsInfo.transform_grid_flag) {
214       typename itk::Matrix<double, Dimension+1, Dimension+1> invMatrix( matrix.GetInverse() );
215       typename itk::Matrix<double, Dimension, Dimension> invRotMatrix( clitk::GetRotationalPartMatrix(invMatrix) );
216       typename itk::Vector<double,Dimension> invTrans =  clitk::GetTranslationPartMatrix(invMatrix);
217
218       // Display warning
219       if (m_ArgsInfo.spacing_given)
220         std::cout << "Warning --spacing ignored (because --transform_grid_flag)" << std::endl;
221       if (m_ArgsInfo.origin_given)
222         std::cout << "Warning --origin ignored (because --transform_grid_flag)" << std::endl;
223
224       // Spacing is influenced by affine transform matrix and input direction
225       typename InputImageType::SpacingType outputSpacing;
226       outputSpacing = invRotMatrix *
227         input->GetDirection() *
228         input->GetSpacing();
229
230       // Origin is influenced by translation but not by input direction
231       typename InputImageType::PointType outputOrigin;
232       outputOrigin = invRotMatrix *
233         input->GetOrigin() +
234         invTrans;
235
236       // Size is influenced by affine transform matrix and input direction
237       // Size is converted to double, transformed and converted back to size type.
238       vnl_vector<double> vnlOutputSize(Dimension);
239       for(unsigned int i=0; i< Dimension; i++) {
240         vnlOutputSize[i] = input->GetLargestPossibleRegion().GetSize()[i];
241       }
242       vnlOutputSize = invRotMatrix *
243         input->GetDirection().GetVnlMatrix() *
244         vnlOutputSize;
245       typename OutputImageType::SizeType outputSize;
246       for(unsigned int i=0; i< Dimension; i++) {
247         // If the size is negative, we have a flip and we must modify
248         // the origin and the spacing accordingly.
249         if(vnlOutputSize[i]<0.) {
250           vnlOutputSize[i] *= -1.;
251           outputOrigin[i] = outputOrigin[i] + outputSpacing[i] * (vnlOutputSize[i]-1);
252           outputSpacing[i] *= -1.;
253         }
254         outputSize[i] = lrint(vnlOutputSize[i]);
255       }
256       resampler->SetSize( outputSize );
257       resampler->SetOutputSpacing( outputSpacing );
258       resampler->SetOutputOrigin( outputOrigin );
259     } else {
260       //Size
261       typename OutputImageType::SizeType outputSize;
262       if (m_ArgsInfo.size_given) {
263         for(unsigned int i=0; i< Dimension; i++)
264           outputSize[i]=m_ArgsInfo.size_arg[i];
265       } else outputSize=input->GetLargestPossibleRegion().GetSize();
266
267       //Spacing
268       typename OutputImageType::SpacingType outputSpacing;
269       if (m_ArgsInfo.spacing_given) {
270         for(unsigned int i=0; i< Dimension; i++)
271           outputSpacing[i]=m_ArgsInfo.spacing_arg[i];
272       } else outputSpacing=input->GetSpacing();
273
274       //Origin
275       typename OutputImageType::PointType outputOrigin;
276       if (m_ArgsInfo.origin_given) {
277         for(unsigned int i=0; i< Dimension; i++)
278           outputOrigin[i]=m_ArgsInfo.origin_arg[i];
279       } else outputOrigin=input->GetOrigin();
280
281       // Set
282       resampler->SetSize( outputSize );
283       resampler->SetOutputSpacing( outputSpacing );
284       resampler->SetOutputOrigin(  outputOrigin );
285
286     }
287
288     if (m_ArgsInfo.verbose_flag) {
289       std::cout << "Setting the output size to " << resampler->GetSize() << "..." << std::endl;
290       std::cout << "Setting the output spacing to " << resampler->GetOutputSpacing() << "..." << std::endl;
291       std::cout << "Setting the output origin to " << resampler->GetOutputOrigin() << "..." << std::endl;
292     }
293
294     resampler->SetInput( input );
295     resampler->SetTransform( affineTransform );
296     resampler->SetInterpolator( genericInterpolator->GetInterpolatorPointer());
297     resampler->SetDefaultPixelValue( static_cast<PixelType>(m_ArgsInfo.pad_arg) );
298
299     try {
300       resampler->Update();
301     } catch(itk::ExceptionObject) {
302       std::cerr<<"Error resampling the image"<<std::endl;
303     }
304
305     typename OutputImageType::Pointer output = resampler->GetOutput();
306
307     // Output
308     typedef itk::ImageFileWriter<OutputImageType> WriterType;
309     typename WriterType::Pointer writer = WriterType::New();
310     writer->SetFileName(m_ArgsInfo.output_arg);
311     writer->SetInput(output);
312     writer->Update();
313
314   }
315   //-------------------------------------------------------------------
316     
317
318   //-------------------------------------------------------------------
319   // Update with the number of dimensions and the pixeltype (components)
320   //-------------------------------------------------------------------
321   template<class args_info_type>
322   template<unsigned int Dimension, class PixelType>
323   void AffineTransformGenericFilter<args_info_type>::UpdateWithDimAndVectorType()
324   {
325     // ImageTypes
326     typedef itk::Image<PixelType, Dimension> InputImageType;
327     typedef itk::Image<PixelType, Dimension> OutputImageType;
328
329     // Read the input
330     typedef itk::ImageFileReader<InputImageType> InputReaderType;
331     typename InputReaderType::Pointer reader = InputReaderType::New();
332     reader->SetFileName( m_InputFileName);
333     reader->Update();
334     typename InputImageType::Pointer input= reader->GetOutput();
335
336     //Filter
337     typedef  itk::VectorResampleImageFilter< InputImageType,OutputImageType, double >  ResampleFilterType;
338     typename ResampleFilterType::Pointer resampler = ResampleFilterType::New();
339
340     // Matrix
341     typename itk::Matrix<double, Dimension+1, Dimension+1> matrix;
342     if (m_ArgsInfo.rotate_given || m_ArgsInfo.translate_given)
343       {
344         if (m_ArgsInfo.matrix_given)
345           {
346             std::cerr << "You must use either rotate/translate or matrix options" << std::cout;
347             return;
348           }
349         itk::Array<double> transformParameters(2 * Dimension);
350         transformParameters.Fill(0.0);
351         if (m_ArgsInfo.rotate_given)
352           {
353             if (Dimension == 2)
354               transformParameters[0] = m_ArgsInfo.rotate_arg[0];
355             else
356               for (unsigned int i = 0; i < 3; i++)
357                 transformParameters[i] = m_ArgsInfo.rotate_arg[i];
358           }
359         if (m_ArgsInfo.translate_given)
360           {
361             int pos = 3;
362             if (Dimension == 2)
363               pos = 1;
364             for (unsigned int i = 0; i < Dimension && i < 3; i++)
365               transformParameters[pos++] = m_ArgsInfo.translate_arg[i];
366           }
367         if (Dimension == 4)
368           {
369             matrix.SetIdentity();
370             itk::Matrix<double, 4, 4> tmp = GetForwardAffineMatrix3D(transformParameters);
371             for (unsigned int i = 0; i < 3; ++i)
372               for (unsigned int j = 0; j < 3; ++j)
373                 matrix[i][j] = tmp[i][j];
374             for (unsigned int i = 0; i < 3; ++i)
375               matrix[i][4] = tmp[i][3];
376           }
377         else
378           matrix = GetForwardAffineMatrix<Dimension>(transformParameters);
379       }
380     else
381       {
382         if (m_ArgsInfo.matrix_given)
383           {
384             matrix= clitk::ReadMatrix<Dimension>(m_ArgsInfo.matrix_arg);
385             if (m_Verbose) std::cout << "Reading the matrix..." << std::endl;
386           }
387         else
388           matrix.SetIdentity();
389       }
390     if (m_Verbose)
391       std::cout << "Using the following matrix:" << std::endl
392                 << matrix << std::endl;
393     typename itk::Matrix<double, Dimension, Dimension> rotationMatrix = clitk::GetRotationalPartMatrix(matrix);
394     typename itk::Vector<double, Dimension> translationPart = clitk::GetTranslationPartMatrix(matrix);
395
396     // Transform
397     typedef itk::AffineTransform<double, Dimension> AffineTransformType;
398     typename AffineTransformType::Pointer affineTransform=AffineTransformType::New();
399     affineTransform->SetMatrix(rotationMatrix);
400     affineTransform->SetTranslation(translationPart);
401
402     // Interp
403     typedef clitk::GenericVectorInterpolator<args_info_type, InputImageType, double> GenericInterpolatorType;
404     typename GenericInterpolatorType::Pointer genericInterpolator=GenericInterpolatorType::New();
405     genericInterpolator->SetArgsInfo(m_ArgsInfo);
406
407     // Properties
408     if (m_ArgsInfo.like_given) {
409       typename InputReaderType::Pointer likeReader=InputReaderType::New();
410       likeReader->SetFileName(m_ArgsInfo.like_arg);
411       likeReader->Update();
412       resampler->SetSize( likeReader->GetOutput()->GetLargestPossibleRegion().GetSize() );
413       resampler->SetOutputSpacing( likeReader->GetOutput()->GetSpacing() );
414       resampler->SetOutputOrigin(  likeReader->GetOutput()->GetOrigin() );
415     } else {
416       //Size
417       typename OutputImageType::SizeType outputSize;
418       if (m_ArgsInfo.size_given) {
419         for(unsigned int i=0; i< Dimension; i++)
420           outputSize[i]=m_ArgsInfo.size_arg[i];
421       } else outputSize=input->GetLargestPossibleRegion().GetSize();
422       std::cout<<"Setting the size to "<<outputSize<<"..."<<std::endl;
423
424       //Spacing
425       typename OutputImageType::SpacingType outputSpacing;
426       if (m_ArgsInfo.spacing_given) {
427         for(unsigned int i=0; i< Dimension; i++)
428           outputSpacing[i]=m_ArgsInfo.spacing_arg[i];
429       } else outputSpacing=input->GetSpacing();
430       std::cout<<"Setting the spacing to "<<outputSpacing<<"..."<<std::endl;
431
432       //Origin
433       typename OutputImageType::PointType outputOrigin;
434       if (m_ArgsInfo.origin_given) {
435         for(unsigned int i=0; i< Dimension; i++)
436           outputOrigin[i]=m_ArgsInfo.origin_arg[i];
437       } else outputOrigin=input->GetOrigin();
438       std::cout<<"Setting the origin to "<<outputOrigin<<"..."<<std::endl;
439
440       // Set
441       resampler->SetSize( outputSize );
442       resampler->SetOutputSpacing( outputSpacing );
443       resampler->SetOutputOrigin(  outputOrigin );
444
445     }
446
447     resampler->SetInput( input );
448     resampler->SetTransform( affineTransform );
449     resampler->SetInterpolator( genericInterpolator->GetInterpolatorPointer());
450     resampler->SetDefaultPixelValue( static_cast<PixelType>(m_ArgsInfo.pad_arg) );
451
452     try {
453       resampler->Update();
454     } catch(itk::ExceptionObject) {
455       std::cerr<<"Error resampling the image"<<std::endl;
456     }
457
458     typename OutputImageType::Pointer output = resampler->GetOutput();
459
460     // Output
461     typedef itk::ImageFileWriter<OutputImageType> WriterType;
462     typename WriterType::Pointer writer = WriterType::New();
463     writer->SetFileName(m_ArgsInfo.output_arg);
464     writer->SetInput(output);
465     writer->Update();
466
467   }
468   //-------------------------------------------------------------------
469   
470   
471   //-------------------------------------------------------------------
472   template<class args_info_type>
473   template<unsigned int Dimension, class PixelType>
474   typename itk::Matrix<double, Dimension+1, Dimension+1>
475    AffineTransformGenericFilter<args_info_type>::createMatrixFromElastixFile(std::string filename)
476   {
477     if (Dimension != 3) {
478       FATAL("Only 3D yet" << std::endl);
479     }
480     typename itk::Matrix<double, Dimension+1, Dimension+1> matrix;
481
482     // Open file
483     std::ifstream is;
484     clitk::openFileForReading(is, filename);
485
486     // Check Transform
487     std::string s; 
488     bool b = GetElastixValueFromTag(is, "Transform ", s);
489     if (!b) {
490       FATAL("Error must read 'Transform' in " << filename << std::endl);
491     }
492     if (s != "EulerTransform") {
493       FATAL("Sorry only 'EulerTransform'" << std::endl);
494     }
495
496     // FIXME check
497     //    (InitialTransformParametersFileName "NoInitialTransform")
498
499     // Get CenterOfRotationPoint
500     GetElastixValueFromTag(is, "CenterOfRotationPoint ", s); // space is needed
501     if (!b) {
502       FATAL("Error must read 'CenterOfRotationPoint' in " << filename << std::endl);
503     }
504     std::vector<std::string> cor; 
505     GetValuesFromValue(s, cor);
506
507     // Get Transformparameters
508     GetElastixValueFromTag(is, "TransformParameters ", s); // space is needed
509     if (!b) {
510       FATAL("Error must read 'TransformParameters' in " << filename << std::endl);
511     }
512     std::vector<std::string> results; 
513     GetValuesFromValue(s, results);
514     
515     // construct a stream from the string
516     itk::CenteredEuler3DTransform<double>::Pointer mat = itk::CenteredEuler3DTransform<double>::New();
517     itk::CenteredEuler3DTransform<double>::ParametersType p;
518     p.SetSize(9);
519     for(uint i=0; i<3; i++)
520       p[i] = atof(results[i].c_str()); // Rotation
521     for(uint i=0; i<3; i++)
522       p[i+3] = atof(cor[i].c_str()); // Centre of rotation
523     for(uint i=0; i<3; i++)
524       p[i+6] = atof(results[i+3].c_str()); // Translation
525     mat->SetParameters(p);
526     
527     if (m_Verbose) {
528       std::cout << "Rotation      (deg) : " << rad2deg(p[0]) << " " << rad2deg(p[1]) << " " << rad2deg(p[2]) << std::endl;
529       std::cout << "Translation   (phy) : " << p[3] << " " << p[4] << " " << p[5] << std::endl;
530       std::cout << "Center of rot (phy) : " << p[6] << " " << p[7] << " " << p[8] << std::endl;
531     }
532
533     for(uint i=0; i<3; i++)
534       for(uint j=0; j<3; j++)
535         matrix[i][j] = mat->GetMatrix()[i][j];
536     // Offset is -Rc + t + c
537     matrix[0][3] = mat->GetOffset()[0];
538     matrix[1][3] = mat->GetOffset()[1];
539     matrix[2][3] = mat->GetOffset()[2];
540     matrix[3][3] = 1;
541     
542     return matrix;
543   }
544
545   //-------------------------------------------------------------------
546   template<class args_info_type>
547   bool
548   AffineTransformGenericFilter<args_info_type>::GetElastixValueFromTag(std::ifstream & is, 
549                                                                        std::string tag, 
550                                                                        std::string & value)
551   {
552     std::string line;
553     is.seekg (0, is.beg);
554     while(std::getline(is, line))   {
555       unsigned pos = line.find(tag);
556       if (pos<line.size()) {
557         value=line.substr(pos+tag.size(),line.size()-2);// remove last ')'
558         value.erase (std::remove (value.begin(), value.end(), '"'), value.end());
559         value.erase (std::remove (value.begin(), value.end(), ')'), value.end());
560         return true;
561       }
562    }
563     return false;
564   }
565   //-------------------------------------------------------------------
566
567
568   //-------------------------------------------------------------------
569   template<class args_info_type>
570   void
571   AffineTransformGenericFilter<args_info_type>::GetValuesFromValue(const std::string & s, 
572                                                                    std::vector<std::string> & values)
573   {
574     std::stringstream strstr(s);
575     std::istream_iterator<std::string> it(strstr);
576     std::istream_iterator<std::string> end;
577     std::vector<std::string> results(it, end);
578     values.clear();
579     values.resize(results.size());
580     for(uint i=0; i<results.size(); i++) values[i] = results[i];
581   }
582   //-------------------------------------------------------------------
583
584
585 } //end clitk
586
587 #endif //#define clitkAffineTransformGenericFilter_txx