CustusX  22.09
An IGT application
cxImportDataTypeWidget.cpp
Go to the documentation of this file.
1 /*=========================================================================
2 This file is part of CustusX, an Image Guided Therapy Application.
3 
4 Copyright (c) SINTEF Department of Medical Technology.
5 All rights reserved.
6 
7 CustusX is released under a BSD 3-Clause license.
8 
9 See Lisence.txt (https://github.com/SINTEFMedtek/CustusX/blob/master/License.txt) for details.
10 =========================================================================*/
11 
12 #include "cxImportDataTypeWidget.h"
13 #include <QVBoxLayout>
14 #include <QHBoxLayout>
15 #include <QLabel>
16 #include <QTableWidget>
17 #include <QHeaderView>
18 #include <QApplication>
19 #include <QDesktopWidget>
20 #include <QCheckBox>
21 #include <QGroupBox>
22 #include <QFileInfo>
23 #include "cxOptionsWidget.h"
25 #include "cxFileManagerService.h"
26 #include "cxLogger.h"
27 #include "cxImage.h"
28 #include "cxPointMetric.h"
30 #include "cxVolumeHelpers.h"
31 #include "cxImageTF3D.h"
32 #include "cxImageLUT2D.h"
33 #include "cxViewService.h"
34 #include "cxImportWidget.h"
35 #include "cxCustomMetaImage.h"
36 
37 namespace cx
38 {
39 
40 ImportDataTypeWidget::ImportDataTypeWidget(ImportWidget *parent, VisServicesPtr services, std::vector<DataPtr> data, std::vector<DataPtr> &parentCandidates, QString filename) :
41  BaseWidget(parent, "ImportDataTypeWidget", "Import"),
42  mImportWidget(parent),
43  mServices(services),
44  mData(data),
45  mFilename(filename),
46  mParentCandidates(parentCandidates),
47  mSelectedIndexInTable(0),
48  mImageTypeCombo(NULL),
49  mModalityCombo(NULL)
50 
51 {
52  mAnatomicalCoordinateSystems = new QComboBox();
53  mAnatomicalCoordinateSystems->addItem("LPS"); //CX
54  mAnatomicalCoordinateSystems->addItem("RAS"); //NIfTI
55 
56  if(isInputFileInNiftiFormat())
57  mAnatomicalCoordinateSystems->setCurrentText("RAS");
58 
59  mShouldImportParentTransform = new QComboBox();
60  mShouldImportParentTransform->addItem("No");
61  mShouldImportParentTransform->addItem("Yes");
62 
63  mParentCandidatesCB = new QComboBox();
64 
65  mShouldConvertDataToUnsigned = new QCheckBox();
66  mShouldConvertDataToUnsigned->setCheckState(Qt::Unchecked);
67 
68  mTableWidget = new QTableWidget();
69  mTableWidget->setRowCount(0);
70  mTableWidget->setColumnCount(4);
71  mTableHeader<<"#"<<"Type"<<"Name"<<"Space";
72  mTableWidget->setHorizontalHeaderLabels(mTableHeader);
73  mTableWidget->horizontalHeader()->setStretchLastSection(true);
74  mTableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
75  mTableWidget->verticalHeader()->setVisible(false);
76  mTableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
77  mTableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
78  mTableWidget->setSelectionMode(QAbstractItemView::SingleSelection);
79  mTableWidget->setShowGrid(false);
80  mTableWidget->setStyleSheet("QTableView {selection-background-color: #ACCEF7;}");
81  mTableWidget->setGeometry(QApplication::desktop()->screenGeometry());
82 
83  QString type, name;
84  for(unsigned i=0; i<mData.size(); ++i)
85  {
86  if(!mData[i])
87  {
88  CX_LOG_WARNING() << "ImportDataTypeWidget::ImportDataTypeWidget: No data";
89  continue;
90  }
91  type = mData[i]->getType();
92  name = mData[i]->getName();
93  QString space = mData[i]->getSpace();
94  //create point metric groups
95  if(type == PointMetric::getTypeName())
96  {
97  space = boost::dynamic_pointer_cast<PointMetric>(mData[i])->getSpace().toString();
98  (mPointMetricGroups[space]).push_back(mData[i]);
99  }
100  //add image or mesh directly to the table
101  else
102  {
103  int newRowIndex = mTableWidget->rowCount();
104  mTableWidget->setRowCount(newRowIndex+1);
105  mTableWidget->setItem(newRowIndex, 0, new QTableWidgetItem("1"));
106  mTableWidget->setItem(newRowIndex, 1, new QTableWidgetItem(name));
107  mTableWidget->setItem(newRowIndex, 2, new QTableWidgetItem(type));
108  mTableWidget->setItem(newRowIndex, 3, new QTableWidgetItem(space));
109  }
110  this->createDataSpecificGui(mData[i]);
111  }
112  this->addPointMetricGroupsToTable();
113 
114  //gui
115  QVBoxLayout *topLayout = new QVBoxLayout(this);
116  this->setLayout(topLayout);
117 
118  QFileInfo fileInfo(filename);
119  QString title = fileInfo.fileName();
120 
121  QGroupBox *groupBox = new QGroupBox(title);
122 
123  QGridLayout *gridLayout = new QGridLayout();
124  gridLayout->addWidget(new QLabel("For all data in the file: "), 0, 0, 1, 2);
125  gridLayout->addWidget(new QLabel("Specify anatomical coordinate system"), 1, 0);
126  gridLayout->addWidget(mAnatomicalCoordinateSystems, 1, 1);
127  gridLayout->addWidget(new QLabel("Import parents transform?"), 2, 0);
128  gridLayout->addWidget(mShouldImportParentTransform, 2, 1);
129  gridLayout->addWidget(new QLabel("Set parent"), 3, 0);
130  gridLayout->addWidget(mParentCandidatesCB, 3, 1);
131  gridLayout->addWidget(new QLabel("Convert data to unsigned?"), 4, 0);
132  gridLayout->addWidget(mShouldConvertDataToUnsigned, 4,1);
133  gridLayout->addWidget(mTableWidget, 5, 0, 1, 2);
134  if(mModalityCombo)
135  gridLayout->addWidget(mModalityCombo);
136  if(mImageTypeCombo)
137  gridLayout->addWidget(mImageTypeCombo);
138 
139  groupBox->setLayout(gridLayout);
140  topLayout->addWidget(groupBox);
141 
144 }
145 
147 {
149  disconnect(mImportWidget, &ImportWidget::parentCandidatesUpdated, this, &ImportDataTypeWidget::update);
150 }
151 
152 
153 void ImportDataTypeWidget::createDataSpecificGui(DataPtr data)
154 {
155  ImagePtr image = boost::dynamic_pointer_cast<Image>(data);
156 
157  if(image)
158  {
159  mModalityAdapter = StringPropertyDataModality::New(mServices->patient());
160  mModalityCombo = new LabeledComboBoxWidget(this, mModalityAdapter);
161  mModalityAdapter->setData(image);
162 
163  mImageTypeAdapter = StringPropertyImageType::New(mServices->patient());
164  mImageTypeCombo = new LabeledComboBoxWidget(this, mImageTypeAdapter);
165  mImageTypeAdapter->setData(image);
166 
167  if(isInputFileInNiftiFormat()) // NIfTI files are usually MR. Set this as the default
168  {
169  mModalityAdapter->setValue(enum2string(imMR));
170  updateImageType();
171  }
172  }
173 }
174 
175 void ImportDataTypeWidget::updateImageType()
176 {
177  // Test code: Trying to use convertToImageSubType on file name to find correct subtype.
178  IMAGE_SUBTYPE imageSubType = convertToImageSubType(mFilename);
179  mImageTypeAdapter->setValue(enum2string(imageSubType));
180 }
181 
182 std::map<QString, QString> ImportDataTypeWidget::getParentCandidateList()
183 {
184  std::map<QString, QString> parentCandidates;
185  for(unsigned i=0; i<mParentCandidates.size(); ++i)
186  {
187  parentCandidates[mParentCandidates[i]->getName()] = mParentCandidates[i]->getUid();
188  }
189 
190  return parentCandidates;
191 }
192 
193 void ImportDataTypeWidget::updateSpaceComboBox(QComboBox *box, QString pointMetricGroupId)
194 {
195  box->clear();
196  std::map<QString, QString> parentCandidates = this->getParentCandidateList();
197  std::map<QString, QString>::iterator it;
198  for(it= parentCandidates.begin(); it != parentCandidates.end(); ++it)
199  {
200  QVariant id(it->second);
201  box->addItem(it->first, id);
202  }
203  std::vector<DataPtr> pointMetricGroup = mPointMetricGroups[pointMetricGroupId];
204  QString currentSpace = pointMetricGroup[0]->getSpace();
205  box->setCurrentText(currentSpace);
206 }
207 
208 void ImportDataTypeWidget::updateParentCandidatesComboBox()
209 {
210  //remember selection
211  QString selectedParentId = (mParentCandidatesCB->itemData(mParentCandidatesCB->currentIndex()).toString());
212 
213  mParentCandidatesCB->clear();
214  std::map<QString, QString> parentCandidates = this->getParentCandidateList();
215  std::map<QString, QString>::iterator it;
216  QVariant emptyId("");
217  mParentCandidatesCB->addItem("", emptyId);
218  int selectedIndex = 0;
219  for(it= parentCandidates.begin(); it != parentCandidates.end(); ++it)
220  {
221  QString idString = it->second;
222  QVariant id(idString);
223  mParentCandidatesCB->addItem(it->first, id);
224  if(selectedParentId.compare(idString, Qt::CaseInsensitive) == 0)
225  selectedIndex = mParentCandidatesCB->count()-1;
226  }
227 
228  if(selectedIndex != 0)
229  mParentCandidatesCB->setCurrentIndex(selectedIndex);
230  else
231  {
232  //TODO parent guess:
233  QString parentGuess = this->getInitialGuessForParentFrame();
234  //CX_LOG_DEBUG() << "ParentGuess: " << parentGuess;
235  mParentCandidatesCB->setCurrentText(parentGuess);
236  }
237 
238 
239 }
240 
241 void ImportDataTypeWidget::importAllData()
242 {
243  for(unsigned i=0; i<mData.size(); ++i)
244  {
245  if(mData[i])
246  {
247  QString parentId = (mParentCandidatesCB->itemData(mParentCandidatesCB->currentIndex()).toString());
248  mData[i]->get_rMd_History()->setParentSpace(parentId);
249 
250  mServices->patient()->insertData(mData[i]);
251  mServices->view()->autoShowData(mData[i]);
252  }
253  }
254 }
255 
256 void ImportDataTypeWidget::applyParentTransformImport()
257 {
258  CX_LOG_DEBUG() << "applyParentTransformImport()";
259 
260  QString parentId = (mParentCandidatesCB->itemData(mParentCandidatesCB->currentIndex()).toString());
261  DataPtr parent = mServices->patient()->getData(parentId);
262 
263  if(!parent)
264  {
265  CX_LOG_ERROR() << "Could not find parent data with uid: " << parentId;
266  return;
267  }
268 
269  std::vector<DataPtr>::iterator it = mData.begin();
270  for(;it!=mData.end(); ++it)
271  {
272  DataPtr data = (*it);
273  data->get_rMd_History()->setRegistration(parent->get_rMd());
274  report("Assigned rMd from data [" + parent->getName() + "] to data [" + data->getName() + "]");
275  }
276 
277  /*
278  if (!mTransformFromParentFrameCheckBox->isChecked())
279  return;
280  if(!mData)
281  return;
282  DataPtr parent = mPatientModelService->getData(mData->getParentSpace());
283  if (!parent)
284  return;
285  mData->get_rMd_History()->setRegistration(parent->get_rMd());
286  report("Assigned rMd from data [" + parent->getName() + "] to data [" + mData->getName() + "]");
287  */
288 }
289 
290 void ImportDataTypeWidget::applyConversionLPS()
291 {
292  CX_LOG_DEBUG() << "applyConversionLPS()";
293 
294  std::vector<DataPtr>::iterator it = mData.begin();
295  for(;it!=mData.end(); ++it)
296  {
297  DataPtr data = (*it);
298  Transform3D sMd = data->get_rMd();
300  Transform3D rMd = sMr.inv() * sMd;
301  data->get_rMd_History()->setRegistration(rMd);
302  report("Nifti import: Converted data " + data->getName() + " from LPS to RAS coordinates.");
303  }
304 
305  /*
306  if (!mNiftiFormatCheckBox->isChecked())
307  return;
308  if(!mData)
309  return;
310  Transform3D sMd = mData->get_rMd();
311  Transform3D sMr = createTransformFromReferenceToExternal(pcsRAS);
312  // rMd = createTransformRotateZ(M_PI) * rMd;
313  Transform3D rMd = sMr.inv() * sMd;
314  mData->get_rMd_History()->setRegistration(rMd);
315  report("Nifti import: Converted data " + mData->getName() + " from LPS to RAS coordinates.");
316  */
317 
318 }
319 
320 void ImportDataTypeWidget::applyConversionToUnsigned()
321 {
322  CX_LOG_DEBUG() << "applyConversionToUnsigned()";
323 
324  std::vector<DataPtr>::iterator it = mData.begin();
325  for(;it!=mData.end(); ++it)
326  {
327  DataPtr data = (*it);
328 
329  ImagePtr image = boost::dynamic_pointer_cast<Image>(data);
330  if (!image)
331  return;
332 
333  ImagePtr converted = convertImageToUnsigned(mServices->patient(), image);
334 
335  image->setVtkImageData(converted->getBaseVtkImageData());
336 
337  ImageTF3DPtr TF3D = converted->getTransferFunctions3D()->createCopy();
338  ImageLUT2DPtr LUT2D = converted->getLookupTable2D()->createCopy();
339  image->setLookupTable2D(LUT2D);
340  image->setTransferFunctions3D(TF3D);
341  //mServices->patient()->insertData(image);
342 
343  DataPtr convertedData = boost::dynamic_pointer_cast<Data>(image);
344  (*it) = convertedData;
345  }
346 
347  /*
348  if (!mConvertToUnsignedCheckBox->isChecked())
349  return;
350 
351  ImagePtr image = boost::dynamic_pointer_cast<Image>(mData);
352  if (!image)
353  return;
354 
355  ImagePtr converted = convertImageToUnsigned(mPatientModelService, image);
356 
357  image->setVtkImageData(converted->getBaseVtkImageData());
358 
359  ImageTF3DPtr TF3D = converted->getTransferFunctions3D()->createCopy();
360  ImageLUT2DPtr LUT2D = converted->getLookupTable2D()->createCopy();
361  image->setLookupTable2D(LUT2D);
362  image->setTransferFunctions3D(TF3D);
363  mPatientModelService->insertData(image);
364  */
365 }
366 
368 {
369  this->updateParentCandidatesComboBox();
370 
371  std::map<QString, QComboBox *>::iterator it;
372  for(it=mSpaceCBs.begin(); it != mSpaceCBs.end(); ++it)
373  {
374  QString id = it->first;
375  QComboBox *box = it->second;
376  this->updateSpaceComboBox(box,id);
377  }
378 }
379 
381 {
382  if(mShouldConvertDataToUnsigned->isChecked())
383  this->applyConversionToUnsigned();
384 
385  this->importAllData();
386 
387  if(mShouldImportParentTransform->currentText() == "Yes")
388  this->applyParentTransformImport();
389  if(mAnatomicalCoordinateSystems->currentText() != "LPS")
390  this->applyConversionLPS();
391 }
392 
393 void ImportDataTypeWidget::showEvent(QShowEvent *event)
394 {
395  BaseWidget::showEvent(event);
396  this->update();
397 }
398 
399 void ImportDataTypeWidget::pointMetricGroupSpaceChanged(int index)
400 {
401  QComboBox *box = qobject_cast<QComboBox*>(QObject::sender());
402  QString newSpace = box->currentData().toString();
403 
404  QString pointMetricsGroupId;
405  std::map<QString, QComboBox *>::iterator it;
406  for(it = mSpaceCBs.begin(); it != mSpaceCBs.end(); ++it)
407  {
408  if(it->second == box)
409  pointMetricsGroupId = it->first;
410  }
411  std::vector<DataPtr> pointMetricGroup = mPointMetricGroups[pointMetricsGroupId];
412  for(unsigned i=0; i<pointMetricGroup.size(); ++i)
413  {
414  CoordinateSystem cs(csDATA, newSpace);
415  boost::dynamic_pointer_cast<PointMetric>(pointMetricGroup[i])->setSpace(cs);
416  }
417 }
418 
419 QString ImportDataTypeWidget::getInitialGuessForParentFrame()
420 {
421  int candidateScore = 0;
422  QString bestCandidate;
423 
424  for(unsigned i=0; i < mData.size(); ++i)
425  {
426  DataPtr data = mData[i];
427  std::map<QString, QString> parentCandidates = this->getParentCandidateList();
428 
429  std::map<QString, QString>::iterator iter;
430  for(iter= parentCandidates.begin(); iter != parentCandidates.end(); ++iter)
431  {
432  int similarity = similatiryMeasure(data->getUid(), iter->second);
433  if(similarity > candidateScore && !isSegmentation(iter->second))
434  {
435  candidateScore = similarity;
436  bestCandidate = iter->first;
437  }
438  }
439  }
440 
441  return bestCandidate;
442 }
443 
444 int ImportDataTypeWidget::similatiryMeasure(QString current, QString candidate)
445 {
446  QStringList currentList = splitStringIntoSeparateParts(current);
447  QStringList candidateList = splitStringIntoSeparateParts(candidate);
448  return countEqualListElements(currentList, candidateList);
449 }
450 
451 QStringList ImportDataTypeWidget::splitStringIntoSeparateParts(QString current)
452 {
453  current = removeParenthesis(current);
454 
455  QStringList list = current.split(".", QString::SkipEmptyParts);
456  QStringList list2;
457  for (int i = 0; i < list.size(); ++i)
458  {
459  list2 << list[i].split("_", QString::SkipEmptyParts);
460  }
461  QStringList currentParts;
462  for (int i = 0; i < list2.size(); ++i)
463  {
464  currentParts << list2[i].split("-", QString::SkipEmptyParts);
465  }
466  return currentParts;
467 }
468 
469 QString ImportDataTypeWidget::removeParenthesis(QString current)
470 {
471  int startParenthesis;
472  do
473  {
474  startParenthesis = current.indexOf("{");
475  int endParenthesis = current.indexOf("}");
476  current.replace(startParenthesis, endParenthesis-startParenthesis+1, "");
477  } while (startParenthesis != -1);
478  return current;
479 }
480 
481 int ImportDataTypeWidget::countEqualListElements(QStringList first, QStringList second)
482 {
483  int retval = 0;
484  int numComparedElements = 0;
485  for (int i = 0; i < first.size(); ++i)
486  {
487  if(excludeElement(first[i]))
488  continue;
489  ++numComparedElements;
490  for (int j = 0; j < second.size(); ++j)
491  {
492  if(first[i].compare(second[j]) == 0)
493  {
494  ++retval;
495  break;//Don't count repeating elements
496  }
497  }
498  }
499 
500  if (retval == numComparedElements)
501  return 0;//Don't match equal list
502  return retval;
503 }
504 
505 bool ImportDataTypeWidget::excludeElement(QString element)
506 {
507  if (isSegmentation(element))
508  return true;
509  return false;
510 }
511 
512 void ImportDataTypeWidget::addPointMetricGroupsToTable()
513 {
514  QString type, name;
515  int groupnr = 0;
516  std::map<QString, std::vector<DataPtr> >::iterator it = mPointMetricGroups.begin();
517  for(; it != mPointMetricGroups.end(); ++it)
518  {
519  groupnr +=1;
520 
521  QString space = it->first;
522  std::vector<DataPtr> datas = it->second;
523  DataPtr data = datas[0];
524  if(datas.empty() || !data)
525  {
526  continue;
527  }
528 
529  QComboBox *spaceCB = new QComboBox();
530  mSpaceCBs[space] = spaceCB;
531  connect(spaceCB, SIGNAL(currentIndexChanged(int)), this, SLOT(pointMetricGroupSpaceChanged(int)));
532  this->updateSpaceComboBox(spaceCB, space);
533 
534  type = data->getType();
535  name = "Point metric group "+QString::number(groupnr);
536 
537  int newRowIndex = mTableWidget->rowCount();
538  mTableWidget->setRowCount(newRowIndex+1);
539  mTableWidget->setItem(newRowIndex, 0, new QTableWidgetItem(QString::number(datas.size())));
540  mTableWidget->setItem(newRowIndex, 1, new QTableWidgetItem(name));
541  mTableWidget->setItem(newRowIndex, 2, new QTableWidgetItem(type));
542  mTableWidget->setCellWidget(newRowIndex, 3, spaceCB);
543  }
544 }
545 
546 bool ImportDataTypeWidget::isInputFileInNiftiFormat()
547 {
548  if(mFilename.endsWith(".nii", Qt::CaseInsensitive))
549  return true;
550  return false;
551 }
552 
553 bool ImportDataTypeWidget::isSegmentation(QString filename)
554 {
555  if(filename.contains("label", Qt::CaseInsensitive))
556  return true;
557  if(filename.contains("seg", Qt::CaseInsensitive))
558  return true;
559  return false;
560 }
561 
562 }
pcsRAS
Right-Anterior-Superior, used by Slicer3D, ITK-Snap, nifti, MINC.
boost::shared_ptr< class VisServices > VisServicesPtr
Definition: cxMainWindow.h:40
imMR
Transform3D Transform3D
Transform3D is a representation of an affine 3D transform.
cxResource_EXPORT Transform3D createTransformFromReferenceToExternal(PATIENT_COORDINATE_SYSTEM external)
static StringPropertyDataModalityPtr New(PatientModelServicePtr patientModelService)
boost::shared_ptr< class Image > ImagePtr
Definition: cxDicomWidget.h:27
Composite widget for string selection.
csDATA
a datas space (d)
Definition: cxDefinitions.h:90
virtual void showEvent(QShowEvent *event)
ImagePtr convertImageToUnsigned(PatientModelServicePtr dataManager, ImagePtr image, vtkImageDataPtr suggestedConvertedVolume, bool verbose)
boost::shared_ptr< class Data > DataPtr
static StringPropertyImageTypePtr New(PatientModelServicePtr patientModelService)
boost::shared_ptr< class ImageLUT2D > ImageLUT2DPtr
ImportDataTypeWidget(ImportWidget *parent, VisServicesPtr services, std::vector< DataPtr > data, std::vector< DataPtr > &parentCandidates, QString filename)
#define CX_LOG_ERROR
Definition: cxLogger.h:99
A volumetric data set.
Definition: cxImage.h:45
IMAGE_SUBTYPE convertToImageSubType(QString imageTypeSubString)
Identification of a Coordinate system.
Data class that represents a single point.
Definition: cxPointMetric.h:42
void parentCandidatesUpdated()
Interface for QWidget which handles widgets uniformly for the system.
Definition: cxBaseWidget.h:88
#define CX_LOG_DEBUG
Definition: cxLogger.h:95
Superclass for all data objects.
Definition: cxData.h:89
void report(QString msg)
Definition: cxLogger.cpp:69
#define CX_LOG_WARNING
Definition: cxLogger.h:98
static QString getTypeName()
Definition: cxPointMetric.h:58
QString enum2string(const ENUM &val)
boost::shared_ptr< class ImageTF3D > ImageTF3DPtr
Namespace for all CustusX production code.