1 /*=========================================================================
2 Program: vv http://www.creatis.insa-lyon.fr/rio/vv
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
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.
13 It is distributed under dual licence
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
24 #include <itkCenteredEuler3DTransform.h>
29 //-----------------------------------------------------------
31 //-----------------------------------------------------------
32 template<class args_info_type>
33 AffineTransformGenericFilter<args_info_type>::AffineTransformGenericFilter()
38 //-------------------------------------------------------------------
41 //-----------------------------------------------------------
43 //-----------------------------------------------------------
44 template<class args_info_type>
45 void AffineTransformGenericFilter<args_info_type>::Update()
47 // Read the Dimension and PixelType
48 int Dimension, Components;
49 std::string PixelType;
50 ReadImageDimensionAndPixelType(m_InputFileName, Dimension, PixelType, Components);
53 if(Dimension==2) UpdateWithDim<2>(PixelType, Components);
55 if(Dimension==3) UpdateWithDim<3>(PixelType, Components);
56 else if (Dimension==4)UpdateWithDim<4>(PixelType, Components);
58 std::cout<<"Error, Only for 2, 3 or 4 Dimensions!!!"<<std::endl ;
62 //-------------------------------------------------------------------
65 //-------------------------------------------------------------------
66 // Update with the number of dimensions
67 //-------------------------------------------------------------------
68 template<class args_info_type>
69 template<unsigned int Dimension>
71 AffineTransformGenericFilter<args_info_type>::UpdateWithDim(std::string PixelType, int Components)
73 if (m_Verbose) std::cout << "Image was detected to be "<<Dimension<<"D and "<<Components<<" component(s) of "<< PixelType<<"..."<<std::endl;
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>();
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>();
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>();
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>();
95 if (m_Verbose) std::cout << "Launching filter in "<< Dimension <<"D and float..." << std::endl;
96 UpdateWithDimAndPixelType<Dimension, float>();
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> >();
105 else std::cerr<<"Number of components is "<<Components<<", not supported!"<<std::endl;
108 //-------------------------------------------------------------------
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>
117 AffineTransformGenericFilter<args_info_type>::UpdateWithDimAndPixelType()
121 typedef itk::Image<PixelType, Dimension> InputImageType;
122 typedef itk::Image<PixelType, Dimension> OutputImageType;
125 typedef itk::ImageFileReader<InputImageType> InputReaderType;
126 typename InputReaderType::Pointer reader = InputReaderType::New();
127 reader->SetFileName( m_InputFileName);
129 typename InputImageType::Pointer input= reader->GetOutput();
132 typedef itk::ResampleImageFilter< InputImageType,OutputImageType > ResampleFilterType;
133 typename ResampleFilterType::Pointer resampler = ResampleFilterType::New();
136 typename itk::Matrix<double, Dimension+1, Dimension+1> matrix;
137 if (m_ArgsInfo.rotate_given || m_ArgsInfo.translate_given)
139 if (m_ArgsInfo.matrix_given)
141 std::cerr << "You must use either rotate/translate or matrix options" << std::cout;
144 itk::Array<double> transformParameters(2 * Dimension);
145 transformParameters.Fill(0.0);
146 if (m_ArgsInfo.rotate_given)
149 transformParameters[0] = m_ArgsInfo.rotate_arg[0];
151 for (unsigned int i = 0; i < 3; i++)
152 transformParameters[i] = m_ArgsInfo.rotate_arg[i];
154 if (m_ArgsInfo.translate_given)
159 for (unsigned int i = 0; i < Dimension && i < 3; i++)
160 transformParameters[pos++] = m_ArgsInfo.translate_arg[i];
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];
173 matrix = GetForwardAffineMatrix<Dimension>(transformParameters);
177 if (m_ArgsInfo.matrix_given)
179 matrix= clitk::ReadMatrix<Dimension>(m_ArgsInfo.matrix_arg);
180 if (m_Verbose) std::cout << "Reading the matrix..." << std::endl;
183 if (m_ArgsInfo.elastix_given) {
184 matrix = createMatrixFromElastixFile<Dimension,PixelType>(m_ArgsInfo.elastix_arg);
187 matrix.SetIdentity();
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);
197 typedef itk::AffineTransform<double, Dimension> AffineTransformType;
198 typename AffineTransformType::Pointer affineTransform=AffineTransformType::New();
199 affineTransform->SetMatrix(rotationMatrix);
200 affineTransform->SetTranslation(translationPart);
203 typedef clitk::GenericInterpolator<args_info_type, InputImageType, double> GenericInterpolatorType;
204 typename GenericInterpolatorType::Pointer genericInterpolator=GenericInterpolatorType::New();
205 genericInterpolator->SetArgsInfo(m_ArgsInfo);
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);
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;
224 // Spacing is influenced by affine transform matrix and input direction
225 typename InputImageType::SpacingType outputSpacing;
226 outputSpacing = invRotMatrix *
227 input->GetDirection() *
230 // Origin is influenced by translation but not by input direction
231 typename InputImageType::PointType outputOrigin;
232 outputOrigin = invRotMatrix *
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];
242 vnlOutputSize = invRotMatrix *
243 input->GetDirection().GetVnlMatrix() *
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.;
254 outputSize[i] = lrint(vnlOutputSize[i]);
256 resampler->SetSize( outputSize );
257 resampler->SetOutputSpacing( outputSpacing );
258 resampler->SetOutputOrigin( outputOrigin );
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();
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();
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();
282 resampler->SetSize( outputSize );
283 resampler->SetOutputSpacing( outputSpacing );
284 resampler->SetOutputOrigin( outputOrigin );
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;
294 resampler->SetInput( input );
295 resampler->SetTransform( affineTransform );
296 resampler->SetInterpolator( genericInterpolator->GetInterpolatorPointer());
297 resampler->SetDefaultPixelValue( static_cast<PixelType>(m_ArgsInfo.pad_arg) );
301 } catch(itk::ExceptionObject) {
302 std::cerr<<"Error resampling the image"<<std::endl;
305 typename OutputImageType::Pointer output = resampler->GetOutput();
308 typedef itk::ImageFileWriter<OutputImageType> WriterType;
309 typename WriterType::Pointer writer = WriterType::New();
310 writer->SetFileName(m_ArgsInfo.output_arg);
311 writer->SetInput(output);
315 //-------------------------------------------------------------------
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()
326 typedef itk::Image<PixelType, Dimension> InputImageType;
327 typedef itk::Image<PixelType, Dimension> OutputImageType;
330 typedef itk::ImageFileReader<InputImageType> InputReaderType;
331 typename InputReaderType::Pointer reader = InputReaderType::New();
332 reader->SetFileName( m_InputFileName);
334 typename InputImageType::Pointer input= reader->GetOutput();
337 typedef itk::VectorResampleImageFilter< InputImageType,OutputImageType, double > ResampleFilterType;
338 typename ResampleFilterType::Pointer resampler = ResampleFilterType::New();
341 typename itk::Matrix<double, Dimension+1, Dimension+1> matrix;
342 if (m_ArgsInfo.rotate_given || m_ArgsInfo.translate_given)
344 if (m_ArgsInfo.matrix_given)
346 std::cerr << "You must use either rotate/translate or matrix options" << std::cout;
349 itk::Array<double> transformParameters(2 * Dimension);
350 transformParameters.Fill(0.0);
351 if (m_ArgsInfo.rotate_given)
354 transformParameters[0] = m_ArgsInfo.rotate_arg[0];
356 for (unsigned int i = 0; i < 3; i++)
357 transformParameters[i] = m_ArgsInfo.rotate_arg[i];
359 if (m_ArgsInfo.translate_given)
364 for (unsigned int i = 0; i < Dimension && i < 3; i++)
365 transformParameters[pos++] = m_ArgsInfo.translate_arg[i];
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];
378 matrix = GetForwardAffineMatrix<Dimension>(transformParameters);
382 if (m_ArgsInfo.matrix_given)
384 matrix= clitk::ReadMatrix<Dimension>(m_ArgsInfo.matrix_arg);
385 if (m_Verbose) std::cout << "Reading the matrix..." << std::endl;
388 matrix.SetIdentity();
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);
397 typedef itk::AffineTransform<double, Dimension> AffineTransformType;
398 typename AffineTransformType::Pointer affineTransform=AffineTransformType::New();
399 affineTransform->SetMatrix(rotationMatrix);
400 affineTransform->SetTranslation(translationPart);
403 typedef clitk::GenericVectorInterpolator<args_info_type, InputImageType, double> GenericInterpolatorType;
404 typename GenericInterpolatorType::Pointer genericInterpolator=GenericInterpolatorType::New();
405 genericInterpolator->SetArgsInfo(m_ArgsInfo);
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() );
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;
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;
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;
441 resampler->SetSize( outputSize );
442 resampler->SetOutputSpacing( outputSpacing );
443 resampler->SetOutputOrigin( outputOrigin );
447 resampler->SetInput( input );
448 resampler->SetTransform( affineTransform );
449 resampler->SetInterpolator( genericInterpolator->GetInterpolatorPointer());
450 resampler->SetDefaultPixelValue( static_cast<PixelType>(m_ArgsInfo.pad_arg) );
454 } catch(itk::ExceptionObject) {
455 std::cerr<<"Error resampling the image"<<std::endl;
458 typename OutputImageType::Pointer output = resampler->GetOutput();
461 typedef itk::ImageFileWriter<OutputImageType> WriterType;
462 typename WriterType::Pointer writer = WriterType::New();
463 writer->SetFileName(m_ArgsInfo.output_arg);
464 writer->SetInput(output);
468 //-------------------------------------------------------------------
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)
477 if (Dimension != 3) {
478 FATAL("Only 3D yet" << std::endl);
480 typename itk::Matrix<double, Dimension+1, Dimension+1> matrix;
484 clitk::openFileForReading(is, filename);
488 bool b = GetElastixValueFromTag(is, "Transform ", s);
490 FATAL("Error must read 'Transform' in " << filename << std::endl);
492 if (s != "EulerTransform") {
493 FATAL("Sorry only 'EulerTransform'" << std::endl);
497 // (InitialTransformParametersFileName "NoInitialTransform")
499 // Get CenterOfRotationPoint
500 GetElastixValueFromTag(is, "CenterOfRotationPoint ", s); // space is needed
502 FATAL("Error must read 'CenterOfRotationPoint' in " << filename << std::endl);
504 std::vector<std::string> cor;
505 GetValuesFromValue(s, cor);
507 // Get Transformparameters
508 GetElastixValueFromTag(is, "TransformParameters ", s); // space is needed
510 FATAL("Error must read 'TransformParameters' in " << filename << std::endl);
512 std::vector<std::string> results;
513 GetValuesFromValue(s, results);
515 // construct a stream from the string
516 itk::CenteredEuler3DTransform<double>::Pointer mat = itk::CenteredEuler3DTransform<double>::New();
517 itk::CenteredEuler3DTransform<double>::ParametersType p;
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);
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;
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];
545 //-------------------------------------------------------------------
546 template<class args_info_type>
548 AffineTransformGenericFilter<args_info_type>::GetElastixValueFromTag(std::ifstream & is,
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());
565 //-------------------------------------------------------------------
568 //-------------------------------------------------------------------
569 template<class args_info_type>
571 AffineTransformGenericFilter<args_info_type>::GetValuesFromValue(const std::string & s,
572 std::vector<std::string> & values)
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);
579 values.resize(results.size());
580 for(uint i=0; i<results.size(); i++) values[i] = results[i];
582 //-------------------------------------------------------------------
587 #endif //#define clitkAffineTransformGenericFilter_txx