35 #include <QPushButton>
37 #include <vtkPolyData.h>
38 #include <vtkPoints.h>
72 mLastRegistration = Transform3D::Identity();
79 XmlOptionFile options =
profile()->getXmlSettings().descend(
"registration").descend(
"WirePhantomWidget");
84 mPipeline->initialize(filters);
86 mPipeline->getNodes()[0]->setValueName(
"US Image:");
87 mPipeline->getNodes()[0]->setHelp(
"Select an US volume acquired from the wire phantom.");
88 mPipeline->setOption(
"Color", QVariant(QColor(
"red")));
90 mLayout =
new QVBoxLayout(
this);
94 QPushButton* showCrossButton =
new QPushButton(
"Show Cross");
95 showCrossButton->setToolTip(
"Load the centerline description of the wire cross");
96 connect(showCrossButton, SIGNAL(clicked()),
this, SLOT(loadNominalCross()));
98 mMeasureButton =
new QPushButton(
"Execute");
99 mMeasureButton->setToolTip(
"Measure deviation of input volume from nominal wire cross.");
100 connect(mMeasureButton, SIGNAL(clicked()),
this, SLOT(measureSlot()));
102 mCalibrationButton =
new QPushButton(
"Probe calib");
103 mCalibrationButton->setToolTip(
""
104 "Estimate probe calibration sMt\n"
105 "based on last accuracy test and\n"
106 "the current probe orientation");
107 connect(mCalibrationButton, SIGNAL(clicked()),
this, SLOT(generate_sMt()));
109 QLayout* buttonsLayout =
new QHBoxLayout;
110 buttonsLayout->addWidget(mMeasureButton);
111 buttonsLayout->addWidget(mCalibrationButton);
113 mResults =
new QTextEdit;
115 mLayout->addWidget(showCrossButton);
116 mLayout->addWidget(mPipelineWidget);
117 mLayout->addLayout(buttonsLayout);
118 mLayout->addWidget(mResults, 1);
129 "<h3>Measure US accuracy using the wire phantom.</h3>"
131 "Select a US recording of the wire phantom, then press"
132 "the register button to find deviation from the nominal"
133 "data. The output is given as a distance from measured"
139 MeshPtr WirePhantomWidget::loadNominalCross()
145 for (std::map<QString, MeshPtr>::iterator iter=meshes.begin(); iter!=meshes.end(); ++iter)
146 if (iter->first.contains(
"wire_phantom_cross_pts"))
147 retval = iter->second;
157 reportError(QString(
"failed to load %s.").arg(nominalCrossFilename));
160 retval->setColor(QColor(
"green"));
161 this->showData(retval);
166 void WirePhantomWidget::showData(
DataPtr data)
171 void WirePhantomWidget::measureSlot()
173 if (mPipeline->getPipelineTimedAlgorithm()->isRunning())
175 connect(mPipeline->getPipelineTimedAlgorithm().get(), SIGNAL(finished()),
this, SLOT(registration()));
176 mPipeline->execute();
185 int N = points->GetNumberOfPoints();
190 for (
int i = 0; i < N; ++i)
191 acc +=
Vector3D(points->GetPoint(i));
195 void WirePhantomWidget::registration()
198 disconnect(mPipeline->getPipelineTimedAlgorithm().get(), SIGNAL(finished()),
this, SLOT(registration()));
212 DataPtr measuredCross = mPipeline->getNodes().back()->getData();
213 MeshPtr nominalCross = this->loadNominalCross();
214 if (!nominalCross || !measuredCross)
216 reportError(
"Missing fixed/moving data. WirePhantom measurement failed.");
223 this->showData(nominalCross);
224 this->showData(measuredCross);
226 SeansVesselReg vesselReg;
227 vesselReg.mt_auto_lts =
true;
228 vesselReg.mt_ltsRatio = 80;
229 vesselReg.mt_doOnlyLinear =
true;
240 Transform3D linearTransform = vesselReg.getLinearResult();
241 std::cout <<
"v2v linear result:\n" << linearTransform << std::endl;
243 vesselReg.checkQuality(linearTransform);
244 mLastRegistration = linearTransform;
255 Vector3D t_delta = linearTransform.matrix().block<3, 1>(0, 3);
256 Eigen::AngleAxisd angleAxis = Eigen::AngleAxisd(linearTransform.matrix().block<3, 3>(0, 0));
257 double angle = angleAxis.angle();
262 Vector3D cross_r = this->findCentroid(nominalCross);
269 std::pair<QString, Transform3D> probePos = this->getLastProbePosition();
272 Vector3D cross_moving_r = linearTransform.coord(cross_r);
273 Vector3D diff_r = (cross_r - cross_moving_r);
274 Vector3D diff_tus = rMt_us.inv().vector(diff_r);
278 QString operator()(
double val)
280 return QString(
"%1").arg(val, 2,
'f', 2);
287 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]));
288 if (!probePos.first.isEmpty())
289 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);
290 result += QString(
"Accuracy |v|: \t%1\tmm\n").arg(fmt(diff_r.length()));
291 result += QString(
"Angle: \t%1\t*\n").arg(fmt(angle /
M_PI * 180.0));
293 mResults->append(result);
294 report(
"Wire Phantom Test Results:\n"+result);
296 this->showDataMetrics(cross_r);
304 void WirePhantomWidget::showDataMetrics(
Vector3D cross_r)
310 Vector3D cross_us = usMnom.coord(cross_r);
318 p1->setCoordinate(cross_r);
329 p2->setCoordinate(cross_us);
338 d0->get_rMd_History()->setParentSpace(
"reference");
339 d0->getArguments()->set(0, p1);
340 d0->getArguments()->set(1, p2);
352 std::pair<QString, Transform3D> WirePhantomWidget::getLastProbePosition()
355 USReconstructInputData usData = mUsReconstructionService->getSelectedFileData();
357 if (usData.mPositions.empty())
358 return std::make_pair(
"", Transform3D::Identity());
359 prMt_us = usData.mPositions[usData.mPositions.size()/2].mPos;
360 return std::make_pair(usData.mFilename, prMt_us);
363 void WirePhantomWidget::generate_sMt()
365 bool translateOnly =
true;
368 std::pair<QString, Transform3D> probePos = this->getLastProbePosition();
370 if (probePos.first.isEmpty())
372 reportWarning(
"Cannot find probe position from last recording, aborting calibration test.");
376 USReconstructInputData usData = mUsReconstructionService->getSelectedFileData();
380 reportWarning(
"Cannot find probe, aborting calibration test.");
392 reportWarning(
"Cannot find moving data, aborting calibration test.");
399 Vector3D cross_r = this->findCentroid(this->loadNominalCross());
409 Vector3D cross_moving_r = mLastRegistration.coord(cross_r);
410 Vector3D diff_r = (cross_r - cross_moving_r);
411 Vector3D diff_tus = rMt_us.inv().vector(diff_r);
419 "Calculated new calibration matrix\n"
420 "adding only translation "
421 "from last accuracy test\n"
440 sQt = usMs.inv() * nomMus * usMs * sMt;
443 "Calculated new calibration matrix\n"
444 "from last accuracy test\n"
446 "Old calibration matrix sMt:\n"
448 "New calibration matrix sQt:\n"
QString qstring_cast(const T &val)
cxResource_EXPORT ProfilePtr profile()
void reportError(QString msg)
SpaceProviderPtr getSpaceProvider()
boost::shared_ptr< class VisServices > VisServicesPtr
Transform3D Transform3D
Transform3D is a representation of an affine 3D transform.
vtkSmartPointer< class vtkPolyData > vtkPolyDataPtr
boost::shared_ptr< class Data > DataPtr
boost::shared_ptr< class Filter > FilterPtr
void reportWarning(QString msg)
boost::shared_ptr< FilterGroup > FilterGroupPtr
Transform3D createTransformTranslate(const Vector3D &translation)
boost::shared_ptr< class DistanceMetric > DistanceMetricPtr
Eigen::Vector3d Vector3D
Vector3D is a representation of a point or vector in 3D.
VisualizationServicePtr visualizationService
static QString getRootConfigPath()
return path to root config folder. May be replaced with getExistingConfigPath()
TrackingServicePtr trackingService
PatientModelServicePtr patientModelService
boost::shared_ptr< class Mesh > MeshPtr
Helper class for xml files used to store ssc/cx data.
RegistrationServicePtr registrationService
vtkSmartPointer< class vtkPoints > vtkPointsPtr
boost::shared_ptr< class Tool > ToolPtr
boost::shared_ptr< class PointMetric > PointMetricPtr