ANIMA  4.0
animaApplyDistortionCorrection.cxx
Go to the documentation of this file.
1 #include <tclap/CmdLine.h>
2 
3 #include <itkMultiplyImageFilter.h>
4 #include <itkAddImageFilter.h>
5 #include <itkExtractImageFilter.h>
6 #include <itkFixedPointInverseDisplacementFieldImageFilter.h>
7 
8 #include <rpiDisplacementFieldTransform.h>
11 
12 void ApplyGeometryToVectorField(itk::Image <itk::Vector <double,3>, 3> *vectorField,
13  itk::Image <double, 4> *geometryImage)
14 {
15  typedef itk::Image <double, 4>::DirectionType MatrixType;
16  MatrixType geometry = geometryImage->GetDirection();
17  geometry(3,3) = 1;
18 
19  for (unsigned int i = 0;i < 3;++i)
20  for (unsigned int j = 0;j < 3;++j)
21  geometry(i,j) *= geometryImage->GetSpacing()[j];
22 
23  typedef itk::Image <itk::Vector <double,3>, 3> VectorFieldType;
24  itk::ImageRegionIterator <VectorFieldType> vectorFieldItr(vectorField,vectorField->GetLargestPossibleRegion());
25 
26  itk::Vector <double,3> tmpVec, tmpOutVec;
27  while (!vectorFieldItr.IsAtEnd())
28  {
29  tmpVec = vectorFieldItr.Get();
30 
31  for (unsigned int i = 0;i < 3;++i)
32  {
33  tmpOutVec[i] = 0;
34  for (unsigned int j = 0;j < 3;++j)
35  tmpOutVec[i] += geometry(i,j) * tmpVec[j];
36  }
37 
38  vectorFieldItr.Set(tmpOutVec);
39  ++vectorFieldItr;
40  }
41 }
42 
43 int main(int ac, const char** av)
44 {
45  std::string descriptionMessage;
46  descriptionMessage += "Resampler tool to apply a distortion correction to one or two 4D volumes\n";
47  descriptionMessage += "INRIA / IRISA - VisAGeS/Empenn Team";
48 
49  TCLAP::CmdLine cmd(descriptionMessage, ' ',ANIMA_VERSION);
50 
51  TCLAP::ValueArg<std::string> forwardArg("f","forward","Input forward image (eg A-P, 4D)",true,"","input forward image",cmd);
52  TCLAP::ValueArg<std::string> backwardArg("b","backward","Input backward image (eg P-A, 3D, or 4D)",false,"","input backward image",cmd);
53  TCLAP::ValueArg<std::string> trArg("t","trsf","Distortion correction field",true,"","distortion correction field",cmd);
54  TCLAP::ValueArg<std::string> outArg("o","output","Output corrected image",true,"","output image",cmd);
55  TCLAP::ValueArg<std::string> outVecArg("O","out-vec","Transformation vector field in real coordinates",false,"","transformation in real coordinates",cmd);
56 
57  TCLAP::SwitchArg fieldInVoxelCoordinates("V","voxel","If set, the input correction field is assumed to be in voxel coordinates",cmd,false);
58  TCLAP::SwitchArg reverseFieldArg("R","reverse","If set, apply the opposite of the input field to the forward image",cmd,false);
59  TCLAP::SwitchArg inverseFieldArg("I","invert","If set, invert the input field (after reverting if R option is on)",cmd,false);
60 
61  TCLAP::ValueArg<unsigned int> nbpArg("T","numberofthreads","Number of threads to run on (default : all cores)",false,itk::MultiThreaderBase::GetGlobalDefaultNumberOfThreads(),"number of threads",cmd);
62 
63  try
64  {
65  cmd.parse(ac,av);
66  }
67  catch (TCLAP::ArgException& e)
68  {
69  std::cerr << "Error: " << e.error() << "for argument " << e.argId() << std::endl;
70  return(1);
71  }
72 
73  const unsigned int Dimension = 3;
74  typedef double PixelType;
75  typedef double TransformPixelType;
76 
77  typedef itk::Image <PixelType, Dimension> ImageType;
78  typedef itk::Image <PixelType, 4> Image4DType;
79 
80  typedef rpi::DisplacementFieldTransform <TransformPixelType,Dimension> TransformType;
81  typedef TransformType::VectorFieldType VectorFieldType;
82  typedef itk::MultiplyImageFilter <VectorFieldType, itk::Image <double,Dimension>, VectorFieldType> MultiplierFilterType;
83 
84  VectorFieldType::Pointer appliedField = anima::readImage<VectorFieldType>(trArg.getValue());
85  appliedField->DisconnectPipeline();
86 
87  Image4DType::Pointer forwardImage = anima::readImage<Image4DType>(forwardArg.getValue());
88 
89  if (fieldInVoxelCoordinates.isSet())
90  ApplyGeometryToVectorField(appliedField,forwardImage);
91 
92  if (reverseFieldArg.isSet())
93  {
94  // Take the opposite of the input field
95  MultiplierFilterType::Pointer vectorMultiplier = MultiplierFilterType::New();
96  vectorMultiplier->SetInput(appliedField);
97  vectorMultiplier->SetConstant(-1.0);
98  vectorMultiplier->SetNumberOfWorkUnits(nbpArg.getValue());
99  vectorMultiplier->Update();
100  vectorMultiplier->InPlaceOn();
101 
102  appliedField = vectorMultiplier->GetOutput();
103  appliedField->DisconnectPipeline();
104  }
105 
106  if (inverseFieldArg.isSet())
107  {
108  // Invert the applied field
109  typedef itk::FixedPointInverseDisplacementFieldImageFilter <VectorFieldType, VectorFieldType> InverseFilterType;
110  InverseFilterType::Pointer fieldInverter = InverseFilterType::New();
111  fieldInverter->SetInput(appliedField);
112  fieldInverter->SetSize(appliedField->GetLargestPossibleRegion().GetSize());
113  fieldInverter->SetOutputOrigin(appliedField->GetOrigin());
114  fieldInverter->SetOutputSpacing(appliedField->GetSpacing());
115  fieldInverter->SetNumberOfWorkUnits(nbpArg.getValue());
116  fieldInverter->Update();
117 
118  appliedField = fieldInverter->GetOutput();
119  appliedField->DisconnectPipeline();
120  }
121 
122  TransformType::Pointer trsf = TransformType::New();
123  trsf->SetParametersAsVectorField(appliedField);
124 
125  Image4DType::Pointer backwardImage;
126  unsigned int numBackwardImages = 0;
127 
128  if (backwardArg.getValue() != "")
129  {
130  backwardImage = anima::readImage<Image4DType> (backwardArg.getValue());
131  numBackwardImages = backwardImage->GetLargestPossibleRegion().GetSize()[Dimension];
132  }
133 
134  TransformType::Pointer oppositeTransform;
135  if (numBackwardImages > 0)
136  {
137  MultiplierFilterType::Pointer vectorMultiplier = MultiplierFilterType::New();
138  vectorMultiplier->SetInput(trsf->GetParametersAsVectorField());
139  vectorMultiplier->SetConstant(-1.0);
140  vectorMultiplier->SetNumberOfWorkUnits(nbpArg.getValue());
141  vectorMultiplier->Update();
142 
143  VectorFieldType::Pointer oppositeField = vectorMultiplier->GetOutput();
144  oppositeField->DisconnectPipeline();
145 
146  oppositeTransform = TransformType::New();
147  oppositeTransform->SetParametersAsVectorField(oppositeField);
148  }
149 
150  unsigned int numForwardImages = forwardImage->GetLargestPossibleRegion().GetSize()[Dimension];
151 
152  Image4DType::Pointer outputImage = Image4DType::New();
153  outputImage->Initialize();
154  outputImage->SetRegions(forwardImage->GetLargestPossibleRegion());
155  outputImage->SetSpacing (forwardImage->GetSpacing());
156  outputImage->SetOrigin (forwardImage->GetOrigin());
157  outputImage->SetDirection (forwardImage->GetDirection());
158  outputImage->Allocate();
159 
160  typedef anima::ResampleImageFilter <ImageType, ImageType> ResampleFilterType;
161 
162  for (unsigned int i = 0;i < numForwardImages;++i)
163  {
164  std::cout << "Applying correction to " << i << "-th image..." << std::flush;
165 
166  // Extract 3D images from forward (and backward if possible)
167  typedef itk::ExtractImageFilter <Image4DType, ImageType> ExtractFilterType;
168  ExtractFilterType::Pointer forwardExtractor = ExtractFilterType::New();
169  forwardExtractor->SetInput(forwardImage);
170 
171  Image4DType::RegionType extractRegion = forwardImage->GetLargestPossibleRegion();
172  extractRegion.SetIndex(Dimension,i);
173  extractRegion.SetSize(Dimension,0);
174  forwardExtractor->SetExtractionRegion(extractRegion);
175  forwardExtractor->SetDirectionCollapseToGuess();
176  forwardExtractor->Update();
177 
178  ResampleFilterType::Pointer forwardResampler = ResampleFilterType::New();
179  forwardResampler->SetInput(forwardExtractor->GetOutput());
180  forwardResampler->SetNumberOfWorkUnits(nbpArg.getValue());
181  forwardResampler->SetTransform(trsf);
182 
183  forwardResampler->SetSize(forwardExtractor->GetOutput()->GetLargestPossibleRegion().GetSize());
184  forwardResampler->SetOutputOrigin(forwardExtractor->GetOutput()->GetOrigin());
185  forwardResampler->SetOutputSpacing(forwardExtractor->GetOutput()->GetSpacing());
186  forwardResampler->SetOutputDirection(forwardExtractor->GetOutput()->GetDirection());
187  forwardResampler->SetDefaultPixelValue(0);
188  forwardResampler->SetScaleIntensitiesWithJacobian(true);
189  forwardResampler->Update();
190 
191  ImageType::Pointer outputSingleImage = forwardResampler->GetOutput();
192 
193  if (i < numBackwardImages)
194  {
195  ExtractFilterType::Pointer backwardExtractor = ExtractFilterType::New();
196  backwardExtractor->SetInput(backwardImage);
197  backwardExtractor->SetExtractionRegion(extractRegion);
198  backwardExtractor->SetDirectionCollapseToGuess();
199  backwardExtractor->Update();
200 
201  ResampleFilterType::Pointer backwardResampler = ResampleFilterType::New();
202  backwardResampler->SetInput(backwardExtractor->GetOutput());
203  backwardResampler->SetNumberOfWorkUnits(nbpArg.getValue());
204  backwardResampler->SetTransform(oppositeTransform);
205 
206  backwardResampler->SetSize(backwardExtractor->GetOutput()->GetLargestPossibleRegion().GetSize());
207  backwardResampler->SetOutputOrigin(backwardExtractor->GetOutput()->GetOrigin());
208  backwardResampler->SetOutputSpacing(backwardExtractor->GetOutput()->GetSpacing());
209  backwardResampler->SetOutputDirection(backwardExtractor->GetOutput()->GetDirection());
210  backwardResampler->SetDefaultPixelValue(0);
211  backwardResampler->SetScaleIntensitiesWithJacobian(true);
212  backwardResampler->Update();
213 
214  // Two input images so average them to get correction
215  typedef itk::AddImageFilter <ImageType,ImageType,ImageType> AddFilterType;
216  AddFilterType::Pointer outputAdder = AddFilterType::New();
217  outputAdder->SetInput1(outputSingleImage);
218  outputAdder->SetInput2(backwardResampler->GetOutput());
219  outputAdder->SetNumberOfWorkUnits(nbpArg.getValue());
220  outputAdder->Update();
221  outputAdder->InPlaceOn();
222 
223  typedef itk::MultiplyImageFilter <ImageType, itk::Image <double,Dimension>, ImageType> MultiplierFilterType;
224  MultiplierFilterType::Pointer outputMultiplier = MultiplierFilterType::New();
225  outputMultiplier->SetInput(outputAdder->GetOutput());
226  outputMultiplier->SetConstant(0.5);
227  outputMultiplier->SetNumberOfWorkUnits(nbpArg.getValue());
228  outputMultiplier->Update();
229  outputMultiplier->InPlaceOn();
230 
231  outputSingleImage = outputMultiplier->GetOutput();
232  outputSingleImage->DisconnectPipeline();
233  }
234 
235  itk::ImageRegionConstIterator <ImageType> singleOutputIterator(outputSingleImage,outputSingleImage->GetLargestPossibleRegion());
236  extractRegion.SetSize(Dimension,1);
237  itk::ImageRegionIterator <Image4DType> globalOutputIterator(outputImage,extractRegion);
238 
239  while (!singleOutputIterator.IsAtEnd())
240  {
241  globalOutputIterator.Set(singleOutputIterator.Get());
242 
243  ++singleOutputIterator;
244  ++globalOutputIterator;
245  }
246 
247  std::cout << " Done" << std::endl;
248  }
249 
250  anima::writeImage<Image4DType> (outArg.getValue(),outputImage);
251 
252  if (outVecArg.getValue() != "")
253  anima::writeImage<VectorFieldType>(outVecArg.getValue(), const_cast <VectorFieldType *> (trsf->GetParametersAsVectorField()));
254 
255  return 0;
256 }
void ApplyGeometryToVectorField(itk::Image< itk::Vector< double, 3 >, 3 > *vectorField, itk::Image< double, 4 > *geometryImage)
int main(int ac, const char **av)