Fraxinus  18.10
An IGT application
cxUsReconstructionFileMaker.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 
13 
14 #include <QTextStream>
15 #include <QDir>
16 #include <QFile>
17 #include <QFileInfo>
18 #include <vtkImageChangeInformation.h>
19 #include <vtkImageData.h>
20 #include "vtkImageAppend.h"
21 #include "vtkMetaImageWriter.h"
22 #include "cxTypeConversions.h"
23 #include "cxLogger.h"
24 #include "cxSettings.h"
25 #include "cxXmlOptionItem.h"
26 #include "cxTimeKeeper.h"
27 #include "cxDataReaderWriter.h"
28 #include "cxUSFrameData.h"
29 #include "cxSavingVideoRecorder.h"
30 #include "cxImageDataContainer.h"
32 #include "cxCustomMetaImage.h"
33 #include "cxErrorObserver.h"
34 
35 
36 typedef vtkSmartPointer<vtkImageAppend> vtkImageAppendPtr;
37 
38 namespace cx
39 {
40 
42  mSessionDescription(sessionDescription)
43 {
44 }
45 
47 {
48 }
49 
51 {
52  return mReconstructData;
53 }
54 
60  std::vector<TimeInfo> imageTimestamps,
61  TimedTransformMap trackerRecordedData,
62  std::map<double, ToolPositionMetadata> trackerRecordedMetadata,
63  std::map<double, ToolPositionMetadata> referenceRecordedMetadata,
64  ToolPtr tool, QString streamUid,
65  bool writeColor, Transform3D rMpr)
66 {
67  if(trackerRecordedData.empty())
68  reportWarning("No tracking data for writing to reconstruction file.");
69 
71 
72  retval.mFilename = mSessionDescription; // not saved yet - no filename
73  retval.mUsRaw = USFrameData::create(mSessionDescription, imageData);
74  retval.rMpr = rMpr;
75  retval.mTrackerRecordedMetadata = trackerRecordedMetadata;
76  retval.mReferenceRecordedMetadata = referenceRecordedMetadata;
77 
78  for (TimedTransformMap::iterator it = trackerRecordedData.begin(); it != trackerRecordedData.end(); ++it)
79  {
80  TimedPosition current;
81  current.mTime = it->first;
82  current.mTimeInfo.setAcquisitionTime(it->first);
83  current.mPos = it->second;
84  retval.mPositions.push_back(current);
85  }
86 
87  std::vector<TimeInfo> fts = imageTimestamps;
88  for (unsigned i=0; i<fts.size(); ++i)
89  {
90  TimedPosition current;
91  current.mTimeInfo = fts[i];
92  current.mTime = current.mTimeInfo.getAcquisitionTime();
93  current.mPos = Transform3D::Identity();
94  // current.mPos = not written - will be found from track positions during reconstruction.
95  retval.mFrames.push_back(current);
96  }
97 
98  if (tool && tool->getProbe())
99  {
100  retval.mProbeDefinition.setData(tool->getProbe()->getProbeDefinition(streamUid));
101  }
102 
103  if (tool)
104  retval.mProbeUid = tool->getUid();
105 
106  this->fillFramePositions(&retval);
107 
108  return retval;
109 }
110 
115 void UsReconstructionFileMaker::fillFramePositions(USReconstructInputData* data) const
116 {
119 }
120 
121 bool UsReconstructionFileMaker::writeTrackerTimestamps(QString reconstructionFolder, QString session, std::vector<TimedPosition> ts)
122 {
123  return this->writeTimestamps(reconstructionFolder+"/"+session+".tts",
124  ts, "tracking timestamps");
125 }
126 
127 bool UsReconstructionFileMaker::writeUSTimestamps(QString reconstructionFolder, QString session, std::vector<TimedPosition> ts)
128 {
129  bool retval = true;
130 
131  retval = this->writeTimestamps(reconstructionFolder+"/"+session+".fts",
132  ts, "frame timestamps", Modified);
133 
134  retval &= this->writeTimestamps(reconstructionFolder+"/"+session+".scanner.frameTimestamps",
135  ts, "frame scanner timestamps", Scanner);
136 
137  retval &= this->writeTimestamps(reconstructionFolder+"/"+session+".softwareArrive.frameTimestamps",
138  ts, "frame arrive in software timestamps", SoftwareArrive);
139  return retval;
140 }
141 
142 bool UsReconstructionFileMaker::writeTimestamps(QString filename, std::vector<TimedPosition> ts, QString type, TimeStampType timeStampType)
143 {
144  bool success = false;
145 
146  QFile file(filename);
147  if(!file.open(QIODevice::WriteOnly | QIODevice::Truncate))
148  {
149  reportError("Cannot open "+file.fileName());
150  return success;
151  }
152  QTextStream stream(&file);
153 
154  for (unsigned i=0; i<ts.size(); ++i)
155  {
156  switch(timeStampType)
157  {
158  case Modified:
159  stream << qstring_cast(ts[i].mTimeInfo.getAcquisitionTime());
160  break;
161  case SoftwareArrive:
162  stream << qstring_cast(ts[i].mTimeInfo.getSoftwareAcquisitionTime());
163  break;
164  case Scanner:
165  stream << qstring_cast(ts[i].mTimeInfo.getScannerAcquisitionTime());
166  break;
167  default:
168  stream << qstring_cast(ts[i].mTime); // Is the same as mTimeInfo.getAcquisitionTime()
169  break;
170  }
171  stream << endl;
172  }
173  file.close();
174  success = true;
175 
176  QFileInfo info(file);
177  mReport << QString("%1, %2 bytes, %3 %4.")
178  .arg(info.fileName())
179  .arg(info.size())
180  .arg(ts.size())
181  .arg(type);
182 // mReport << info.fileName()+", "+qstring_cast(info.size())+" bytes, "+qstring_cast(ts.size())+" frame timestamps.";
183 
184  return success;
185 }
186 
187 bool UsReconstructionFileMaker::writeUSTransforms(QString reconstructionFolder, QString session, std::vector<TimedPosition> ts)
188 {
189  return this->writeTransforms(reconstructionFolder+"/"+session+".fp", ts, "frame transforms rMu");
190 }
191 
192 bool UsReconstructionFileMaker::writeTrackerMetadata(QString reconstructionFolder, QString session, const std::map<double, ToolPositionMetadata>& ts)
193 {
194  QString filename = reconstructionFolder+"/"+session+".probe.toolmeta";
195  return this->writeMetadata(filename, ts, "tracker metadata");
196 }
197 
198 bool UsReconstructionFileMaker::writeReferenceMetadata(QString reconstructionFolder, QString session, const std::map<double, ToolPositionMetadata>& ts)
199 {
200  QString filename = reconstructionFolder+"/"+session+".ref.toolmeta";
201  return this->writeMetadata(filename, ts, "tracker metadata");
202 }
203 
204 bool UsReconstructionFileMaker::writeMetadata(QString filename, const std::map<double, ToolPositionMetadata>& ts, QString type)
205 {
206  bool success = false;
207  QFile file(filename);
208  if(!file.open(QIODevice::WriteOnly | QIODevice::Truncate))
209  {
210  reportError("Cannot open "+file.fileName());
211  return success;
212  }
213  QTextStream stream(&file);
214 
215  for (std::map<double, ToolPositionMetadata>::const_iterator i=ts.begin(); i!=ts.end(); ++i)
216  {
217  stream << i->second.toString() << endl;
218  }
219  file.close();
220  success = true;
221 
222  QFileInfo info(file);
223  mReport << info.fileName()+", "+qstring_cast(info.size())+" bytes, "+qstring_cast(ts.size())+" " + type + ".";
224 
225  return success;
226 }
227 
228 bool UsReconstructionFileMaker::writeTrackerTransforms(QString reconstructionFolder, QString session, std::vector<TimedPosition> ts)
229 {
230  return this->writeTransforms(reconstructionFolder+"/"+session+".tp", ts, "tracking transforms prMt");
231 }
232 
233 bool UsReconstructionFileMaker::writeTransforms(QString filename, std::vector<TimedPosition> ts, QString type)
234 {
235  bool success = false;
236  QFile file(filename);
237  if(!file.open(QIODevice::WriteOnly | QIODevice::Truncate))
238  {
239  reportError("Cannot open "+file.fileName());
240  return success;
241  }
242  QTextStream stream(&file);
243 
244  for (unsigned i=0; i<ts.size(); ++i)
245  {
246  Transform3D transform = ts[i].mPos;
247  stream << transform(0,0) << " ";
248  stream << transform(0,1) << " ";
249  stream << transform(0,2) << " ";
250  stream << transform(0,3);
251  stream << endl;
252  stream << transform(1,0) << " ";
253  stream << transform(1,1) << " ";
254  stream << transform(1,2) << " ";
255  stream << transform(1,3);
256  stream << endl;
257  stream << transform(2,0) << " ";
258  stream << transform(2,1) << " ";
259  stream << transform(2,2) << " ";
260  stream << transform(2,3);
261  stream << endl;
262  }
263  file.close();
264  success = true;
265 
266  QFileInfo info(file);
267  mReport << info.fileName()+", "+qstring_cast(info.size())+" bytes, "+qstring_cast(ts.size())+" " + type + ".";
268 
269  return success;
270 }
271 
275 void UsReconstructionFileMaker::writeProbeConfiguration(QString reconstructionFolder, QString session, ProbeDefinition data, QString uid)
276 {
277  XmlOptionFile file = XmlOptionFile(reconstructionFolder + "/" + session + ".probedata.xml");
278  data.addXml(file.getElement("configuration"));
279  file.getElement("tool").toElement().setAttribute("toolID", uid);
280  file.save();
281 }
282 
283 QString UsReconstructionFileMaker::createUniqueFolder(QString patientFolder, QString sessionDescription)
284 {
285  QString retval("");
286  QDir patientDir(patientFolder + "/US_Acq");
287 
288  QString subfolder = sessionDescription;
289  QString subfolderAbsolutePath = patientDir.absolutePath()+"/"+subfolder;
290  QString newPathName = subfolderAbsolutePath;
291  int i=1;
292  while(!findNewSubfolder(newPathName))
293  {
294  newPathName = subfolderAbsolutePath+"_"+QString::number(i++);
295  }
296  patientDir.mkpath(newPathName);
297  patientDir.cd(newPathName);
298 
299  retval = patientDir.absolutePath();
300  return retval;
301 }
302 
303 QString UsReconstructionFileMaker::createFolder(QString patientFolder, QString sessionDescription)
304 {
305  QString retval("");
306  QDir patientDir(patientFolder + "/US_Acq");
307 
308  QString subfolder = sessionDescription;
309  QString subfolderAbsolutePath = patientDir.absolutePath()+"/"+subfolder;
310  QString newPathName = subfolderAbsolutePath;
311  patientDir.mkpath(newPathName);
312  patientDir.cd(newPathName);
313 
314  retval = patientDir.absolutePath();
315  return retval;
316 }
317 
318 bool UsReconstructionFileMaker::findNewSubfolder(QString subfolderAbsolutePath)
319 {
320  QDir dir;
321  if(dir.exists(subfolderAbsolutePath))
322  return false;
323 
324  return true;
325 }
326 
327 void UsReconstructionFileMaker::report()
328 {
329  foreach(QString string, mReport)
330  {
331  reportSuccess(string);
332  }
333 }
334 
335 void UsReconstructionFileMaker::writeUSImages(QString path, ImageDataContainerPtr images, bool compression, std::vector<TimedPosition> pos)
336 {
337  CX_ASSERT(images->size()==pos.size());
338  vtkMetaImageWriterPtr writer = vtkMetaImageWriterPtr::New();
339 
340  for (unsigned i=0; i<images->size(); ++i)
341  {
342  vtkImageDataPtr currentImage = images->get(i);
343  QString filename = QString("%1/%2_%3.mhd").arg(path).arg(mSessionDescription).arg(i);
344 
345  writer->SetInputData(currentImage);
346  writer->SetFileName(cstring_cast(filename));
347  writer->SetCompression(compression);
348  {
350  writer->Write();
351  }
352 
353  CustomMetaImagePtr customReader = CustomMetaImage::create(filename);
354  customReader->setTransform(pos[i].mPos);
355  customReader->setModality("US");
356  customReader->setImageType(mSessionDescription);
357  }
358 }
359 
360 void UsReconstructionFileMaker::writeMask(QString path, QString session, vtkImageDataPtr mask)
361 {
362  QString filename = QString("%1/%2.mask.mhd").arg(path).arg(session);
363  if (!mask)
364  {
365  reportWarning(QString("No mask found, ignoring write to %1").arg(filename));
366  return;
367  }
368 
369  vtkMetaImageWriterPtr writer = vtkMetaImageWriterPtr::New();
370  writer->SetInputData(mask);
371  writer->SetFileName(cstring_cast(filename));
372  writer->SetCompression(false);
373  writer->Write();
374 }
375 
376 
377 void UsReconstructionFileMaker::writeREADMEFile(QString reconstructionFolder, QString session)
378 {
379  QString text = ""
380 "* ==== Format description \n"
381 "* Refer to \n"
382 "* http://custusx.org/uploads/developer_doc/nightly/org_custusx_acquisition.html \n"
383 "* for a description of the files. \n"
384 "*/ \n";
385 
386  QFile file(reconstructionFolder+"/"+session+".README.txt");
387  if(!file.open(QIODevice::WriteOnly | QIODevice::Truncate))
388  {
389  reportError("Cannot open "+file.fileName());
390  return;
391  }
392  QTextStream stream(&file);
393  stream << text;
394  file.close();
395 }
396 
397 QString UsReconstructionFileMaker::writeToNewFolder(QString path, bool compression)
398 {
399  TimeKeeper timer;
400  mReconstructData.mFilename = path+"/"+mSessionDescription+".fts"; // use fts since this is a single unique file.
401 
402  mReport.clear();
403  mReport << "Made reconstruction folder: " + path;
404  QString session = mSessionDescription;
405 
406  this->writeTrackerMetadata(path, session, mReconstructData.mTrackerRecordedMetadata);
407  this->writeReferenceMetadata(path, session, mReconstructData.mReferenceRecordedMetadata);
408  this->writeTrackerTimestamps(path, session, mReconstructData.mPositions);
409  this->writeTrackerTransforms(path, session, mReconstructData.mPositions);
410  this->writeUSTimestamps(path, session, mReconstructData.mFrames);
411  this->writeUSTransforms(path, session, mReconstructData.mFrames);
412  this->writeProbeConfiguration(path, session, mReconstructData.mProbeDefinition.mData, mReconstructData.mProbeUid);
413  this->writeMask(path, session, mReconstructData.getMask());
414  this->writeREADMEFile(path, session);
415 
416  ImageDataContainerPtr imageData = mReconstructData.mUsRaw->getImageContainer();
417  if (imageData)
418  this->writeUSImages(path, imageData, compression, mReconstructData.mFrames);
419  else
420  mReport << "failed to find frame data, save failed.";
421 
422  int time = std::max(1, timer.getElapsedms());
423  mReport << QString("Completed save to %1. Spent %2s, %3fps").arg(mSessionDescription).arg(time/1000).arg(imageData->size()*1000/time);
424 
425  this->report();
426  mReport.clear();
427 
428  return mReconstructData.mFilename;
429 }
430 
431 
432 
433 }//namespace cx
QString qstring_cast(const T &val)
DoubleBoundingBox3D transform(const Transform3D &m, const DoubleBoundingBox3D &bb)
void reportError(QString msg)
Definition: cxLogger.cpp:71
void addXml(QDomNode dataNode) const
std::map< double, ToolPositionMetadata > mTrackerRecordedMetadata
UsReconstructionFileMaker(QString sessionDescription)
#define CX_ASSERT(statement)
Definition: cxLogger.h:116
One position with timestamp.
Transform3D Transform3D
Transform3D is a representation of an affine 3D transform.
vtkSmartPointer< vtkImageAppend > vtkImageAppendPtr
std::vector< TimedPosition > mFrames
cstring_cast_Placeholder cstring_cast(const T &val)
QString writeToNewFolder(QString path, bool compression)
std::map< double, ToolPositionMetadata > mReferenceRecordedMetadata
QDomElement getElement()
return the current element
static std::vector< double > interpolateFramePositionsFromTracking(USReconstructInputData *data)
boost::shared_ptr< class CustomMetaImage > CustomMetaImagePtr
Transform3D rMpr
patient registration
void setAcquisitionTime(double mSecsSinceEpoch)
Definition: cxData.h:65
int getElapsedms() const
void reportWarning(QString msg)
Definition: cxLogger.cpp:70
double getAcquisitionTime() const
Definition: cxData.h:61
vtkSmartPointer< class vtkMetaImageWriter > vtkMetaImageWriterPtr
static QString createFolder(QString patientFolder, QString sessionDescription)
void reportSuccess(QString msg)
Definition: cxLogger.cpp:72
std::vector< TimedPosition > mPositions
ProbeDefinition mData
Definition: cxProbeSector.h:54
Definition of characteristics for an Ultrasound Probe Sector.
void save()
save entire document.
QString mFilename
filename used for current data read
vtkSmartPointer< class vtkImageData > vtkImageDataPtr
USFrameDataPtr mUsRaw
All imported US data frames with pointers to each frame.
static void transformFramePositionsTo_rMu(USReconstructInputData *data)
static USFrameDataPtr create(ImagePtr inputFrameData)
static QString createUniqueFolder(QString patientFolder, QString sessionDescription)
Helper class for xml files used to store ssc/cx data.
std::map< double, Transform3D > TimedTransformMap
static CustomMetaImagePtr create(QString filename)
void setData(ProbeDefinition data)
boost::shared_ptr< class ImageDataContainer > ImageDataContainerPtr
Definition: cxUSFrameData.h:24
Namespace for all CustusX production code.
boost::shared_ptr< class Tool > ToolPtr