Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
ImageResampler.cpp
Go to the documentation of this file.
1 /*===================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center,
6 Division of Medical and Biological Informatics.
7 All rights reserved.
8 
9 This software is distributed WITHOUT ANY WARRANTY; without
10 even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 A PARTICULAR PURPOSE.
12 
13 See LICENSE.txt or http://www.mitk.org for details.
14 
15 ===================================================================*/
16 
17 
18 #include "mitkCommandLineParser.h"
19 
20 #include <mitkIOUtil.h>
22 #include <mitkImage.h>
23 #include <mitkImageCast.h>
24 #include <mitkITKImageImport.h>
25 #include <mitkImageTimeSelector.h>
27 #include <mitkProperties.h>
28 
29 // ITK
30 #include <itksys/SystemTools.hxx>
31 #include <itkDirectory.h>
32 #include "itkLinearInterpolateImageFunction.h"
33 #include "itkWindowedSincInterpolateImageFunction.h"
34 #include "itkNearestNeighborInterpolateImageFunction.h"
35 #include "itkIdentityTransform.h"
36 #include "itkResampleImageFilter.h"
38 
39 using namespace std;
40 
41 typedef itk::Image<double, 3> InputImageType;
42 typedef itk::Image<unsigned char, 3> BinaryImageType;
43 
44 
45 static mitk::Image::Pointer TransformToReference(mitk::Image *reference, mitk::Image *moving, bool sincInterpol = false, bool nn = false)
46 {
47  // Convert to itk Images
48 
49  // Identify Transform
50  typedef itk::IdentityTransform<double, 3> T_Transform;
51  T_Transform::Pointer _pTransform = T_Transform::New();
52  _pTransform->SetIdentity();
53 
54  typedef itk::WindowedSincInterpolateImageFunction< InputImageType, 3> WindowedSincInterpolatorType;
56 
57  typedef itk::LinearInterpolateImageFunction< InputImageType> LinearInterpolateImageFunctionType;
59 
60  typedef itk::NearestNeighborInterpolateImageFunction< BinaryImageType> NearestNeighborInterpolateImageFunctionType;
62 
63 
64  if (!nn)
65  {
68  mitk::CastToItkImage(reference,itkReference);
69  mitk::CastToItkImage(moving,itkMoving);
70  typedef itk::ResampleImageFilter<InputImageType, InputImageType> ResampleFilterType;
71 
72 
74  resampler->SetInput(itkMoving);
75  resampler->SetReferenceImage( itkReference );
76  resampler->UseReferenceImageOn();
77  resampler->SetTransform(_pTransform);
78  if ( sincInterpol)
79  resampler->SetInterpolator(sinc_interpolator);
80  else
81  resampler->SetInterpolator(lin_interpolator);
82 
83  resampler->Update();
84 
85  // Convert back to mitk
87  result->InitializeByItk(resampler->GetOutput());
88  GrabItkImageMemory( resampler->GetOutput() , result );
89  return result;
90  }
91 
92 
95  mitk::CastToItkImage(reference,itkReference);
96  mitk::CastToItkImage(moving,itkMoving);
97 
98 
99  typedef itk::ResampleImageFilter<BinaryImageType, BinaryImageType> ResampleFilterType;
100 
101 
103  resampler->SetInput(itkMoving);
104  resampler->SetReferenceImage( itkReference );
105  resampler->UseReferenceImageOn();
106  resampler->SetTransform(_pTransform);
107  resampler->SetInterpolator(nn_interpolator);
108 
109  resampler->Update();
110  // Convert back to mitk
112  result->InitializeByItk(resampler->GetOutput());
113  GrabItkImageMemory( resampler->GetOutput() , result );
114  return result;
115 
116 }
117 
118 
119 static std::vector<std::string> &split(const std::string &s, char delim, std::vector<std::string> &elems)
120 {
121  std::stringstream ss(s);
122  std::string item;
123  while (std::getline(ss, item, delim))
124  {
125  elems.push_back(item);
126  }
127  return elems;
128 }
129 
130 static std::vector<std::string> split(const std::string &s, char delim)
131 {
132  std::vector < std::string > elems;
133  return split(s, delim, elems);
134 }
135 
136 
137 static mitk::Image::Pointer ResampleBySpacing(mitk::Image *input, float *spacing, bool useLinInt = true, bool useNN = false)
138 {
139  if (!useNN)
140  {
142  CastToItkImage(input,itkImage);
143 
148  // Identity transform.
149  // We don't want any transform on our image except rescaling which is not
150  // specified by a transform but by the input/output spacing as we will see
151  // later.
152  // So no transform will be specified.
153  typedef itk::IdentityTransform<double, 3> T_Transform;
154 
155  // The resampler type itself.
156  typedef itk::ResampleImageFilter<InputImageType, InputImageType> T_ResampleFilter;
157 
158  // Prepare the resampler.
159  // Instantiate the transform and specify it should be the id transform.
160  T_Transform::Pointer _pTransform = T_Transform::New();
161  _pTransform->SetIdentity();
162 
163  // Instantiate the resampler. Wire in the transform and the interpolator.
165 
166  // Specify the input.
167  _pResizeFilter->SetInput(itkImage);
168 
169  _pResizeFilter->SetTransform(_pTransform);
170 
171  // Set the output origin.
172  _pResizeFilter->SetOutputOrigin(itkImage->GetOrigin());
173 
174  // Compute the size of the output.
175  // The size (# of pixels) in the output is recomputed using
176  // the ratio of the input and output sizes.
177  InputImageType::SpacingType inputSpacing = itkImage->GetSpacing();
178  InputImageType::SpacingType outputSpacing;
179  const InputImageType::RegionType& inputSize = itkImage->GetLargestPossibleRegion();
180 
181  InputImageType::SizeType outputSize;
182  typedef InputImageType::SizeType::SizeValueType SizeValueType;
183 
184  // Set the output spacing.
185  outputSpacing[0] = spacing[0];
186  outputSpacing[1] = spacing[1];
187  outputSpacing[2] = spacing[2];
188 
189  outputSize[0] = static_cast<SizeValueType>(inputSize.GetSize()[0] * inputSpacing[0] / outputSpacing[0] + .5);
190  outputSize[1] = static_cast<SizeValueType>(inputSize.GetSize()[1] * inputSpacing[1] / outputSpacing[1] + .5);
191  outputSize[2] = static_cast<SizeValueType>(inputSize.GetSize()[2] * inputSpacing[2] / outputSpacing[2] + .5);
192 
193  _pResizeFilter->SetOutputSpacing(outputSpacing);
194  _pResizeFilter->SetSize(outputSize);
195 
196  typedef itk::LinearInterpolateImageFunction< InputImageType > LinearInterpolatorType;
198 
199 
200  typedef itk::WindowedSincInterpolateImageFunction< InputImageType, 4> WindowedSincInterpolatorType;
202 
203  if (useLinInt)
204  _pResizeFilter->SetInterpolator(lin_interpolator);
205  else
206  _pResizeFilter->SetInterpolator(sinc_interpolator);
207 
208  _pResizeFilter->Update();
209 
211  image->InitializeByItk(_pResizeFilter->GetOutput());
212  mitk::GrabItkImageMemory( _pResizeFilter->GetOutput(), image);
213  return image;
214  }
215 
217  CastToItkImage(input,itkImage);
218 
223  // Identity transform.
224  // We don't want any transform on our image except rescaling which is not
225  // specified by a transform but by the input/output spacing as we will see
226  // later.
227  // So no transform will be specified.
228  typedef itk::IdentityTransform<double, 3> T_Transform;
229 
230  // The resampler type itself.
231  typedef itk::ResampleImageFilter<BinaryImageType, BinaryImageType> T_ResampleFilter;
232 
233  // Prepare the resampler.
234  // Instantiate the transform and specify it should be the id transform.
235  T_Transform::Pointer _pTransform = T_Transform::New();
236  _pTransform->SetIdentity();
237 
238  // Instantiate the resampler. Wire in the transform and the interpolator.
240 
241  // Specify the input.
242  _pResizeFilter->SetInput(itkImage);
243 
244  _pResizeFilter->SetTransform(_pTransform);
245 
246  // Set the output origin.
247  _pResizeFilter->SetOutputOrigin(itkImage->GetOrigin());
248 
249  // Compute the size of the output.
250  // The size (# of pixels) in the output is recomputed using
251  // the ratio of the input and output sizes.
252  BinaryImageType::SpacingType inputSpacing = itkImage->GetSpacing();
253  BinaryImageType::SpacingType outputSpacing;
254  const BinaryImageType::RegionType& inputSize = itkImage->GetLargestPossibleRegion();
255 
256  BinaryImageType::SizeType outputSize;
257  typedef BinaryImageType::SizeType::SizeValueType SizeValueType;
258 
259  // Set the output spacing.
260  outputSpacing[0] = spacing[0];
261  outputSpacing[1] = spacing[1];
262  outputSpacing[2] = spacing[2];
263 
264  outputSize[0] = static_cast<SizeValueType>(inputSize.GetSize()[0] * inputSpacing[0] / outputSpacing[0] + .5);
265  outputSize[1] = static_cast<SizeValueType>(inputSize.GetSize()[1] * inputSpacing[1] / outputSpacing[1] + .5);
266  outputSize[2] = static_cast<SizeValueType>(inputSize.GetSize()[2] * inputSpacing[2] / outputSpacing[2] + .5);
267 
268  _pResizeFilter->SetOutputSpacing(outputSpacing);
269  _pResizeFilter->SetSize(outputSize);
270 
271  typedef itk::NearestNeighborInterpolateImageFunction< BinaryImageType> NearestNeighborInterpolateImageType;
273  _pResizeFilter->SetInterpolator(nn_interpolator);
274 
275  _pResizeFilter->Update();
276 
278  image->InitializeByItk(_pResizeFilter->GetOutput());
279  mitk::GrabItkImageMemory( _pResizeFilter->GetOutput(), image);
280  return image;
281 
282 }
283 
285 static void SaveImage(std::string fileName, mitk::Image* image, std::string fileType )
286 {
287  std::cout << "----Save to " << fileName;
288 
289  mitk::IOUtil::Save(image, fileName);
290 }
291 
292 mitk::Image::Pointer ResampleDWIbySpacing(mitk::Image::Pointer input, float* spacing, bool useLinInt = true)
293 {
294 
295  itk::Vector<double, 3> spacingVector;
296  spacingVector[0] = spacing[0];
297  spacingVector[1] = spacing[1];
298  spacingVector[2] = spacing[2];
299 
300  typedef itk::ResampleDwiImageFilter<short> ResampleFilterType;
301 
303  mitk::CastToItkImage(input, itkVectorImagePointer);
304 
306  resampler->SetInput( itkVectorImagePointer );
307  resampler->SetInterpolation(ResampleFilterType::Interpolate_Linear);
308  resampler->SetNewSpacing(spacingVector);
309  resampler->Update();
310 
311  mitk::Image::Pointer output = mitk::GrabItkImageMemory( resampler->GetOutput() );
314  mitk::DiffusionPropertyHelper propertyHelper( output );
315  propertyHelper.InitializeImage();
316 
317  return output;
318 }
319 
320 int main( int argc, char* argv[] )
321 {
322  mitkCommandLineParser parser;
323  parser.setArgumentPrefix("--","-");
324 
325  parser.setTitle("Image Resampler");
326  parser.setCategory("Preprocessing Tools");
327  parser.setContributor("MBI");
328  parser.setDescription("Resample an image to eigther a specific spacing or to a reference image.");
329 
330  // Add command line argument names
331  parser.addArgument("help", "h",mitkCommandLineParser::Bool, "Show this help text");
332  parser.addArgument("input", "i", mitkCommandLineParser::InputImage, "Input:", "Input file",us::Any(),false);
333  parser.addArgument("output", "o", mitkCommandLineParser::OutputFile, "Output:", "Output file",us::Any(),false);
334  parser.addArgument("spacing", "s", mitkCommandLineParser::String, "Spacing:", "Resample provide x,y,z spacing in mm (e.g. -r 1,1,3), is not applied to tensor data",us::Any());
335  parser.addArgument("reference", "r", mitkCommandLineParser::InputImage, "Reference:", "Resample using supplied reference image. Also cuts image to same dimensions",us::Any());
336  parser.addArgument("win-sinc", "w", mitkCommandLineParser::Bool, "Windowed-sinc interpolation:", "Use windowed-sinc interpolation (3) instead of linear interpolation ",us::Any());
337  parser.addArgument("nearest-neigh", "n", mitkCommandLineParser::Bool, "Nearest Neighbor:", "Use Nearest Neighbor interpolation instead of linear interpolation ",us::Any());
338 
339 
340  map<string, us::Any> parsedArgs = parser.parseArguments(argc, argv);
341 
342  // Handle special arguments
343  bool useSpacing = false;
344  bool useLinearInterpol = true;
345  bool useNN= false;
346  {
347  if (parsedArgs.size() == 0)
348  {
349  return EXIT_FAILURE;
350  }
351 
352  if (parsedArgs.count("sinc-int"))
353  useLinearInterpol = false;
354 
355  if (parsedArgs.count("nearest-neigh"))
356  useNN = true;
357 
358  // Show a help message
359  if ( parsedArgs.count("help") || parsedArgs.count("h"))
360  {
361  std::cout << parser.helpText();
362  return EXIT_SUCCESS;
363  }
364  }
365 
366  std::string outputFile = us::any_cast<string>(parsedArgs["output"]);
367  std::string inputFile = us::any_cast<string>(parsedArgs["input"]);
368 
369  std::vector<std::string> spacings;
370  float spacing[3];
371  if (parsedArgs.count("spacing"))
372  {
373 
374  std::string arg = us::any_cast<string>(parsedArgs["spacing"]);
375  if (arg != "")
376  {
377  spacings = split(arg ,',');
378  spacing[0] = atoi(spacings.at(0).c_str());
379  spacing[1] = atoi(spacings.at(1).c_str());
380  spacing[2] = atoi(spacings.at(2).c_str());
381  useSpacing = true;
382  }
383  }
384 
385  std::string refImageFile = "";
386  if (parsedArgs.count("reference"))
387  {
388  refImageFile = us::any_cast<string>(parsedArgs["reference"]);
389  }
390 
391  if (refImageFile =="" && useSpacing == false)
392  {
393  MITK_ERROR << "No information how to resample is supplied. Use eigther --spacing or --reference !";
394  return EXIT_FAILURE;
395  }
396 
397 
398  mitk::Image::Pointer refImage;
399  if (!useSpacing)
400  refImage = mitk::IOUtil::LoadImage(refImageFile);
401 
402  mitk::Image::Pointer inputDWI = mitk::IOUtil::LoadImage(inputFile);
404  {
405  mitk::Image::Pointer outputImage;
406 
407  if (useSpacing)
408  outputImage = ResampleDWIbySpacing(inputDWI, spacing);
409  else
410  {
411  MITK_WARN << "Not supported yet, to resample a DWI please set a new spacing.";
412  return EXIT_FAILURE;
413  }
414 
415  mitk::IOUtil::Save(outputImage, outputFile.c_str());
416 
417  return EXIT_SUCCESS;
418  }
419  mitk::Image::Pointer inputImage = mitk::IOUtil::LoadImage(inputFile);
420 
421 
422  mitk::Image::Pointer resultImage;
423 
424  if (useSpacing)
425  resultImage = ResampleBySpacing(inputImage,spacing,useLinearInterpol,useNN);
426  else
427  resultImage = TransformToReference(refImage,inputImage,useLinearInterpol,useNN);
428 
429 
430  mitk::IOUtil::SaveImage(resultImage, outputFile);
431 
432  return EXIT_SUCCESS;
433 }
mitk::Image::Pointer ResampleDWIbySpacing(mitk::Image::Pointer input, float *spacing, bool useLinInt=true)
static void Save(const mitk::BaseData *data, const std::string &path)
Save a mitk::BaseData instance.
Definition: mitkIOUtil.cpp:824
static const std::string REFERENCEBVALUEPROPERTYNAME
int main(int argc, char *argv[])
itk::SmartPointer< Self > Pointer
#define MITK_ERROR
Definition: mitkLogMacros.h:24
void setContributor(std::string contributor)
STL namespace.
Helper class for mitk::Images containing diffusion weighted data.
ValueType * any_cast(Any *operand)
Definition: usAny.h:377
static mitk::Image::Pointer TransformToReference(mitk::Image *reference, mitk::Image *moving, bool sincInterpol=false, bool nn=false)
std::map< std::string, us::Any > parseArguments(const StringContainerType &arguments, bool *ok=nullptr)
Image::Pointer GrabItkImageMemory(itk::SmartPointer< ItkOutputImageType > &itkimage, mitk::Image *mitkImage=nullptr, const BaseGeometry *geometry=nullptr, bool update=true)
Grabs the memory of an itk::Image (with a specific type) and puts it into an mitk::Image.The memory is managed by the mitk::Image after calling this function. The itk::Image remains valid until the mitk::Image decides to free the memory.
void InitializeImage()
Make certain the owned image is up to date with all necessary properties.
static bool SaveImage(mitk::Image::Pointer image, const std::string &path)
SaveImage Convenience method to save an arbitrary mitkImage.
Definition: mitkIOUtil.cpp:870
#define MITK_WARN
Definition: mitkLogMacros.h:23
itk::Image< double, 3 > InputImageType
void addArgument(const std::string &longarg, const std::string &shortarg, Type type, const std::string &argLabel, const std::string &argHelp=std::string(), const us::Any &defaultValue=us::Any(), bool optional=true, bool ignoreRest=false, bool deprecated=false)
Image class for storing images.
Definition: mitkImage.h:76
Definition: usAny.h:163
itk::Image< unsigned char, 3 > BinaryImageType
void setCategory(std::string category)
static Pointer New()
void setArgumentPrefix(const std::string &longPrefix, const std::string &shortPrefix)
static Pointer New()
Resample DWI channel by channel.
static mitk::Image::Pointer ResampleBySpacing(mitk::Image *input, float *spacing, bool useLinInt=true, bool useNN=false)
void MITKCORE_EXPORT CastToItkImage(const mitk::Image *mitkImage, itk::SmartPointer< ItkOutputImageType > &itkOutputImage)
Cast an mitk::Image to an itk::Image with a specific type.
std::string helpText() const
static void SaveImage(std::string fileName, mitk::Image *image, std::string fileType)
Save images according to file type.
GradientDirectionsContainerType::Pointer GetGradientContainer() const
static const std::string GRADIENTCONTAINERPROPERTYNAME
void setTitle(std::string title)
void setDescription(std::string description)
static std::vector< std::string > & split(const std::string &s, char delim, std::vector< std::string > &elems)
static mitk::Image::Pointer LoadImage(const std::string &path)
LoadImage Convenience method to load an arbitrary mitkImage.
Definition: mitkIOUtil.cpp:597
static itkEventMacro(BoundingShapeInteractionEvent, itk::AnyEvent) class MITKBOUNDINGSHAPE_EXPORT BoundingShapeInteractor Pointer New()
Basic interaction methods for mitk::GeometryData.