CustusX  15.8
An IGT application
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
cxSeansVesselRegistrationWidget.cpp
Go to the documentation of this file.
1 /*=========================================================================
2 This file is part of CustusX, an Image Guided Therapy Application.
3 
4 Copyright (c) 2008-2014, SINTEF Department of Medical Technology
5 All rights reserved.
6 
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9 
10 1. Redistributions of source code must retain the above copyright notice,
11  this list of conditions and the following disclaimer.
12 
13 2. Redistributions in binary form must reproduce the above copyright notice,
14  this list of conditions and the following disclaimer in the documentation
15  and/or other materials provided with the distribution.
16 
17 3. Neither the name of the copyright holder nor the names of its contributors
18  may be used to endorse or promote products derived from this software
19  without specific prior written permission.
20 
21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
25 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 =========================================================================*/
32 
34 
35 #include <QPushButton>
36 #include <QLabel>
37 #include <QSpinBox>
38 #include <QCheckBox>
39 #include <QGroupBox>
40 #include <vtkCellArray.h>
41 #include "cxTypeConversions.h"
42 #include "cxLogger.h"
43 #include "cxTimedAlgorithm.h"
47 #include "cxMesh.h"
48 #include "cxView.h"
49 #include "cxGeometricRep.h"
50 #include "cxGraphicalPrimitives.h"
51 #include "cxRegistrationService.h"
52 #include "cxViewService.h"
53 #include "cxPatientModelService.h"
54 
55 namespace cx
56 {
57 
59  RegistrationBaseWidget(services, parent, "org_custusx_registration_method_vessel_seans_widget", "Seans Vessel Registration"),
60  mLTSRatioSpinBox(new QSpinBox()), mLinearCheckBox(new QCheckBox()), mAutoLTSCheckBox(new QCheckBox()),
61  mRegisterButton(new QPushButton("Register"))
62 {
63  mRegisterButton->setEnabled(false);
64  connect(mRegisterButton, &QPushButton::clicked, this, &SeansVesselRegistrationWidget::registerSlot);
65 
67  this, &SeansVesselRegistrationWidget::inputChanged);
69  this, &SeansVesselRegistrationWidget::inputChanged);
70 
71  QVBoxLayout* topLayout = new QVBoxLayout(this);
72  QGridLayout* layout = new QGridLayout();
73  topLayout->addLayout(layout);
74 
75  mVesselRegOptionsButton = new QPushButton("Options", this);
76  mVesselRegOptionsButton->setEnabled(false);
77  mVesselRegOptionsButton->setCheckable(true);
78 
79  mVesselRegOptionsWidget = this->createGroupbox(this->createOptionsWidget(),
80  "Vessel registration options");
81  connect(mVesselRegOptionsButton, SIGNAL(clicked(bool)), mVesselRegOptionsWidget, SLOT(setVisible(bool)));
82  mVesselRegOptionsWidget->setVisible(mVesselRegOptionsButton->isChecked());
83 
84  QGridLayout* entryLayout = new QGridLayout;
85  entryLayout->setColumnStretch(1, 1);
86 
87  mFixedImage.reset(new StringPropertyRegistrationFixedImage(services.registrationService, services.patientModelService));
88  new LabeledComboBoxWidget(this, mFixedImage, entryLayout, 0);
89  mMovingImage.reset(new StringPropertyRegistrationMovingImage(services.registrationService, services.patientModelService));
90  new LabeledComboBoxWidget(this, mMovingImage, entryLayout, 1);
91 
92  layout->addLayout(entryLayout, 0, 0, 2, 2);
93  layout->addWidget(mRegisterButton, 2, 0);
94  layout->addWidget(mVesselRegOptionsButton, 2, 1);
95  layout->addWidget(mVesselRegOptionsWidget, 3, 0, 1, 2);
96 }
97 
99 {
100 }
101 
102 void SeansVesselRegistrationWidget::inputChanged()
103 {
104  if(mServices.registrationService->getMovingData() && mServices.registrationService->getFixedData())
105  {
106  mRegisterButton->setEnabled(true);
107  mVesselRegOptionsButton->setEnabled(true);
108  mVesselRegOptionsWidget->setVisible(mVesselRegOptionsButton->isChecked());
109  }
110  else
111  {
112  mRegisterButton->setEnabled(false);
113  mVesselRegOptionsButton->setEnabled(false);
114  mVesselRegOptionsWidget->setVisible(false);
115  }
116 }
117 
118 void SeansVesselRegistrationWidget::registerSlot()
119 {
120 // int lts_ratio = mLTSRatioSpinBox->value();
121 // double stop_delta = 0.001; //TODO, add user interface
122 // double lambda = 0; //TODO, add user interface
123 // double sigma = 1.0; //TODO, add user interface
124 // bool lin_flag = mLinearCheckBox->isChecked(); //TODO, add user interface
125 // int sample = 1; //TODO, add user interface
126 // int single_point_thre = 1; //TODO, add user interface
127 // bool verbose = 1; //TODO, add user interface
128 
129  QString logPath = mServices.patientModelService->getActivePatientFolder() + "/Logs/";
130 
131 // mRegistrationService->doVesselRegistration(lts_ratio, stop_delta, lambda, sigma, lin_flag, sample, single_point_thre, verbose,
132 // logPath);
133 
134  SeansVesselReg vesselReg;
135  vesselReg.mt_auto_lts = true;
136  vesselReg.mt_ltsRatio = mLTSRatioSpinBox->value();
137  vesselReg.mt_doOnlyLinear = mLinearCheckBox->isChecked();
138  vesselReg.mt_auto_lts = mAutoLTSCheckBox->isChecked();
139 
140  if (vesselReg.mt_auto_lts)
141  {
142  reportDebug("Using automatic lts_ratio");
143  }
144  else
145  {
146  reportDebug("Using lts_ratio: " + qstring_cast(vesselReg.mt_ltsRatio));
147  }
148 
149  if(!mServices.registrationService->getMovingData())
150  {
151  reportWarning("Moving volume not set.");
152  return;
153  }
154  else if(!mServices.registrationService->getFixedData())
155  {
156  reportWarning("Fixed volume not set.");
157  return;
158  }
159 
160  bool success = vesselReg.execute(mServices.registrationService->getMovingData(), mServices.registrationService->getFixedData(), logPath);
161  if (!success)
162  {
163  reportWarning("Vessel registration failed.");
164  return;
165  }
166 
167  Transform3D linearTransform = vesselReg.getLinearResult();
168  std::cout << "v2v linear result:\n" << linearTransform << std::endl;
169  //std::cout << "v2v inverted linear result:\n" << linearTransform.inverse() << std::endl;
170 
171  vesselReg.checkQuality(linearTransform);
172 
173  // The registration is performed in space r. Thus, given an old data position rMd, we find the
174  // new one as rM'd = Q * rMd, where Q is the inverted registration output.
175  // Delta is thus equal to Q:
176  Transform3D delta = linearTransform.inv();
177  //std::cout << "delta:\n" << delta << std::endl;
178  mServices.registrationService->applyImage2ImageRegistration(delta, "Vessel based");
179 }
180 
186 {
187 public:
188  SeansVesselRegistrationDebugger(RegServices services, double ltsRatio, bool linear) :
189  mServices(services)
190  {
191  mRegistrator.mt_doOnlyLinear = linear;
192  mRegistrator.mt_ltsRatio = ltsRatio;
193  mRegistrator.mt_auto_lts = false;
194 
195  mContext = mRegistrator.createContext(mServices.registrationService->getMovingData(), mServices.registrationService->getFixedData());
196 
197  //mMovingData = mRegistrator.convertToPolyData(mContext->mSourcePoints);
198  mMovingData = mContext->getMovingPoints();
199  mFixedData = mContext->getFixedPoints();
200 
201  MeshPtr moving(new Mesh("v2vreg_moving", "v2vreg_moving", mMovingData));
202  moving->setColor(QColor("red"));
203 
204  MeshPtr fixed(new Mesh("v2vreg_fixed", "v2vreg_fixed", mFixedData));
205  fixed->setColor(QColor("green"));
206 
207  mPolyLines = vtkPolyDataPtr::New();
208  MeshPtr lines(new Mesh("v2vreg_lines", "v2vreg_lines", mPolyLines));
209  lines->setColor(QColor("cornflowerblue"));
210 
211  ViewPtr view = mServices.visualizationService->get3DView();
212 
213  m_mRep = GeometricRep::New();
214  m_mRep->setMesh(moving);
215  view->addRep(m_mRep);
216 
217  m_fRep = GeometricRep::New();
218  m_fRep->setMesh(fixed);
219  view->addRep(m_fRep);
220 
221  m_lineRep = GeometricRep::New();
222  m_lineRep->setMesh(lines);
223  view->addRep(m_lineRep);
224 
225  this->update();
226 
227  report("Initialized V2V algorithm (debug). Use Step to iterate.");
228  }
230  {
231  ViewPtr view = mServices.visualizationService->get3DView();
232  view->removeRep(m_mRep);
233  view->removeRep(m_fRep);
234  view->removeRep(m_lineRep);
235  report("Closed V2V algorithm (debug).");
236  }
237  void stepL()
238  {
239  if (!mContext)
240  return;
241  mRegistrator.performOneRegistration(mContext, true);
242  this->update();
243  report(QString("One Linear V2V iteration, metric=%1").arg(mContext->mMetric));
244  }
245  void stepNL()
246  {
247  if (!mContext)
248  return;
249  mRegistrator.performOneRegistration(mContext, false);
250  this->update();
251  report(QString("One Nonlinear V2V iteration, metric=%1").arg(mContext->mMetric));
252  }
253  void apply()
254  {
255  if (!mContext)
256  return;
257 
258  Transform3D linearTransform = mRegistrator.getLinearResult(mContext);
259  std::cout << "v2v linear result:\n" << linearTransform << std::endl;
260 
261  mRegistrator.checkQuality(linearTransform);
262  Transform3D delta = linearTransform.inv();
263  mServices.registrationService->applyImage2ImageRegistration(delta, "Vessel based");
264 
265  report(QString("Applied linear registration from debug iteration."));
266  }
267  void update()
268  {
269  if (!mContext)
270  return;
271  mRegistrator.computeDistances(mContext);
272 // vtkPolyDataPtr temp = mRegistrator.convertToPolyData(mContext->mSourcePoints);
273 // mMovingData->SetPoints(temp->GetPoints());
274 // mMovingData->SetVerts(temp->GetVerts());
275 
276  vtkPolyDataPtr moving = mContext->getMovingPoints();
277  mMovingData->SetPoints(moving->GetPoints());
278  mMovingData->SetVerts(moving->GetVerts());
279 
280  vtkPolyDataPtr fixed = mContext->getFixedPoints();
281  mFixedData->SetPoints(fixed->GetPoints());
282  mFixedData->SetVerts(fixed->GetVerts());
283 
284  // // draw lines: slow but nice
285  // mLines.clear();
286  // View* view = mServices.visualizationService->get3DView();
287  // for (int i=0; i<mContext->mSortedSourcePoints->GetNumberOfPoints(); ++i)
288  // {
289  // GraphicalLine3DPtr line(new GraphicalLine3D(view->getRenderer()));
290  // line->setValue(Vector3D(mContext->mSortedSourcePoints->GetPoint(i)),
291  // Vector3D(mContext->mSortedTargetPoints->GetPoint(i)));
292  // line->setColor(Vector3D(1,0,0));
293  // mLines.push_back(line);
294  // }
295 
296  // draw lines
297  mPolyLines->Allocate();
298  vtkPointsPtr verts = vtkPointsPtr::New();
299  for (int i = 0; i < mContext->mSortedSourcePoints->GetNumberOfPoints(); ++i)
300  {
301  verts->InsertNextPoint(mContext->mSortedSourcePoints->GetPoint(i));
302  verts->InsertNextPoint(mContext->mSortedTargetPoints->GetPoint(i));
303 
304  vtkIdType connectivity[2];
305  connectivity[0] = 2 * i;
306  connectivity[1] = 2 * i + 1;
307  mPolyLines->InsertNextCell(VTK_LINE, 2, connectivity);
308  }
309  mPolyLines->SetPoints(verts);
310  }
311 
312 private:
313  SeansVesselReg mRegistrator;
315  vtkPolyDataPtr mMovingData, mFixedData;
316  vtkPolyDataPtr mPolyLines;
317  GeometricRepPtr m_mRep, m_fRep, m_lineRep;
318  // std::vector<GraphicalLine3DPtr> mLines;
319  RegServices mServices;
320 };
321 
322 void SeansVesselRegistrationWidget::debugInit()
323 {
324  mDebugger.reset(new SeansVesselRegistrationDebugger(mServices, mLTSRatioSpinBox->value(),
325  mLinearCheckBox->isChecked()));
326 }
327 void SeansVesselRegistrationWidget::debugRunOneLinearStep()
328 {
329  if (mDebugger)
330  mDebugger->stepL();
331 }
332 void SeansVesselRegistrationWidget::debugRunOneNonlinearStep()
333 {
334  if (mDebugger)
335  mDebugger->stepNL();
336 }
337 
338 void SeansVesselRegistrationWidget::debugApply()
339 {
340  if (mDebugger)
341  mDebugger->apply();
342 }
343 
344 void SeansVesselRegistrationWidget::debugClear()
345 {
346  mDebugger.reset();
347 }
348 
349 QWidget* SeansVesselRegistrationWidget::createOptionsWidget()
350 {
351  QWidget* retval = new QWidget(this);
352  QGridLayout* layout = new QGridLayout(retval);
353 
354  mLTSRatioSpinBox->setSingleStep(1);
355  mLTSRatioSpinBox->setValue(80);
356 
357  mLinearCheckBox->setChecked(true);
358  mAutoLTSCheckBox->setChecked(true);
359 
360  int line = 0;
361  layout->addWidget(new QLabel("Auto LTS:"), line, 0);
362  layout->addWidget(mAutoLTSCheckBox, line, 1);
363  ++line;
364  layout->addWidget(new QLabel("LTS Ratio:"), line, 0);
365  layout->addWidget(mLTSRatioSpinBox, line, 1);
366  ++line;
367  layout->addWidget(new QLabel("Linear:"), line, 0);
368  layout->addWidget(mLinearCheckBox, line, 1);
369  ++line;
370  layout->addWidget(new QLabel("Debug"), line, 0);
371  QHBoxLayout* debugLayout = new QHBoxLayout;
372  layout->addLayout(debugLayout, line, 1, 1, 1);
373  this->createAction(this, QIcon(), "Init",
374  "Initialize the V2V algorithm.\n Display only, registration will not be updated in CustusX (Debug)",
375  SLOT(debugInit()), debugLayout);
376  this->createAction(this, QIcon(), "Lin", "Run one Linear step in the V2V algorithm. (Debug)",
377  SLOT(debugRunOneLinearStep()), debugLayout);
378  this->createAction(this, QIcon(), "NL",
379  "Run one Nonlinear step in the V2V algorithm. (Should be one at the end only)(Debug)",
380  SLOT(debugRunOneNonlinearStep()), debugLayout);
381  this->createAction(this, QIcon(), "Apply", "Apply results from the debug iteration", SLOT(debugApply()), debugLayout);
382  this->createAction(this, QIcon(), "Clear", "Clear debugging of the V2V algorithm.", SLOT(debugClear()), debugLayout);
383 
384  return retval;
385 }
386 
387 }//namespace cx
QString qstring_cast(const T &val)
A mesh data set.
Definition: cxMesh.h:61
void performOneRegistration(ContextPtr context, bool linear)
Register the source points to the target point in a single ste.
QGroupBox * createGroupbox(QWidget *widget, QString boxname)
Create a group box with a given name.
Transform3D Transform3D
Transform3D is a representation of an affine 3D transform.
Composite widget for string selection.
boost::shared_ptr< class View > ViewPtr
void fixedDataChanged(QString uid)
vtkSmartPointer< class vtkPolyData > vtkPolyDataPtr
Definition: cxProbeSector.h:47
void computeDistances(ContextPtr context)
Compute distances between the two datasets.
QAction * createAction(QObject *parent, QIcon iconName, QString text, QString tip, T slot, QLayout *layout=NULL, QToolButton *button=new QToolButton())
Definition: cxBaseWidget.h:129
void reportWarning(QString msg)
Definition: cxLogger.cpp:91
SeansVesselRegistrationDebugger(RegServices services, double ltsRatio, bool linear)
ContextPtr createContext(DataPtr source, DataPtr target)
static GeometricRepPtr New(const QString &uid="")
VisualizationServicePtr visualizationService
Definition: cxVisServices.h:60
void movingDataChanged(QString uid)
SeansVesselRegistrationWidget(RegServices services, QWidget *parent)
void report(QString msg)
Definition: cxLogger.cpp:90
void checkQuality(Transform3D linearTransform)
boost::shared_ptr< Context > ContextPtr
PatientModelServicePtr patientModelService
boost::shared_ptr< class Mesh > MeshPtr
Transform3D getLinearResult(ContextPtr context=ContextPtr())
void reportDebug(QString msg)
Definition: cxLogger.cpp:89
RegistrationServicePtr registrationService
Definition: cxRegServices.h:60
vtkSmartPointer< class vtkPoints > vtkPointsPtr
boost::shared_ptr< class GeometricRep > GeometricRepPtr