CustusX  15.8
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<double> imageTimestamps,
81  TimedTransformMap trackerRecordedData,
82  ToolPtr tool,
83  bool writeColor, Transform3D rMpr)
84 {
85  if(trackerRecordedData.empty())
86  reportWarning("No tracking data for writing to reconstruction file.");
87 
89 
90  retval.mFilename = mSessionDescription; // not saved yet - no filename
91  retval.mUsRaw = USFrameData::create(mSessionDescription, imageData);
92  retval.rMpr = rMpr;
93 
94  for (TimedTransformMap::iterator it = trackerRecordedData.begin(); it != trackerRecordedData.end(); ++it)
95  {
96  TimedPosition current;
97  current.mTime = it->first;
98  current.mPos = it->second;
99  retval.mPositions.push_back(current);
100  }
101 
102  std::vector<double> fts = imageTimestamps;
103  for (unsigned i=0; i<fts.size(); ++i)
104  {
105  TimedPosition current;
106  current.mTime = fts[i];
107  current.mPos = Transform3D::Identity();
108  // current.mPos = not written - will be found from track positions during reconstruction.
109  retval.mFrames.push_back(current);
110  }
111 
112  if (tool && tool->getProbe())
113  {
114  retval.mProbeData.setData(tool->getProbe()->getProbeData());
115  }
116 
117  if (tool)
118  retval.mProbeUid = tool->getUid();
119 
120  this->fillFramePositions(&retval);
121 
122  return retval;
123 }
124 
129 void UsReconstructionFileMaker::fillFramePositions(USReconstructInputData* data) const
130 {
133 }
134 
135 bool UsReconstructionFileMaker::writeTrackerTimestamps(QString reconstructionFolder, QString session, std::vector<TimedPosition> ts)
136 {
137  return this->writeTimestamps(reconstructionFolder+"/"+session+".tts",
138  ts, "tracking timestamps");
139 }
140 
141 bool UsReconstructionFileMaker::writeUSTimestamps(QString reconstructionFolder, QString session, std::vector<TimedPosition> ts)
142 {
143  return this->writeTimestamps(reconstructionFolder+"/"+session+".fts",
144  ts, "frame timestamps");
145 }
146 
147 bool UsReconstructionFileMaker::writeTimestamps(QString filename, std::vector<TimedPosition> ts, QString type)
148 {
149  bool success = false;
150 
151  QFile file(filename);
152  if(!file.open(QIODevice::WriteOnly | QIODevice::Truncate))
153  {
154  reportError("Cannot open "+file.fileName());
155  return success;
156  }
157  QTextStream stream(&file);
158 
159  for (unsigned i=0; i<ts.size(); ++i)
160  {
161  stream << qstring_cast(ts[i].mTime);
162  stream << endl;
163  }
164  file.close();
165  success = true;
166 
167  QFileInfo info(file);
168  mReport << QString("%1, %2 bytes, %3 %4.")
169  .arg(info.fileName())
170  .arg(info.size())
171  .arg(ts.size())
172  .arg(type);
173 // mReport << info.fileName()+", "+qstring_cast(info.size())+" bytes, "+qstring_cast(ts.size())+" frame timestamps.";
174 
175  return success;
176 }
177 
178 bool UsReconstructionFileMaker::writeUSTransforms(QString reconstructionFolder, QString session, std::vector<TimedPosition> ts)
179 {
180  return this->writeTransforms(reconstructionFolder+"/"+session+".fp", ts, "frame transforms rMu");
181 }
182 
183 bool UsReconstructionFileMaker::writeTrackerTransforms(QString reconstructionFolder, QString session, std::vector<TimedPosition> ts)
184 {
185  return this->writeTransforms(reconstructionFolder+"/"+session+".tp", ts, "tracking transforms prMt");
186 }
187 
188 bool UsReconstructionFileMaker::writeTransforms(QString filename, std::vector<TimedPosition> ts, QString type)
189 {
190  bool success = false;
191  QFile file(filename);
192  if(!file.open(QIODevice::WriteOnly | QIODevice::Truncate))
193  {
194  reportError("Cannot open "+file.fileName());
195  return success;
196  }
197  QTextStream stream(&file);
198 
199  for (unsigned i=0; i<ts.size(); ++i)
200  {
201  Transform3D transform = ts[i].mPos;
202  stream << transform(0,0) << " ";
203  stream << transform(0,1) << " ";
204  stream << transform(0,2) << " ";
205  stream << transform(0,3);
206  stream << endl;
207  stream << transform(1,0) << " ";
208  stream << transform(1,1) << " ";
209  stream << transform(1,2) << " ";
210  stream << transform(1,3);
211  stream << endl;
212  stream << transform(2,0) << " ";
213  stream << transform(2,1) << " ";
214  stream << transform(2,2) << " ";
215  stream << transform(2,3);
216  stream << endl;
217  }
218  file.close();
219  success = true;
220 
221  QFileInfo info(file);
222  mReport << info.fileName()+", "+qstring_cast(info.size())+" bytes, "+qstring_cast(ts.size())+" " + type + ".";
223 
224  return success;
225 }
226 
230 void UsReconstructionFileMaker::writeProbeConfiguration(QString reconstructionFolder, QString session, ProbeDefinition data, QString uid)
231 {
232  XmlOptionFile file = XmlOptionFile(reconstructionFolder + "/" + session + ".probedata.xml");
233  data.addXml(file.getElement("configuration"));
234  file.getElement("tool").toElement().setAttribute("toolID", uid);
235  file.save();
236 }
237 
238 QString UsReconstructionFileMaker::createUniqueFolder(QString patientFolder, QString sessionDescription)
239 {
240  QString retval("");
241  QDir patientDir(patientFolder + "/US_Acq");
242 
243  QString subfolder = sessionDescription;
244  QString subfolderAbsolutePath = patientDir.absolutePath()+"/"+subfolder;
245  QString newPathName = subfolderAbsolutePath;
246  int i=1;
247  while(!findNewSubfolder(newPathName))
248  {
249  newPathName = subfolderAbsolutePath+"_"+QString::number(i++);
250  }
251  patientDir.mkpath(newPathName);
252  patientDir.cd(newPathName);
253 
254  retval = patientDir.absolutePath();
255  return retval;
256 }
257 
258 QString UsReconstructionFileMaker::createFolder(QString patientFolder, QString sessionDescription)
259 {
260  QString retval("");
261  QDir patientDir(patientFolder + "/US_Acq");
262 
263  QString subfolder = sessionDescription;
264  QString subfolderAbsolutePath = patientDir.absolutePath()+"/"+subfolder;
265  QString newPathName = subfolderAbsolutePath;
266  patientDir.mkpath(newPathName);
267  patientDir.cd(newPathName);
268 
269  retval = patientDir.absolutePath();
270  return retval;
271 }
272 
273 bool UsReconstructionFileMaker::findNewSubfolder(QString subfolderAbsolutePath)
274 {
275  QDir dir;
276  if(dir.exists(subfolderAbsolutePath))
277  return false;
278 
279  return true;
280 }
281 
282 void UsReconstructionFileMaker::report()
283 {
284  foreach(QString string, mReport)
285  {
286  reportSuccess(string);
287  }
288 }
289 
290 void UsReconstructionFileMaker::writeUSImages(QString path, ImageDataContainerPtr images, bool compression, std::vector<TimedPosition> pos)
291 {
292  CX_ASSERT(images->size()==pos.size());
293  vtkMetaImageWriterPtr writer = vtkMetaImageWriterPtr::New();
294 
295  for (unsigned i=0; i<images->size(); ++i)
296  {
297  vtkImageDataPtr currentImage = images->get(i);
298  QString filename = QString("%1/%2_%3.mhd").arg(path).arg(mSessionDescription).arg(i);
299 
300  writer->SetInputData(currentImage);
301  writer->SetFileName(cstring_cast(filename));
302  writer->SetCompression(compression);
303  {
304  StaticMutexVtkLocker lock;
305  writer->Write();
306  }
307 
308  CustomMetaImagePtr customReader = CustomMetaImage::create(filename);
309  customReader->setTransform(pos[i].mPos);
310  customReader->setModality("US");
311  customReader->setImageType(mSessionDescription);
312  }
313 }
314 
315 void UsReconstructionFileMaker::writeMask(QString path, QString session, vtkImageDataPtr mask)
316 {
317  QString filename = QString("%1/%2.mask.mhd").arg(path).arg(session);
318  if (!mask)
319  {
320  reportWarning(QString("No mask found, ignoring write to %1").arg(filename));
321  return;
322  }
323 
324  vtkMetaImageWriterPtr writer = vtkMetaImageWriterPtr::New();
325  writer->SetInputData(mask);
326  writer->SetFileName(cstring_cast(filename));
327  writer->SetCompression(false);
328  writer->Write();
329 }
330 
331 
332 void UsReconstructionFileMaker::writeREADMEFile(QString reconstructionFolder, QString session)
333 {
334  QString text = ""
335 "* ==== Format description \n"
336 "* Refer to \n"
337 "* http://custusx.org/uploads/developer_doc/nightly/org_custusx_acquisition.html \n"
338 "* for a description of the files. \n"
339 "*/ \n";
340 
341  QFile file(reconstructionFolder+"/"+session+".README.txt");
342  if(!file.open(QIODevice::WriteOnly | QIODevice::Truncate))
343  {
344  reportError("Cannot open "+file.fileName());
345  return;
346  }
347  QTextStream stream(&file);
348  stream << text;
349  file.close();
350 }
351 
352 QString UsReconstructionFileMaker::writeToNewFolder(QString path, bool compression)
353 {
354  TimeKeeper timer;
355  mReconstructData.mFilename = path+"/"+mSessionDescription+".fts"; // use fts since this is a single unique file.
356 
357  mReport.clear();
358  mReport << "Made reconstruction folder: " + path;
359  QString session = mSessionDescription;
360 
361  this->writeTrackerTimestamps(path, session, mReconstructData.mPositions);
362  this->writeTrackerTransforms(path, session, mReconstructData.mPositions);
363  this->writeUSTimestamps(path, session, mReconstructData.mFrames);
364  this->writeUSTransforms(path, session, mReconstructData.mFrames);
365  this->writeProbeConfiguration(path, session, mReconstructData.mProbeData.mData, mReconstructData.mProbeUid);
366  this->writeMask(path, session, mReconstructData.getMask());
367  this->writeREADMEFile(path, session);
368 
369  ImageDataContainerPtr imageData = mReconstructData.mUsRaw->getImageContainer();
370  if (imageData)
371  this->writeUSImages(path, imageData, compression, mReconstructData.mFrames);
372  else
373  mReport << "failed to find frame data, save failed.";
374 
375  int time = std::max(1, timer.getElapsedms());
376  mReport << QString("Completed save to %1. Spent %2s, %3fps").arg(mSessionDescription).arg(time/1000).arg(imageData->size()*1000/time);
377 
378  this->report();
379  mReport.clear();
380 
381  return mReconstructData.mFilename;
382 }
383 
384 
385 
386 }//namespace cx
QString qstring_cast(const T &val)
DoubleBoundingBox3D transform(const Transform3D &m, const DoubleBoundingBox3D &bb)
void reportError(QString msg)
Definition: cxLogger.cpp:92
UsReconstructionFileMaker(QString sessionDescription)
#define CX_ASSERT(statement)
Definition: cxLogger.h:128
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)
static std::vector< double > interpolateFramePositionsFromTracking(USReconstructInputData *data)
boost::shared_ptr< class CustomMetaImage > CustomMetaImagePtr
Transform3D rMpr
patient registration
int getElapsedms() const
void reportWarning(QString msg)
Definition: cxLogger.cpp:91
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