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