57 mProcess =
new QProcess(
this);
58 connect(mProcess, SIGNAL(stateChanged(QProcess::ProcessState)),
this, SLOT(processStateChanged(QProcess::ProcessState)));
59 connect(mProcess, SIGNAL(error(QProcess::ProcessError)),
this, SLOT(processError(QProcess::ProcessError)));
60 connect(mProcess, SIGNAL(
finished(
int, QProcess::ExitStatus)),
this, SLOT(processFinished(
int, QProcess::ExitStatus)));
65 disconnect(mProcess, SIGNAL(error(QProcess::ProcessError)),
this, SLOT(processError(QProcess::ProcessError)));
71 disconnect(mProcess, SIGNAL(readyRead()),
this, SLOT(processReadyRead()));
75 connect(mProcess, SIGNAL(readyRead()),
this, SLOT(processReadyRead()));
77 mProcess->setProcessChannelMode(QProcess::MergedChannels);
78 mProcess->setReadChannel(QProcess::StandardOutput);
87 QStringList parameterfiles)
92 if (!fixed || !moving)
94 reportWarning(
"Failed to start elastiX registration, fixed or missing image missing.");
98 if (mProcess->state() != QProcess::NotRunning)
100 reportWarning(
"Failed to start elastiX registration, process already running");
105 QDir().mkpath(outdir);
107 QString initFilename = this->writeInitTransformToElastixfile(fixed, moving, outdir);
108 this->writeInitTransformToCalfile(fixed, moving, outdir);
110 mLastOutdir = outdir;
113 cmd <<
"\"" + application +
"\"";
114 cmd <<
"-f" << mServices->patient()->getActivePatientFolder()+
"/"+fixed->getFilename();
115 cmd <<
"-m" << mServices->patient()->getActivePatientFolder()+
"/"+moving->getFilename();
116 cmd <<
"-out" << outdir;
117 cmd <<
"-t0" << initFilename;
118 for (
int i=0; i<parameterfiles.size(); ++i)
119 cmd <<
"-p" << parameterfiles[i];
121 QString commandLine = cmd.join(
" ");
122 report(QString(
"Executing registration with command line: [%1]").arg(commandLine));
126 QString path = QFileInfo(application).absolutePath();
127 QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
128 env.insert(
"LD_LIBRARY_PATH", path);
129 mProcess->setProcessEnvironment(env);
131 mProcess->start(commandLine);
142 std::cout <<
"TODO: check ElastixExecuter::isFinished()" << std::endl;
143 return mProcess->atEnd();
148 return mProcess->state()!=QProcess::NotRunning;
151 QString ElastixExecuter::writeInitTransformToElastixfile(
171 Transform3D ffMf = this->getFileTransform_ddMd(mFixed);
172 Transform3D mmMm = this->getFileTransform_ddMd(mMoving);
181 QString elastiXText = QString(
""
182 "// Input transform file\n"
183 "// Auto-generated by CustusX on %1\n"
185 "(Transform \"EulerTransform\")\n"
186 "(NumberOfParameters 6)\n"
187 "(TransformParameters %2 %3)\n"
188 "(InitialTransformParametersFileName \"NoInitialTransform\")\n"
189 "(HowToCombineTransforms \"Compose\")\n"
191 "// EulerTransform specific\n"
192 "(CenterOfRotationPoint %4)\n"
193 "(ComputeZYX \"false\")\n"
199 QFile initTransformFile(outdir+
"/t0.txt");
200 if (!initTransformFile.open(QIODevice::WriteOnly | QIODevice::Text))
202 reportWarning(QString(
"Failed to open file %1 for writing.").arg(initTransformFile.fileName()));
204 initTransformFile.write(elastiXText.toLatin1());
205 return initTransformFile.fileName();
208 QString ElastixExecuter::writeInitTransformToCalfile(
213 Transform3D mMf = moving->get_rMd().inv() * fixed->get_rMd();
215 TransformFile file(outdir+
"/moving_M_fixed_initial.cal");
218 return file.fileName();
221 void ElastixExecuter::processReadyRead()
223 report(QString(mProcess->readAllStandardOutput()));
226 void ElastixExecuter::processError(QProcess::ProcessError error)
229 msg +=
"Registration process reported an error: ";
233 case QProcess::FailedToStart:
234 msg +=
"Failed to start";
236 case QProcess::Crashed:
239 case QProcess::Timedout:
242 case QProcess::WriteError:
243 msg +=
"Write Error";
245 case QProcess::ReadError:
248 case QProcess::UnknownError:
249 msg +=
"Unknown Error";
252 msg +=
"Invalid error";
258 void ElastixExecuter::processFinished(
int code, QProcess::ExitStatus status)
260 if (status == QProcess::CrashExit)
265 void ElastixExecuter::processStateChanged(QProcess::ProcessState newState)
270 msg +=
"Registration process";
272 if (newState == QProcess::Running)
277 if (newState == QProcess::NotRunning)
282 if (newState == QProcess::Starting)
288 QString ElastixExecuter::findMostRecentTransformOutputFile()
const
293 QString filename = QString(mLastOutdir +
"/TransformParameters.%1.txt").arg(i);
294 if (!QFileInfo(filename).exists())
303 QString patFolder = mServices->patient()->getActivePatientFolder();
311 Transform3D mmMff = this->getAffineResult_mmMff(ok);
312 Transform3D ffMf = this->getFileTransform_ddMd(mFixed);
313 Transform3D mmMm = this->getFileTransform_ddMd(mMoving);
315 return mmMm.inv() * mmMff * ffMf;
318 Transform3D ElastixExecuter::getAffineResult_mmMff(
bool* ok)
320 QString filename = this->findMostRecentTransformOutputFile();
323 if (filename.isEmpty())
328 TransformFile file(mLastOutdir+
"/moving_M_fixed_registered.cal");
341 ElastixParameterFile file(filename);
343 bool useDirectionCosines = file.readParameterBool(
"UseDirectionCosines");
344 if (useDirectionCosines)
346 reportWarning(
"Elastix UseDirectionCosines is not supported. Result is probably wrong.");
349 QString transformType = file.readParameterString(
"Transform");
350 if (transformType==
"EulerTransform")
358 else if (transformType==
"AffineTransform")
371 reportWarning(QString(
"TransformType [%1] is not supported by CustusX. Registration result from %2 ignored.").arg(transformType).arg(filename));
374 filename = file.readParameterString(
"InitialTransformParametersFileName");
375 if (filename.isEmpty() || filename==
"NoInitialTransform")
393 QString filename = QString(mLastOutdir +
"/result.%1.mhd").arg(i);
394 if (!QFileInfo(filename).exists())
399 if (retval.isEmpty())
402 QString paramFilename = QString(mLastOutdir +
"/TransformParameters.%1.txt").arg(i-1);
406 if ((transform==
"BSplineTransform") || (transform==
"SplineKernelTransform"))
408 report(QString(
"Reading result file %1 created with transform %2").arg(retval).arg(transform));
431 if (transformType!=
"EulerTransform")
432 reportError(
"Assert failure: attempting to read EulerTransform");
435 if (numberOfParameters!=6)
437 reportWarning(QString(
"Expected 6 Euler parameters, got %1").arg(numberOfParameters));
438 return Transform3D::Identity();
454 if (transformType!=
"AffineTransform")
455 reportError(
"Assert failure: attempting to read AffineTransform");
458 if (numberOfParameters!=12)
460 reportWarning(QString(
"Expected 12 Euler parameters, got %1").arg(numberOfParameters));
461 return Transform3D::Identity();
468 for (
int r=0; r<3; ++r)
469 for (
int c=0; c<3; ++c)
471 for (
int r=0; r<3; ++r)
479 if (!mFile.open(QIODevice::ReadOnly | QIODevice::Text))
481 reportWarning(QString(
"Can't open ElastiX result file %1").arg(filename));
483 mText = QString(mFile.readAll());
487 QString ElastixParameterFile::readParameterRawValue(QString key)
489 QStringList lines = mText.split(
'\n');
491 QString regexpStr = QString(
""
503 QRegExp rx(regexpStr);
519 QString retval = this->readParameterRawValue(key);
520 if (retval.startsWith(
"\"") && retval.endsWith(
"\""))
522 retval = retval.replace(0, 1,
"");
523 retval = retval.replace(retval.size()-1, 1,
"");
532 return (text==
"true") ?
true :
false;
537 QString retval = this->readParameterRawValue(key);
538 return retval.toInt();
543 QString retval = this->readParameterRawValue(key);
QString qstring_cast(const T &val)
ElastixParameterFile(QString filename)
bool setInput(QString application, DataPtr fixed, DataPtr moving, QString outdir, QStringList parameterfiles)
DoubleBoundingBox3D transform(const Transform3D &m, const DoubleBoundingBox3D &bb)
void finished()
should be emitted when at the end of postProcessingSlot
QString readParameterString(QString key)
void reportError(QString msg)
Base class for algorithms that wants to time their execution.
boost::shared_ptr< class RegServices > RegServicesPtr
virtual bool isFinished() const
int readParameterInt(QString key)
ElastixExecuter(RegServicesPtr services, QObject *parent=NULL)
Transform3D Transform3D
Transform3D is a representation of an affine 3D transform.
QString timestampSecondsFormatNice()
QString getNonlinearResultVolume(bool *ok=0)
boost::shared_ptr< class Data > DataPtr
boost::shared_ptr< class CustomMetaImage > CustomMetaImagePtr
void reportWarning(QString msg)
bool readParameterBool(QString key)
Eigen::Vector3d Vector3D
Vector3D is a representation of a point or vector in 3D.
virtual ~ElastixExecuter()
virtual bool isRunning() const
std::vector< double > readParameterDoubleVector(QString key)
void aboutToStart()
emitted at start of execute. Use to perform preprocessing
Transform3D readEulerTransform()
void setDisplayProcessMessages(bool on)
Transform3D readAffineTransform()
std::vector< double > convertQString2DoubleVector(const QString &input, bool *ok)
Transform3D getAffineResult_mMf(bool *ok=0)
void started(int maxSteps)
emitted at start of run.