CustusX  2021.04.21-dev+develop.337f9
An IGT application
cxCustomMetaImage.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 #include "cxCustomMetaImage.h"
12 
13 #include <QFile>
14 #include <QTextStream>
15 #include <QStringList>
16 #include "cxLogger.h"
17 #include "cxData.h"
18 
19 #include "cxTypeConversions.h"
20 #include "cxEnumConversion.h"
21 
22 namespace cx
23 {
24 
25 
26 IMAGE_MODALITY convertToModality(QString modalityString)
27 {
28  IMAGE_MODALITY retval = imUNKNOWN;
29 
30  if(modalityString.contains(enum2string<IMAGE_MODALITY>(imUNKNOWN), Qt::CaseInsensitive))
31  retval = imUNKNOWN;
32  else if(modalityString.contains(enum2string<IMAGE_MODALITY>(imCT), Qt::CaseInsensitive))
33  retval = imCT;
34  else if(modalityString.contains(enum2string<IMAGE_MODALITY>(imMR), Qt::CaseInsensitive))
35  retval = imMR;
36  else if(modalityString.contains(enum2string<IMAGE_MODALITY>(imUS), Qt::CaseInsensitive))
37  retval = imUS;
38  else if(modalityString.contains(enum2string<IMAGE_MODALITY>(imPET), Qt::CaseInsensitive))
39  retval = imPET;
40  else if(modalityString.contains(enum2string<IMAGE_MODALITY>(imSC), Qt::CaseInsensitive))
41  retval = imSC;
42  else
43  CX_LOG_WARNING() << "convertToModality - Cannot convert the string \"" << modalityString << "\" to a known image modality";
44 
45  return retval;
46 }
47 
48 
49 IMAGE_SUBTYPE convertToImageSubType(QString imageTypeSubString)
50 {
51  IMAGE_SUBTYPE retval = istUNKNOWN;
52 
53  if (imageTypeSubString.isEmpty() || imageTypeSubString == " ")
54  retval = istEMPTY;
55  else if(imageTypeSubString.contains(enum2string<IMAGE_SUBTYPE>(istUNKNOWN), Qt::CaseInsensitive))
56  retval = istUNKNOWN;
57  else if(imageTypeSubString.contains(enum2string<IMAGE_SUBTYPE>(istMRT1), Qt::CaseInsensitive))
58  retval = istMRT1;
59  else if(imageTypeSubString.contains(enum2string<IMAGE_SUBTYPE>(istMRT2), Qt::CaseInsensitive))
60  retval = istMRT2;
61  else if(imageTypeSubString.contains(enum2string<IMAGE_SUBTYPE>(istMRFLAIR), Qt::CaseInsensitive))
62  retval = istMRFLAIR;
63  else if(imageTypeSubString.contains(enum2string<IMAGE_SUBTYPE>(istANGIO), Qt::CaseInsensitive))
64  retval = istANGIO;
65  else if(imageTypeSubString.contains(enum2string<IMAGE_SUBTYPE>(istUSBMODE), Qt::CaseInsensitive))
66  retval = istUSBMODE;
67  else if(imageTypeSubString.contains("bmode", Qt::CaseInsensitive))
68  retval = istUSBMODE;
69  else if(imageTypeSubString.contains("b_mode", Qt::CaseInsensitive))
70  retval = istUSBMODE;
71  else if(imageTypeSubString.contains("b mode", Qt::CaseInsensitive))
72  retval = istUSBMODE;
73  else if(imageTypeSubString.contains("seg", Qt::CaseInsensitive))
74  retval = istSEGMENTATION;
75  else if(imageTypeSubString.contains("label", Qt::CaseInsensitive))
76  retval = istSEGMENTATION;
77  else
78  CX_LOG_WARNING() << "convertToImageSubType - Cannot convert the string \"" << imageTypeSubString << "\" to a known image subtype";
79 
80  return retval;
81 }
82 
83 
85  mFilename(filename)
86 {}
87 
88 QString CustomMetaImage::readKey(QString key)
89 {
90  QFile file(mFilename);
91 
92  QString line;
93  if (file.open(QIODevice::ReadOnly))
94  {
95  QTextStream t(&file);
96  while (!t.atEnd())
97  {
98  line.clear();
99  line = t.readLine();
100  // do something with the line
101  if (line.startsWith(key, Qt::CaseInsensitive))
102  {
103  QStringList list = line.split("=", QString::SkipEmptyParts);
104  if (list.size() >= 2)
105  {
106  list = list.mid(1);
107  return list.join("=");
108  }
109  }
110  }
111  file.close();
112  }
113 
114  return "";
115 }
116 
118 {
119  QString modalityString = this->readKey("Modality");
120  return convertToModality(modalityString);
121 }
122 
124 {
125  QString imageTypeString = this->readKey("ImageType3");
126  return convertToImageSubType(imageTypeString);
127 }
128 
132 void CustomMetaImage::remove(QStringList* data, QStringList keys)
133 {
134  QRegExp regexp(QString("(^%1)").arg(keys.join("|^")));
135  QStringList removeThese = data->filter(regexp);
136  for (int i=0; i<removeThese.size(); ++i)
137  data->removeAll(removeThese[i]);
138 }
139 
145 void CustomMetaImage::append(QStringList* data, QString key, QString value)
146 {
147  // find index of ElementDataFile - this is the last element according to MHD standard (but we might have appended something else after it).
148  int last = data->lastIndexOf(QRegExp("^ElementDataFile.*"));
149  data->insert(last, QString("%1 = %2").arg(key).arg(value));
150 }
151 
152 void CustomMetaImage::setKey(QString key, QString value)
153 {
154  QFile file(mFilename);
155 
156  if (!file.open(QIODevice::ReadWrite))
157  {
158  reportError("Failed to open file " + mFilename + ".");
159  return;
160  }
161 
162  QStringList data = QTextStream(&file).readAll().split("\n");
163 
164  this->remove(&data, QStringList()<<key);
165  this->append(&data, key, value);
166 
167  file.resize(0);
168  file.write(data.join("\n").toLatin1());
169 }
170 
171 void CustomMetaImage::setModality(IMAGE_MODALITY value)
172 {
173  this->setKey("Modality", enum2string(value));
174 }
175 
176 void CustomMetaImage::setImageType(IMAGE_SUBTYPE value)
177 {
178  this->setKey("ImageType3", enum2string(value));
179 }
180 
181 
183 {
184  //read the specific TransformMatrix-tag from the header
185  Vector3D p_r(0, 0, 0);
186  Vector3D e_x(1, 0, 0);
187  Vector3D e_y(0, 1, 0);
188  Vector3D e_z(0, 0, 1);
189 
190  QFile file(mFilename);
191 
192  QString line;
193  if (file.open(QIODevice::ReadOnly))
194  {
195  QTextStream t(&file);
196  while (!t.atEnd())
197  {
198  line.clear();
199  line = t.readLine();
200  // do something with the line
201  if (line.startsWith("Position", Qt::CaseInsensitive) || line.startsWith("Offset", Qt::CaseInsensitive))
202  {
203  QStringList list = line.split(" ", QString::SkipEmptyParts);
204  if (list.size()>=5)
205  p_r = Vector3D(list[2].toDouble(), list[3].toDouble(), list[4].toDouble());
206  }
207  else if (line.startsWith("TransformMatrix", Qt::CaseInsensitive) || line.startsWith("Orientation",
208  Qt::CaseInsensitive))
209  {
210  QStringList list = line.split(" ", QString::SkipEmptyParts);
211 
212  if (list.size()>=8)
213  {
214  e_x = Vector3D(list[2].toDouble(), list[3].toDouble(), list[4].toDouble());
215  e_y = Vector3D(list[5].toDouble(), list[6].toDouble(), list[7].toDouble());
216  e_z = cross(e_x, e_y);
217  }
218  }
219  }
220  file.close();
221  }
222 
223  Transform3D rMd = Transform3D::Identity();
224 
225  // add rotational part
226  for (unsigned i = 0; i < 3; ++i)
227  {
228  rMd(i,0) = e_x[i];
229  rMd(i,1) = e_y[i];
230  rMd(i,2) = e_z[i];
231  }
232 
233 
234  // add translational part
235  rMd(0,3) = p_r[0];
236  rMd(1,3) = p_r[1];
237  rMd(2,3) = p_r[2];
238  return rMd;
239 }
240 
242 {
243  QFile file(mFilename);
244 
245  if (!file.open(QIODevice::ReadWrite))
246  {
247  reportWarning("Could not save transform because: Failed to open file " + mFilename);
248  return;
249  }
250 
251  QStringList data = QTextStream(&file).readAll().split("\n");
252 
253  this->remove(&data, QStringList()<<"TransformMatrix"<<"Offset"<<"Position"<<"Orientation");
254 
255  int dim = 3; // hardcoded - will fail for 2d images
256  std::stringstream tmList;
257  for (int c=0; c<dim; ++c)
258  for (int r=0; r<dim; ++r)
259  tmList << " " << M(r,c);
260  this->append(&data, "TransformMatrix", qstring_cast(tmList.str()));
261 
262  std::stringstream posList;
263  for (int r=0; r<dim; ++r)
264  posList << " " << M(r,3);
265  this->append(&data, "Offset", qstring_cast(posList.str()));
266 
267  file.resize(0);
268  file.write(data.join("\n").toLatin1());
269 }
270 
271 }
void setImageType(IMAGE_SUBTYPE value)
QString qstring_cast(const T &val)
void reportError(QString msg)
Definition: cxLogger.cpp:71
IMAGE_SUBTYPE readImageType()
CustomMetaImage(QString filename)
QString readKey(QString key)
istMRT1
imMR
Transform3D Transform3D
Transform3D is a representation of an affine 3D transform.
imPET
IMAGE_MODALITY convertToModality(QString modalityString)
istANGIO
istMRFLAIR
void setModality(IMAGE_MODALITY value)
imSC
istUSBMODE
Vector3D cross(const Vector3D &a, const Vector3D &b)
compute cross product of a and b.
Definition: cxVector3D.cpp:41
IMAGE_MODALITY readModality()
void reportWarning(QString msg)
Definition: cxLogger.cpp:70
istEMPTY
IMAGE_SUBTYPE convertToImageSubType(QString imageTypeSubString)
istSEGMENTATION
istMRT2
Eigen::Vector3d Vector3D
Vector3D is a representation of a point or vector in 3D.
Definition: cxVector3D.h:42
imUNKNOWN
imUS
#define CX_LOG_WARNING
Definition: cxLogger.h:98
imCT
void setKey(QString key, QString value)
void setTransform(const Transform3D M)
QString enum2string(const ENUM &val)
istUNKNOWN
Namespace for all CustusX production code.