1 #include <tclap/CmdLine.h> 3 #include <itkResampleImageFilter.h> 4 #include <itkMinimumMaximumImageFilter.h> 6 #include <itkNearestNeighborInterpolateImageFunction.h> 7 #include <itkLinearInterpolateImageFunction.h> 8 #include <itkBSplineInterpolateImageFunction.h> 9 #include <itkWindowedSincInterpolateImageFunction.h> 10 #include <itkConstantBoundaryCondition.h> 11 #include <itkImageRegionIterator.h> 13 #include <itkExtractImageFilter.h> 20 #include <itkTransformToDisplacementFieldFilter.h> 34 typedef TransformSeriesReaderType::OutputTransformType TransformType;
35 TransformSeriesReaderType *trReader =
new TransformSeriesReaderType;
37 trReader->SetInvertTransform(!args.
invert);
39 trReader->SetNumberOfWorkUnits(args.
pthread);
41 typename TransformType::Pointer
transfo = trReader->GetOutputTransform();
43 if (!transfo->IsLinear())
44 throw itk::ExceptionObject(__FILE__,__LINE__,
"Transformation is not globally linear",ITK_LOCATION);
46 typedef itk::MatrixOffsetTransformBase <double, 3> LinearTransformType;
47 LinearTransformType::Pointer linearTrsf = LinearTransformType::New();
48 linearTrsf->SetIdentity();
49 for (
unsigned int i = 0;i < transfo->GetNumberOfTransforms();++i)
50 linearTrsf->Compose(dynamic_cast <LinearTransformType *> (transfo->GetNthTransform(i).GetPointer()));
52 LinearTransformType::MatrixType linearMatrix = linearTrsf->GetMatrix();
55 GFReaderType gfReader;
57 gfReader.SetGradientIndependentNormalization(
false);
60 GFReaderType::GradientVectorType directions = gfReader.GetGradients();
62 vnl_vector_fixed <double,3> tmpDir(0.0);
63 for (
unsigned int i = 0;i < directions.size();++i)
67 for (
unsigned int j = 0;j < 3;++j)
70 for (
unsigned int k = 0;k < 3;++k)
71 tmpDir[j] += linearMatrix(j,k) * directions[i][k];
73 norm += directions[i][j] * directions[i][j];
74 normAfter += tmpDir[j] * tmpDir[j];
79 for (
unsigned int j = 0;j < 3;++j)
80 tmpDir[j] *= std::sqrt(norm / normAfter);
83 directions[i] = tmpDir;
86 std::ofstream outputFile(outputGradientsFileName);
87 for (
unsigned int i = 0;i < 3;++i)
89 for (
unsigned int j = 0;j < directions.size();++j)
90 outputFile << directions[j][i] <<
" ";
92 outputFile << std::endl;
98 template <
class ImageType>
102 typedef itk::VectorImage<double, ImageType::ImageDimension> OutputType;
105 typedef typename TransformSeriesReaderType::OutputTransformType TransformType;
106 TransformSeriesReaderType *trReader =
new TransformSeriesReaderType;
108 trReader->SetInvertTransform(args.
invert);
110 trReader->SetNumberOfWorkUnits(args.
pthread);
112 typename TransformType::Pointer
transfo = trReader->GetOutputTransform();
114 std::cout <<
"Image to transform is vector." << std::endl;
116 typedef itk::ResampleImageFilter<ImageType, OutputType> ResampleFilterType;
117 typename ResampleFilterType::Pointer vectorResampler = ResampleFilterType::New();
118 typename itk::InterpolateImageFunction <ImageType>::Pointer interpolator;
121 interpolator = itk::NearestNeighborInterpolateImageFunction<ImageType>::New();
123 interpolator = itk::LinearInterpolateImageFunction<ImageType>::New();
126 itk::ExceptionObject excp(__FILE__, __LINE__,
127 "bspline and sinc interpolation not suported for vector images yet.",
132 vectorResampler->SetTransform(transfo);
133 vectorResampler->SetInterpolator(interpolator);
135 typename ImageType::SizeType size;
136 typename ImageType::PointType
origin;
137 typename ImageType::SpacingType
spacing;
138 typename ImageType::DirectionType direction;
139 direction.SetIdentity();
140 unsigned int imageIODimension = std::min(geometryImageIO->GetNumberOfDimensions(),ImageType::GetImageDimension());
142 for (
unsigned int i = 0;i < imageIODimension;++i)
144 size[i] = geometryImageIO->GetDimensions(i);
145 origin[i] = geometryImageIO->GetOrigin(i);
146 spacing[i] = geometryImageIO->GetSpacing(i);
147 for(
unsigned int j = 0;j < imageIODimension;++j)
148 direction(i,j) = geometryImageIO->GetDirection(j)[i];
152 for (
unsigned int i = imageIODimension;i < ImageType::GetImageDimension();++i)
160 vectorResampler->SetSize(size);
161 vectorResampler->SetOutputOrigin(origin);
162 vectorResampler->SetOutputSpacing(spacing);
163 vectorResampler->SetOutputDirection(direction);
165 vectorResampler->SetInput(anima::readImage<ImageType>(args.
input));
166 vectorResampler->SetNumberOfWorkUnits(args.
pthread);
167 vectorResampler->Update();
169 anima::writeImage<OutputType>(args.
output, vectorResampler->GetOutput());
172 template <
class ImageType>
176 typedef itk::Image <double, ImageType::ImageDimension> OutputType;
177 const unsigned int InternalImageDimension = 3;
178 typedef itk::Image <double, InternalImageDimension> InternalImageType;
181 typedef typename TransformSeriesReaderType::OutputTransformType TransformType;
182 TransformSeriesReaderType *trReader =
new TransformSeriesReaderType;
184 trReader->SetInvertTransform(args.
invert);
186 trReader->SetNumberOfWorkUnits(args.
pthread);
188 typename TransformType::Pointer
transfo = trReader->GetOutputTransform();
190 std::cout <<
"Image to transform is 4D scalar." << std::endl;
191 typename itk::InterpolateImageFunction <InternalImageType>::Pointer interpolator;
194 interpolator = itk::NearestNeighborInterpolateImageFunction<InternalImageType>::New();
196 interpolator = itk::LinearInterpolateImageFunction<InternalImageType>::New();
198 interpolator = itk::BSplineInterpolateImageFunction<InternalImageType>::New();
201 const unsigned int WindowRadius = 4;
202 typedef itk::Function::HammingWindowFunction<WindowRadius> WindowFunctionType;
203 typedef itk::ConstantBoundaryCondition<InternalImageType> BoundaryConditionType;
204 interpolator = itk::WindowedSincInterpolateImageFunction
205 <InternalImageType, WindowRadius, WindowFunctionType, BoundaryConditionType,
double >::New();
208 typename OutputType::PointType
origin;
209 typename OutputType::SpacingType
spacing;
210 typename OutputType::DirectionType direction;
211 direction.SetIdentity();
213 typename OutputType::RegionType outputRegion;
214 for (
unsigned int i = 0;i < InternalImageDimension;++i)
216 outputRegion.SetIndex(i,0);
217 outputRegion.SetSize(i,geometryImageIO->GetDimensions(i));
218 origin[i] = geometryImageIO->GetOrigin(i);
219 spacing[i] = geometryImageIO->GetSpacing(i);
220 for(
unsigned int j = 0;j < InternalImageDimension;++j)
221 direction(i,j) = geometryImageIO->GetDirection(j)[i];
224 typename ImageType::Pointer inputImage = anima::readImage<ImageType> (args.
input);
225 for (
unsigned int i = InternalImageDimension;i < ImageType::GetImageDimension();++i)
227 outputRegion.SetIndex(i,0);
228 outputRegion.SetSize(i,inputImage->GetLargestPossibleRegion().GetSize()[i]);
229 origin[i] = inputImage->GetOrigin()[i];
230 spacing[i] = inputImage->GetSpacing()[i];
231 direction(i,i) = inputImage->GetDirection()(i,i);
234 typename OutputType::Pointer outputImage = OutputType::New();
235 outputImage->Initialize();
236 outputImage->SetRegions(outputRegion);
237 outputImage->SetOrigin(origin);
238 outputImage->SetSpacing(spacing);
239 outputImage->SetDirection(direction);
240 outputImage->Allocate();
242 typedef itk::MinimumMaximumImageFilter <ImageType> MinMaxFilterType;
243 typename MinMaxFilterType::Pointer minMaxFilter = MinMaxFilterType::New();
244 minMaxFilter->SetInput(inputImage);
245 minMaxFilter->SetNumberOfWorkUnits(args.
pthread);
246 minMaxFilter->Update();
248 double minImageValue = minMaxFilter->GetMinimum();
249 if (minImageValue < 0)
250 minImageValue = -1024;
254 unsigned int numImages = inputImage->GetLargestPossibleRegion().GetSize()[InternalImageDimension];
256 for (
unsigned int i = 0;i < numImages;++i)
259 std::cout <<
"Resampling sub-image " << i+1 <<
"/" << numImages << std::flush;
261 std::cout<<
"\033[K\rResampling sub-image " << i+1 <<
"/" << numImages << std::flush;
264 typename ResampleFilterType::Pointer scalarResampler = ResampleFilterType::New();
265 scalarResampler->SetTransform(transfo);
266 scalarResampler->SetInterpolator(interpolator);
268 typename InternalImageType::SizeType internalSize;
269 typename InternalImageType::PointType internalOrigin;
270 typename InternalImageType::SpacingType internalSpacing;
271 typename InternalImageType::DirectionType internalDirection;
272 internalDirection.SetIdentity();
274 for (
unsigned int j = 0;j < InternalImageDimension;++j)
276 internalSize[j] = geometryImageIO->GetDimensions(j);
277 internalOrigin[j] = geometryImageIO->GetOrigin(j);
278 internalSpacing[j] = geometryImageIO->GetSpacing(j);
279 for(
unsigned int k = 0;k < InternalImageDimension;++k)
280 internalDirection(j,k) = geometryImageIO->GetDirection(k)[j];
283 scalarResampler->SetSize(internalSize);
284 scalarResampler->SetOutputOrigin(internalOrigin);
285 scalarResampler->SetOutputSpacing(internalSpacing);
286 scalarResampler->SetOutputDirection(internalDirection);
287 scalarResampler->SetDefaultPixelValue(minImageValue);
289 typedef itk::ExtractImageFilter <ImageType, InternalImageType> ExtractFilterType;
290 typename ExtractFilterType::Pointer extractFilter = ExtractFilterType::New();
291 extractFilter->SetInput(inputImage);
292 extractFilter->SetDirectionCollapseToGuess();
294 typename ImageType::RegionType extractRegion = inputImage->GetLargestPossibleRegion();
295 extractRegion.SetIndex(InternalImageDimension,i);
296 extractRegion.SetSize(InternalImageDimension,0);
298 extractFilter->SetExtractionRegion(extractRegion);
299 extractFilter->SetNumberOfWorkUnits(args.
pthread);
301 extractFilter->Update();
303 scalarResampler->SetInput(extractFilter->GetOutput());
304 scalarResampler->SetNumberOfWorkUnits(args.
pthread);
305 scalarResampler->Update();
307 extractRegion.SetSize(InternalImageDimension,1);
308 for (
unsigned int j = 0;j < InternalImageDimension;++j)
310 extractRegion.SetIndex(j,scalarResampler->GetOutput()->GetLargestPossibleRegion().GetIndex()[j]);
311 extractRegion.SetSize(j,scalarResampler->GetOutput()->GetLargestPossibleRegion().GetSize()[j]);
314 itk::ImageRegionIterator <InternalImageType> internalOutItr(scalarResampler->GetOutput(),
315 scalarResampler->GetOutput()->GetLargestPossibleRegion());
316 itk::ImageRegionIterator <OutputType> outItr(outputImage,extractRegion);
318 while (!outItr.IsAtEnd())
320 outItr.Set(internalOutItr.Get());
327 std::cout << std::endl;
329 anima::writeImage<OutputType>(args.
output, outputImage);
334 template <
class ImageType>
338 typedef itk::Image <double, ImageType::ImageDimension> OutputType;
341 typedef typename TransformSeriesReaderType::OutputTransformType TransformType;
342 TransformSeriesReaderType *trReader =
new TransformSeriesReaderType;
344 trReader->SetInvertTransform(args.
invert);
346 trReader->SetNumberOfWorkUnits(args.
pthread);
348 typename TransformType::Pointer
transfo = trReader->GetOutputTransform();
350 std::cout <<
"Image to transform is scalar" << std::endl;
352 typename ResampleFilterType::Pointer scalarResampler = ResampleFilterType::New();
353 typename itk::InterpolateImageFunction <ImageType>::Pointer interpolator;
356 interpolator = itk::NearestNeighborInterpolateImageFunction<ImageType>::New();
358 interpolator = itk::LinearInterpolateImageFunction<ImageType>::New();
360 interpolator = itk::BSplineInterpolateImageFunction<ImageType>::New();
363 const unsigned int WindowRadius = 4;
364 typedef itk::Function::HammingWindowFunction<WindowRadius> WindowFunctionType;
365 typedef itk::ConstantBoundaryCondition<ImageType> BoundaryConditionType;
366 interpolator = itk::WindowedSincInterpolateImageFunction
367 <ImageType, WindowRadius, WindowFunctionType, BoundaryConditionType,
double >::New();
370 scalarResampler->SetTransform(transfo);
371 scalarResampler->SetInterpolator(interpolator);
373 typename ImageType::SizeType size;
374 typename ImageType::PointType
origin;
375 typename ImageType::SpacingType
spacing;
376 typename ImageType::DirectionType direction;
377 direction.SetIdentity();
378 unsigned int imageIODimension = std::min(geometryImageIO->GetNumberOfDimensions(),ImageType::GetImageDimension());
380 for (
unsigned int i = 0;i < imageIODimension;++i)
382 size[i] = geometryImageIO->GetDimensions(i);
383 origin[i] = geometryImageIO->GetOrigin(i);
384 spacing[i] = geometryImageIO->GetSpacing(i);
385 for(
unsigned int j = 0; j < imageIODimension; ++j)
386 direction(i,j) = geometryImageIO->GetDirection(j)[i];
390 for (
unsigned int i = imageIODimension;i < ImageType::GetImageDimension();++i)
398 scalarResampler->SetSize(size);
399 scalarResampler->SetOutputOrigin(origin);
400 scalarResampler->SetOutputSpacing(spacing);
401 scalarResampler->SetOutputDirection(direction);
403 typename ImageType::Pointer inputImage = anima::readImage<ImageType>(args.
input);
405 typedef itk::MinimumMaximumImageFilter <ImageType> MinMaxFilterType;
406 typename MinMaxFilterType::Pointer minMaxFilter = MinMaxFilterType::New();
407 minMaxFilter->SetInput(inputImage);
408 minMaxFilter->SetNumberOfWorkUnits(args.
pthread);
409 minMaxFilter->Update();
411 double minImageValue = minMaxFilter->GetMinimum();
412 if (minImageValue < 0)
413 minImageValue = -1024;
417 scalarResampler->SetDefaultPixelValue(minImageValue);
418 scalarResampler->SetInput(inputImage);
419 scalarResampler->SetNumberOfWorkUnits(args.
pthread);
420 scalarResampler->Update();
422 anima::writeImage<OutputType>(args.
output, scalarResampler->GetOutput());
425 template <
class ComponentType,
int Dimension>
429 if (inputImageIO->GetNumberOfComponents() > 1)
432 throw itk::ExceptionObject (__FILE__, __LINE__,
"Number of dimensions not supported for vector image resampling", ITK_LOCATION);
434 applyVectorTransfo < itk::VectorImage<ComponentType, 3> > (geometryImageIO, args);
439 applyScalarTransfo < itk::Image<ComponentType, 3> > (geometryImageIO, args);
441 applyScalarTransfo4D < itk::Image<ComponentType, 4> > (geometryImageIO, args);
445 template <
class ComponentType>
449 if (inputImageIO->GetNumberOfDimensions() > 4)
450 throw itk::ExceptionObject(__FILE__, __LINE__,
"Number of dimensions not supported.", ITK_LOCATION);
452 if (inputImageIO->GetNumberOfDimensions() > 3)
453 checkIfComponentsAreVectors<ComponentType, 4> (inputImageIO, geometryImageIO, args);
455 checkIfComponentsAreVectors<ComponentType, 3> (inputImageIO, geometryImageIO, args);
459 int main(
int ac,
const char** av)
461 std::string descriptionMessage =
"Resampler tool to apply a series of transformations to an image.\n" 462 "Input transform is an XML file describing all transforms to apply.\n" 463 "Such args file should look like this:\n" 464 "<TransformationList>\n" 466 "<Type>linear</Type> (it can be svf or dense too)\n" 467 "<Path>FileName</Path>\n" 468 "<Inversion>0</Inversion>\n" 469 "</Transformation>\n" 471 "</TransformationList>\n" 472 "Note that only geometries and input with the same number of dimensions are supported for now.\n" 473 "The default interpolation method is linear, it can be [nearest, linear, bspline, sinc]." 474 "INRIA / IRISA - VisAGeS/Empenn Team";
476 TCLAP::CmdLine cmd(descriptionMessage,
' ',ANIMA_VERSION);
478 TCLAP::ValueArg<std::string> inArg(
"i",
"input",
"Input image",
true,
"",
"input image",cmd);
479 TCLAP::ValueArg<std::string> trArg(
"t",
"trsf",
"Transformations XML list",
true,
"",
"transformations list",cmd);
480 TCLAP::ValueArg<std::string> outArg(
"o",
"output",
"Output resampled image",
true,
"",
"output image",cmd);
481 TCLAP::ValueArg<std::string> geomArg(
"g",
"geometry",
"Geometry image",
true,
"",
"geometry image",cmd);
483 TCLAP::ValueArg<std::string> outTrArg(
"T",
"output_trsf",
"Output resulting transformation field (dense not SVF)",
false,
"",
"output transfo", cmd);
484 TCLAP::ValueArg<std::string> bvecArg(
"",
"grad",
"DWI gradient file",
false,
"",
"gradient file",cmd);
485 TCLAP::ValueArg<std::string> bvecOutArg(
"O",
"out-grad",
"Output gradient file",
false,
"",
"gradient file",cmd);
487 TCLAP::ValueArg<unsigned int> expOrderArg(
"e",
"exp-order",
"Order of field exponentiation approximation (in between 0 and 1, default: 0)",
false,0,
"exponentiation order",cmd);
488 TCLAP::SwitchArg invertArg(
"I",
"invert",
"Invert the transformation series",cmd,
false);
489 TCLAP::ValueArg<std::string> interpolationArg(
"n",
491 "interpolation method to use [nearest, linear, bspline, sinc]",
494 "interpolation method",
497 TCLAP::ValueArg<unsigned int> nbpArg(
"p",
"numberofthreads",
"Number of threads to run on (default : all cores)",
498 false,itk::MultiThreaderBase::GetGlobalDefaultNumberOfThreads(),
"number of threads",cmd);
504 catch (TCLAP::ArgException& e)
506 std::cerr <<
"Error: " << e.error() <<
"for argument " << e.argId() << std::endl;
511 itk::ImageIOBase::Pointer inputImageIO = itk::ImageIOFactory::CreateImageIO(inArg.getValue().c_str(),
512 itk::ImageIOFactory::ReadMode);
513 itk::ImageIOBase::Pointer geometryImageIO = itk::ImageIOFactory::CreateImageIO(geomArg.getValue().c_str(),
514 itk::ImageIOFactory::ReadMode);
517 std::cerr <<
"Itk could not find suitable IO factory for the input." << std::endl;
522 std::cerr <<
"Itk could not find suitable IO factory for the geometry image." << std::endl;
525 if(inputImageIO->GetNumberOfDimensions() != geometryImageIO->GetNumberOfDimensions())
527 std::cerr <<
"Input and geometry images have to have the same number of dimensions." << std::endl;
532 inputImageIO->SetFileName(inArg.getValue());
533 inputImageIO->ReadImageInformation();
534 geometryImageIO->SetFileName(geomArg.getValue());
535 geometryImageIO->ReadImageInformation();
538 args.
input = inArg.getValue();
539 args.
output = outArg.getValue();
541 args.
transfo = trArg.getValue();
542 args.
invert = invertArg.getValue();
543 args.
pthread = nbpArg.getValue();
547 bool badInterpolation =
true;
548 std::string interpolations[4] = {
"nearest",
"linear",
"bspline",
"sinc"};
549 for(
int i = 0; i < 4; ++i)
553 badInterpolation =
false;
558 if (badInterpolation)
559 std::cerr <<
"Interpolation method not supported, it must be one of [nearest, linear, bspline, sinc]." << std::endl;
569 catch ( itk::ExceptionObject & err )
571 std::cerr <<
"Can't apply transformation, be sure to use valid arguments..." << std::endl;
572 std::cerr << err << std::endl;
576 if (bvecArg.getValue() !=
"")
578 std::string outputGradientFileName = bvecOutArg.getValue();
579 if (outputGradientFileName ==
"")
581 outputGradientFileName = bvecArg.getValue();
582 outputGradientFileName = outputGradientFileName.erase(outputGradientFileName.find_first_of(
'.'));
583 outputGradientFileName +=
"_tr.bvec";
590 catch (itk::ExceptionObject & err)
592 std::cerr <<
"Can't apply transformation to gradients, be sure to use valid arguments..." << std::endl;
593 std::cerr << err << std::endl;
599 if (outTrArg.getValue() !=
"")
601 typedef double CoordinateRepType;
602 typedef itk::Vector< CoordinateRepType, 3> VectorPixelType;
603 typedef itk::Image< VectorPixelType, 3> DisplacementFieldImageType;
604 typedef itk::TransformToDisplacementFieldFilter <DisplacementFieldImageType, CoordinateRepType> DisplacementFieldGeneratorType;
606 DisplacementFieldGeneratorType::Pointer dispFieldGenerator = DisplacementFieldGeneratorType::New();
607 DisplacementFieldImageType::DirectionType dirMatrix;
608 DisplacementFieldImageType::SpacingType spacingVector;
609 DisplacementFieldImageType::PointType originVector;
610 DisplacementFieldImageType::SizeType sizeOutput;
611 DisplacementFieldImageType::IndexType indexOutput;
614 typedef TransformSeriesReaderType::OutputTransformType TransformType;
615 TransformSeriesReaderType *trReader =
new TransformSeriesReaderType;
618 trReader->SetInvertTransform(!args.
invert);
620 typename TransformType::Pointer
transfo = trReader->GetOutputTransform();
622 for (
unsigned int i = 0; i < 3; ++i)
624 originVector[i] = geometryImageIO->GetOrigin(i);
625 spacingVector[i] = geometryImageIO->GetSpacing(i);
627 sizeOutput[i] = geometryImageIO->GetDimensions(i);
629 for (
unsigned int j = 0; j < 3; ++j)
630 dirMatrix(i,j) = geometryImageIO->GetDirection(j)[i];
633 dispFieldGenerator->UseReferenceImageOff();
634 dispFieldGenerator->SetOutputDirection(dirMatrix);
635 dispFieldGenerator->SetOutputOrigin(originVector);
636 dispFieldGenerator->SetOutputSpacing(spacingVector);
637 dispFieldGenerator->SetOutputStartIndex(indexOutput);
638 dispFieldGenerator->SetSize(sizeOutput);
640 dispFieldGenerator->SetTransform(transfo);
641 dispFieldGenerator->SetNumberOfWorkUnits(nbpArg.getValue());
642 dispFieldGenerator->Update();
644 anima::writeImage <DisplacementFieldImageType>(outTrArg.getValue(), dispFieldGenerator->GetOutput());
std::string interpolation
void SetGradientFileName(std::string fName)
#define ANIMA_RETRIEVE_COMPONENT_TYPE(imageIO, function,...)
unsigned int exponentiationOrder