SMILX  1.01
milxQtDICOMPlugin.cpp
1 /*=========================================================================
2  The Software is copyright (c) Commonwealth Scientific and Industrial Research Organisation (CSIRO)
3  ABN 41 687 119 230.
4  All rights reserved.
5 
6  Licensed under the CSIRO BSD 3-Clause License
7  You may not use this file except in compliance with the License.
8  You may obtain a copy of the License in the file LICENSE.md or at
9 
10  https://stash.csiro.au/projects/SMILI/repos/smili/browse/license.txt
11 
12  Unless required by applicable law or agreed to in writing, software
13  distributed under the License is distributed on an "AS IS" BASIS,
14  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  See the License for the specific language governing permissions and
16  limitations under the License.
17 =========================================================================*/
18 #include "milxQtDICOMPlugin.h"
19 
20 #include <qplugin.h>
21 
22 #include <milxGlobal.h>
23 
24 //Image typedefs
25 typedef unsigned char charPixelType;
26 typedef itk::Image<charPixelType, milx::imgDimension> charImageType;
27 typedef short shortPixelType;
28 typedef itk::Image<shortPixelType, milx::imgDimension> shortImageType;
29 typedef unsigned short ushortPixelType;
30 typedef itk::Image<ushortPixelType, milx::imgDimension> ushortImageType;
31 typedef int intPixelType;
32 typedef itk::Image<intPixelType, milx::imgDimension> intImageType;
33 typedef unsigned int uintPixelType;
34 typedef itk::Image<intPixelType, milx::imgDimension> uintImageType;
35 typedef float floatPixelType;
36 typedef itk::Image<floatPixelType, milx::imgDimension> floatImageType;
37 typedef itk::VectorImage<floatPixelType, milx::imgDimension> vectorImageType;
38 
40 {
42  MainWindow = qobject_cast<milxQtMain *>(theParent);
43 
44  threaded = false;
45  dockable = true;
46  consoleWindow = false;
47  extension = true;
48  pluginName = "DICOM";
49  //~ dataName = "";
50  valid = true;
51 
52  manager = new milxQtManager(MainWindow);
53  manager->hide();
54  dock = new QDockWidget(tr("DICOM Manager"), MainWindow);
55  dock->setFeatures(QDockWidget::AllDockWidgetFeatures);
56  dock->setWidget(manager);
57  dock->setObjectName("DICOM Manager");
58 
59  createActions();
60  createMenu();
61  createWizard();
62  createRTWizard();
63  createConnections();
65 }
66 
67 milxQtDICOMPlugin::~milxQtDICOMPlugin()
68 {
69  if(isRunning() && threaded)
70  quit();
71  cout << "DICOM Plugin Destroyed." << endl;
72 }
73 
75 {
76  return pluginName;
77 }
78 
80 {
81  QString openPythonExt = "";
82 
83  return openPythonExt;
84 }
85 
87 {
88  QStringList exts;
89 
90  return exts;
91 }
92 
94 {
95  QStringList exts;
96 
97  return exts;
98 }
99 
101 {
102  QString savePythonExt = "";
103 
104  return savePythonExt;
105 }
106 
107 void milxQtDICOMPlugin::SetInputCollection(vtkPolyDataCollection* collection, QStringList &filenames)
108 {
109 
110 }
111 
112 void milxQtDICOMPlugin::open(QString filename)
113 {
114 
115 }
116 
117 void milxQtDICOMPlugin::save(QString filename)
118 {
119 
120 }
121 
123 {
124  return NULL;
125 } //No image result
126 
128 {
129  //~ denoiseModel = new milxQtDICOMModel;
130 
131  return NULL;
132  //~ return denoiseModel;
133 } //No image result
134 
136 {
137  return NULL;
138 } //No image result
139 
141 {
142  return dock;
143 }
144 
146 {
147  //~ if(pluginWindow(window) == 0)
148  return false;
149  //~ else
150  //~ return true;
151 }
152 
153 //~ milxQtDeNoiseModel* milxQtDeNoisePlugin::pluginWindow(QWidget *window)
154 //~ {
155  //~ if(window)
156  //~ return qobject_cast<milxQtDeNoiseModel *>(window);
157  //~ return 0;
158 //~ }
159 
161 {
162  //~ if(!MainWindow->isActiveModel())
163  //~ return;
164 
165  //~ milxQtModel *currentWin = MainWindow->activeModel();
166  //~ milxQtDeNoiseModel *denoiseModel = new milxQtDeNoiseModel(MainWindow); //hierarchical deletion
167  //~ denoiseModel->setName(currentWin->getName());
168  //~ denoiseModel->SetInput(currentWin->GetOutput());
169  //~ denoiseModel->generateModel();
170 
171  //~ MainWindow->display(denoiseModel);
172 }
173 
174 //~ void milxQtDICOMPlugin::run()
175 //~ {
176  //~ QMutexLocker locker(&mutex); //Lock memory
177 
178  //~ ///Execute own thread work here
179 
180  //~ //exec();
181 //~ }
182 
183 //~ void milxQtDICOMPlugin::createConnections()
184 //~ {
185  //~ //QObject::connect(denoiseAct, SIGNAL(triggered(bool)), denoiseModel, SLOT(denoise()));
186 //~ }
187 
189 {
190  bool success = true;
191  QString directoryPath;
192  QPointer<QFileDialog> fileOpener = new QFileDialog;
193  QSettings settings("Shekhar Chandra", "milxQt");
194 
196  if(directoryPath.isEmpty())
197  {
198  QString path = settings.value("recentPath").toString();
199  directoryPath = fileOpener->getExistingDirectory(NULL, tr("Open DICOM Directory"),
200  path,
201  QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
202  }
203 
204  if(directoryPath.isEmpty())
205  return;
206 
208  MainWindow->printInfo("Trying to read DICOMs in " + directoryPath);
209  qApp->processEvents();
210  std::vector<std::string> UIDs = milx::File::GetDICOMSeriesUIDs(directoryPath.toStdString());
211 
213  QStringList directories;
214  if(UIDs.empty())
215  {
216  MainWindow->printWarning("Found no series found in input directory. Checking internal directories");
217  QDir directory(directoryPath);
218  directory.setFilter(QDir::AllDirs | QDir::NoDotAndDotDot | QDir::NoSymLinks);
219  directories = directory.entryList();
220  }
221  else
222  {
223  MainWindow->printInfo(QString("Total of ") + QString::number(UIDs.size()) + " UID(s) found");
224  directories.push_back("");
225  }
226 
227  emit working(-1);
228  size_t count = 0;
229  foreach(const QString &dir, directories)
230  {
231  QString relPath = directoryPath + "/" + dir;
232  MainWindow->printInfo("Reading DICOMs in " + dir);
233 
234  qApp->processEvents();
235  UIDs = milx::File::GetDICOMSeriesUIDs(relPath.toStdString(), true);
236  std::vector<std::string> seriesNames(UIDs.size(), "");
237  MainWindow->printInfo(QString("Total of ") + QString::number(UIDs.size()) + " UID(s) found in " + dir);
238 
240  QStringList headingList;
241  headingList << "Tag" << "Value";
242  int caseTabIndex = manager->newTab("Tags "+dir, headingList);
243 
244  for(size_t j = 0; j < UIDs.size(); j ++)
245  {
246  qApp->processEvents();
247  std::string caseID;
248  std::string echoID = "";
249  std::string seriesID = "";
250  std::string acqID = "";
251  std::string instanceID = "";
252  std::vector< std::pair<std::string, std::string> > tags;
253  if (!milx::File::GetDICOMTags<floatImageType>(relPath.toStdString(), tags, UIDs[j], caseID, echoID, seriesID, acqID, instanceID))
254  continue;
255 
256  QStringList entryName;
257  entryName << UIDs[j].c_str() << "";
258 
259  //cout << "Loading tags into browser." << endl;
260  QList<QStringList> entryList;
261  for(int k = 0; k < tags.size(); k ++)
262  {
263  QStringList tagList;
264  std::string tag = tags[k].first;
265  std::string value = tags[k].second;
266 
267  tagList << tag.c_str() << value.c_str();
268 
269  //manager->addItem(caseTabIndex, tagList, Qt::NoItemFlags);
270  entryList.push_back(tagList);
271  }
272  manager->addTreeItem(caseTabIndex, entryName, entryList, Qt::NoItemFlags);
273  }
274  count ++;
275  }
276  MainWindow->printInfo(QString("Processed ") + QString::number(count) + " DICOM folders in " + directoryPath);
277 
278  manager->show();
279  MainWindow->printInfo("Done.");
280  emit done(-1);
281 }
282 
284 {
285  bool success = true;
286  QString directoryPath;
287  QPointer<QFileDialog> fileOpener = new QFileDialog;
288  QSettings settings("Shekhar Chandra", "milxQt");
289 
291  if (directoryPath.isEmpty())
292  {
293  QString path = settings.value("recentPath").toString();
294  directoryPath = fileOpener->getExistingDirectory(NULL, tr("Open DICOM Directory"),
295  path,
296  QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
297  }
298 
299  if (directoryPath.isEmpty())
300  return;
301 
303  std::vector<std::string> UIDs = milx::File::GetDICOMSeriesUIDs(directoryPath.toStdString());
304 
306  QStringList headingList;
307  headingList << "Tag" << "Value";
308  int caseTabIndex = manager->newTab("Tag Browser", headingList);
309 
310  emit working(-1);
311  for (size_t j = 0; j < UIDs.size(); j++)
312  {
313  qApp->processEvents();
314  std::string caseID;
315  std::string echoID = "";
316  std::string seriesID = "";
317  std::string acqID = "";
318  std::string instanceID = "";
319  floatImageType::Pointer floatImg;
320  std::vector< std::pair<std::string, std::string> > tags;
321  if (!milx::File::OpenDICOMSeriesAndTags<floatImageType>(directoryPath.toStdString(), floatImg, tags, UIDs[j], caseID, echoID, seriesID, acqID, instanceID))
322  continue;
323 
324  QStringList entryName;
325  entryName << UIDs[j].c_str() << "";
326 
327  //cout << "Loading tags into browser." << endl;
328  QList<QStringList> entryList;
329  for (int k = 0; k < tags.size(); k++)
330  {
331  QStringList tagList;
332  std::string tag = tags[k].first;
333  std::string value = tags[k].second;
334 
335  tagList << tag.c_str() << value.c_str();
336 
337  //manager->addItem(caseTabIndex, tagList, Qt::NoItemFlags);
338  entryList.push_back(tagList);
339  }
340  manager->addTreeItem(caseTabIndex, entryName, entryList, Qt::NoItemFlags);
341  qApp->processEvents();
342 
343  //Display Image
344  QPointer<milxQtImage> resultImg = new milxQtImage;
345  resultImg->setName(UIDs[j].c_str());
346  resultImg->setData(floatImg);
347  resultImg->generateImage();
348  MainWindow->display(resultImg);
349  }
350 
351  manager->show();
352  MainWindow->printInfo("Done.");
353  emit done(-1);
354 }
355 
357 {
358  cout << "Opening DICOM-RT" << endl;
359  //use wizaed to ask
360  wizardRT.restart();
361 
362  int ret = wizardRT.exec();
363 
364  if(ret == QDialog::Rejected)
365  {
366  wizardRT.restart();
367  return;
368  }
369 
370  //Ensure the names set correctly
371  rsFilename = txtRSName->text();
372  inputRTDirectoryname = txtRTInputName->text();
373  outputRTDirectoryname = txtRTOutputName->text();
374  qApp->processEvents();
375 
376  //Open RS file
377  emit working(-1);
378 // MainWindow->printInfo("Opening RS file ...");
379 // floatImageType::Pointer floatImg = milx::File::ReadImageUsingITK<floatImageType>(rsFilename.toStdString());
380 // charImageType::Pointer charImg = milx::File::ReadImageUsingITK<charImageType>(rsFilename.toStdString());
381  qApp->processEvents();
382 
384  const std::vector<std::string> UIDs = milx::File::GetDICOMSeriesUIDs(inputRTDirectoryname.toStdString());
385 
386  if(UIDs.empty())
387  {
388  MainWindow->printError("No series found in input directory");
389  return;
390  }
391 
393  std::string seriesName = UIDs[0];
394  charImageType::Pointer charImg;
395 
396 #if (ITK_VERSION_MAJOR > 3) //Review only members
397  ExportDICOM_RT<charImageType>(inputRTDirectoryname.toStdString(), rsFilename.toStdString(), outputRTDirectoryname.toStdString(), charImg, seriesName);
398 #endif // (ITK_VERSION_MAJOR > 3)
399 
400  MainWindow->printInfo("Done.");
401  emit done(-1);
402 }
403 
405 {
406  cout << "Converting DICOMs" << endl;
407  //use wizaed to ask
408  wizard.restart();
409 
410  int ret = wizard.exec();
411 
412  if(ret == QDialog::Rejected)
413  {
414  wizard.restart();
415  return;
416  }
417 
418  //Ensure the names set correctly
419  inputDirectoryname = txtInputName->text();
420  outputDirectoryname = txtOutputName->text();
421 
422  qApp->processEvents();
423 
427  std::vector<std::string> UIDs = milx::File::GetDICOMSeriesUIDs(inputDirectoryname.toStdString(), true);
428 
430  QStringList directories;
431  if(UIDs.empty())
432  {
433  MainWindow->printWarning("Found no series found in input directory. Checking internal directories");
434  QDir directory(inputDirectoryname);
435  directory.setFilter(QDir::AllDirs | QDir::NoDotAndDotDot | QDir::NoSymLinks);
436  directories = directory.entryList();
437  }
438  else
439  {
440  MainWindow->printInfo(QString("Total of ") + QString::number(UIDs.size()) + " UID(s) found");
441  directories.push_back("");
442  }
443 
445  emit working(-1);
446  foreach(const QString &dir, directories)
447  {
448  qApp->processEvents();
449  QString relPath = inputDirectoryname + "/" + dir;
450  QString relOutputPath = outputDirectoryname + "/" + dir;
451  UIDs = milx::File::GetDICOMSeriesUIDs(relPath.toStdString(), true);
452  std::vector<std::string> seriesNames(UIDs.size(), "");
453  MainWindow->printInfo(QString("Total of ") + QString::number(UIDs.size()) + " UID(s) found in " + dir);
454 
455  QDir outputSubjectDirectory(relOutputPath);
457  bool exist = outputSubjectDirectory.exists();
458  if (!exist)
459  {
460  exist = QDir().mkpath(relOutputPath);
461  if (!exist)
462  continue;
463  }
464 
465  for(size_t j = 0; j < UIDs.size(); j ++)
466  {
467  qApp->processEvents();
468  seriesNames[j] = UIDs[j];
469  const std::vector<std::string> seriesFilenames = milx::File::GetDICOMSeriesFilenames(relPath.toStdString(), seriesNames[j]);
470 
471  //Read Header
472  size_t dimensions = 3;
473  std::string pixelType, componentType;
474  if (!milx::File::ReadImageInformation(seriesFilenames.front(), pixelType, componentType, dimensions))
475  {
476  milx::PrintError("Failed Reading First Image. Check the image type/file. Skipping.");
477  continue;
478  }
479  milx::PrintInfo("UID: " + seriesNames[j]);
480  milx::PrintInfo("Pixel Type: " + pixelType);
481  milx::PrintInfo("Component Type: " + componentType);
482  milx::PrintInfo("Dimensions: " + milx::NumberToString(dimensions));
483 
484  //Open image using relevant type
485  std::string caseID;
486  std::string echoID = "";
487  std::string seriesID = "";
488  std::string acqID = "";
489  std::string instanceID = "";
490  itk::SmartPointer<vectorImageType> vectorImage;
491  itk::SmartPointer<charImageType> labelledImage;
492  itk::SmartPointer<shortImageType> shortImage;
493  itk::SmartPointer<ushortImageType> ushortImage;
494  itk::SmartPointer<intImageType> intImage;
495  itk::SmartPointer<uintImageType> uintImage;
496  itk::SmartPointer<floatImageType> floatImage;
497  std::vector< std::pair<std::string, std::string> > tags;
498  bool labelledImages = false, shortImages = false, ushortImages = false, integerImages = false, uintegerImages = false, vectorImages = false;
499  if (pixelType == "vector" || dimensions > 3)
500  {
501  milx::PrintInfo("Detected vector images.");
502  if (!milx::File::OpenDICOMSeriesAndTags<vectorImageType>(relPath.toStdString(), vectorImage, tags, seriesNames[j], caseID, echoID, seriesID, acqID, instanceID)) //Error NOT printed inside
503  {
504  milx::PrintError("Failed Reading Vector Images. Skipping.");
505  continue;
506  }
507  vectorImages = true;
508  }
509  else if (componentType == "unsigned_char" || componentType == "unsigned char")
510  {
511  milx::PrintInfo("Detected labelled images.");
512  if (!milx::File::OpenDICOMSeriesAndTags<charImageType>(relPath.toStdString(), labelledImage, tags, seriesNames[j], caseID, echoID, seriesID, acqID, instanceID)) //Error NOT printed inside
513  {
514  milx::PrintError("Failed Reading Labelled Images. Skipping.");
515  continue;
516  }
517  labelledImages = true;
518  }
519  else if (componentType == "short" || componentType == "int16")
520  {
521  milx::PrintInfo("Detected short images.");
522  if (!milx::File::OpenDICOMSeriesAndTags<shortImageType>(relPath.toStdString(), shortImage, tags, seriesNames[j], caseID, echoID, seriesID, acqID, instanceID)) //Error NOT printed inside
523  {
524  milx::PrintError("Failed Reading Short Images. Skipping.");
525  continue;
526  }
527  shortImages = true;
528  }
529  else if (componentType == "unsigned_short" || componentType == "unsigned short")
530  {
531  milx::PrintInfo("Detected unsigned short images.");
532  if (!milx::File::OpenDICOMSeriesAndTags<ushortImageType>(relPath.toStdString(), ushortImage, tags, seriesNames[j], caseID, echoID, seriesID, acqID, instanceID)) //Error NOT printed inside
533  {
534  milx::PrintError("Failed Reading Unsigned Short Images. Skipping.");
535  continue;
536  }
537  ushortImages = true;
538  }
539  else if (componentType == "int" || componentType == "signed" || componentType == "int32" || componentType == "int64")
540  {
541  milx::PrintInfo("Detected integer images.");
542  if (!milx::File::OpenDICOMSeriesAndTags<intImageType>(relPath.toStdString(), intImage, tags, seriesNames[j], caseID, echoID, seriesID, acqID, instanceID)) //Error NOT printed inside
543  {
544  milx::PrintError("Failed Reading Integer Images. Skipping.");
545  continue;
546  }
547  integerImages = true;
548  }
549  else if (componentType == "unsigned_int" || componentType == "unsigned int" || componentType == "unsigned")
550  {
551  milx::PrintInfo("Detected unsigned int images.");
552  if (!milx::File::OpenDICOMSeriesAndTags<uintImageType>(relPath.toStdString(), uintImage, tags, seriesNames[j], caseID, echoID, seriesID, acqID, instanceID)) //Error NOT printed inside
553  {
554  milx::PrintError("Failed Reading Unsigned Integer Images. Skipping.");
555  continue;
556  }
557  uintegerImages = true;
558  }
559  else
560  {
561  milx::PrintInfo("Detected floating point images.");
562  if (!milx::File::OpenDICOMSeriesAndTags<floatImageType>(relPath.toStdString(), floatImage, tags, seriesNames[j], caseID, echoID, seriesID, acqID, instanceID)) //Error NOT printed inside
563  {
564  milx::PrintError("Failed Reading Images. Skipping.");
565  continue;
566  }
567  }
568 
569  //edit the series to ensure valid name and no spaces
570  QString nameSimplified = seriesNames[j].c_str();
571  nameSimplified = nameSimplified.simplified();
572  nameSimplified.replace(" ", ""); //no spaces
573  seriesNames[j] = nameSimplified.toStdString();
574  QString caseSimplified = caseID.c_str();
575  caseSimplified = caseSimplified.simplified();
576  caseSimplified.replace(" ", ""); //no spaces
577  caseID = caseSimplified.toStdString();
578 
579  MainWindow->printInfo(QString("Opened: ") + seriesNames[j].c_str());
580  qApp->processEvents();
581 
582  //create filename
583  std::string filename = relOutputPath.toStdString() + "/" + dir.toStdString() + "_" + caseID + "_" + seriesNames[j] + ".nii.gz";
584  if(caseID == "-1")
585  filename = relOutputPath.toStdString() + "/" + dir.toStdString() + seriesNames[j] + ".nii.gz";
586  MainWindow->printInfo(QString("Saving DICOM as ") + filename.c_str());
587 
588  //Save as relevant type
589  if(vectorImages)
590  milx::File::SaveImage<vectorImageType>(filename, vectorImage);
591  else if(labelledImages)
592  milx::File::SaveImage<charImageType>(filename, labelledImage);
593  else if(shortImages)
594  milx::File::SaveImage<shortImageType>(filename, shortImage);
595  else if(ushortImages)
596  milx::File::SaveImage<ushortImageType>(filename, ushortImage);
597  else if(integerImages)
598  milx::File::SaveImage<intImageType>(filename, intImage);
599  else if(uintegerImages)
600  milx::File::SaveImage<uintImageType>(filename, uintImage);
601  else
602  milx::File::SaveImage<floatImageType>(filename, floatImage);
603  }
604  }
605 
606  qApp->processEvents();
607  emit done(-1);
608  MainWindow->printInfo("Done");
609 }
610 
612 {
613  cout << "Anonymizing DICOMs" << endl;
614  typedef itk::GDCMSeriesFileNames NamesGeneratorType;
615  typedef std::vector< std::string > FileNamesContainer;
616  typedef std::vector< std::string > SeriesIdContainer;
617 
618  //use wizaed to ask
619  wizardAnonymize.restart();
620 
621  int ret = wizardAnonymize.exec();
622 
623  if(ret == QDialog::Rejected)
624  {
625  wizardAnonymize.restart();
626  return;
627  }
628 
629  if (!valid)
630  {
631  return;
632  }
633 
634  qApp->processEvents();
635 
636  MainWindow->printInfo(QString("DICOM directory ") + inputAnonymizeDirectoryname);
637  MainWindow->printInfo(QString("Output directory ") + outputAnonymizeDirectoryname);
638  MainWindow->printInfo(QString("Prefix anonymisation ") + outputPrefix);
639  MainWindow->printInfo(QString("Starting at ID ") + QString::number(outputInitID));
640 
641 
642  emit working(-1);
643  MainWindow->printInfo(QString("Working..."));
645  unsigned int initial_id = outputInitID;
646  QDir subjectsDir(inputAnonymizeDirectoryname);
647  subjectsDir.setFilter(QDir::Dirs | QDir::NoDotAndDotDot);
648 
650  QStringList entries = subjectsDir.entryList();
651  for( QStringList::ConstIterator entry=entries.begin(); entry!=entries.end(); ++entry)
652  {
653  bool first = true;
654  qApp->processEvents();
655  QFileInfo finfo(subjectsDir, *entry);
656 
657 // std::cout << "Entry -> " << (*entry).toStdString() << std::endl;
658 // std::cout << "Processing -> " << finfo.absoluteFilePath().toStdString() << std::endl;
659  QDir subdir(finfo.absoluteFilePath());
660  QString subjectPath = subdir.absolutePath();
661 // std::cout << "Processing -> " << subjectPath.toStdString() << std::endl;
662  QDir::setCurrent(subjectPath);
663 
665  try
666  {
667  NamesGeneratorType::Pointer nameGenerator = NamesGeneratorType::New();
668  nameGenerator->SetUseSeriesDetails( true );
669  nameGenerator->SetRecursive(true);
670  nameGenerator->AddSeriesRestriction("0008|0021" ); // -> need check if possible split by subject
671  nameGenerator->SetDirectory(subjectPath.toStdString().c_str());
672 
675  const SeriesIdContainer & seriesUID = nameGenerator->GetSeriesUIDs();
676  if (seriesUID.size() > 0)
677  {
678  QString outputSubjectPath = outputAnonymizeDirectoryname+ QDir::separator() + outputPrefix + QString::number(initial_id);
679  QDir outputSubjectDirectory(outputSubjectPath);
680 
682  bool exist = outputSubjectDirectory.exists();
683  if (!exist)
684  {
685  exist = QDir().mkpath(outputSubjectPath);
686  if (! exist)
687  {
688  continue;
689  }
690  }
691 
692  SeriesIdContainer::const_iterator seriesItr = seriesUID.begin();
693  SeriesIdContainer::const_iterator seriesEnd = seriesUID.end();
694 
696  while( seriesItr != seriesEnd )
697  {
698  qApp->processEvents();
699  std::cout << seriesItr->c_str() << std::endl;
700  FileNamesContainer temp = nameGenerator->GetFileNames(seriesItr->c_str());
701 
702  std::vector<std::string>::iterator fileIterator;
703  unsigned int dcm_index = 0;
704 
706  for (fileIterator = temp.begin(); fileIterator != temp.end(); fileIterator++)
707  {
709  QString rel_path = subdir.relativeFilePath(QString::fromStdString(*fileIterator));
710  QFileInfo img_info(rel_path);
711  QString rel_dir = img_info.path();
712 
714  bool success = anonymizeDicomImage(*fileIterator, outputSubjectPath, rel_dir, initial_id, dcm_index, first);
715  if (success)
716  {
717  dcm_index++;
718  }
719  else
720  {
721  std::cout << "Failed to anonymise " << *fileIterator << std::endl;
722  }
723  qApp->processEvents();
724  }
725  seriesItr++;
726  }
727  initial_id++;
728  }
729  }
730  catch (itk::ExceptionObject &ex)
731  {
732  std::cerr << ex << std::endl;
733  return;
734  }
735  }
736 
737  qApp->processEvents();
738  emit done(-1);
739  MainWindow->printInfo("Done");
740 }
741 
743 {
744  QSettings settings("Shekhar Chandra", "milxQt");
745  //Add supported file entry
746  QString exts = openMedImageExts.c_str();
747  QString path = settings.value("recentPath").toString();
748 
749  if(!txtRSName->text().isEmpty())
750  path = txtRSName->text();
751 
752  QFileDialog *fileOpener = new QFileDialog;
753  rsFilename = fileOpener->getOpenFileName(&wizardRT,
754  tr("Select RS File to Open"),
755  path,
756  tr(exts.toStdString().c_str()) );
757  txtRSName->setText(rsFilename);
758 }
759 
760 void milxQtDICOMPlugin::showInputFileDialog()
761 {
762  QSettings settings("Shekhar Chandra", "milxQt");
763  //Add supported file entry
764  QString path = settings.value("recentPath").toString();
765 
766  QFileDialog *fileOpener = new QFileDialog;
767  inputDirectoryname = fileOpener->getExistingDirectory(&wizard,
768  tr("Select Open Directory"),
769  path,
770  QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
771  txtInputName->setText(inputDirectoryname);
772 }
773 
774 void milxQtDICOMPlugin::showRTInputFileDialog()
775 {
776  QSettings settings("Shekhar Chandra", "milxQt");
777  //Add supported file entry
778  QString path = settings.value("recentPath").toString();
779 
780  QFileDialog *fileOpener = new QFileDialog;
781  inputRTDirectoryname = fileOpener->getExistingDirectory(&wizardRT,
782  tr("Select Open Directory"),
783  path,
784  QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
785  txtRTInputName->setText(inputRTDirectoryname);
786  txtRSName->setText(inputRTDirectoryname);
787 }
788 
789 void milxQtDICOMPlugin::showInputFileDialogAnonymize()
790 {
791  QSettings settings("Shekhar Chandra", "milxQt");
792  //Add supported file entry
793  QString path = settings.value("recentPath").toString();
794 
795  QFileDialog *fileOpener = new QFileDialog;
796  inputAnonymizeDirectoryname = fileOpener->getExistingDirectory(&wizardAnonymize,
797  tr("Select Open Directory"),
798  path,
799  QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
800  txtInputAnonymizeName->setText(inputAnonymizeDirectoryname);
801 }
802 
803 void milxQtDICOMPlugin::showOutputFileDialog()
804 {
805  QSettings settings("Shekhar Chandra", "milxQt");
806  //Add supported file entry
807  QString path = settings.value("recentPath").toString();
808 
809  QFileDialog *fileOpener = new QFileDialog;
810  outputDirectoryname = fileOpener->getExistingDirectory(&wizard,
811  tr("Select Save Directory"),
812  path,
813  QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
814  txtOutputName->setText(outputDirectoryname);
815 }
816 
817 void milxQtDICOMPlugin::showRTOutputFileDialog()
818 {
819  QSettings settings("Shekhar Chandra", "milxQt");
820  //Add supported file entry
821  QString path = settings.value("recentPath").toString();
822 
823  QFileDialog *fileOpener = new QFileDialog;
824  outputRTDirectoryname = fileOpener->getExistingDirectory(&wizardRT,
825  tr("Select Save Directory"),
826  path,
827  QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
828  txtRTOutputName->setText(outputRTDirectoryname);
829 }
830 
831 void milxQtDICOMPlugin::showOutputFileDialogAnonymize()
832 {
833  QSettings settings("Shekhar Chandra", "milxQt");
834  //Add supported file entry
835  QString path = settings.value("recentPath").toString();
836 
837  QFileDialog *fileOpener = new QFileDialog;
838  outputAnonymizeDirectoryname = fileOpener->getExistingDirectory(&wizardAnonymize,
839  tr("Select Save Directory"),
840  path,
841  QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
842  txtOutputAnonymizeName->setText(outputAnonymizeDirectoryname);
843 }
844 
845 void milxQtDICOMPlugin::createActions()
846 {
847  actionOpenSeries = new QAction(MainWindow);
848  actionOpenSeries->setIcon(QIcon(":/resources/toolbar/open_series.png"));
849  actionOpenSeries->setText(QApplication::translate("MainWindow", "Open Series", 0, QApplication::UnicodeUTF8));
850  actionOpenSeries->setShortcut(tr("Ctrl+Alt+o"));
851  actionTags = new QAction(MainWindow);
852  actionTags->setIcon(QIcon(":/resources/toolbar/search.png"));
853  actionTags->setText(QApplication::translate("MainWindow", "View Tags", 0, QApplication::UnicodeUTF8));
854  actionTags->setShortcut(tr("Ctrl+Alt+t"));
855  actionConvertStructure = new QAction(MainWindow);
856  actionConvertStructure->setText(QApplication::translate("DICOMPlugin", "Convert RT/Structure Set ...", 0, QApplication::UnicodeUTF8));
857  actionConvertStructure->setShortcut(tr("Ctrl+Alt+s"));
858  actionConvertStructure->setDisabled(true);
859 #if (ITK_VERSION_MAJOR > 3) //Review only members
860  actionConvertStructure->setDisabled(false);
861 #endif // (ITK_VERSION_MAJOR > 3)
862  actionConvert = new QAction(MainWindow);
863  actionConvert->setText(QApplication::translate("DICOMPlugin", "Convert ...", 0, QApplication::UnicodeUTF8));
864  actionConvert->setShortcut(tr("Ctrl+Alt+c"));
865  actionAnonymize = new QAction(MainWindow);
866  actionAnonymize->setText(QApplication::translate("DICOMPlugin", "Anonymize ...", 0, QApplication::UnicodeUTF8));
867  actionAnonymize->setShortcut(tr("Ctrl+Alt+a"));
868 }
869 
870 void milxQtDICOMPlugin::createMenu()
871 {
872  menuDICOM = new QMenu(MainWindow);
873  menuDICOM->setTitle(QApplication::translate("DICOMPlugin", "DICOM", 0, QApplication::UnicodeUTF8));
874  menuDICOM->addAction(actionOpenSeries);
875  menuDICOM->addAction(actionTags);
876  menuDICOM->addAction(actionConvertStructure);
877  menuDICOM->addAction(actionConvert);
878  menuDICOM->addAction(actionAnonymize);
879 
880  menuToAdd.append(menuDICOM);
881 }
882 
883 void milxQtDICOMPlugin::createWizard()
884 {
885  //intro
886  QWizardPage *introPage = new QWizardPage;
887  introPage->setTitle("Introduction");
888 
889  QLabel *label1 = new QLabel("This wizard will help you process DICOM series.");
890  label1->setWordWrap(true);
891  QLabel *label2 = new QLabel("You will be asked to provide a directory where the DICOM are located.");
892  label2->setWordWrap(true);
893  QLabel *label3 = new QLabel("You will then be asked to provide an output directory for the process data to be stored.");
894  label3->setWordWrap(true);
895  QVBoxLayout *introLayout = new QVBoxLayout;
896  introLayout->addWidget(label1);
897  introLayout->addWidget(label2);
898  introLayout->addWidget(label3);
899  introPage->setLayout(introLayout);
900 
901  //ask for input
902  QWizardPage *inputPage = new QWizardPage;
903  inputPage->setTitle("Input Directory");
904 
905  QLabel *label4 = new QLabel("Please provide the directory to be analysed.");
906  label4->setWordWrap(true);
907  txtInputName = new QLineEdit;
908  QPushButton *btnInputName = new QPushButton;
909  connect(btnInputName, SIGNAL(clicked()), this, SLOT(showInputFileDialog()));
910  btnInputName->setText("Browse...");
911  QHBoxLayout *inputNameLayout = new QHBoxLayout;
912  inputNameLayout->addWidget(txtInputName);
913  inputNameLayout->addWidget(btnInputName);
914  QGroupBox *inputGroupBox = new QGroupBox("Series Directory");
915  inputGroupBox->setLayout(inputNameLayout);
916  QVBoxLayout *inputLayout = new QVBoxLayout;
917  inputLayout->addWidget(label4);
918  inputLayout->addWidget(inputGroupBox);
919  inputPage->setLayout(inputLayout);
920 
921  //ask for output
922  QWizardPage *outputPage = new QWizardPage;
923  outputPage->setTitle("Output Directory");
924 
925  QLabel *label5 = new QLabel("Please provide the output directory for the processing.");
926  label5->setWordWrap(true);
927  txtOutputName = new QLineEdit;
928  QPushButton *btnOutputName = new QPushButton;
929  btnOutputName->setText("Browse...");
930  connect(btnOutputName, SIGNAL(clicked()), this, SLOT(showOutputFileDialog()));
931  QHBoxLayout *ouputNameLayout = new QHBoxLayout;
932  ouputNameLayout->addWidget(txtOutputName);
933  ouputNameLayout->addWidget(btnOutputName);
934  QGroupBox *outputGroupBox = new QGroupBox("Output Directory");
935  outputGroupBox->setLayout(ouputNameLayout);
936  QVBoxLayout *outputLayout = new QVBoxLayout;
937  outputLayout->addWidget(label5);
938  outputLayout->addWidget(outputGroupBox);
939  outputPage->setLayout(outputLayout);
940 
941  //dicom wizard class var
942  wizard.addPage(introPage);
943  wizard.addPage(inputPage);
944  wizard.addPage(outputPage);
945  wizard.setWindowTitle("DICOM Wizard");
946 }
947 
948 void milxQtDICOMPlugin::createRTWizard()
949 {
950  //intro
951  QWizardPage *introPage = new QWizardPage;
952  introPage->setTitle("Introduction");
953 
954  QLabel *label1 = new QLabel("This wizard will help you process DICOM series.");
955  label1->setWordWrap(true);
956  QLabel *label2 = new QLabel("You will be asked to provide a directory where the DICOM are located.");
957  label2->setWordWrap(true);
958  QLabel *label3 = new QLabel("You will then be asked to provide an output directory for the process data to be stored.");
959  label3->setWordWrap(true);
960  QVBoxLayout *introLayout = new QVBoxLayout;
961  introLayout->addWidget(label1);
962  introLayout->addWidget(label2);
963  introLayout->addWidget(label3);
964  introPage->setLayout(introLayout);
965 
966  //ask for input
967  QWizardPage *inputPage = new QWizardPage;
968  inputPage->setTitle("Input Directory");
969 
970  QLabel *label4 = new QLabel("Please provide the directory to be analysed.");
971  label4->setWordWrap(true);
972  txtRTInputName = new QLineEdit;
973  QPushButton *btnInputName = new QPushButton;
974  connect(btnInputName, SIGNAL(clicked()), this, SLOT(showRTInputFileDialog()));
975  btnInputName->setText("Browse...");
976  QHBoxLayout *inputNameLayout = new QHBoxLayout;
977  inputNameLayout->addWidget(txtRTInputName);
978  inputNameLayout->addWidget(btnInputName);
979  QGroupBox *inputGroupBox = new QGroupBox("Series Directory");
980  inputGroupBox->setLayout(inputNameLayout);
981  QVBoxLayout *inputLayout = new QVBoxLayout;
982  inputLayout->addWidget(label4);
983  inputLayout->addWidget(inputGroupBox);
984  inputPage->setLayout(inputLayout);
985 
986  //ask for output
987  QWizardPage *outputPage = new QWizardPage;
988  outputPage->setTitle("Output Directory");
989 
990  QLabel *label5 = new QLabel("Please provide the output directory for the processing.");
991  label5->setWordWrap(true);
992  txtRTOutputName = new QLineEdit;
993  QPushButton *btnOutputName = new QPushButton;
994  btnOutputName->setText("Browse...");
995  connect(btnOutputName, SIGNAL(clicked()), this, SLOT(showRTOutputFileDialog()));
996  QHBoxLayout *ouputNameLayout = new QHBoxLayout;
997  ouputNameLayout->addWidget(txtRTOutputName);
998  ouputNameLayout->addWidget(btnOutputName);
999  QGroupBox *outputGroupBox = new QGroupBox("Output Directory");
1000  outputGroupBox->setLayout(ouputNameLayout);
1001  QVBoxLayout *outputLayout = new QVBoxLayout;
1002  outputLayout->addWidget(label5);
1003  outputLayout->addWidget(outputGroupBox);
1004  outputPage->setLayout(outputLayout);
1005 
1006  //ask for RS file
1007  QWizardPage *rsPage = new QWizardPage;
1008  rsPage->setTitle("RS File");
1009 
1010  QLabel *label6 = new QLabel("Please provide the RS file for processing.");
1011  label6->setWordWrap(true);
1012  txtRSName = new QLineEdit;
1013  QPushButton *btnRSName = new QPushButton;
1014  btnRSName->setText("Browse...");
1015  connect(btnRSName, SIGNAL(clicked()), this, SLOT(showRSFileDialog()));
1016  QHBoxLayout *rsNameLayout = new QHBoxLayout;
1017  rsNameLayout->addWidget(txtRSName);
1018  rsNameLayout->addWidget(btnRSName);
1019  QGroupBox *rsGroupBox = new QGroupBox("RS File");
1020  rsGroupBox->setLayout(rsNameLayout);
1021  QVBoxLayout *rsLayout = new QVBoxLayout;
1022  rsLayout->addWidget(label6);
1023  rsLayout->addWidget(rsGroupBox);
1024  rsPage->setLayout(rsLayout);
1025 
1026  //dicom RT wizard class var
1027  wizardRT.addPage(introPage);
1028  wizardRT.addPage(inputPage);
1029  wizardRT.addPage(outputPage);
1030  wizardRT.addPage(rsPage);
1031  wizardRT.setWindowTitle("DICOM RT Wizard");
1032 }
1033 
1035 {
1037  QWizardPage *introPage = new QWizardPage;
1038  introPage->setTitle("Introduction");
1039 
1040  QLabel *label1 = new QLabel("This wizard will help you anonymize DICOM series.");
1041  label1->setWordWrap(true);
1042  QLabel *label2 = new QLabel("You will be asked to provide the 'top'' directory in which the folders of the patients are located.");
1043  label2->setWordWrap(true);
1044  QLabel *label3 = new QLabel("You will then be asked to provide an output directory.");
1045  label3->setWordWrap(true);
1046  QLabel *label3a = new QLabel("Then, you will then be asked to provide a prefix that will be used to replace the patient name eg. 'ANON'.");
1047  label3a->setWordWrap(true);
1048  QLabel *label3b = new QLabel("You will finally be asked to provide an initial ID for the first case to be anonymized (this ID will be incremented per subject).");
1049  label3b->setWordWrap(true);
1050  QVBoxLayout *introLayout = new QVBoxLayout;
1051  introLayout->addWidget(label1);
1052  introLayout->addWidget(label2);
1053  introLayout->addWidget(label3);
1054  introLayout->addWidget(label3a);
1055  introLayout->addWidget(label3b);
1056  introPage->setLayout(introLayout);
1057 
1058  //ask for input
1060  QWizardPage *inputPage = new QWizardPage;
1061  inputPage->setTitle("Input Directory");
1062 
1063  QLabel *label4 = new QLabel("Please provide the top directory in which the subjects' folders are located.");
1064  label4->setWordWrap(true);
1065  txtInputAnonymizeName = new QLineEdit;
1066  QPushButton *btnInputName = new QPushButton;
1067  connect(btnInputName, SIGNAL(clicked()), this, SLOT(showInputFileDialogAnonymize()));
1068  btnInputName->setText("Browse...");
1069  QHBoxLayout *inputNameLayout = new QHBoxLayout;
1070  inputNameLayout->addWidget(txtInputAnonymizeName);
1071  inputNameLayout->addWidget(btnInputName);
1072  QGroupBox *inputGroupBox = new QGroupBox("Series Directory");
1073  inputGroupBox->setLayout(inputNameLayout);
1074  QVBoxLayout *inputLayout = new QVBoxLayout;
1075  inputLayout->addWidget(label4);
1076  inputLayout->addWidget(inputGroupBox);
1077  inputPage->setLayout(inputLayout);
1078 
1080  QWizardPage *outputPage = new QWizardPage;
1081  outputPage->setTitle("Output Directory");
1082 
1083  QLabel *label5 = new QLabel("Please provide the output directory.");
1084  label5->setWordWrap(true);
1085  txtOutputAnonymizeName = new QLineEdit;
1086  QPushButton *btnOutputName = new QPushButton;
1087  btnOutputName->setText("Browse...");
1088  connect(btnOutputName, SIGNAL(clicked()), this, SLOT(showOutputFileDialogAnonymize()));
1089  QHBoxLayout *ouputNameLayout = new QHBoxLayout;
1090  ouputNameLayout->addWidget(txtOutputAnonymizeName);
1091  ouputNameLayout->addWidget(btnOutputName);
1092  QGroupBox *outputGroupBox = new QGroupBox("Output Directory");
1093  outputGroupBox->setLayout(ouputNameLayout);
1094  QVBoxLayout *outputLayout = new QVBoxLayout;
1095  outputLayout->addWidget(label5);
1096  outputLayout->addWidget(outputGroupBox);
1097  outputPage->setLayout(outputLayout);
1098 
1100  QWizardPage *prefixPage = new QWizardPage;
1101  prefixPage->setTitle("Prefix anonymization");
1102 
1103  QLabel *label6 = new QLabel("Please provide the pefix for naming anonymized subject. If left emply 'Anon' will be used");
1104  label6->setWordWrap(true);
1105  txtOutputPrefix = new QLineEdit;
1106  txtOutputPrefix->setText("Anon");
1107  QHBoxLayout *prfxNameLayout = new QHBoxLayout;
1108  prfxNameLayout->addWidget(txtOutputPrefix);
1109  QGroupBox *prefixGroupBox = new QGroupBox("Output prefix");
1110  prefixGroupBox->setLayout(prfxNameLayout);
1111  QVBoxLayout *prefixLayout = new QVBoxLayout;
1112  prefixLayout->addWidget(label6);
1113  prefixLayout->addWidget(prefixGroupBox);
1114  prefixPage->setLayout(prefixLayout);
1115 
1117  QWizardPage *outputIDPage = new QWizardPage;
1118  outputIDPage->setTitle("Output Directory");
1119 
1120  QLabel *label7 = new QLabel("Please provide the initial ID for anonymisation (integer). If left empty, '0' will be used");
1121  label7->setWordWrap(true);
1122  txtOutputInitID = new QLineEdit;
1123  txtOutputInitID->setText("0");
1124  QHBoxLayout *InitIDNameLayout = new QHBoxLayout;
1125  InitIDNameLayout->addWidget(txtOutputInitID);
1126  //InitIDNameLayout->addWidget(btnInitIDName);
1127  QGroupBox *InitIDGroupBox = new QGroupBox("Initial ID");
1128  InitIDGroupBox->setLayout(InitIDNameLayout);
1129  QVBoxLayout *InitIDLayout = new QVBoxLayout;
1130  InitIDLayout->addWidget(label7);
1131  InitIDLayout->addWidget(InitIDGroupBox);
1132  outputIDPage->setLayout(InitIDLayout);
1133 
1135  QWizardPage *optionPage = new QWizardPage;
1136  optionPage->setTitle("Options");
1137 
1138  QHBoxLayout *splitLayout = new QHBoxLayout;
1139 
1140  QVBoxLayout *optionLayout = new QVBoxLayout;
1141  QLabel *label8 = new QLabel("Output options:");
1142  label8->setWordWrap(true);
1143 
1144  checkboxPreserveFolderArc = new QCheckBox("Preserve folder architecture", &wizardAnonymize);
1145  checkboxPreserveFolderArc->setChecked(true);
1146 
1147  QVBoxLayout *anonOptionLayout = new QVBoxLayout;
1148  QLabel *label10 = new QLabel("Anonymization options:");
1149  label10->setWordWrap(true);
1150 
1151  anonPatientInfo = new QCheckBox("Anonymize Patient info", &wizardAnonymize);
1152  anonPatientInfo->setChecked(true);
1153  anonPhysician = new QCheckBox("Anonymize Physician(s) info", &wizardAnonymize);
1154  anonOperator = new QCheckBox("Anonymize Operator info", &wizardAnonymize);
1155  anonScanDate = new QCheckBox("Anonymize Scan Date", &wizardAnonymize);
1156  optionLayout->addWidget(label10);
1157  optionLayout->addWidget(checkboxPreserveFolderArc);
1158  optionLayout->addWidget(anonPatientInfo);
1159  optionLayout->addWidget(anonPhysician);
1160  optionLayout->addWidget(anonOperator);
1161  optionLayout->addWidget(anonScanDate);
1162  optionLayout->setAlignment(Qt::AlignTop);
1163 
1164  QLabel *label9 = new QLabel("Items for default filename:");
1165  label8->setWordWrap(true);
1166 
1167  checkboxPatientName = new QCheckBox("Patient anonymized name", &wizardAnonymize);
1168  checkboxPatientName->setChecked(true);
1169  checkboxPatientID = new QCheckBox("PatientID", &wizardAnonymize);
1170  checkboxPatientID->setChecked(true);
1171  checkboxSeriesDate = new QCheckBox("SeriesDate", &wizardAnonymize);
1172  checkboxSeriesDate->setChecked(true);
1173  checkboxSeriesTime = new QCheckBox("SeriesTime", &wizardAnonymize);
1174  checkboxSeriesTime->setChecked(true);
1175  checkboxStudyID = new QCheckBox("StudyID", &wizardAnonymize);
1176  checkboxStudyDesc = new QCheckBox("StudyDesc", &wizardAnonymize);
1177  checkboxStudyDesc->setChecked(true);
1178  checkboxSeriesNumber = new QCheckBox("SeriesNumber", &wizardAnonymize);
1179  checkboxSeriesNumber->setChecked(true);
1180  checkboxSeriesNumber->setEnabled(false);
1181  checkboxSequenceName = new QCheckBox("SequenceName", &wizardAnonymize);
1182  checkboxSequenceName->setChecked(true);
1183  checkboxProtocolName = new QCheckBox("ProtocolName", &wizardAnonymize);
1184  checkboxProtocolName->setChecked(true);
1185  checkboxSeriesDescription = new QCheckBox("SeriesDescription", &wizardAnonymize);
1186 
1187  anonOptionLayout->addWidget(label8);
1188  anonOptionLayout->addWidget(label9);
1189  anonOptionLayout->addWidget(checkboxPatientName);
1190  anonOptionLayout->addWidget(checkboxPatientID);
1191  anonOptionLayout->addWidget(checkboxSeriesDate);
1192  anonOptionLayout->addWidget(checkboxSeriesTime);
1193  anonOptionLayout->addWidget(checkboxStudyID);
1194  anonOptionLayout->addWidget(checkboxStudyDesc);
1195  anonOptionLayout->addWidget(checkboxSeriesNumber);
1196  anonOptionLayout->addWidget(checkboxSequenceName);
1197  anonOptionLayout->addWidget(checkboxProtocolName);
1198  anonOptionLayout->addWidget(checkboxSeriesDescription);
1199  anonOptionLayout->setAlignment(Qt::AlignTop);
1200 
1201  splitLayout->addLayout(optionLayout);
1202  splitLayout->addLayout(anonOptionLayout);
1203  optionPage->setLayout(splitLayout);
1204 
1205  //wizard class var
1206  wizardAnonymize.addPage(introPage);
1207  wizardAnonymize.addPage(inputPage);
1208  wizardAnonymize.addPage(outputPage);
1209  wizardAnonymize.addPage(prefixPage);
1210  wizardAnonymize.addPage(outputIDPage);
1211  wizardAnonymize.addPage(optionPage);
1212 
1213  wizardAnonymize.setWindowTitle("DICOM Anonymisation Wizard");
1214 
1215  QAbstractButton *final = wizardAnonymize.button(QWizard::FinishButton);
1216  connect(final, SIGNAL(clicked()), this, SLOT(affectValues()));
1217 }
1218 
1219 void milxQtDICOMPlugin::createConnections()
1220 {
1221 // connect(MainWindow, SIGNAL(windowActivated(QWidget*)), this, SLOT(updateManager(QWidget*)));
1222  connect(actionOpenSeries, SIGNAL(activated()), this, SLOT(openSeries()));
1223  connect(actionTags, SIGNAL(activated()), this, SLOT(viewTags()));
1224  connect(actionConvertStructure, SIGNAL(activated()), this, SLOT(openStructureSet()));
1225  connect(actionConvert, SIGNAL(activated()), this, SLOT(convert()));
1226  connect(actionAnonymize, SIGNAL(activated()), this, SLOT(anonymize()));
1227 
1228  connect(this, SIGNAL(working(int)), MainWindow, SLOT(working(int)));
1229  connect(this, SIGNAL(done(int)), MainWindow, SLOT(done(int)));
1230 }
1231 
1232 bool milxQtDICOMPlugin::anonymizeDicomImage(const std::string &input, const QString &subject_output_folder, const QString &rel_dir, unsigned int index_subject, unsigned int index_dicom, bool &isFirst)
1233 {
1234  QString logName= outputAnonymizeDirectoryname + QDir::separator() + "anonymization.log";
1235  std::string log = "Anonymizing image: " + input;
1236  writeLog(logName, log);
1237  MainWindow->printInfo(QString("Anonymizing: ") + input.c_str());
1238 
1239  //TODO: This should be retrieved directly from dicom.
1240  // And specific image type created then.
1241  typedef signed short shortPixelType;
1242  typedef itk::Image<shortPixelType, milx::imgDimension> shortImageType;
1243 
1245  std::ostringstream index;
1246  index << index_subject;
1247  std::string anonymization_value = outputPrefix.toStdString() + index.str();
1248 
1251  typedef itk::ImageFileReader< shortImageType > ReaderType;
1252  typedef itk::ImageFileReader< rgbImageType > rgbReaderType;
1253 
1256  ReaderType::Pointer reader = ReaderType::New();
1257  ImageIOType::Pointer gdcmImageIO = ImageIOType::New();
1258  reader->SetFileName(input.c_str());
1259  reader->SetImageIO( gdcmImageIO );
1260  reader->AddObserver(itk::ProgressEvent(), milx::ProgressUpdates);
1261  try
1262  {
1263  reader->Update();
1264  }
1265  catch (itk::ExceptionObject &ex)
1266  {
1267  std::cerr << ex << std::endl;
1268  return false;
1269  }
1270  shortImageType::Pointer floatImg = reader->GetOutput();
1271 
1273  if (isFirst)
1274  {
1275  QString fileMappingName = outputAnonymizeDirectoryname + QDir::separator() + "subjects_mapping.txt";
1276  QFile file_mapping(fileMappingName);
1277  if (file_mapping.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Append))
1278  {
1279  isFirst = false;
1281  std::string name_tag("0010|0010");
1282  std::string name_value;
1283  getTagValue(gdcmImageIO, name_tag, name_value);
1284 
1286  QTextStream out(&file_mapping);
1287  out.setCodec("UTF-8");
1288  out << QString::fromStdString(name_value) << "," << QString::fromStdString(anonymization_value) << "\n";
1289  file_mapping.close();
1290  }
1291  }
1292 
1296  std::string spl_per_px("0028|0002");
1297  std::string spl_per_pxl_value;
1298  getTagValue(gdcmImageIO, spl_per_px, spl_per_pxl_value);
1299  bool isRGB = false;
1300  if (spl_per_pxl_value == "3")
1301  {
1302  isRGB = true;
1303  }
1304 
1306  std::vector<std::string> dicomTags;
1307  if (anonPatientInfo->isChecked())
1308  {
1309  dicomTags.push_back("0010|0010"); //name
1310  dicomTags.push_back("0010|0020"); //id
1311  dicomTags.push_back("0010|1005");
1312  dicomTags.push_back("0010|1040");
1313  dicomTags.push_back("0010|2154");
1314  dicomTags.push_back("0010|0030"); //DOB
1315  dicomTags.push_back("0010|0032"); //DOB Time
1316  dicomTags.push_back("0010|1020"); //size
1317  dicomTags.push_back("0010|1030"); //weight
1318  }
1319 
1320  if (anonPhysician->isChecked())
1321  {
1322  dicomTags.push_back("0008|0090"); //phys name
1323  dicomTags.push_back("0008|0092");
1324  dicomTags.push_back("0008|0094");
1325  dicomTags.push_back("0008|1048"); //phys record
1326  dicomTags.push_back("0008|1050"); //perform phys name
1327  dicomTags.push_back("0008|1060"); //phys read
1328  dicomTags.push_back("0032|1032");
1329  dicomTags.push_back("0040|0006");
1330  dicomTags.push_back("4008|0114");
1331  }
1332 
1333  if (anonOperator->isChecked())
1334  {
1335  dicomTags.push_back("0008|1070");
1336  }
1337 
1338  if (anonScanDate->isChecked())
1339  {
1340  dicomTags.push_back("0008|002A"); //acq date time
1341  dicomTags.push_back("0008|0020"); //study date
1342  dicomTags.push_back("0008|0021"); //series date
1343  dicomTags.push_back("0008|0022"); //acq date
1344  }
1345 
1347  QString outputSequence = subject_output_folder + QDir::separator();
1348  if (checkboxPreserveFolderArc->isChecked())
1349  {
1350  outputSequence = outputSequence + rel_dir;
1351  }
1352  else
1353  {
1354  std::string tag1("0020|0011");
1355  std::string append1;
1356  getTagValue(gdcmImageIO, tag1, append1);
1357  removeForbiddenChar(append1, "\\/:*?\"<>|");
1358  outputSequence = outputSequence + QString::fromStdString(append1) + "_";
1359 
1360  std::string tag2("0018|0024");
1361  std::string append2;
1362  getTagValue(gdcmImageIO, tag2, append2);
1363  removeForbiddenChar(append2, "\\/:*?\"<>|");
1364  outputSequence = outputSequence + QString::fromStdString(append2);
1365  }
1366 
1367  QDir outputSequenceDirectory(outputSequence);
1368  bool exist = outputSequenceDirectory.exists();
1369  if (!exist)
1370  {
1371  exist = QDir().mkpath(outputSequence);
1372  if (! exist)
1373  {
1374  MainWindow->printError("Failed to create directory: " + outputSequence);
1375  std::cout << "Create fail: " << anonymization_value << std::endl;
1376  return false;
1377  }
1378  }
1379 
1381  log = "Component: [" + gdcmImageIO->GetComponentTypeAsString(gdcmImageIO->GetInternalComponentType()) + "]";
1382  log += ", Pixel type: [" + gdcmImageIO->GetPixelTypeAsString(gdcmImageIO->GetPixelType()) + "]\n";
1383  writeLog(logName, log);
1384 
1386  if (!isRGB) // If normal image
1387  {
1388  log = "Changing header";
1389  writeLog(logName, log);
1390  DictionaryType & dictionary = floatImg->GetMetaDataDictionary();
1391  std::vector<std::string>::iterator dicomTagIterator;
1392  for (dicomTagIterator = dicomTags.begin(); dicomTagIterator != dicomTags.end(); dicomTagIterator++)
1393  {
1394  itk::EncapsulateMetaData<std::string>(dictionary, *dicomTagIterator, anonymization_value);
1395  }
1396 
1397  //make output filename
1398  std::string filename;
1399  makeFilename(outputSequence, gdcmImageIO, index_dicom, filename, index_subject);
1400 
1401 
1402  typedef itk::ImageFileWriter< shortImageType > Writer1Type;
1403  gdcmImageIO->KeepOriginalUIDOn();
1404  Writer1Type::Pointer writer1 = Writer1Type::New();
1405  writer1->SetInput(floatImg);
1406  writer1->SetFileName(filename.c_str());
1407  writer1->SetImageIO( gdcmImageIO);
1408  writer1->AddObserver(itk::ProgressEvent(), milx::ProgressUpdates);
1409  log = "Writing image as " + filename;
1410  writeLog(logName, log);
1411  MainWindow->printInfo(QString("Writing image as: ") + filename.c_str());
1412  try
1413  {
1414  writer1->Update();
1415  }
1416  catch (itk::ExceptionObject &ex)
1417  {
1418  MainWindow->printError(ex.GetDescription());
1419  std::cerr << ex << std::endl;
1420  return false;
1421  }
1422  }
1423  else // If RGB image
1424  {
1425  rgbReaderType::Pointer readerrgb = rgbReaderType::New();
1426 
1427  gdcmImageIO = NULL;
1428  gdcmImageIO = ImageIOType::New();
1429  readerrgb->SetFileName(input.c_str());
1430  readerrgb->SetImageIO(gdcmImageIO);
1431  readerrgb->AddObserver(itk::ProgressEvent(), milx::ProgressUpdates);
1432  try
1433  {
1434  readerrgb->Update();
1435  }
1436  catch (itk::ExceptionObject &ex)
1437  {
1438  std::cerr << ex << std::endl;
1439  return false;
1440  }
1441  rgbImageType::Pointer rgbImg = readerrgb->GetOutput();
1442 
1443  ImageIOType::Pointer gdcmImageIO2 = ImageIOType::New();
1444 
1445  log = "Changing header";
1446  writeLog(logName, log);
1447 
1448  DictionaryType & dictionary = rgbImg->GetMetaDataDictionary();
1449  std::vector<std::string>::iterator dicomTagIterator;
1450  for (dicomTagIterator = dicomTags.begin(); dicomTagIterator != dicomTags.end(); dicomTagIterator++)
1451  {
1452  itk::EncapsulateMetaData<std::string>(dictionary, *dicomTagIterator, anonymization_value);
1453  }
1454 
1455  //make output filename
1456  std::string filename;
1457  makeFilename(outputSequence, gdcmImageIO, index_dicom, filename, index_subject);
1458 
1459  typedef itk::ImageFileWriter< rgbImageType > Writer1Type;
1460  gdcmImageIO2->SetMetaDataDictionary(dictionary);
1461  gdcmImageIO2->SetUseCompression(gdcmImageIO->GetUseCompression());
1462  gdcmImageIO2->SetIORegion(gdcmImageIO->GetIORegion());
1463  gdcmImageIO2->SetUIDPrefix(gdcmImageIO->GetUIDPrefix());
1464  gdcmImageIO2->KeepOriginalUIDOn();
1465 
1466  Writer1Type::Pointer writer1 = Writer1Type::New();
1467  writer1->SetInput(rgbImg);
1468  //writer1->SetMetaDataDictionary(dictionary);
1469  writer1->SetFileName(filename.c_str());
1470  writer1->SetImageIO(gdcmImageIO2);
1471  writer1->AddObserver(itk::ProgressEvent(), milx::ProgressUpdates);
1472  writer1->UseInputMetaDataDictionaryOff();
1473  log = "Writing image as " + filename;
1474  writeLog(logName, log);
1475  MainWindow->printInfo(QString("Writing image as: ") + filename.c_str());
1476  try
1477  {
1478  writer1->Update();
1479  }
1480  catch (itk::ExceptionObject &ex)
1481  {
1482  MainWindow->printError(ex.GetDescription());
1483  std::cerr << ex << std::endl;
1484  return false;
1485  }
1486  }
1487  log = "Success\n";
1488  writeLog(logName, log);
1489  return true;
1490 }
1491 
1492 void milxQtDICOMPlugin::makeFilename(const QString &path, ImageIOType::Pointer gdcmImageIO, unsigned int index, std::string &filename, unsigned int index_subject)
1493 {
1494  std::string tag_idx("0020|0013");
1495  std::string append_idx;
1496  getTagValue(gdcmImageIO, tag_idx, append_idx);
1497 
1498  std::ostringstream index_dcm;
1499  index_dcm << std::setfill('0') << std::setw(4) << append_idx;
1500 
1501 
1502  QString str_separator(QDir::separator());
1503  filename = path.toStdString() + str_separator.toStdString();
1504 
1505  if (checkboxPatientName->isChecked())
1506  {
1507  std::string append = outputPrefix.toStdString();
1508  removeForbiddenChar(append, "\\/:*?\"<>|");
1509  filename = filename + append + "_";
1510  }
1511 
1512  if (checkboxPatientID->isChecked())
1513  {
1514  std::ostringstream SubID;
1515  SubID << index_subject;
1516  filename = filename + SubID.str() + "_";
1517  }
1518 
1519  if (checkboxSeriesDate->isChecked())
1520  {
1521  std::string tag("0008|0021");
1522  std::string append;
1523  getTagValue(gdcmImageIO, tag, append);
1524  if (append != "")
1525  {
1526  filename = filename + append + "_";
1527  }
1528  }
1529 
1530  if (checkboxSeriesTime->isChecked())
1531  {
1532  std::string tag("0008|0031");
1533  std::string append;
1534  getTagValue(gdcmImageIO, tag, append);
1535  if (append != "")
1536  {
1537  filename = filename + append + "_";
1538  }
1539  }
1540 
1541  if (checkboxStudyID->isChecked())
1542  {
1543  std::string tag("0020|0010");
1544  std::string append;
1545  getTagValue(gdcmImageIO, tag, append);
1546  removeForbiddenChar(append, "\\/:*?\"<>|");
1547  if (append != "")
1548  {
1549  filename = filename + append + "_";
1550  }
1551  }
1552 
1553  if (checkboxStudyDesc->isChecked())
1554  {
1555  std::string tag("0008|1030");
1556  std::string append;
1557  getTagValue(gdcmImageIO, tag, append);
1558  removeForbiddenChar(append, "\\/:*?\"<>|");
1559  if (append != "")
1560  {
1561  filename = filename + append + "_";
1562  }
1563  }
1564 
1565  if (checkboxSeriesNumber->isChecked())
1566  {
1567  std::string tag("0020|0011");
1568  std::string append;
1569  getTagValue(gdcmImageIO, tag, append);
1570  if (append != "")
1571  {
1572  filename = filename + append + "_";
1573  }
1574  }
1575 
1576  if (checkboxSequenceName->isChecked())
1577  {
1578  std::string tag("0018|0024");
1579  std::string append;
1580  getTagValue(gdcmImageIO, tag, append);
1581  removeForbiddenChar(append, "\\/:*?\"<>|");
1582  if (append != "")
1583  {
1584  filename = filename + append + "_";
1585  }
1586  }
1587 
1588  if (checkboxProtocolName->isChecked())
1589  {
1590  std::string tag("0018|1030");
1591  std::string append;
1592  getTagValue(gdcmImageIO, tag, append);
1593  removeForbiddenChar(append, "\\/:*?\"<>|");
1594  if (append != "")
1595  {
1596  filename = filename + append + "_";
1597  }
1598  }
1599 
1600  if (checkboxSeriesDescription->isChecked())
1601  {
1602  std::string tag("0008|103e");
1603  std::string append;
1604  getTagValue(gdcmImageIO, tag, append);
1605  removeForbiddenChar(append, "\\/:*?\"<>|");
1606  if (append != "")
1607  {
1608  filename = filename + append + "_";
1609  }
1610  }
1611 
1612  filename = filename + index_dcm.str() + ".IMA";
1613 }
1614 
1615 void milxQtDICOMPlugin::removeForbiddenChar(std::string &str, char* charsToRemove)
1616 {
1617  for (unsigned int i = 0; i < strlen(charsToRemove); ++i)
1618  {
1619  str.erase(remove(str.begin(), str.end(), charsToRemove[i]), str.end());
1620  }
1621 }
1622 
1623 void milxQtDICOMPlugin::getTagValue(ImageIOType::Pointer gdcmImageIO, const std::string &tag, std::string & tag_value)
1624 {
1625  itk::MetaDataDictionary & dic = gdcmImageIO->GetMetaDataDictionary();
1626  itk::MetaDataDictionary::ConstIterator tag_iter = dic.Find(tag);
1627 
1628  if (tag_iter == dic.End()) //If we don't find the tag
1629  {
1630  return;
1631  }
1632 
1633  MetaDataStringType::ConstPointer entryValue= dynamic_cast<const MetaDataStringType *>(tag_iter->second.GetPointer());
1634  if(entryValue)
1635  {
1636  tag_value = entryValue->GetMetaDataObjectValue();
1637  QString tag_simplified = QString::fromStdString(tag_value);
1638  tag_simplified = tag_simplified.simplified();
1639  tag_value = tag_simplified.toStdString();
1640  std::replace(tag_value.begin(), tag_value.end(),' ','_');
1641  }
1642 }
1643 
1644 void milxQtDICOMPlugin::writeLog(QString &filename, std::string &output)
1645 {
1646  QFile file_log(filename);
1647  if (file_log.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Append))
1648  {
1649  QTextStream out_log(&file_log);
1650  out_log.setCodec("UTF-8");
1651  out_log << QString::fromStdString(output) << "\n";
1652  file_log.close();
1653  }
1654 }
1655 
1657 {
1658  outputAnonymizeDirectoryname = txtOutputAnonymizeName->text();
1659  inputAnonymizeDirectoryname = txtInputAnonymizeName->text();
1660  QDir output(outputAnonymizeDirectoryname);
1661  QDir input(inputAnonymizeDirectoryname);
1662  if (output.exists() && input.exists())
1663  {
1664  valid = true;
1665  }
1666  else
1667  {
1668  valid = false;
1669  }
1670 
1671  if (!txtOutputPrefix->text().isEmpty())
1672  {
1673  outputPrefix = txtOutputPrefix->text();
1674  }
1675  else
1676  {
1677  outputPrefix = "Anon";
1678  }
1679 
1680  QString value = txtOutputInitID->text();
1681  if (!value.isEmpty())
1682  outputInitID = value.toInt();
1683  else
1684  outputInitID = 1;
1685 }
1686 
1687 Q_EXPORT_PLUGIN2(DICOMPlugin, milxQtDICOMPluginFactory);
1688 
void openSeries()
Open DICOM image series.
virtual void SetInputCollection(vtkPolyDataCollection *collection, QStringList &filenames)
Pass a collection to internal plugin class. [Implement this in your plugin].
virtual void save(QString filename)
Save the result as a file using the plugin. [Implement this in your plugin].
bool threaded
Threaded plugin?
virtual QString openFileSupport()
Get the file support string for opening (extension wildcard list). [Implement this in your plugin]...
QPointer< milxQtManager > manager
Manager widget.
virtual bool isPluginWindow(QWidget *window)
Is the window provided a plugin generated window? In this case a milxQtShapeModel window...
QAction * actionOpenSeries
open series action
virtual QString name()
Get the Name of the plugin. [Implement this in your plugin].
QPointer< QDockWidget > dock
Dock widget.
void setName(const QString filename)
Set the name of the data.
This class represents the MILX Qt Render Window Display object using QVTK.
bool consoleWindow
console window?
static std::vector< std::string > GetDICOMSeriesFilenames(const std::string directoryPath, const std::string seriesName, bool recursive=false)
Returns the filenames for a given UID/Series name for a given directory.
Definition: milxFile.cxx:151
virtual void open(QString filename)
Open the file using the plugin. [Implement this in your plugin].
This class represents the MILX Qt Image Display object using VTK.
Definition: milxQtImage.h:118
A manager (tabbed) widget class for displaying information about data such as case ID etc...
Definition: milxQtManager.h:31
virtual QStringList openExtensions()
Get a list of supported file format extensions. [Implement this in your plugin].
void done(int value)
Send signal that computation is done. Value carries the progress,.
void PrintError(const std::string msg)
Displays a generic msg to standard error with carriage return.
Definition: milxGlobal.h:202
bool extension
Extension rather than a plugin?
virtual milxQtModel * modelResult()
Get the model result. The result can then be displayed in milxQtMain etc. [Implement this in your plu...
virtual milxQtImage * imageResult()
Get the image result. The result can then be displayed in milxQtMain etc.[Implement this in your plug...
QAction * actionTags
open series action
void makeFilename(const QString &path, ImageIOType::Pointer gdcmImageIO, unsigned int index, std::string &filename, unsigned int index_subject)
Small helper to make filename from dicom tags.
void convert()
Convert a DICOM series (or a path to a number of series) to Nifti (*.nii.gz) images.
This class represents the MILX Qt Model/Mesh Display object using VTK.
Definition: milxQtModel.h:115
milxQtDICOMPlugin(QObject *theParent=0)
Default destructor.
void working(int value)
Send signal that computation is in progress. Value carries the progress,.
bool dockable
Dockable plugin?
virtual milxQtRenderWindow * genericResult()
Get the generic result, which is a milxQtRenderWindow. The result can then be displayed in milxQtMain...
void affectValues()
Function called when the wizard for anonymization is validated It will verify that everything is in o...
virtual QStringList saveExtensions()
Get a list of supported file format extensions. [Implement this in your plugin].
The interface for any plugins that can be made for milxQtMain.
void viewTags()
View DICOM tags of image series in the manager.
void PrintInfo(const std::string msg)
Displays a generic msg to standard output with carriage return.
Definition: milxGlobal.h:174
QAction * actionAnonymize
Anonymize action.
std::string NumberToString(double num, unsigned zeroPad=0)
Number to string converter.
Definition: milxGlobal.h:112
QMenu * menuDICOM
DICOM menu.
static bool ReadImageInformation(const std::string filename, std::string &pixeltype, std::string &componentType, size_t &dimensions)
Reads just the header of an image file (without reading the image data), and writes the info into the...
Definition: milxFile.cxx:69
bool anonymizeDicomImage(const std::string &input, const QString &subject_output_folder, const QString &rel_dir, unsigned int index_subject, unsigned int index_dicom, bool &isFirst)
Function used to anonymize a single dicom image.
QAction * actionConvertStructure
convert RT action
virtual QDockWidget * dockWidget()
Return the dock widget (if one is provided by plugin). [Implement this in your plugin].
static std::vector< std::string > GetDICOMSeriesUIDs(const std::string directoryPath, bool recursive=false)
DICOM Related.
Definition: milxFile.cxx:115
virtual QString saveFileSupport()
Get the file support string for saving (extension wildcard list). [Implement this in your plugin]...
This class represents the MILX Qt Main Window object using Qt.
Definition: milxQtMain.h:85
QAction * actionConvert
convert action
void getTagValue(ImageIOType::Pointer gdcmImageIO, const std::string &tag, std::string &tag_value)
Retrieve tag value fromt he gdcmImageIO object.
virtual void loadExtension()
Load the extension. [Implement this in your plugin].
void openStructureSet()
Open DICOM RT image series.