Fraxinus  16.5.0-fx-rc1
An IGT application
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
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) 2008-2014, SINTEF Department of Medical Technology
5 All rights reserved.
6 
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9 
10 1. Redistributions of source code must retain the above copyright notice,
11  this list of conditions and the following disclaimer.
12 
13 2. Redistributions in binary form must reproduce the above copyright notice,
14  this list of conditions and the following disclaimer in the documentation
15  and/or other materials provided with the distribution.
16 
17 3. Neither the name of the copyright holder nor the names of its contributors
18  may be used to endorse or promote products derived from this software
19  without specific prior written permission.
20 
21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
25 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 =========================================================================*/
32 
34 
35 #include <QTextStream>
36 #include <QDir>
37 #include <QFile>
38 #include <QFileInfo>
39 #include <vtkImageChangeInformation.h>
40 #include <vtkImageData.h>
41 #include "vtkImageAppend.h"
42 #include "vtkMetaImageWriter.h"
43 #include "cxTypeConversions.h"
44 #include "cxLogger.h"
45 #include "cxSettings.h"
46 #include "cxXmlOptionItem.h"
47 #include "cxTimeKeeper.h"
48 #include "cxDataReaderWriter.h"
49 #include "cxUSFrameData.h"
50 #include "cxSavingVideoRecorder.h"
51 #include "cxImageDataContainer.h"
53 #include "cxCustomMetaImage.h"
54 
55 
56 typedef vtkSmartPointer<vtkImageAppend> vtkImageAppendPtr;
57 
58 namespace cx
59 {
60 
62  mSessionDescription(sessionDescription)
63 {
64 }
65 
67 {
68 }
69 
71 {
72  return mReconstructData;
73 }
74 
80  std::vector<TimeInfo> imageTimestamps,
81  TimedTransformMap trackerRecordedData,
82  std::map<double, ToolPositionMetadata> trackerRecordedMetadata,
83  std::map<double, ToolPositionMetadata> referenceRecordedMetadata,
84  ToolPtr tool, QString streamUid,
85  bool writeColor, Transform3D rMpr)
86 {
87  if(trackerRecordedData.empty())
88  reportWarning("No tracking data for writing to reconstruction file.");
89 
91 
92  retval.mFilename = mSessionDescription; // not saved yet - no filename
93  retval.mUsRaw = USFrameData::create(mSessionDescription, imageData);
94  retval.rMpr = rMpr;
95  retval.mTrackerRecordedMetadata = trackerRecordedMetadata;
96  retval.mReferenceRecordedMetadata = referenceRecordedMetadata;
97 
98  for (TimedTransformMap::iterator it = trackerRecordedData.begin(); it != trackerRecordedData.end(); ++it)
99  {
100  TimedPosition current;
101  current.mTime = it->first;
102  current.mTimeInfo.setAcquisitionTime(it->first);
103  current.mPos = it->second;
104  retval.mPositions.push_back(current);
105  }
106 
107  std::vector<TimeInfo> fts = imageTimestamps;
108  for (unsigned i=0; i<fts.size(); ++i)
109  {
110  TimedPosition current;
111  current.mTimeInfo = fts[i];
112  current.mTime = current.mTimeInfo.getAcquisitionTime();
113  current.mPos = Transform3D::Identity();
114  // current.mPos = not written - will be found from track positions during reconstruction.
115  retval.mFrames.push_back(current);
116  }
117 
118  if (tool && tool->getProbe())
119  {
120  retval.mProbeDefinition.setData(tool->getProbe()->getProbeDefinition(streamUid));
121  }
122 
123  if (tool)
124  retval.mProbeUid = tool->getUid();
125 
126  this->fillFramePositions(&retval);
127 
128  return retval;
129 }
130 
135 void UsReconstructionFileMaker::fillFramePositions(USReconstructInputData* data) const
136 {
139 }
140 
141 bool UsReconstructionFileMaker::writeTrackerTimestamps(QString reconstructionFolder, QString session, std::vector<TimedPosition> ts)
142 {
143  return this->writeTimestamps(reconstructionFolder+"/"+session+".tts",
144  ts, "tracking timestamps");
145 }
146 
147 bool UsReconstructionFileMaker::writeUSTimestamps(QString reconstructionFolder, QString session, std::vector<TimedPosition> ts)
148 {
149  bool retval = true;
150 
151  retval = this->writeTimestamps(reconstructionFolder+"/"+session+".fts",
152  ts, "frame timestamps", Modified);
153 
154  retval &= this->writeTimestamps(reconstructionFolder+"/"+session+".scanner.frameTimestamps",
155  ts, "frame scanner timestamps", Scanner);
156 
157  retval &= this->writeTimestamps(reconstructionFolder+"/"+session+".softwareArrive.frameTimestamps",
158  ts, "frame arrive in software timestamps", SoftwareArrive);
159  return retval;
160 }
161 
162 bool UsReconstructionFileMaker::writeTimestamps(QString filename, std::vector<TimedPosition> ts, QString type, TimeStampType timeStampType)
163 {
164  bool success = false;
165 
166  QFile file(filename);
167  if(!file.open(QIODevice::WriteOnly | QIODevice::Truncate))
168  {
169  reportError("Cannot open "+file.fileName());
170  return success;
171  }
172  QTextStream stream(&file);
173 
174  for (unsigned i=0; i<ts.size(); ++i)
175  {
176  switch(timeStampType)
177  {
178  case Modified:
179  stream << qstring_cast(ts[i].mTimeInfo.getAcquisitionTime());
180  break;
181  case SoftwareArrive:
182  stream << qstring_cast(ts[i].mTimeInfo.getSoftwareAcquisitionTime());
183  break;
184  case Scanner:
185  stream << qstring_cast(ts[i].mTimeInfo.getScannerAcquisitionTime());
186  break;
187  default:
188  stream << qstring_cast(ts[i].mTime); // Is the same as mTimeInfo.getAcquisitionTime()
189  break;
190  }
191  stream << endl;
192  }
193  file.close();
194  success = true;
195 
196  QFileInfo info(file);
197  mReport << QString("%1, %2 bytes, %3 %4.")
198  .arg(info.fileName())
199  .arg(info.size())
200  .arg(ts.size())
201  .arg(type);
202 // mReport << info.fileName()+", "+qstring_cast(info.size())+" bytes, "+qstring_cast(ts.size())+" frame timestamps.";
203 
204  return success;
205 }
206 
207 bool UsReconstructionFileMaker::writeUSTransforms(QString reconstructionFolder, QString session, std::vector<TimedPosition> ts)
208 {
209  return this->writeTransforms(reconstructionFolder+"/"+session+".fp", ts, "frame transforms rMu");
210 }
211 
212 bool UsReconstructionFileMaker::writeTrackerMetadata(QString reconstructionFolder, QString session, const std::map<double, ToolPositionMetadata>& ts)
213 {
214  QString filename = reconstructionFolder+"/"+session+".probe.toolmeta";
215  return this->writeMetadata(filename, ts, "tracker metadata");
216 }
217 
218 bool UsReconstructionFileMaker::writeReferenceMetadata(QString reconstructionFolder, QString session, const std::map<double, ToolPositionMetadata>& ts)
219 {
220  QString filename = reconstructionFolder+"/"+session+".ref.toolmeta";
221  return this->writeMetadata(filename, ts, "tracker metadata");
222 }
223 
224 bool UsReconstructionFileMaker::writeMetadata(QString filename, const std::map<double, ToolPositionMetadata>& ts, QString type)
225 {
226  bool success = false;
227  QFile file(filename);
228  if(!file.open(QIODevice::WriteOnly | QIODevice::Truncate))
229  {
230  reportError("Cannot open "+file.fileName());
231  return success;
232  }
233  QTextStream stream(&file);
234 
235  for (std::map<double, ToolPositionMetadata>::const_iterator i=ts.begin(); i!=ts.end(); ++i)
236  {
237  stream << i->second.toString() << endl;
238  }
239  file.close();
240  success = true;
241 
242  QFileInfo info(file);
243  mReport << info.fileName()+", "+qstring_cast(info.size())+" bytes, "+qstring_cast(ts.size())+" " + type + ".";
244 
245  return success;
246 }
247 
248 bool UsReconstructionFileMaker::writeTrackerTransforms(QString reconstructionFolder, QString session, std::vector<TimedPosition> ts)
249 {
250  return this->writeTransforms(reconstructionFolder+"/"+session+".tp", ts, "tracking transforms prMt");
251 }
252 
253 bool UsReconstructionFileMaker::writeTransforms(QString filename, std::vector<TimedPosition> ts, QString type)
254 {
255  bool success = false;
256  QFile file(filename);
257  if(!file.open(QIODevice::WriteOnly | QIODevice::Truncate))
258  {
259  reportError("Cannot open "+file.fileName());
260  return success;
261  }
262  QTextStream stream(&file);
263 
264  for (unsigned i=0; i<ts.size(); ++i)
265  {
266  Transform3D transform = ts[i].mPos;
267  stream << transform(0,0) << " ";
268  stream << transform(0,1) << " ";
269  stream << transform(0,2) << " ";
270  stream << transform(0,3);
271  stream << endl;
272  stream << transform(1,0) << " ";
273  stream << transform(1,1) << " ";
274  stream << transform(1,2) << " ";
275  stream << transform(1,3);
276  stream << endl;
277  stream << transform(2,0) << " ";
278  stream << transform(2,1) << " ";
279  stream << transform(2,2) << " ";
280  stream << transform(2,3);
281  stream << endl;
282  }
283  file.close();
284  success = true;
285 
286  QFileInfo info(file);
287  mReport << info.fileName()+", "+qstring_cast(info.size())+" bytes, "+qstring_cast(ts.size())+" " + type + ".";
288 
289  return success;
290 }
291 
295 void UsReconstructionFileMaker::writeProbeConfiguration(QString reconstructionFolder, QString session, ProbeDefinition data, QString uid)
296 {
297  XmlOptionFile file = XmlOptionFile(reconstructionFolder + "/" + session + ".probedata.xml");
298  data.addXml(file.getElement("configuration"));
299  file.getElement("tool").toElement().setAttribute("toolID", uid);
300  file.save();
301 }
302 
303 QString UsReconstructionFileMaker::createUniqueFolder(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  int i=1;
312  while(!findNewSubfolder(newPathName))
313  {
314  newPathName = subfolderAbsolutePath+"_"+QString::number(i++);
315  }
316  patientDir.mkpath(newPathName);
317  patientDir.cd(newPathName);
318 
319  retval = patientDir.absolutePath();
320  return retval;
321 }
322 
323 QString UsReconstructionFileMaker::createFolder(QString patientFolder, QString sessionDescription)
324 {
325  QString retval("");
326  QDir patientDir(patientFolder + "/US_Acq");
327 
328  QString subfolder = sessionDescription;
329  QString subfolderAbsolutePath = patientDir.absolutePath()+"/"+subfolder;
330  QString newPathName = subfolderAbsolutePath;
331  patientDir.mkpath(newPathName);
332  patientDir.cd(newPathName);
333 
334  retval = patientDir.absolutePath();
335  return retval;
336 }
337 
338 bool UsReconstructionFileMaker::findNewSubfolder(QString subfolderAbsolutePath)
339 {
340  QDir dir;
341  if(dir.exists(subfolderAbsolutePath))
342  return false;
343 
344  return true;
345 }
346 
347 void UsReconstructionFileMaker::report()
348 {
349  foreach(QString string, mReport)
350  {
351  reportSuccess(string);
352  }
353 }
354 
355 void UsReconstructionFileMaker::writeUSImages(QString path, ImageDataContainerPtr images, bool compression, std::vector<TimedPosition> pos)
356 {
357  CX_ASSERT(images->size()==pos.size());
358  vtkMetaImageWriterPtr writer = vtkMetaImageWriterPtr::New();
359 
360  for (unsigned i=0; i<images->size(); ++i)
361  {
362  vtkImageDataPtr currentImage = images->get(i);
363  QString filename = QString("%1/%2_%3.mhd").arg(path).arg(mSessionDescription).arg(i);
364 
365  writer->SetInputData(currentImage);
366  writer->SetFileName(cstring_cast(filename));
367  writer->SetCompression(compression);
368  {
369  StaticMutexVtkLocker lock;
370  writer->Write();
371  }
372 
373  CustomMetaImagePtr customReader = CustomMetaImage::create(filename);
374  customReader->setTransform(pos[i].mPos);
375  customReader->setModality("US");
376  customReader->setImageType(mSessionDescription);
377  }
378 }
379 
380 void UsReconstructionFileMaker::writeMask(QString path, QString session, vtkImageDataPtr mask)
381 {
382  QString filename = QString("%1/%2.mask.mhd").arg(path).arg(session);
383  if (!mask)
384  {
385  reportWarning(QString("No mask found, ignoring write to %1").arg(filename));
386  return;
387  }
388 
389  vtkMetaImageWriterPtr writer = vtkMetaImageWriterPtr::New();
390  writer->SetInputData(mask);
391  writer->SetFileName(cstring_cast(filename));
392  writer->SetCompression(false);
393  writer->Write();
394 }
395 
396 
397 void UsReconstructionFileMaker::writeREADMEFile(QString reconstructionFolder, QString session)
398 {
399  QString text = ""
400 "* ==== Format description \n"
401 "* Refer to \n"
402 "* http://custusx.org/uploads/developer_doc/nightly/org_custusx_acquisition.html \n"
403 "* for a description of the files. \n"
404 "*/ \n";
405 
406  QFile file(reconstructionFolder+"/"+session+".README.txt");
407  if(!file.open(QIODevice::WriteOnly | QIODevice::Truncate))
408  {
409  reportError("Cannot open "+file.fileName());
410  return;
411  }
412  QTextStream stream(&file);
413  stream << text;
414  file.close();
415 }
416 
417 QString UsReconstructionFileMaker::writeToNewFolder(QString path, bool compression)
418 {
419  TimeKeeper timer;
420  mReconstructData.mFilename = path+"/"+mSessionDescription+".fts"; // use fts since this is a single unique file.
421 
422  mReport.clear();
423  mReport << "Made reconstruction folder: " + path;
424  QString session = mSessionDescription;
425 
426  this->writeTrackerMetadata(path, session, mReconstructData.mTrackerRecordedMetadata);
427  this->writeReferenceMetadata(path, session, mReconstructData.mReferenceRecordedMetadata);
428  this->writeTrackerTimestamps(path, session, mReconstructData.mPositions);
429  this->writeTrackerTransforms(path, session, mReconstructData.mPositions);
430  this->writeUSTimestamps(path, session, mReconstructData.mFrames);
431  this->writeUSTransforms(path, session, mReconstructData.mFrames);
432  this->writeProbeConfiguration(path, session, mReconstructData.mProbeDefinition.mData, mReconstructData.mProbeUid);
433  this->writeMask(path, session, mReconstructData.getMask());
434  this->writeREADMEFile(path, session);
435 
436  ImageDataContainerPtr imageData = mReconstructData.mUsRaw->getImageContainer();
437  if (imageData)
438  this->writeUSImages(path, imageData, compression, mReconstructData.mFrames);
439  else
440  mReport << "failed to find frame data, save failed.";
441 
442  int time = std::max(1, timer.getElapsedms());
443  mReport << QString("Completed save to %1. Spent %2s, %3fps").arg(mSessionDescription).arg(time/1000).arg(imageData->size()*1000/time);
444 
445  this->report();
446  mReport.clear();
447 
448  return mReconstructData.mFilename;
449 }
450 
451 
452 
453 }//namespace cx
QString qstring_cast(const T &val)
DoubleBoundingBox3D transform(const Transform3D &m, const DoubleBoundingBox3D &bb)
void reportError(QString msg)
Definition: cxLogger.cpp:92
std::map< double, ToolPositionMetadata > mTrackerRecordedMetadata
UsReconstructionFileMaker(QString sessionDescription)
#define CX_ASSERT(statement)
Definition: cxLogger.h:131
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
static std::vector< double > interpolateFramePositionsFromTracking(USReconstructInputData *data)
boost::shared_ptr< class CustomMetaImage > CustomMetaImagePtr
Transform3D rMpr
patient registration
void setAcquisitionTime(double mSecsSinceEpoch)
Definition: cxData.h:86
int getElapsedms() const
void reportWarning(QString msg)
Definition: cxLogger.cpp:91
double getAcquisitionTime() const
Definition: cxData.h:82
vtkSmartPointer< class vtkMetaImageWriter > vtkMetaImageWriterPtr
static QString createFolder(QString patientFolder, QString sessionDescription)
void reportSuccess(QString msg)
Definition: cxLogger.cpp:93
std::vector< TimedPosition > mPositions
ProbeDefinition mData
Definition: cxProbeSector.h:75
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)
std::map< double, Transform3D > TimedTransformMap
static CustomMetaImagePtr create(QString filename)
void setData(ProbeDefinition data)
boost::shared_ptr< class ImageDataContainer > ImageDataContainerPtr
Definition: cxUSFrameData.h:45
boost::shared_ptr< class Tool > ToolPtr