56 mProcess =
new QProcess(
this);
57 connect(mProcess, SIGNAL(stateChanged(QProcess::ProcessState)),
this, SLOT(processStateChanged(QProcess::ProcessState)));
58 connect(mProcess, SIGNAL(error(QProcess::ProcessError)),
this, SLOT(processError(QProcess::ProcessError)));
59 connect(mProcess, SIGNAL(
finished(
int, QProcess::ExitStatus)),
this, SLOT(processFinished(
int, QProcess::ExitStatus)));
64 disconnect(mProcess, SIGNAL(error(QProcess::ProcessError)),
this, SLOT(processError(QProcess::ProcessError)));
70 disconnect(mProcess, SIGNAL(readyRead()),
this, SLOT(processReadyRead()));
74 connect(mProcess, SIGNAL(readyRead()),
this, SLOT(processReadyRead()));
76 mProcess->setProcessChannelMode(QProcess::MergedChannels);
77 mProcess->setReadChannel(QProcess::StandardOutput);
86 QStringList parameterfiles)
91 if (!fixed || !moving)
93 reportWarning(
"Failed to start elastiX registration, fixed or missing image missing.");
97 if (mProcess->state() != QProcess::NotRunning)
99 reportWarning(
"Failed to start elastiX registration, process already running");
104 QDir().mkpath(outdir);
106 QString initFilename = this->writeInitTransformToElastixfile(fixed, moving, outdir);
107 this->writeInitTransformToCalfile(fixed, moving, outdir);
109 mLastOutdir = outdir;
113 cmd <<
"-f" << mServices.
patientModelService->getActivePatientFolder()+
"/"+fixed->getFilename();
114 cmd <<
"-m" << mServices.
patientModelService->getActivePatientFolder()+
"/"+moving->getFilename();
115 cmd <<
"-out" << outdir;
116 cmd <<
"-t0" << initFilename;
117 for (
int i=0; i<parameterfiles.size(); ++i)
118 cmd <<
"-p" << parameterfiles[i];
120 QString commandLine = cmd.join(
" ");
121 report(QString(
"Executing registration with command line: [%1]").arg(commandLine));
123 mProcess->start(commandLine);
134 std::cout <<
"TODO: check ElastixExecuter::isFinished()" << std::endl;
135 return mProcess->atEnd();
140 return mProcess->state()!=QProcess::NotRunning;
143 QString ElastixExecuter::writeInitTransformToElastixfile(
163 Transform3D ffMf = this->getFileTransform_ddMd(mFixed);
164 Transform3D mmMm = this->getFileTransform_ddMd(mMoving);
173 QString elastiXText = QString(
""
174 "// Input transform file\n"
175 "// Auto-generated by CustusX on %1\n"
177 "(Transform \"EulerTransform\")\n"
178 "(NumberOfParameters 6)\n"
179 "(TransformParameters %2 %3)\n"
180 "(InitialTransformParametersFileName \"NoInitialTransform\")\n"
181 "(HowToCombineTransforms \"Compose\")\n"
183 "// EulerTransform specific\n"
184 "(CenterOfRotationPoint %4)\n"
185 "(ComputeZYX \"false\")\n"
191 QFile initTransformFile(outdir+
"/t0.txt");
192 if (!initTransformFile.open(QIODevice::WriteOnly | QIODevice::Text))
194 reportWarning(QString(
"Failed to open file %1 for writing.").arg(initTransformFile.fileName()));
196 initTransformFile.write(elastiXText.toLatin1());
197 return initTransformFile.fileName();
200 QString ElastixExecuter::writeInitTransformToCalfile(
205 Transform3D mMf = moving->get_rMd().inv() * fixed->get_rMd();
207 TransformFile file(outdir+
"/moving_M_fixed_initial.cal");
210 return file.fileName();
213 void ElastixExecuter::processReadyRead()
215 report(QString(mProcess->readAllStandardOutput()));
218 void ElastixExecuter::processError(QProcess::ProcessError error)
221 msg +=
"Registration process reported an error: ";
225 case QProcess::FailedToStart:
226 msg +=
"Failed to start";
228 case QProcess::Crashed:
231 case QProcess::Timedout:
234 case QProcess::WriteError:
235 msg +=
"Write Error";
237 case QProcess::ReadError:
240 case QProcess::UnknownError:
241 msg +=
"Unknown Error";
244 msg +=
"Invalid error";
250 void ElastixExecuter::processFinished(
int code, QProcess::ExitStatus status)
252 if (status == QProcess::CrashExit)
257 void ElastixExecuter::processStateChanged(QProcess::ProcessState newState)
262 msg +=
"Registration process";
264 if (newState == QProcess::Running)
269 if (newState == QProcess::NotRunning)
274 if (newState == QProcess::Starting)
280 QString ElastixExecuter::findMostRecentTransformOutputFile()
const
285 QString filename = QString(mLastOutdir +
"/TransformParameters.%1.txt").arg(i);
286 if (!QFileInfo(filename).exists())
303 Transform3D mmMff = this->getAffineResult_mmMff(ok);
304 Transform3D ffMf = this->getFileTransform_ddMd(mFixed);
305 Transform3D mmMm = this->getFileTransform_ddMd(mMoving);
307 return mmMm.inv() * mmMff * ffMf;
310 Transform3D ElastixExecuter::getAffineResult_mmMff(
bool* ok)
312 QString filename = this->findMostRecentTransformOutputFile();
315 if (filename.isEmpty())
320 TransformFile file(mLastOutdir+
"/moving_M_fixed_registered.cal");
333 ElastixParameterFile file(filename);
335 bool useDirectionCosines = file.readParameterBool(
"UseDirectionCosines");
336 if (useDirectionCosines)
338 reportWarning(
"Elastix UseDirectionCosines is not supported. Result is probably wrong.");
341 QString transformType = file.readParameterString(
"Transform");
342 if (transformType==
"EulerTransform")
350 else if (transformType==
"AffineTransform")
363 reportWarning(QString(
"TransformType [%1] is not supported by CustusX. Registration result from %2 ignored.").arg(transformType).arg(filename));
366 filename = file.readParameterString(
"InitialTransformParametersFileName");
367 if (filename.isEmpty() || filename==
"NoInitialTransform")
385 QString filename = QString(mLastOutdir +
"/result.%1.mhd").arg(i);
386 if (!QFileInfo(filename).exists())
391 if (retval.isEmpty())
394 QString paramFilename = QString(mLastOutdir +
"/TransformParameters.%1.txt").arg(i-1);
398 if ((transform==
"BSplineTransform") || (transform==
"SplineKernelTransform"))
400 report(QString(
"Reading result file %1 created with transform %2").arg(retval).arg(transform));
423 if (transformType!=
"EulerTransform")
424 reportError(
"Assert failure: attempting to read EulerTransform");
427 if (numberOfParameters!=6)
429 reportWarning(QString(
"Expected 6 Euler parameters, got %1").arg(numberOfParameters));
430 return Transform3D::Identity();
446 if (transformType!=
"AffineTransform")
447 reportError(
"Assert failure: attempting to read AffineTransform");
450 if (numberOfParameters!=12)
452 reportWarning(QString(
"Expected 12 Euler parameters, got %1").arg(numberOfParameters));
453 return Transform3D::Identity();
460 for (
int r=0; r<3; ++r)
461 for (
int c=0; c<3; ++c)
463 for (
int r=0; r<3; ++r)
471 if (!mFile.open(QIODevice::ReadOnly | QIODevice::Text))
473 reportWarning(QString(
"Can't open ElastiX result file %1").arg(filename));
475 mText = QString(mFile.readAll());
479 QString ElastixParameterFile::readParameterRawValue(QString key)
481 QStringList lines = mText.split(
'\n');
483 QString regexpStr = QString(
""
495 QRegExp rx(regexpStr);
511 QString retval = this->readParameterRawValue(key);
512 if (retval.startsWith(
"\"") && retval.endsWith(
"\""))
514 retval = retval.replace(0, 1,
"");
515 retval = retval.replace(retval.size()-1, 1,
"");
524 return (text==
"true") ?
true :
false;
529 QString retval = this->readParameterRawValue(key);
530 return retval.toInt();
535 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()
< emitted at start of run.
QString readParameterString(QString key)
void reportError(QString msg)
Base class for algorithms that wants to time their execution.
virtual bool isFinished() const
int readParameterInt(QString key)
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()
ElastixExecuter(RegServices services, QObject *parent=NULL)
virtual bool isRunning() const
std::vector< double > readParameterDoubleVector(QString key)
void aboutToStart()
emitted at start of execute. Use to perform preprocessing
Transform3D readEulerTransform()
PatientModelServicePtr patientModelService
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)