SMILX  1.01
milxQtRegistrationAlgos.cpp
1 #include "milxQtRegistrationAlgos.h"
2 #include "milxQtRegistration.h"
3 
4 milxQtRegistrationAlgos::milxQtRegistrationAlgos(QObject * parent) : QObject(parent)
5 {
6  return;
7 }
8 
10 {
11  future = QtConcurrent::run(this, &milxQtRegistrationAlgos::affine, params);
12 }
13 
15 {
16  future = QtConcurrent::run(this, &milxQtRegistrationAlgos::demon, params);
17 }
18 
20 {
22 
23  char referenceName[FILENAME_MAX + 1],
24  floatingName[FILENAME_MAX + 1],
25  outputName[FILENAME_MAX + 1];
26 
27  strncpy(referenceName, params.referenceName.toLatin1().constData(), FILENAME_MAX);
28  strncpy(floatingName, params.floatingName.toLatin1().constData(), FILENAME_MAX);
29  strncpy(outputName, params.outputName.toLatin1().constData(), FILENAME_MAX);
30 
31 
32  bool result = reg.RegisterAffineITK(std::string(referenceName),
33  std::string(floatingName),
34  std::string(outputName),
35  false, std::string(""),
36  std::string(""));
37 
38  if (result == true)
39  emit registrationCompleted();
40  else
41  emit error("affine()", "Itk affine registration error");
42 
43  return 0;
44 }
45 
47 {
49 
50  char referenceName[FILENAME_MAX + 1],
51  floatingName[FILENAME_MAX + 1],
52  outputName[FILENAME_MAX + 1];
53 
54  strncpy(referenceName, params.referenceName.toLatin1().constData(), FILENAME_MAX);
55  strncpy(floatingName, params.floatingName.toLatin1().constData(), FILENAME_MAX);
56  strncpy(outputName, params.outputName.toLatin1().constData(), FILENAME_MAX);
57 
58  bool result = reg.RegisterMilxNonRigid(std::string(referenceName),
59  std::string(floatingName),
60  std::string(outputName),
61  false);
62 
63 
64  if (result == true)
65  emit registrationCompleted();
66  else
67  emit error("demon()", "Itk demon registration error");
68 
69  return 0;
70 }
71 
72 #ifdef USE_NIFTI_REG
73 void milxQtRegistrationAlgos::cpp2def_async(milxQtRegistrationParams params)
74 {
75  future = QtConcurrent::run(this, &milxQtRegistrationAlgos::cpp2def, params);
76 }
77 
78 void milxQtRegistrationAlgos::f3d_async(milxQtRegistrationParams params)
79 {
80  future = QtConcurrent::run(this, &milxQtRegistrationAlgos::f3d, params);
81 }
82 
83 void milxQtRegistrationAlgos::aladin_async(milxQtRegistrationParams params)
84 {
85  future = QtConcurrent::run(this, &milxQtRegistrationAlgos::aladin, params);
86 }
87 
88 void milxQtRegistrationAlgos::average_async(QString outputName, QStringList filenames)
89 {
90  future = QtConcurrent::run(this, &milxQtRegistrationAlgos::average, outputName, filenames);
91 }
92 
93 void milxQtRegistrationAlgos::similarities_async(milxQtRegistration * image)
94 {
95  future = QtConcurrent::run(this, &milxQtRegistrationAlgos::similarities, image);
96 }
97 
98 int milxQtRegistrationAlgos::average(QString outputName, QStringList filenames)
99 {
100  if (filenames.size() < 2) {
101  emit error("average()", "Error while computing average, invalid number of file: minimum 2");
102  return EXIT_FAILURE;
103  }
104 
105  // Transformt the QtStrings in a char * array
106  char * * arguments;
107  int nbargs = filenames.count() + 2;
108 
109  // Allocate the array and copy the strings
110  arguments = (char * *)malloc(nbargs * sizeof(char *));
111  for (int i = 0; i < nbargs; i++)
112  {
113  arguments[i] = (char *)malloc(sizeof(char) * (FILENAME_MAX + 1));
114 
115  QString path;
116  if (i == 0) {
117  path = "";
118  }
119  else if (i == 1) {
120  path = outputName;
121  }
122  else {
123  path = filenames[i - 2];
124  }
125 
126  QByteArray byteArray = path.toAscii();
127  strncpy(arguments[i], byteArray.data(), FILENAME_MAX);
128  }
129 
130  //Check the name of the first file to verify if they are analyse or nifti image
131  std::string n(arguments[2]);
132  if (n.find(".nii.gz") != std::string::npos ||
133  n.find(".nii") != std::string::npos ||
134  n.find(".hdr") != std::string::npos ||
135  n.find(".img") != std::string::npos ||
136  n.find(".img.gz") != std::string::npos)
137  {
138  // Input arguments are image filename
139  // Read the first image to average
140  nifti_image *tempImage = reg_io_ReadImageHeader(arguments[2]);
141  if (tempImage == NULL) {
142  // fprintf(stderr, "The following image can not be read: %s\n", arguments[2]);
143  for (int j = 0; j < nbargs; j++) {
144  free(arguments[j]);
145  }
146  free(arguments);
147  emit error("average()", "Error while computing average, the following image can not be read: \"" + QString(arguments[2]) + "\".");
148 
149  return EXIT_FAILURE;
150  }
151  reg_checkAndCorrectDimension(tempImage);
152 
153  // Create the average image
154  nifti_image *averageImage = nifti_copy_nim_info(tempImage);
155  averageImage->scl_slope = 1.f;
156  averageImage->scl_inter = 0.f;
157  nifti_image_free(tempImage);
158  tempImage = NULL;
159  averageImage->datatype = NIFTI_TYPE_FLOAT32;
160  if (sizeof(PrecisionTYPE) == sizeof(double))
161  averageImage->datatype = NIFTI_TYPE_FLOAT64;
162  averageImage->nbyper = sizeof(PrecisionTYPE);
163  averageImage->data = (void *)calloc(averageImage->nvox, averageImage->nbyper);
164 
165  int imageTotalNumber = 0;
166  for (int i = 2; i<nbargs; ++i)
167  {
168  nifti_image *tempImage = reg_io_ReadImageFile(arguments[i]);
169  if (tempImage == NULL) {
170  //fprintf(stderr, "[!] The following image can not be read: %s\n", arguments[i]);
171  for (int j = 0; j < nbargs; j++) {
172  free(arguments[j]);
173  }
174  free(arguments);
175  emit error("average()", "Error while computing average, the following image can not be read: \"" + QString(arguments[i]) + "\".");
176  return EXIT_FAILURE;
177  }
178  reg_checkAndCorrectDimension(tempImage);
179  if (sizeof(PrecisionTYPE) == sizeof(double))
180  reg_tools_changeDatatype<double>(tempImage);
181  else reg_tools_changeDatatype<float>(tempImage);
182  if (averageImage->nvox != tempImage->nvox) {
183  //fprintf(stderr, "[!] All images must have the same size. Error when processing: %s\n", arguments[i]);
184  for (int j = 0; j < nbargs; j++) {
185  free(arguments[j]);
186  }
187  free(arguments);
188  emit error("average()", "Error while computing average, all images must have the same size. Error when processing: \"" + QString(arguments[i]) + "\".");
189  return EXIT_FAILURE;
190  }
191  // if(sizeof(PrecisionTYPE)==sizeof(double))
192  // average_norm_intensity<double>(tempImage);
193  // else average_norm_intensity<float>(tempImage);
194  reg_tools_addImageToImage(averageImage, tempImage, averageImage);
195  imageTotalNumber++;
196  nifti_image_free(tempImage);
197  tempImage = NULL;
198  }
199  reg_tools_divideValueToImage(averageImage, averageImage, (float)imageTotalNumber);
200 
201  reg_io_WriteImageFile(averageImage, arguments[1]);
202  nifti_image_free(averageImage);
203  }
204  else
205  {
206  // Free variables
207  for (int j = 0; j < nbargs; j++) {
208  free(arguments[j]);
209  }
210  free(arguments);
211  emit error("average()", "Error while computing average, invalid filetype input (check accepted file extensions: .nii, .nii.gz, .hdr, .img, .img.gz)");
212  return EXIT_FAILURE;
213  }
214 
215  // Free variables
216  for (int j = 0; j < nbargs; j++) {
217  free(arguments[j]);
218  }
219  free(arguments);
220  emit averageCompleted();
221  return EXIT_SUCCESS;
222 }
223 
224 int milxQtRegistrationAlgos::cpp2def(milxQtRegistrationParams params)
225 {
226  char referenceName[FILENAME_MAX + 1],
227  defOutputName[FILENAME_MAX + 1],
228  cppOutputName[FILENAME_MAX + 1];
229 
230  strncpy(referenceName, params.referenceName.toLatin1().constData(), FILENAME_MAX);
231  strncpy(defOutputName, params.defOutputName.toLatin1().constData(), FILENAME_MAX);
232  strncpy(cppOutputName, params.cppOutputName.toLatin1().constData(), FILENAME_MAX);
233 
234  // Create some variables
235  mat44 *affineTransformation = NULL;
236  nifti_image *referenceImage = NULL;
237  nifti_image *inputTransformationImage = NULL;
238  nifti_image *outputTransformationImage = NULL;
239  // First check if the input filename is an image
240  if (reg_isAnImageFileName(cppOutputName))
241  {
242  inputTransformationImage = reg_io_ReadImageFile(cppOutputName);
243  if (inputTransformationImage == NULL)
244  {
245  fprintf(stderr, "[NiftyReg ERROR] Error when reading the provided transformation: %s\n",
246  cppOutputName);
247  return 1;
248  }
249  reg_checkAndCorrectDimension(inputTransformationImage);
250  // If the input transformation is a grid, check that the reference image has been specified
251  if (inputTransformationImage->intent_p1 == SPLINE_GRID ||
252  inputTransformationImage->intent_p1 == SPLINE_VEL_GRID)
253  {
254  referenceImage = reg_io_ReadImageHeader(referenceName);
255  if (referenceImage == NULL)
256  {
257  fprintf(stderr, "[NiftyReg ERROR] Error when reading the reference image: %s\n",
258  referenceName);
259  return 1;
260  }
261  reg_checkAndCorrectDimension(referenceImage);
262  }
263  }
264  else
265  {
266  // Read the affine transformation
267  affineTransformation = (mat44 *)malloc(sizeof(mat44));
268  reg_tool_ReadAffineFile(affineTransformation, cppOutputName);
269  referenceImage = reg_io_ReadImageHeader(referenceName);
270  if (referenceImage == NULL)
271  {
272  emit error("cpp2def()", "Error while while computing deformation field, the reference image (\"" + QString(referenceName) + "\") can not be read.");
273  return 1;
274  }
275  reg_checkAndCorrectDimension(referenceImage);
276  }
277  // Create a dense field
278  if (affineTransformation != NULL ||
279  inputTransformationImage->intent_p1 == SPLINE_GRID ||
280  inputTransformationImage->intent_p1 == SPLINE_VEL_GRID)
281  {
282  // Create a field image from the reference image
283  outputTransformationImage = nifti_copy_nim_info(referenceImage);
284  outputTransformationImage->ndim = outputTransformationImage->dim[0] = 5;
285  outputTransformationImage->nt = outputTransformationImage->dim[4] = 1;
286  outputTransformationImage->nu = outputTransformationImage->dim[5] = outputTransformationImage->nz>1 ? 3 : 2;
287  outputTransformationImage->nvox = (size_t)outputTransformationImage->nx *
288  outputTransformationImage->ny * outputTransformationImage->nz *
289  outputTransformationImage->nt * outputTransformationImage->nu;
290  outputTransformationImage->nbyper = sizeof(float);
291  outputTransformationImage->datatype = NIFTI_TYPE_FLOAT32;
292  outputTransformationImage->intent_code = NIFTI_INTENT_VECTOR;
293  memset(outputTransformationImage->intent_name, 0, 16);
294  strcpy(outputTransformationImage->intent_name, "NREG_TRANS");
295  outputTransformationImage->scl_slope = 1.f;
296  outputTransformationImage->scl_inter = 0.f;
297  }
298  else
299  {
300  // Create a deformation field from in the input transformation
301  outputTransformationImage = nifti_copy_nim_info(inputTransformationImage);
302  }
303  // Allocate the output field data array
304  outputTransformationImage->data = (void *)malloc
305  (outputTransformationImage->nvox*outputTransformationImage->nbyper);
306 
307  // Create a deformation or displacement field
308  if (affineTransformation != NULL)
309  {
310  reg_affine_getDeformationField(affineTransformation, outputTransformationImage);
311  }
312  else
313  {
314  switch (static_cast<int>(reg_round(inputTransformationImage->intent_p1)))
315  {
316  case DEF_FIELD:
317  //printf("[NiftyReg] The specified transformation is a deformation field:\n[NiftyReg] %s\n", inputTransformationImage->fname);
318  // the current in transformation is copied
319  memcpy(outputTransformationImage->data, inputTransformationImage->data,
320  outputTransformationImage->nvox*outputTransformationImage->nbyper);
321  break;
322  case DISP_FIELD:
323  //printf("[NiftyReg] The specified transformation is a displacement field:\n[NiftyReg] %s\n", inputTransformationImage->fname);
324  // the current in transformation is copied and converted
325  memcpy(outputTransformationImage->data, inputTransformationImage->data,
326  outputTransformationImage->nvox*outputTransformationImage->nbyper);
327  reg_getDeformationFromDisplacement(outputTransformationImage);
328  break;
329  case SPLINE_GRID:
330  // printf("[NiftyReg] The specified transformation is a spline parametrisation:\n[NiftyReg] %s\n", inputTransformationImage->fname);
331  // The output field is filled with an identity deformation field
332  memset(outputTransformationImage->data,
333  0,
334  outputTransformationImage->nvox*outputTransformationImage->nbyper);
335  reg_getDeformationFromDisplacement(outputTransformationImage);
336  // The spline transformation is composed with the identity field
337  reg_spline_getDeformationField(inputTransformationImage,
338  outputTransformationImage,
339  NULL, // no mask
340  true, // composition is used,
341  true // b-spline are used
342  );
343  break;
344  case DEF_VEL_FIELD:
345  //printf("[NiftyReg] The specified transformation is a deformation velocity field:\n[NiftyReg] %s\n", inputTransformationImage->fname);
346  // The flow field is exponentiated
347  reg_defField_getDeformationFieldFromFlowField(inputTransformationImage,
348  outputTransformationImage,
349  false // step number is not updated
350  );
351  break;
352  case DISP_VEL_FIELD:
353  //printf("[NiftyReg] The specified transformation is a displacement velocity field:\n[NiftyReg] %s\n", inputTransformationImage->fname);
354  // The input transformation is converted into a def flow
355  reg_getDeformationFromDisplacement(outputTransformationImage);
356  // The flow field is exponentiated
357  reg_defField_getDeformationFieldFromFlowField(inputTransformationImage,
358  outputTransformationImage,
359  false // step number is not updated
360  );
361  break;
362  case SPLINE_VEL_GRID:
363  //printf("[NiftyReg] The specified transformation is a spline velocity parametrisation:\n[NiftyReg] %s\n", inputTransformationImage->fname);
364  // The spline parametrisation is converted into a dense flow and exponentiated
365  reg_spline_getDefFieldFromVelocityGrid(inputTransformationImage,
366  outputTransformationImage,
367  false // step number is not updated
368  );
369  break;
370  default:
371  emit error("cpp2def()", "[NiftyReg ERROR] Unknown input transformation type");
372  return 1;
373  }
374  }
375  outputTransformationImage->intent_p1 = DEF_FIELD;
376  outputTransformationImage->intent_p2 = 0;
377 
378 
379  // Save the generated transformation
380  reg_io_WriteImageFile(outputTransformationImage, defOutputName);
381 
382  // Free the allocated images and arrays
383  if (affineTransformation != NULL) free(affineTransformation);
384  if (referenceImage != NULL) nifti_image_free(referenceImage);
385  if (inputTransformationImage != NULL) nifti_image_free(inputTransformationImage);
386  if (outputTransformationImage != NULL) nifti_image_free(outputTransformationImage);
387  emit cpp2defCompleted();
388  return 0;
389 
390 
391 }
392 
393 int milxQtRegistrationAlgos::f3d(milxQtRegistrationParams params)
394 {
395  char referenceName[FILENAME_MAX + 1],
396  floatingName[FILENAME_MAX + 1],
397  outputName[FILENAME_MAX + 1],
398  cppOutputName[FILENAME_MAX + 1];
399 
400  strncpy(referenceName, params.referenceName.toLatin1().constData(), FILENAME_MAX);
401  strncpy(floatingName, params.floatingName.toLatin1().constData(), FILENAME_MAX);
402  strncpy(outputName, params.outputName.toLatin1().constData(), FILENAME_MAX);
403  strncpy(cppOutputName, params.cppOutputName.toLatin1().constData(), FILENAME_MAX);
404 
405  int maxiterationNumber = params.maxit;
406 
407 
408  PrecisionTYPE spacing[3];
409  spacing[0] = params.spacing[0];
410  spacing[1] = params.spacing[1];
411  spacing[2] = params.spacing[2];
412 
413  unsigned int levelNumber = params.ln;
414  unsigned int levelToPerform = params.lp;
415  bool noPyramid = params.nopy;
416  bool useSym = params.useSym;
417 
418  time_t start;
419  time(&start);
420  int verbose = true;
421 
422  nifti_image *referenceImage = NULL;
423  nifti_image *floatingImage = NULL;
424 
425  referenceImage = reg_io_ReadImageFile(referenceName);
426  if (referenceImage == NULL)
427  {
428  emit error("f3d()", "F3D registration error: Error when reading the reference image \"" + QString(referenceName) + "\".");
429  return 1;
430  }
431 
432  floatingImage = reg_io_ReadImageFile(floatingName);
433  if (floatingImage == NULL)
434  {
435  emit error("f3d()", "F3D registration error: Error when reading the floating image \"" + QString(floatingName) + "\".");
436  return 1;
437  }
438 
439  //\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
440  // Check the type of registration object to create
441 #ifdef _USE_CUDA
442  CUcontext ctx;
443 #endif // _USE_CUDA
444  reg_f3d<PrecisionTYPE> *REG = NULL;
445 
446  if (useSym)
447  {
448  REG = new reg_f3d_sym<PrecisionTYPE>(referenceImage->nt, floatingImage->nt);
449  }
450 
451  if (REG == NULL)
452  REG = new reg_f3d<PrecisionTYPE>(referenceImage->nt, floatingImage->nt);
453  REG->SetReferenceImage(referenceImage);
454  REG->SetFloatingImage(floatingImage);
455 
456  // Create some pointers that could be used
457  mat44 affineMatrix;
458  nifti_image *inputCCPImage = NULL;
459  nifti_image *referenceMaskImage = NULL;
460  nifti_image *floatingMaskImage = NULL;
461 
462  int refBinNumber = 0;
463  int floBinNumber = 0;
464 
465  /* read the input parameter */
466  // Verbose off
467  REG->DoNotPrintOutInformation();
468 
469  REG->SetMaximalIterationNumber(maxiterationNumber);
470  REG->SetSpacing(0, spacing[0]);
471  REG->SetSpacing(1, spacing[1]);
472  REG->SetSpacing(2, spacing[2]);
473  REG->SetLevelNumber(levelNumber);
474  REG->SetLevelToPerform(levelToPerform);
475  if (noPyramid)
476  {
477  REG->DoNotUsePyramidalApproach();
478  }
479 
480  // Run the registration
481  REG->Run();
482 
483  // Save the control point result
484  nifti_image *outputControlPointGridImage = REG->GetControlPointPositionImage();
485  if (cppOutputName[0] == '\0') strcpy(cppOutputName, "outputCPP.nii.gz");
486  memset(outputControlPointGridImage->descrip, 0, 80);
487  strcpy(outputControlPointGridImage->descrip, "Control point position from NiftyReg (reg_f3d)");
488  if (strcmp("NiftyReg F3D2", REG->GetExecutableName()) == 0)
489  strcpy(outputControlPointGridImage->descrip, "Velocity field grid from NiftyReg (reg_f3d2)");
490  reg_io_WriteImageFile(outputControlPointGridImage, cppOutputName);
491  nifti_image_free(outputControlPointGridImage);
492  outputControlPointGridImage = NULL;
493 
494  // Save the backward control point result
495  if (REG->GetSymmetricStatus())
496  {
497  // _backward is added to the forward control point grid image name
498  std::string b(cppOutputName);
499  if (b.find(".nii.gz") != std::string::npos)
500  b.replace(b.find(".nii.gz"), 7, "_backward.nii.gz");
501  else if (b.find(".nii") != std::string::npos)
502  b.replace(b.find(".nii"), 4, "_backward.nii");
503  else if (b.find(".hdr") != std::string::npos)
504  b.replace(b.find(".hdr"), 4, "_backward.hdr");
505  else if (b.find(".img.gz") != std::string::npos)
506  b.replace(b.find(".img.gz"), 7, "_backward.img.gz");
507  else if (b.find(".img") != std::string::npos)
508  b.replace(b.find(".img"), 4, "_backward.img");
509  else if (b.find(".png") != std::string::npos)
510  b.replace(b.find(".png"), 4, "_backward.png");
511  else if (b.find(".nrrd") != std::string::npos)
512  b.replace(b.find(".nrrd"), 5, "_backward.nrrd");
513  else b.append("_backward.nii");
514  nifti_image *outputBackwardControlPointGridImage = REG->GetBackwardControlPointPositionImage();
515  memset(outputBackwardControlPointGridImage->descrip, 0, 80);
516  strcpy(outputBackwardControlPointGridImage->descrip, "Backward Control point position from NiftyReg (reg_f3d)");
517  if (strcmp("NiftyReg F3D2", REG->GetExecutableName()) == 0)
518  strcpy(outputBackwardControlPointGridImage->descrip, "Backward velocity field grid from NiftyReg (reg_f3d2)");
519  reg_io_WriteImageFile(outputBackwardControlPointGridImage, b.c_str());
520  nifti_image_free(outputBackwardControlPointGridImage);
521  outputBackwardControlPointGridImage = NULL;
522  }
523 
524  // Save the warped image result(s)
525  nifti_image **outputWarpedImage = (nifti_image **)malloc(2 * sizeof(nifti_image *));
526  outputWarpedImage[0] = NULL;
527  outputWarpedImage[1] = NULL;
528  outputWarpedImage = REG->GetWarpedImage();
529  if (outputName[0] == '\0') strcpy(outputName, "outputResult.nii");
530 
531  memset(outputWarpedImage[0]->descrip, 0, 80);
532  strcpy(outputWarpedImage[0]->descrip, "Warped image using NiftyReg (reg_f3d)");
533  if (strcmp("NiftyReg F3D SYM", REG->GetExecutableName()) == 0)
534  {
535  strcpy(outputWarpedImage[0]->descrip, "Warped image using NiftyReg (reg_f3d_sym)");
536  strcpy(outputWarpedImage[1]->descrip, "Warped image using NiftyReg (reg_f3d_sym)");
537  }
538  if (strcmp("NiftyReg F3D2", REG->GetExecutableName()) == 0)
539  {
540  strcpy(outputWarpedImage[0]->descrip, "Warped image using NiftyReg (reg_f3d2)");
541  strcpy(outputWarpedImage[1]->descrip, "Warped image using NiftyReg (reg_f3d2)");
542  }
543  if (REG->GetSymmetricStatus())
544  {
545  if (outputWarpedImage[1] != NULL)
546  {
547  std::string b(outputName);
548  if (b.find(".nii.gz") != std::string::npos)
549  b.replace(b.find(".nii.gz"), 7, "_backward.nii.gz");
550  else if (b.find(".nii") != std::string::npos)
551  b.replace(b.find(".nii"), 4, "_backward.nii");
552  else if (b.find(".hdr") != std::string::npos)
553  b.replace(b.find(".hdr"), 4, "_backward.hdr");
554  else if (b.find(".img.gz") != std::string::npos)
555  b.replace(b.find(".img.gz"), 7, "_backward.img.gz");
556  else if (b.find(".img") != std::string::npos)
557  b.replace(b.find(".img"), 4, "_backward.img");
558  else if (b.find(".png") != std::string::npos)
559  b.replace(b.find(".png"), 4, "_backward.png");
560  else if (b.find(".nrrd") != std::string::npos)
561  b.replace(b.find(".nrrd"), 5, "_backward.nrrd");
562  else b.append("_backward.nii");
563  reg_io_WriteImageFile(outputWarpedImage[1], b.c_str());
564  }
565  }
566  reg_io_WriteImageFile(outputWarpedImage[0], outputName);
567  if (outputWarpedImage[0] != NULL)
568  nifti_image_free(outputWarpedImage[0]);
569  outputWarpedImage[0] = NULL;
570  if (outputWarpedImage[1] != NULL)
571  nifti_image_free(outputWarpedImage[1]);
572  outputWarpedImage[1] = NULL;
573  free(outputWarpedImage);
574  outputWarpedImage = NULL;
575 #ifdef _USE_CUDA
576  cudaCommon_unsetCUDACard(&ctx);
577 #endif
578  // Erase the registration object
579  delete REG;
580 
581  // Clean the allocated images
582  if (referenceImage != NULL) nifti_image_free(referenceImage);
583  if (floatingImage != NULL) nifti_image_free(floatingImage);
584 
585  time_t end;
586  time(&end);
587  int minutes = (int)floorf(float(end - start) / 60.0f);
588  int seconds = (int)(end - start - 60 * minutes);
589 
590  emit registrationCompleted();
591  return 0;
592 }
593 
594 int milxQtRegistrationAlgos::aladin(milxQtRegistrationParams params)
595 {
596  time_t start;
597  time(&start);
598 
599  char referenceName[FILENAME_MAX + 1],
600  floatingName[FILENAME_MAX + 1],
601  outputName[FILENAME_MAX + 1];
602 
603  strncpy(referenceName, params.referenceName.toLatin1().constData(), FILENAME_MAX);
604  strncpy(floatingName, params.floatingName.toLatin1().constData(), FILENAME_MAX);
605  strncpy(outputName, params.outputName.toLatin1().constData(), FILENAME_MAX);
606 
607  int referenceImageFlag = 1;
608  int floatingImageFlag = 1;
609  int outputResultFlag = 1;
610 
611  int maxIter = params.maxit;
612  int symFlag = params.useSym;
613  int nLevels = params.ln;
614  int levelsToPerform = params.lp;
615  float blockPercentage = params.percentBlock;
616  int affineFlag = 1;
617  int rigidFlag = 1;
618 
619  if (params.rigOnly)
620  {
621  rigidFlag = 1;
622  affineFlag = 0;
623  }
624 
625  if (params.affineDirect)
626  {
627  rigidFlag = 0;
628  affineFlag = 1;
629  }
630 
631  char *outputAffineName = NULL;
632  int outputAffineFlag = 0;
633 
634  char *referenceMaskName = NULL;
635  int referenceMaskFlag = 0;
636 
637 // char *floatingMaskName = NULL;
638 // int floatingMaskFlag = 0;
639 
640  float inlierLts=50.0f;
641  int alignCentre=1;
642  int interpolation = 1;
643  float floatingSigma = 0.0;
644  float referenceSigma=0.0;
645 
646  if (!referenceImageFlag || !floatingImageFlag) {
647  //fprintf(stderr, "Err:\tThe reference and the floating image have to be defined.\n");
648  emit error("aladin()", "Aladin registration error: The reference and the floating image have to be defined");
649  return 1;
650  }
651 
652  reg_aladin<PrecisionTYPE> *REG;
653 //#ifdef _BUILD_NR_DEV ///using git version 83d8d1182ed4c227ce4764f1fdab3b1797eecd8d
654  if (symFlag)
655  {
656  REG = new reg_aladin_sym<PrecisionTYPE>;
657  fprintf(stdout, "Using symmetric Aladin\n");
658 // if ((referenceMaskFlag && !floatingMaskName) || (!referenceMaskFlag && floatingMaskName))
659 // {
660  //fprintf(stderr, "[NiftyReg Warning] You have one image mask option turned on but not the other.\n");
661  //fprintf(stderr, "[NiftyReg Warning] This will affect the degree of symmetry achieved.\n");
662 // }
663  }
664  else
665  {
666 //#endif
667  REG = new reg_aladin<PrecisionTYPE>;
668 //#ifdef _BUILD_NR_DEV
669 // if (floatingMaskFlag)
670 // {
671  //fprintf(stderr, "Note: Floating mask flag only used in symmetric method. Ignoring this option\n");
672 // }
673  }
674 //#endif
675  REG->SetMaxIterations(maxIter);
676  REG->SetNumberOfLevels(nLevels);
677  REG->SetLevelsToPerform(levelsToPerform);
678  REG->SetReferenceSigma(referenceSigma);
679  REG->SetFloatingSigma(floatingSigma);
680  REG->SetAlignCentre(alignCentre);
681  REG->SetPerformAffine(affineFlag);
682  REG->SetPerformRigid(rigidFlag);
683  REG->SetBlockPercentage(blockPercentage);
684  REG->SetInlierLts(inlierLts);
685  REG->SetInterpolation(interpolation);
686 
687  if (REG->GetLevelsToPerform() > REG->GetNumberOfLevels())
688  REG->SetLevelsToPerform(REG->GetNumberOfLevels());
689 
690  /* Read the reference image and check its dimension */
691  nifti_image *referenceHeader = reg_io_ReadImageFile(referenceName);
692  if (referenceHeader == NULL) {
693  //fprintf(stderr, "* ERROR Error when reading the reference image: %s\n", referenceImageName);
694  emit error("aladin()", "Aladin registration error: Error when reading the reference image (\"" + QString(referenceName) + "\").");
695  return 1;
696  }
697 
698  /* Read teh floating image and check its dimension */
699  nifti_image *floatingHeader = reg_io_ReadImageFile(floatingName);
700  if (floatingHeader == NULL) {
701  //fprintf(stderr, "* ERROR Error when reading the floating image: %s\n", floatingImageName);
702  emit error("aladin()", "Aladin registration error: Error when reading the floating image (\"" + QString(floatingName) + "\").");
703  return 1;
704  }
705 
706  // Set the reference and floating image
707  REG->SetInputReference(referenceHeader);
708  REG->SetInputFloating(floatingHeader);
709 
710  /* read the reference mask image */
711  nifti_image *referenceMaskImage = NULL;
712  if (referenceMaskFlag) {
713  referenceMaskImage = reg_io_ReadImageFile(referenceMaskName);
714  if (referenceMaskImage == NULL) {
715  //fprintf(stderr, "* ERROR Error when reading the reference mask image: %s\n", referenceMaskName);
716  emit error("aladin()", "Aladin registration error: Error when reading the reference mask image (\"" + QString(referenceMaskName) + "\").");
717  return 1;
718  }
719  /* check the dimension */
720  for (int i = 1; i <= referenceHeader->dim[0]; i++) {
721  if (referenceHeader->dim[i] != referenceMaskImage->dim[i]) {
722  //fprintf(stderr, "* ERROR The reference image and its mask do not have the same dimension\n");
723  emit error("aladin()", "Aladin registration error: The reference image and its mask do not have the same dimension.");
724  return 1;
725  }
726  }
727  REG->SetInputMask(referenceMaskImage);
728  }
729 #ifdef _BUILD_NR_DEV
730  nifti_image *floatingMaskImage = NULL;
731  if (floatingMaskFlag && symFlag) {
732  floatingMaskImage = reg_io_ReadImageFile(floatingMaskName);
733  if (floatingMaskImage == NULL) {
734  //fprintf(stderr, "* ERROR Error when reading the floating mask image: %s\n", referenceMaskName);
735  emit error("aladin()", "Aladin registration error: Error when reading the floating mask image (\"" + QString(floatingMaskName) + "\").");
736  return 1;
737  }
738  /* check the dimension */
739  for (int i = 1; i <= floatingHeader->dim[0]; i++) {
740  if (floatingHeader->dim[i] != floatingMaskImage->dim[i]) {
741  //fprintf(stderr, "* ERROR The floating image and its mask do not have the same dimension\n");
742  emit error("aladin()", "Aladin registration error: Error the floating image and its mask do not have the same dimension.");
743  return 1;
744  }
745  }
746  REG->SetInputFloatingMask(floatingMaskImage);
747  }
748 #endif
749  REG->Run();
750 
751  // The warped image is saved
752  nifti_image *outputResultImage = REG->GetFinalWarpedImage();
753  if (!outputResultFlag) strcpy(outputName, "outputResult.nii.gz");
754  reg_io_WriteImageFile(outputResultImage, outputName);
755  nifti_image_free(outputResultImage);
756 
757  /* The affine transformation is saved */
758  if (outputAffineFlag)
759  reg_tool_WriteAffineFile(REG->GetTransformationMatrix(), outputAffineName);
760  else reg_tool_WriteAffineFile(REG->GetTransformationMatrix(), (char *)"outputAffine.txt");
761 
762  nifti_image_free(referenceHeader);
763  nifti_image_free(floatingHeader);
764 
765  delete REG;
766  time_t end;
767  time(&end);
768  int minutes = (int)floorf((end - start) / 60.0f);
769  int seconds = (int)(end - start - 60 * minutes);
770 
771 
772  emit registrationCompleted();
773  return 0;
774 }
775 
776 int milxQtRegistrationAlgos::similarities(milxQtRegistration * image)
777 {
778 
779  milxQtSimilarities similarities;
780 
781  // We compute the similarity before the registration (i == 0) and after the registration (i == 1)
782  for (int i = 0; i < 2; i++)
783  {
784  QString similarityOutput = image->createFile(QDir::tempPath() + QDir::separator() + "similarity_XXXXXX.txt");
785  char referenceName[FILENAME_MAX + 1],
786  floatingName[FILENAME_MAX + 1],
787  outputName[FILENAME_MAX + 1];
788 
789  strncpy(referenceName, image->reference->getPath().toLatin1().constData(), FILENAME_MAX);
790 
791  if (i == 0)
792  strncpy(floatingName, image->getPath().toLatin1().constData(), FILENAME_MAX);
793  else if (i == 1)
794  strncpy(floatingName, image->getOutputPath().toLatin1().constData(), FILENAME_MAX);
795 
796  strncpy(outputName, similarityOutput.toLatin1().constData(), FILENAME_MAX);
797 
798 
799  /* Read the reference image */
800  nifti_image *refImage = reg_io_ReadImageFile(referenceName);
801  if (refImage == NULL)
802  {
803  emit error("similarity()", "Similarity measure error: Error when reading the reference image (\"" + QString(referenceName) + "\").");
804  return 1;
805  }
806  reg_checkAndCorrectDimension(refImage);
807  reg_tools_changeDatatype<float>(refImage);
808 
809  /* Read the floating image */
810  nifti_image *floImage = reg_io_ReadImageFile(floatingName);
811  if (floImage == NULL)
812  {
813  emit error("similarity()", "Similarity measure error: Error when reading the floating image (\"" + QString(floatingName) + "\").");
814  return 1;
815  }
816  reg_checkAndCorrectDimension(floImage);
817  reg_tools_changeDatatype<float>(floImage);
818 
819  /* Read and create the mask array */
820  int *refMask = NULL;
821  int refMaskVoxNumber = refImage->nx*refImage->ny*refImage->nz;
822  refMask = (int *)calloc(refMaskVoxNumber, sizeof(int));
823  for (int j = 0; j<refMaskVoxNumber; ++j) refMask[j] = j;
824 
825 
826  /* Create the warped floating image */
827  nifti_image *warpedFloImage = nifti_copy_nim_info(refImage);
828  warpedFloImage->ndim = warpedFloImage->dim[0] = floImage->ndim;
829  warpedFloImage->nt = warpedFloImage->dim[4] = floImage->nt;
830  warpedFloImage->nu = warpedFloImage->dim[5] = floImage->nu;
831  warpedFloImage->nvox = (size_t)warpedFloImage->nx * warpedFloImage->ny *
832  warpedFloImage->nz * warpedFloImage->nt * warpedFloImage->nu;
833  warpedFloImage->cal_min = floImage->cal_min;
834  warpedFloImage->cal_max = floImage->cal_max;
835  warpedFloImage->scl_inter = floImage->scl_inter;
836  warpedFloImage->scl_slope = floImage->scl_slope;
837  warpedFloImage->datatype = floImage->datatype;
838  warpedFloImage->nbyper = floImage->nbyper;
839  warpedFloImage->data = (void *)malloc(warpedFloImage->nvox*warpedFloImage->nbyper);
840 
841  /* Create the deformation field */
842  nifti_image *defField = nifti_copy_nim_info(refImage);
843  defField->ndim = defField->dim[0] = 5;
844  defField->nt = defField->dim[4] = 1;
845  defField->nu = defField->dim[5] = refImage->nz>1 ? 3 : 2;
846  defField->nvox = (size_t)defField->nx * defField->ny *
847  defField->nz * defField->nt * defField->nu;
848  defField->datatype = NIFTI_TYPE_FLOAT32;
849  defField->nbyper = sizeof(float);
850  defField->data = (void *)calloc(defField->nvox, defField->nbyper);
851  defField->scl_slope = 1.f;
852  defField->scl_inter = 0.f;
853  reg_tools_multiplyValueToImage(defField, defField, 0.f);
854  defField->intent_p1 = DISP_FIELD;
855  reg_getDeformationFromDisplacement(defField);
856 
857  /* Warp the floating image */
858  reg_resampleImage(floImage,
859  warpedFloImage,
860  defField,
861  refMask,
862  3,
863  std::numeric_limits<float>::quiet_NaN());
864  nifti_image_free(defField);
865 
866  FILE *outFile = NULL;
867  outFile = fopen(outputName, "w");
868 
869  /* Compute the NCC if required */
870  {
871  float *refPtr = static_cast<float *>(refImage->data);
872  float *warPtr = static_cast<float *>(warpedFloImage->data);
873  double refMeanValue = 0.;
874  double warMeanValue = 0.;
875  refMaskVoxNumber = 0;
876  for (size_t i = 0; i<refImage->nvox; ++i) {
877  if (refMask[i]>-1 && refPtr[i] == refPtr[i] && warPtr[i] == warPtr[i]) {
878  refMeanValue += refPtr[i];
879  warMeanValue += warPtr[i];
880  ++refMaskVoxNumber;
881  }
882  }
883  if (refMaskVoxNumber == 0)
884  fprintf(stderr, "No active voxel\n");
885  refMeanValue /= (double)refMaskVoxNumber;
886  warMeanValue /= (double)refMaskVoxNumber;
887  double refSTDValue = 0.;
888  double warSTDValue = 0.;
889  double measure = 0.;
890  for (size_t i = 0; i<refImage->nvox; ++i) {
891  if (refMask[i]>-1 && refPtr[i] == refPtr[i] && warPtr[i] == warPtr[i]) {
892  refSTDValue += reg_pow2((double)refPtr[i] - refMeanValue);
893  warSTDValue += reg_pow2((double)warPtr[i] - warMeanValue);
894  measure += ((double)refPtr[i] - refMeanValue) *
895  ((double)warPtr[i] - warMeanValue);
896  }
897  }
898  refSTDValue /= (double)refMaskVoxNumber;
899  warSTDValue /= (double)refMaskVoxNumber;
900  measure /= sqrt(refSTDValue)*sqrt(warSTDValue)*
901  (double)refMaskVoxNumber;
902  if (outFile != NULL)
903  fprintf(outFile, "%g\n", measure);
904  else printf("NCC: %g\n", measure);
905  }
906  /* Compute the LNCC if required */
907  {
908  reg_lncc *lncc_object = new reg_lncc();
909  for (int j = 0; j < (refImage->nt < warpedFloImage->nt ? refImage->nt : warpedFloImage->nt); ++j)
910  lncc_object->SetActiveTimepoint(j);
911  lncc_object->InitialiseMeasure(refImage,
912  warpedFloImage,
913  refMask,
914  warpedFloImage,
915  NULL,
916  NULL);
917  double measure = lncc_object->GetSimilarityMeasureValue();
918  if (outFile != NULL)
919  fprintf(outFile, "%g\n", measure);
920  else printf("LNCC: %g\n", measure);
921  delete lncc_object;
922  }
923  /* Compute the NMI if required */
924  {
925  reg_nmi *nmi_object = new reg_nmi();
926  for (int j = 0; j < (refImage->nt < warpedFloImage->nt ? refImage->nt : warpedFloImage->nt); ++j)
927  nmi_object->SetActiveTimepoint(i);
928  nmi_object->InitialiseMeasure(refImage,
929  warpedFloImage,
930  refMask,
931  warpedFloImage,
932  NULL,
933  NULL);
934  double measure = nmi_object->GetSimilarityMeasureValue();
935  if (outFile != NULL)
936  fprintf(outFile, "%g\n", measure);
937  else printf("NMI: %g\n", measure);
938  delete nmi_object;
939  }
940  /* Compute the SSD if required */
941  {
942  reg_ssd *ssd_object = new reg_ssd();
943  for (int j = 0; j < (refImage->nt < warpedFloImage->nt ? refImage->nt : warpedFloImage->nt); ++j)
944  ssd_object->SetActiveTimepoint(i);
945  ssd_object->InitialiseMeasure(refImage,
946  warpedFloImage,
947  refMask,
948  warpedFloImage,
949  NULL,
950  NULL);
951  double measure = ssd_object->GetSimilarityMeasureValue();
952  if (outFile != NULL)
953  fprintf(outFile, "%g\n", measure);
954  else printf("SSD: %g\n", measure);
955  delete ssd_object;
956  }
957  // Close the output file if required
958  if (outFile != NULL)
959  fclose(outFile);
960 
961  // Free the allocated images
962  nifti_image_free(refImage);
963  nifti_image_free(floImage);
964  free(refMask);
965 
966  // Read the results
967  QFile inputFile(similarityOutput);
968  if (inputFile.open(QIODevice::ReadOnly))
969  {
970  int lineNumber = 0;
971  QTextStream in(&inputFile);
972  while (!in.atEnd())
973  {
974  QString line = in.readLine();
975  bool ok = false;
976  double value = line.toDouble(&ok);
977 
978  if (ok && lineNumber == 0) {
979  similarities.ncc = value;
980  }
981  else if (ok && lineNumber == 1) {
982  similarities.lncc = value;
983  }
984  else if (ok && lineNumber == 2) {
985  similarities.nmi = value;
986  }
987  else if (ok && lineNumber == 3) {
988  similarities.ssd = value;
989  }
990 
991  lineNumber++;
992  }
993 
994  if (i == 0)
995  image->similarities_before = similarities;
996  else if (i == 1)
997  image->similarities_after = similarities;
998 
999 
1000  inputFile.close();
1001  }
1002 
1003  // Remove the file
1004  if (QFile::exists(similarityOutput))
1005  {
1006  QFile::remove(similarityOutput);
1007  }
1008  }
1009 
1010 
1011  emit similaritiesComputed();
1012  return 0;
1013 }
1014 
1015 #endif
1016 
1017 #ifdef USE_ELASTIX
1018 
1019 void milxQtRegistrationAlgos::elastix_async(milxQtRegistrationParams params)
1020 {
1021  future = QtConcurrent::run(this, &milxQtRegistrationAlgos::elastix, params);
1022 }
1023 
1024 int milxQtRegistrationAlgos::elastix(milxQtRegistrationParams params)
1025 {
1026  // Create the arguments from the parameters
1027  QStringList args;
1028  args.append("smilx.exe");
1029 
1030  args.append("-f");
1031  args.append(params.referenceName);
1032 
1033  args.append("-m");
1034  args.append(params.floatingName);
1035 
1036  args.append("-out");
1037  args.append(params.outputFolder);
1038 
1039  args.append("-p");
1040  args.append(params.parameterFile);
1041 
1042  // Some typedef's.
1043  typedef elx::ElastixMain ElastixMainType;
1044  typedef ElastixMainType::Pointer ElastixMainPointer;
1045  typedef std::vector< ElastixMainPointer > ElastixMainVectorType;
1046  typedef ElastixMainType::ObjectPointer ObjectPointer;
1047  typedef ElastixMainType::DataObjectContainerPointer DataObjectContainerPointer;
1048  typedef ElastixMainType::FlatDirectionCosinesType FlatDirectionCosinesType;
1049 
1050  typedef ElastixMainType::ArgumentMapType ArgumentMapType;
1051  typedef ArgumentMapType::value_type ArgumentMapEntryType;
1052 
1053  typedef std::pair< std::string, std::string > ArgPairType;
1054  typedef std::queue< ArgPairType > ParameterFileListType;
1055  typedef ParameterFileListType::value_type ParameterFileListEntryType;
1056 
1057  // Support Mevis Dicom Tiff (if selected in cmake)
1058  RegisterMevisDicomTiff();
1059 
1060  // Some declarations and initialisations.
1061  ElastixMainVectorType elastices;
1062 
1063  ObjectPointer transform = 0;
1064  DataObjectContainerPointer fixedImageContainer = 0;
1065  DataObjectContainerPointer movingImageContainer = 0;
1066  DataObjectContainerPointer fixedMaskContainer = 0;
1067  DataObjectContainerPointer movingMaskContainer = 0;
1068  FlatDirectionCosinesType fixedImageOriginalDirection;
1069  int returndummy = 0;
1070  unsigned long nrOfParameterFiles = 0;
1071  ArgumentMapType argMap;
1072  ParameterFileListType parameterFileList;
1073  bool outFolderPresent = false;
1074  std::string outFolder = "";
1075  std::string logFileName = "";
1076 
1077  // Put command line parameters into parameterFileList.
1078  for (unsigned int i = 1; static_cast<long>(i) < (args.count() - 1); i += 2)
1079  {
1080  std::string key(args[i].toStdString());
1081  std::string value(args[i + 1].toStdString());
1082 
1083  if (key == "-p")
1084  {
1085  // Queue the ParameterFileNames.
1086  nrOfParameterFiles++;
1087  parameterFileList.push(
1088  ParameterFileListEntryType(key.c_str(), value.c_str()));
1089  // The different '-p' are stored in the argMap, with
1090  // keys p(1), p(2), etc.
1091  std::ostringstream tempPname("");
1092  tempPname << "-p(" << nrOfParameterFiles << ")";
1093  std::string tempPName = tempPname.str();
1094  argMap.insert(ArgumentMapEntryType(tempPName.c_str(), value.c_str()));
1095  }
1096  else
1097  {
1098  if (key == "-out")
1099  {
1100  // Make sure that last character of the output folder equals a '/' or '\'.
1101  const char last = value[value.size() - 1];
1102  if (last != '/' && last != '\\') {
1103  value.append("/");
1104  }
1105  value = itksys::SystemTools::ConvertToOutputPath(value.c_str());
1106 
1107  // Note that on Windows, in case the output folder contains a space,
1108  // the path name is double quoted by ConvertToOutputPath, which is undesirable.
1109  // So, we remove these quotes again.
1110 
1111  if (itksys::SystemTools::StringStartsWith(value.c_str(), "\"")
1112  && itksys::SystemTools::StringEndsWith(value.c_str(), "\""))
1113  {
1114  value = value.substr(1, value.length() - 2);
1115  }
1116 
1117  // Save this information.
1118  outFolderPresent = true;
1119  outFolder = value;
1120 
1121  } // end if key == "-out"
1122 
1123  // Attempt to save the arguments in the ArgumentMap.
1124  if (argMap.count(key.c_str()) == 0)
1125  {
1126  argMap.insert(ArgumentMapEntryType(key.c_str(), value.c_str()));
1127  }
1128  else
1129  {
1130  // Duplicate arguments.
1131  std::cerr << "WARNING!" << std::endl;
1132  std::cerr << "Argument " << key.c_str() << "is only required once." << std::endl;
1133  std::cerr << "Arguments " << key.c_str() << " " << value.c_str() << "are ignored" << std::endl;
1134  }
1135 
1136  } // end else (so, if key does not equal "-p")
1137 
1138  } // end for loop
1139 
1140  // The argv0 argument, required for finding the component.dll/so's.
1141  argMap.insert(ArgumentMapEntryType("-argv0", args[0].toStdString()));
1142 
1143  // Check if at least once the option "-p" is given.
1144  if (nrOfParameterFiles == 0)
1145  {
1146  std::cerr << "ERROR: No CommandLine option \"-p\" given!" << std::endl;
1147  returndummy |= -1;
1148  }
1149 
1150  // Check if the -out option is given.
1151  if (outFolderPresent)
1152  {
1153  // Check if the output directory exists.
1154  bool outFolderExists = itksys::SystemTools::FileIsDirectory(outFolder.c_str());
1155  if (!outFolderExists)
1156  {
1157  std::cerr << "ERROR: the output directory \"" << outFolder << "\" does not exist." << std::endl;
1158  std::cerr << "You are responsible for creating it." << std::endl;
1159  returndummy |= -2;
1160  }
1161  else
1162  {
1163  // Setup xout.
1164  // CODE REMOVE FROM HERE, AND ADDED IN MILX REGISTRATION WINDOW, WE ONLY EXECUTE THE SETUP ONCE
1165  /*
1166  logFileName = outFolder + "elastix.log";
1167  int returndummy2 = elx::xoutSetup(logFileName.c_str(), false, false);
1168  if (returndummy2)
1169  {
1170  std::cerr << "ERROR while setting up xout." << std::endl;
1171  }
1172  returndummy |= returndummy2;
1173  */
1174  }
1175  }
1176  else
1177  {
1178  returndummy = -2;
1179  std::cerr << "ERROR: No CommandLine option \"-out\" given!" << std::endl;
1180  }
1181 
1182  // Stop if some fatal errors occurred.
1183  if (returndummy)
1184  {
1185  emit error("elastix()", "Elastix registration error, error code: " + QString::number(returndummy) + ".");
1186  return returndummy;
1187  }
1188 
1189  elxout << std::endl;
1190 
1191  // Declare a timer, start it and print the start time.
1192  tmr::Timer::Pointer totaltimer = tmr::Timer::New();
1193  totaltimer->StartTimer();
1194  elxout << "elastix is started at " << totaltimer->PrintStartTime()
1195  << ".\n" << std::endl;
1196 
1197  // Print where elastix was run.
1198  // elxout << "which elastix: " << argv[0] << std::endl;
1199  itksys::SystemInformation info;
1200  info.RunCPUCheck();
1201  info.RunOSCheck();
1202  info.RunMemoryCheck();
1203  elxout << "elastix runs at: " << info.GetHostname() << std::endl;
1204  elxout << " " << info.GetOSName() << " "
1205  << info.GetOSRelease() << (info.Is64Bits() ? " (x64), " : ", ")
1206  << info.GetOSVersion() << std::endl;
1207  elxout << " with " << info.GetTotalPhysicalMemory() << " MB memory, and "
1208  << info.GetNumberOfPhysicalCPU() << " cores @ "
1209  << static_cast< unsigned int >(info.GetProcessorClockFrequency())
1210  << " MHz." << std::endl;
1211 
1212  // ********************* START REGISTRATION *********************
1213  //
1214  // Do the (possibly multiple) registration(s).
1215 
1216  for (unsigned int i = 0; i < nrOfParameterFiles; i++)
1217  {
1218  // Create another instance of ElastixMain.
1219  elastices.push_back(ElastixMainType::New());
1220 
1221  // Set stuff we get from a former registration.
1222  elastices[i]->SetInitialTransform(transform);
1223  elastices[i]->SetFixedImageContainer(fixedImageContainer);
1224  elastices[i]->SetMovingImageContainer(movingImageContainer);
1225  elastices[i]->SetFixedMaskContainer(fixedMaskContainer);
1226  elastices[i]->SetMovingMaskContainer(movingMaskContainer);
1227  elastices[i]->SetOriginalFixedImageDirectionFlat(fixedImageOriginalDirection);
1228 
1229  // Set the current elastix-level.
1230  elastices[i]->SetElastixLevel(i);
1231  elastices[i]->SetTotalNumberOfElastixLevels(nrOfParameterFiles);
1232 
1233  // Delete the previous ParameterFileName.
1234  if (argMap.count("-p"))
1235  {
1236  argMap.erase("-p");
1237  }
1238 
1239  // Read the first parameterFileName in the queue.
1240  ArgPairType argPair = parameterFileList.front();
1241  parameterFileList.pop();
1242 
1243  // Put it in the ArgumentMap.
1244  argMap.insert(ArgumentMapEntryType(argPair.first, argPair.second));
1245 
1246  // Print a start message.
1247  elxout << "-------------------------------------------------------------------------" << "\n" << std::endl;
1248  elxout << "Running elastix with parameter file " << i
1249  << ": \"" << argMap["-p"] << "\".\n" << std::endl;
1250 
1251  // Declare a timer, start it and print the start time.
1252  tmr::Timer::Pointer timer = tmr::Timer::New();
1253  timer->StartTimer();
1254  elxout << "Current time: " << timer->PrintStartTime() << "." << std::endl;
1255 
1256  // Start registration.
1257  returndummy = elastices[i]->Run(argMap);
1258 
1259  // Check for errors.
1260  if (returndummy != 0)
1261  {
1262  xl::xout["error"] << "Errors occurred!" << std::endl;
1263  emit error("elastix()", "Elastix registration error, error code: " + QString::number(returndummy) + ".");
1264  return returndummy;
1265  }
1266 
1267  // Get the transform, the fixedImage and the movingImage
1268  // in order to put it in the (possibly) next registration.
1269 
1270  transform = elastices[i]->GetFinalTransform();
1271  fixedImageContainer = elastices[i]->GetFixedImageContainer();
1272  movingImageContainer = elastices[i]->GetMovingImageContainer();
1273  fixedMaskContainer = elastices[i]->GetFixedMaskContainer();
1274  movingMaskContainer = elastices[i]->GetMovingMaskContainer();
1275  fixedImageOriginalDirection = elastices[i]->GetOriginalFixedImageDirectionFlat();
1276 
1277  // Print a finish message.
1278  elxout << "Running elastix with parameter file " << i
1279  << ": \"" << argMap["-p"] << "\", has finished.\n" << std::endl;
1280 
1281  // Stop timer and print it.
1282  timer->StopTimer();
1283  elxout << "\nCurrent time: " << timer->PrintStopTime() << "." << std::endl;
1284  elxout << "Time used for running elastix with this parameter file: "
1285  << timer->PrintElapsedTimeDHMS() << ".\n" << std::endl;
1286 
1287  // Try to release some memory.
1288  elastices[i] = 0;
1289 
1290  } // end loop over registrations
1291 
1292  elxout << "-------------------------------------------------------------------------" << "\n" << std::endl;
1293 
1294  // Stop totaltimer and print it.
1295  totaltimer->StopTimer();
1296  elxout << "Total time elapsed: " << totaltimer->PrintElapsedTimeDHMS() << ".\n" << std::endl;
1297 
1298  // Make sure all the components that are defined in a Module (.DLL/.so)
1299  // are deleted before the modules are closed.
1300 
1301  for (unsigned int i = 0; i < nrOfParameterFiles; i++)
1302  {
1303  elastices[i] = 0;
1304  }
1305 
1306  transform = 0;
1307  fixedImageContainer = 0;
1308  movingImageContainer = 0;
1309  fixedMaskContainer = 0;
1310  movingMaskContainer = 0;
1311 
1312  // Close the modules.
1313  ElastixMainType::UnloadComponents();
1314 
1315  // Remove all unecessary files
1316  elastixClean(params);
1317 
1318  // Exit and return the error code.
1319  emit registrationCompleted();
1320  return returndummy;
1321 }
1322 
1323 void milxQtRegistrationAlgos::elastixClean(milxQtRegistrationParams params)
1324 {
1325  // copy output to the correct path
1326  // we look for the output
1327  QString src_basepath = params.outputFolder + "/" + "result.";
1328  QString src_path;
1329 
1330  int i = -1;
1331  do
1332  {
1333  i++;
1334  src_path = src_basepath + QString::number(i) +".nii";
1335  } while (QFile::exists(src_path));
1336 
1337  i--;
1338 
1339  if (i != -1)
1340  {
1341  src_path = src_basepath + QString::number(i) + ".nii";
1342  if (QFile::exists(params.outputName))
1343  {
1344  QFile::remove(params.outputName);
1345  }
1346  QFile::copy(src_path, params.outputName);
1347  QFile::remove(src_path);
1348  }
1349 
1350  // remove file
1351  QDir directory(params.outputFolder);
1352  QStringList nameFilter;
1353  nameFilter << "elastix.log" << "IterationInfo.*" << "TransformParameters.*" << "result.*";
1354  QStringList fileList = directory.entryList(nameFilter);
1355 
1356  for (i = 0; i < fileList.size(); i++)
1357  {
1358  QString filepath = params.outputFolder + "/" + fileList[i];
1359  if (QFile::exists(filepath))
1360  {
1361  QFile::remove(filepath);
1362  }
1363  }
1364 }
1365 #endif
Contain all the values of similarity measurement.
QFuture< int > future
Used to start the functions asynchroniously.
Contain all the informations and functions required to register an image.
void affine_async(milxQtRegistrationParams params)
Perform a ITK affine registration asynchroniously.
QString getPath()
Get the path of the file.
milxQtRegistrationAlgos(QObject *parent)
The standard constructor.
void error(QString functionName, QString errorMsg)
An error happened during the registration.
void registrationCompleted()
The registration has been completed.
double ncc
Normalized Cross Correlation.
QString createFile(QString pathtemplate)
Create a file and return the path.
milxQtSimilarities similarities_after
Similarities after the registration.
int demon(milxQtRegistrationParams params)
Perform a ITK demon registration.
double ssd
Sum Squared Difference.
int affine(milxQtRegistrationParams params)
Perform a ITK affine registration.
milxQtRegistration * reference
Reference image for the registration.
double nmi
Normalize mutual information.
milxQtSimilarities similarities_before
Similarities before the registration.
void demon_async(milxQtRegistrationParams params)
Perform a ITK demon registration asynchroniously.
double lncc
Localy Normalized Cross Correlation.
QString getOutputPath()
Return the path of the output file.