14 #include <QPushButton>
16 #include <vtkPolyData.h>
17 #include <vtkPoints.h>
50 mLastRegistration = Transform3D::Identity();
54 XmlOptionFile options =
profile()->getXmlSettings().descend(
"registration").descend(
"WirePhantomWidget");
59 mPipeline->initialize(filters);
61 mPipeline->getNodes()[0]->setValueName(
"US Image:");
62 mPipeline->getNodes()[0]->setHelp(
"Select an US volume acquired from the wire phantom.");
63 mPipeline->setOption(
"Color", QVariant(QColor(
"red")));
65 mLayout =
new QVBoxLayout(
this);
69 QPushButton* showCrossButton =
new QPushButton(
"Show Cross");
70 showCrossButton->setToolTip(
"Load the centerline description of the wire cross");
71 connect(showCrossButton, SIGNAL(clicked()),
this, SLOT(loadNominalCross()));
73 mMeasureButton =
new QPushButton(
"Execute");
74 mMeasureButton->setToolTip(
"Measure deviation of input volume from nominal wire cross.");
75 connect(mMeasureButton, SIGNAL(clicked()),
this, SLOT(measureSlot()));
77 mCalibrationButton =
new QPushButton(
"Probe calib");
78 mCalibrationButton->setToolTip(
""
79 "Estimate probe calibration sMt\n"
80 "based on last accuracy test and\n"
81 "the current probe orientation");
82 connect(mCalibrationButton, SIGNAL(clicked()),
this, SLOT(generate_sMt()));
84 QLayout* buttonsLayout =
new QHBoxLayout;
85 buttonsLayout->addWidget(mMeasureButton);
86 buttonsLayout->addWidget(mCalibrationButton);
88 mResults =
new QTextEdit;
90 mLayout->addWidget(showCrossButton);
91 mLayout->addWidget(mPipelineWidget);
92 mLayout->addLayout(buttonsLayout);
93 mLayout->addWidget(mResults, 1);
104 "<h3>Measure US accuracy using the wire phantom.</h3>"
106 "Select a US recording of the wire phantom, then press"
107 "the register button to find deviation from the nominal"
108 "data. The output is given as a distance from measured"
114 MeshPtr WirePhantomWidget::loadNominalCross()
119 std::map<QString, MeshPtr> meshes =
mServices->patient()->getDataOfType<
Mesh>();
120 for (std::map<QString, MeshPtr>::iterator iter=meshes.begin(); iter!=meshes.end(); ++iter)
121 if (iter->first.contains(
"wire_phantom_cross_pts"))
122 retval = iter->second;
127 retval = boost::dynamic_pointer_cast<Mesh>(
mServices->patient()->importData(nominalCrossFilename, infoText));
132 reportError(QString(
"failed to load %s.").arg(nominalCrossFilename));
135 retval->setColor(QColor(
"green"));
136 this->showData(retval);
141 void WirePhantomWidget::showData(
DataPtr data)
143 mServices->view()->getGroup(0)->addData(data->getUid());
146 void WirePhantomWidget::measureSlot()
148 if (mPipeline->getPipelineTimedAlgorithm()->isRunning())
150 connect(mPipeline->getPipelineTimedAlgorithm().get(), SIGNAL(finished()),
this, SLOT(registration()));
151 mPipeline->execute();
160 int N = points->GetNumberOfPoints();
165 for (
int i = 0; i < N; ++i)
166 acc +=
Vector3D(points->GetPoint(i));
170 void WirePhantomWidget::registration()
173 disconnect(mPipeline->getPipelineTimedAlgorithm().get(), SIGNAL(finished()),
this, SLOT(registration()));
187 DataPtr measuredCross = mPipeline->getNodes().back()->getData();
188 MeshPtr nominalCross = this->loadNominalCross();
189 if (!nominalCross || !measuredCross)
191 reportError(
"Missing fixed/moving data. WirePhantom measurement failed.");
195 mServices->registration()->setFixedData(nominalCross);
196 mServices->registration()->setMovingData(measuredCross);
198 this->showData(nominalCross);
199 this->showData(measuredCross);
201 SeansVesselReg vesselReg;
202 vesselReg.mt_auto_lts =
true;
203 vesselReg.mt_ltsRatio = 80;
204 vesselReg.mt_doOnlyLinear =
true;
205 QString logPath =
mServices->patient()->getActivePatientFolder() +
"/Logs/";
208 bool success = vesselReg.initialize(
mServices->registration()->getMovingData(),
mServices->registration()->getFixedData(), logPath);
209 success = success && vesselReg.execute();
216 Transform3D linearTransform = vesselReg.getLinearResult();
217 std::cout <<
"v2v linear result:\n" << linearTransform << std::endl;
219 vesselReg.checkQuality(linearTransform);
220 mLastRegistration = linearTransform;
227 mServices->registration()->setLastRegistrationTime(QDateTime::currentDateTime());
228 mServices->registration()->addImage2ImageRegistration(delta,
"Wire Phantom Measurement");
231 Vector3D t_delta = linearTransform.matrix().block<3, 1>(0, 3);
232 Eigen::AngleAxisd angleAxis = Eigen::AngleAxisd(linearTransform.matrix().block<3, 3>(0, 0));
233 double angle = angleAxis.angle();
238 Vector3D cross_r = this->findCentroid(nominalCross);
245 std::pair<QString, Transform3D> probePos = this->getLastProbePosition();
248 Vector3D cross_moving_r = linearTransform.coord(cross_r);
249 Vector3D diff_r = (cross_r - cross_moving_r);
250 Vector3D diff_tus = rMt_us.inv().vector(diff_r);
254 QString operator()(
double val)
256 return QString(
"%1").arg(val, 2,
'f', 2);
262 result += QString(
"Results for: %1\n").arg(
mServices->registration()->getMovingData()->getName());
263 result += QString(
"Shift vector (r): \t%1\t%2\t%3\n").arg(fmt(diff_r[0])).arg(fmt(diff_r[1])).arg(fmt(diff_r[2]));
264 if (!probePos.first.isEmpty())
265 result += QString(
"Shift vector (probe): \t%1\t%2\t%3\t(used tracking data from %4)\n").arg(fmt(diff_tus[0])).arg(fmt(diff_tus[1])).arg(fmt(diff_tus[2])).arg(probePos.first);
266 result += QString(
"Accuracy |v|: \t%1\tmm\n").arg(fmt(diff_r.length()));
267 result += QString(
"Angle: \t%1\t*\n").arg(fmt(angle /
M_PI * 180.0));
269 mResults->append(result);
270 report(
"Wire Phantom Test Results:\n"+result);
272 this->showDataMetrics(cross_r);
280 void WirePhantomWidget::showDataMetrics(
Vector3D cross_r)
286 Vector3D cross_us = usMnom.coord(cross_r);
290 p1 =
mServices->patient()->createSpecificData<PointMetric>(
"cross_nominal");
292 p1->get_rMd_History()->setParentSpace(
mServices->registration()->getFixedData()->getUid());
293 p1->setSpace(
mServices->spaceProvider()->getD(
mServices->registration()->getFixedData()));
294 p1->setCoordinate(cross_r);
301 p2 =
mServices->patient()->createSpecificData<PointMetric>(
"cross_us");
303 p2->get_rMd_History()->setParentSpace(
mServices->registration()->getMovingData()->getUid());
304 p2->setSpace(
mServices->spaceProvider()->getD(
mServices->registration()->getMovingData()));
305 p2->setCoordinate(cross_us);
312 d0 =
mServices->patient()->createSpecificData<DistanceMetric>(
"accuracy");
314 d0->get_rMd_History()->setParentSpace(
"reference");
315 d0->getArguments()->set(0, p1);
316 d0->getArguments()->set(1, p2);
328 std::pair<QString, Transform3D> WirePhantomWidget::getLastProbePosition()
331 USReconstructInputData usData = mUsReconstructionService->getSelectedFileData();
333 if (usData.mPositions.empty())
334 return std::make_pair(
"", Transform3D::Identity());
335 prMt_us = usData.mPositions[usData.mPositions.size()/2].mPos;
336 return std::make_pair(usData.mFilename, prMt_us);
339 void WirePhantomWidget::generate_sMt()
341 bool translateOnly =
true;
344 std::pair<QString, Transform3D> probePos = this->getLastProbePosition();
346 if (probePos.first.isEmpty())
348 reportWarning(
"Cannot find probe position from last recording, aborting calibration test.");
352 USReconstructInputData usData = mUsReconstructionService->getSelectedFileData();
356 reportWarning(
"Cannot find probe, aborting calibration test.");
366 if (!
mServices->registration()->getMovingData())
368 reportWarning(
"Cannot find moving data, aborting calibration test.");
375 Vector3D cross_r = this->findCentroid(this->loadNominalCross());
385 Vector3D cross_moving_r = mLastRegistration.coord(cross_r);
386 Vector3D diff_r = (cross_r - cross_moving_r);
387 Vector3D diff_tus = rMt_us.inv().vector(diff_r);
395 "Calculated new calibration matrix\n"
396 "adding only translation "
397 "from last accuracy test\n"
416 sQt = usMs.inv() * nomMus * usMs * sMt;
419 "Calculated new calibration matrix\n"
420 "from last accuracy test\n"
422 "Old calibration matrix sMt:\n"
424 "New calibration matrix sQt:\n"