35 #include <QTextStream>
39 #include <vtkImageChangeInformation.h>
40 #include <vtkImageData.h>
41 #include "vtkImageAppend.h"
42 #include "vtkMetaImageWriter.h"
62 mSessionDescription(sessionDescription)
72 return mReconstructData;
80 std::vector<double> imageTimestamps,
85 if(trackerRecordedData.empty())
86 reportWarning(
"No tracking data for writing to reconstruction file.");
94 for (TimedTransformMap::iterator it = trackerRecordedData.begin(); it != trackerRecordedData.end(); ++it)
97 current.
mTime = it->first;
98 current.
mPos = it->second;
102 std::vector<double> fts = imageTimestamps;
103 for (
unsigned i=0; i<fts.size(); ++i)
106 current.
mTime = fts[i];
107 current.
mPos = Transform3D::Identity();
109 retval.
mFrames.push_back(current);
112 if (tool && tool->getProbe())
120 this->fillFramePositions(&retval);
135 bool UsReconstructionFileMaker::writeTrackerTimestamps(QString reconstructionFolder, QString session, std::vector<TimedPosition> ts)
137 bool success =
false;
139 QFile file(reconstructionFolder+
"/"+session+
".tts");
140 if(!file.open(QIODevice::WriteOnly | QIODevice::Truncate))
145 QTextStream stream(&file);
147 for (
unsigned i=0; i<ts.size(); ++i)
156 QFileInfo info(file);
157 mReport << info.fileName()+
", "+
qstring_cast(info.size())+
" bytes, "+
qstring_cast(ts.size())+
" tracking timestamps.";
162 bool UsReconstructionFileMaker::writeUSTransforms(QString reconstructionFolder, QString session, std::vector<TimedPosition> ts)
164 return this->writeTransforms(reconstructionFolder+
"/"+session+
".fp", ts,
"frame transforms rMu");
167 bool UsReconstructionFileMaker::writeTrackerTransforms(QString reconstructionFolder, QString session, std::vector<TimedPosition> ts)
169 return this->writeTransforms(reconstructionFolder+
"/"+session+
".tp", ts,
"tracking transforms prMt");
172 bool UsReconstructionFileMaker::writeTransforms(QString filename, std::vector<TimedPosition> ts, QString type)
174 bool success =
false;
175 QFile file(filename);
176 if(!file.open(QIODevice::WriteOnly | QIODevice::Truncate))
181 QTextStream stream(&file);
183 for (
unsigned i=0; i<ts.size(); ++i)
205 QFileInfo info(file);
211 bool UsReconstructionFileMaker::writeUSTimestamps(QString reconstructionFolder, QString session, std::vector<TimedPosition> ts)
213 bool success =
false;
215 QFile file(reconstructionFolder+
"/"+session+
".fts");
216 if(!file.open(QIODevice::WriteOnly | QIODevice::Truncate))
221 QTextStream stream(&file);
223 for (
unsigned i=0; i<ts.size(); ++i)
231 QFileInfo info(file);
240 void UsReconstructionFileMaker::writeProbeConfiguration(QString reconstructionFolder, QString session, ProbeDefinition data, QString uid)
242 XmlOptionFile file = XmlOptionFile(reconstructionFolder +
"/" + session +
".probedata.xml");
243 data.addXml(file.getElement(
"configuration"));
244 file.getElement(
"tool").toElement().setAttribute(
"toolID", uid);
251 QDir patientDir(patientFolder +
"/US_Acq");
253 QString subfolder = sessionDescription;
254 QString subfolderAbsolutePath = patientDir.absolutePath()+
"/"+subfolder;
255 QString newPathName = subfolderAbsolutePath;
257 while(!findNewSubfolder(newPathName))
259 newPathName = subfolderAbsolutePath+
"_"+QString::number(i++);
261 patientDir.mkpath(newPathName);
262 patientDir.cd(newPathName);
264 retval = patientDir.absolutePath();
271 QDir patientDir(patientFolder +
"/US_Acq");
273 QString subfolder = sessionDescription;
274 QString subfolderAbsolutePath = patientDir.absolutePath()+
"/"+subfolder;
275 QString newPathName = subfolderAbsolutePath;
276 patientDir.mkpath(newPathName);
277 patientDir.cd(newPathName);
279 retval = patientDir.absolutePath();
283 bool UsReconstructionFileMaker::findNewSubfolder(QString subfolderAbsolutePath)
286 if(dir.exists(subfolderAbsolutePath))
292 void UsReconstructionFileMaker::report()
294 foreach(QString
string, mReport)
300 void UsReconstructionFileMaker::writeUSImages(QString path,
ImageDataContainerPtr images,
bool compression, std::vector<TimedPosition> pos)
305 for (
unsigned i=0; i<images->size(); ++i)
308 QString filename = QString(
"%1/%2_%3.mhd").arg(path).arg(mSessionDescription).arg(i);
310 writer->SetInputData(currentImage);
312 writer->SetCompression(compression);
314 StaticMutexVtkLocker lock;
319 customReader->setTransform(pos[i].mPos);
320 customReader->setModality(
"US");
321 customReader->setImageType(mSessionDescription);
325 void UsReconstructionFileMaker::writeMask(QString path, QString session,
vtkImageDataPtr mask)
327 QString filename = QString(
"%1/%2.mask.mhd").arg(path).arg(session);
330 reportWarning(QString(
"No mask found, ignoring write to %1").arg(filename));
335 writer->SetInputData(mask);
337 writer->SetCompression(
false);
342 void UsReconstructionFileMaker::writeREADMEFile(QString reconstructionFolder, QString session)
345 "* ==== Format description \n"
347 "* All files describing one acquisition lie the same folder. The files all have \n"
348 "* the name format US-Acq_<index>_<TS><stream>.<type>, \n"
350 "* - <index> is a running index, for convenience. \n"
351 "* - <TS> is a timestamp \n"
352 "* - <stream> is the uid of the video stream. Not used prior to cx3.5.0. \n"
353 "* - <type> is the format of that specific file. \n"
355 "* Together, the files contains information about the us images and their \n"
356 "* timestamps, the tracking positions and their timestamps, and the probe \n"
359 "* In the following, we use <filebase> = US-Acq_<index>_<TS><stream>. \n"
362 "* ==== <filebase>.mhd (obsolete) \n"
364 "* Used prior to version cx3.4.0. \n"
365 "* A file in the metaheader file format containing the uncompressed image data. \n"
366 "* the z-direction is the time axis, i.e. the z dim is the number of us frames. \n"
367 "* See http://www.itk.org/Wiki/MetaIO/Documentation for more. \n"
369 "* Two extra tags are added: \n"
371 "ConfigurationID = <path:inside:ProbeCalibConfigs.xml> \n"
372 "ProbeCalibration = <not used> \n"
374 "* The ConfigurationID refers to a specific configuration within \n"
375 "* ProbeCalibConfigs.xml, using colon separators. \n"
377 "* ==== <filebase>_<index>.mhd \n"
379 "* A sequence of files in the metaheader file format containing the image data, one file\n"
380 "* for each frame. The frame index is given by the index in the file name. \n"
381 "* See http://www.itk.org/Wiki/MetaIO/Documentation for more. \n"
382 "* Replaces single image files. \n"
384 "* ==== ProbeCalibConfigs.xml (obsolete) \n"
386 "* This file contains the probe definition, and is copied from the \n"
387 "* config/tool/Tools folder \n"
389 "* ==== <filebase>.probedata.xml \n"
391 "* This file contains the probe definition. Replaces ProbeCalibConfigs.xml. \n"
393 "* ==== <filebase>.fts \n"
395 "* This file contains the frame timestamps. This is a sequence of \n"
396 "* newline-separated floating-point numbers in milliceconds. The starting point \n"
397 "* is irrelevant. The number of timestamps must equal the number of us frames. \n"
400 "* ==== <filebase>.tp \n"
402 "* This file contains the tracking positions. This is a newline-separated \n"
403 "* sequence of matrices, one for each tracking sample. Each matrix is the prMt, \n"
404 "* i.e. the transform from tool to patient reference. \n"
405 "* The last line of the matrix (always containing 0 0 0 1) is omitted. The matrix \n"
406 "* numbers is whitespace-separated with newline between rows. Thus the number of \n"
407 "* lines in this file is (# tracking positions) x 3. \n"
410 "* ==== <filebase>.tts \n"
412 "* This file contains the tracking timestamps. The format equals .fts , \n"
413 "* but the number of timestamps equals the number of tracking positions. \n"
415 "* ==== <filebase>.fp \n"
417 "* This file contains the frame positions. This is a newline-separated \n"
418 "* sequence of matrices, one for each US frame. Each matrix is the rMu, \n"
419 "* i.e. the transform from lower-left centered image space to \n"
420 "* global reference. \n"
421 "* The last line of the matrix (always containing 0 0 0 1) is omitted. The matrix \n"
422 "* numbers is whitespace-separated with newline between rows. Thus the number of \n"
423 "* lines in this file is (# tracking positions) x 3. \n"
425 "* ==== <filebase>.mask.mhd \n"
427 "* This file contains the image mask. The binary image shows what parts \n"
428 "* of the frame images contain valid US data. This file is only written,\n"
429 "* not read. It can be constructed from the probe data. \n"
434 QFile file(reconstructionFolder+
"/"+session+
".README.txt");
435 if(!file.open(QIODevice::WriteOnly | QIODevice::Truncate))
440 QTextStream stream(&file);
448 mReconstructData.
mFilename = path+
"/"+mSessionDescription+
".fts";
451 mReport <<
"Made reconstruction folder: " + path;
452 QString session = mSessionDescription;
454 this->writeTrackerTimestamps(path, session, mReconstructData.
mPositions);
455 this->writeTrackerTransforms(path, session, mReconstructData.
mPositions);
456 this->writeUSTimestamps(path, session, mReconstructData.
mFrames);
457 this->writeUSTransforms(path, session, mReconstructData.
mFrames);
459 this->writeMask(path, session, mReconstructData.
getMask());
460 this->writeREADMEFile(path, session);
464 this->writeUSImages(path, imageData, compression, mReconstructData.
mFrames);
466 mReport <<
"failed to find frame data, save failed.";
469 mReport << QString(
"Completed save to %1. Spent %2s, %3fps").arg(mSessionDescription).arg(time/1000).arg(imageData->size()*1000/time);
QString qstring_cast(const T &val)
DoubleBoundingBox3D transform(const Transform3D &m, const DoubleBoundingBox3D &bb)
void reportError(QString msg)
~UsReconstructionFileMaker()
UsReconstructionFileMaker(QString sessionDescription)
#define CX_ASSERT(statement)
One position with timestamp.
Transform3D Transform3D
Transform3D is a representation of an affine 3D transform.
vtkSmartPointer< vtkImageAppend > vtkImageAppendPtr
cstring_cast_Placeholder cstring_cast(const T &val)
QString writeToNewFolder(QString path, bool compression)
boost::shared_ptr< class CustomMetaImage > CustomMetaImagePtr
void reportWarning(QString msg)
vtkSmartPointer< class vtkMetaImageWriter > vtkMetaImageWriterPtr
static QString createFolder(QString patientFolder, QString sessionDescription)
void reportSuccess(QString msg)
USReconstructInputData getReconstructData()
static USFrameDataPtr create(ImagePtr inputFrameData)
static QString createUniqueFolder(QString patientFolder, QString sessionDescription)
std::map< double, Transform3D > TimedTransformMap
void setData(ProbeDefinition data)
boost::shared_ptr< class ImageDataContainer > ImageDataContainerPtr
boost::shared_ptr< class Tool > ToolPtr