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();
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");
344 if (useDirectionCosines)
346 reportWarning(
"Elastix UseDirectionCosines is not supported. Result is probably wrong.");
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));
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));
430 QString transformType = this->readParameterString(
"Transform");
431 if (transformType!=
"EulerTransform")
432 reportError(
"Assert failure: attempting to read EulerTransform");
434 int numberOfParameters = this->readParameterInt(
"NumberOfParameters");
435 if (numberOfParameters!=6)
437 reportWarning(QString(
"Expected 6 Euler parameters, got %1").arg(numberOfParameters));
438 return Transform3D::Identity();
440 std::vector<double> tp = this->readParameterDoubleVector(
"TransformParameters");
441 std::vector<double> cor = this->readParameterDoubleVector(
"CenterOfRotationPoint");
453 QString transformType = this->readParameterString(
"Transform");
454 if (transformType!=
"AffineTransform")
455 reportError(
"Assert failure: attempting to read AffineTransform");
457 int numberOfParameters = this->readParameterInt(
"NumberOfParameters");
458 if (numberOfParameters!=12)
460 reportWarning(QString(
"Expected 12 Euler parameters, got %1").arg(numberOfParameters));
461 return Transform3D::Identity();
463 std::vector<double> tp = this->readParameterDoubleVector(
"TransformParameters");
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.
virtual bool isFinished() const
int readParameterInt(QString key)
std::string toString(T const &value)
converts any type to a string
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)
boost::shared_ptr< class RegServices > RegServicesPtr
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.
Namespace for all CustusX production code.