CustusX  15.3.4-beta
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, "SeansVesselRegistrationWidget", "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 
103 {
104  return "<html>"
105  "<h3>Seans Vessel Registration.</h3>"
106  "<p>Select two datasets you want to registere to eachother, adjust the input parameters.</p>"
107  "<p><i>Adjust the parameters and click the register button.</i></p>"
108  "</html>";
109 }
110 
111 void SeansVesselRegistrationWidget::inputChanged()
112 {
113  if(mServices.registrationService->getMovingData() && mServices.registrationService->getFixedData())
114  {
115  mRegisterButton->setEnabled(true);
116  mVesselRegOptionsButton->setEnabled(true);
117  mVesselRegOptionsWidget->setVisible(mVesselRegOptionsButton->isChecked());
118  }
119  else
120  {
121  mRegisterButton->setEnabled(false);
122  mVesselRegOptionsButton->setEnabled(false);
123  mVesselRegOptionsWidget->setVisible(false);
124  }
125 }
126 
127 void SeansVesselRegistrationWidget::registerSlot()
128 {
129 // int lts_ratio = mLTSRatioSpinBox->value();
130 // double stop_delta = 0.001; //TODO, add user interface
131 // double lambda = 0; //TODO, add user interface
132 // double sigma = 1.0; //TODO, add user interface
133 // bool lin_flag = mLinearCheckBox->isChecked(); //TODO, add user interface
134 // int sample = 1; //TODO, add user interface
135 // int single_point_thre = 1; //TODO, add user interface
136 // bool verbose = 1; //TODO, add user interface
137 
138  QString logPath = mServices.patientModelService->getActivePatientFolder() + "/Logs/";
139 
140 // mRegistrationService->doVesselRegistration(lts_ratio, stop_delta, lambda, sigma, lin_flag, sample, single_point_thre, verbose,
141 // logPath);
142 
143  SeansVesselReg vesselReg;
144  vesselReg.mt_auto_lts = true;
145  vesselReg.mt_ltsRatio = mLTSRatioSpinBox->value();
146  vesselReg.mt_doOnlyLinear = mLinearCheckBox->isChecked();
147  vesselReg.mt_auto_lts = mAutoLTSCheckBox->isChecked();
148 
149  if (vesselReg.mt_auto_lts)
150  {
151  reportDebug("Using automatic lts_ratio");
152  }
153  else
154  {
155  reportDebug("Using lts_ratio: " + qstring_cast(vesselReg.mt_ltsRatio));
156  }
157 
158  if(!mServices.registrationService->getMovingData())
159  {
160  reportWarning("Moving volume not set.");
161  return;
162  }
163  else if(!mServices.registrationService->getFixedData())
164  {
165  reportWarning("Fixed volume not set.");
166  return;
167  }
168 
169  bool success = vesselReg.execute(mServices.registrationService->getMovingData(), mServices.registrationService->getFixedData(), logPath);
170  if (!success)
171  {
172  reportWarning("Vessel registration failed.");
173  return;
174  }
175 
176  Transform3D linearTransform = vesselReg.getLinearResult();
177  std::cout << "v2v linear result:\n" << linearTransform << std::endl;
178  //std::cout << "v2v inverted linear result:\n" << linearTransform.inverse() << std::endl;
179 
180  vesselReg.checkQuality(linearTransform);
181 
182  // The registration is performed in space r. Thus, given an old data position rMd, we find the
183  // new one as rM'd = Q * rMd, where Q is the inverted registration output.
184  // Delta is thus equal to Q:
185  Transform3D delta = linearTransform.inv();
186  //std::cout << "delta:\n" << delta << std::endl;
187  mServices.registrationService->applyImage2ImageRegistration(delta, "Vessel based");
188 }
189 
195 {
196 public:
197  SeansVesselRegistrationDebugger(RegServices services, double ltsRatio, bool linear) :
198  mServices(services)
199  {
200  mRegistrator.mt_doOnlyLinear = linear;
201  mRegistrator.mt_ltsRatio = ltsRatio;
202  mRegistrator.mt_auto_lts = false;
203 
204  mContext = mRegistrator.createContext(mServices.registrationService->getMovingData(), mServices.registrationService->getFixedData());
205 
206  //mMovingData = mRegistrator.convertToPolyData(mContext->mSourcePoints);
207  mMovingData = mContext->getMovingPoints();
208  mFixedData = mContext->getFixedPoints();
209 
210  MeshPtr moving(new Mesh("v2vreg_moving", "v2vreg_moving", mMovingData));
211  moving->setColor(QColor("red"));
212 
213  MeshPtr fixed(new Mesh("v2vreg_fixed", "v2vreg_fixed", mFixedData));
214  fixed->setColor(QColor("green"));
215 
216  mPolyLines = vtkPolyDataPtr::New();
217  MeshPtr lines(new Mesh("v2vreg_lines", "v2vreg_lines", mPolyLines));
218  lines->setColor(QColor("cornflowerblue"));
219 
220  ViewPtr view = mServices.visualizationService->get3DView();
221 
222  m_mRep = GeometricRep::New();
223  m_mRep->setMesh(moving);
224  view->addRep(m_mRep);
225 
226  m_fRep = GeometricRep::New();
227  m_fRep->setMesh(fixed);
228  view->addRep(m_fRep);
229 
230  m_lineRep = GeometricRep::New();
231  m_lineRep->setMesh(lines);
232  view->addRep(m_lineRep);
233 
234  this->update();
235 
236  report("Initialized V2V algorithm (debug). Use Step to iterate.");
237  }
239  {
240  ViewPtr view = mServices.visualizationService->get3DView();
241  view->removeRep(m_mRep);
242  view->removeRep(m_fRep);
243  view->removeRep(m_lineRep);
244  report("Closed V2V algorithm (debug).");
245  }
246  void stepL()
247  {
248  if (!mContext)
249  return;
250  mRegistrator.performOneRegistration(mContext, true);
251  this->update();
252  report(QString("One Linear V2V iteration, metric=%1").arg(mContext->mMetric));
253  }
254  void stepNL()
255  {
256  if (!mContext)
257  return;
258  mRegistrator.performOneRegistration(mContext, false);
259  this->update();
260  report(QString("One Nonlinear V2V iteration, metric=%1").arg(mContext->mMetric));
261  }
262  void apply()
263  {
264  if (!mContext)
265  return;
266 
267  Transform3D linearTransform = mRegistrator.getLinearResult(mContext);
268  std::cout << "v2v linear result:\n" << linearTransform << std::endl;
269 
270  mRegistrator.checkQuality(linearTransform);
271  Transform3D delta = linearTransform.inv();
272  mServices.registrationService->applyImage2ImageRegistration(delta, "Vessel based");
273 
274  report(QString("Applied linear registration from debug iteration."));
275  }
276  void update()
277  {
278  if (!mContext)
279  return;
280  mRegistrator.computeDistances(mContext);
281 // vtkPolyDataPtr temp = mRegistrator.convertToPolyData(mContext->mSourcePoints);
282 // mMovingData->SetPoints(temp->GetPoints());
283 // mMovingData->SetVerts(temp->GetVerts());
284 
285  vtkPolyDataPtr moving = mContext->getMovingPoints();
286  mMovingData->SetPoints(moving->GetPoints());
287  mMovingData->SetVerts(moving->GetVerts());
288 
289  vtkPolyDataPtr fixed = mContext->getFixedPoints();
290  mFixedData->SetPoints(fixed->GetPoints());
291  mFixedData->SetVerts(fixed->GetVerts());
292 
293  // // draw lines: slow but nice
294  // mLines.clear();
295  // View* view = mServices.visualizationService->get3DView();
296  // for (int i=0; i<mContext->mSortedSourcePoints->GetNumberOfPoints(); ++i)
297  // {
298  // GraphicalLine3DPtr line(new GraphicalLine3D(view->getRenderer()));
299  // line->setValue(Vector3D(mContext->mSortedSourcePoints->GetPoint(i)),
300  // Vector3D(mContext->mSortedTargetPoints->GetPoint(i)));
301  // line->setColor(Vector3D(1,0,0));
302  // mLines.push_back(line);
303  // }
304 
305  // draw lines
306  mPolyLines->Allocate();
307  vtkPointsPtr verts = vtkPointsPtr::New();
308  for (int i = 0; i < mContext->mSortedSourcePoints->GetNumberOfPoints(); ++i)
309  {
310  verts->InsertNextPoint(mContext->mSortedSourcePoints->GetPoint(i));
311  verts->InsertNextPoint(mContext->mSortedTargetPoints->GetPoint(i));
312 
313  vtkIdType connectivity[2];
314  connectivity[0] = 2 * i;
315  connectivity[1] = 2 * i + 1;
316  mPolyLines->InsertNextCell(VTK_LINE, 2, connectivity);
317  }
318  mPolyLines->SetPoints(verts);
319  }
320 
321 private:
322  SeansVesselReg mRegistrator;
324  vtkPolyDataPtr mMovingData, mFixedData;
325  vtkPolyDataPtr mPolyLines;
326  GeometricRepPtr m_mRep, m_fRep, m_lineRep;
327  // std::vector<GraphicalLine3DPtr> mLines;
328  RegServices mServices;
329 };
330 
331 void SeansVesselRegistrationWidget::debugInit()
332 {
333  mDebugger.reset(new SeansVesselRegistrationDebugger(mServices, mLTSRatioSpinBox->value(),
334  mLinearCheckBox->isChecked()));
335 }
336 void SeansVesselRegistrationWidget::debugRunOneLinearStep()
337 {
338  if (mDebugger)
339  mDebugger->stepL();
340 }
341 void SeansVesselRegistrationWidget::debugRunOneNonlinearStep()
342 {
343  if (mDebugger)
344  mDebugger->stepNL();
345 }
346 
347 void SeansVesselRegistrationWidget::debugApply()
348 {
349  if (mDebugger)
350  mDebugger->apply();
351 }
352 
353 void SeansVesselRegistrationWidget::debugClear()
354 {
355  mDebugger.reset();
356 }
357 
358 QWidget* SeansVesselRegistrationWidget::createOptionsWidget()
359 {
360  QWidget* retval = new QWidget(this);
361  QGridLayout* layout = new QGridLayout(retval);
362 
363  mLTSRatioSpinBox->setSingleStep(1);
364  mLTSRatioSpinBox->setValue(80);
365 
366  mLinearCheckBox->setChecked(true);
367  mAutoLTSCheckBox->setChecked(true);
368 
369  int line = 0;
370  layout->addWidget(new QLabel("Auto LTS:"), line, 0);
371  layout->addWidget(mAutoLTSCheckBox, line, 1);
372  ++line;
373  layout->addWidget(new QLabel("LTS Ratio:"), line, 0);
374  layout->addWidget(mLTSRatioSpinBox, line, 1);
375  ++line;
376  layout->addWidget(new QLabel("Linear:"), line, 0);
377  layout->addWidget(mLinearCheckBox, line, 1);
378  ++line;
379  layout->addWidget(new QLabel("Debug"), line, 0);
380  QHBoxLayout* debugLayout = new QHBoxLayout;
381  layout->addLayout(debugLayout, line, 1, 1, 1);
382  this->createAction(this, QIcon(), "Init",
383  "Initialize the V2V algorithm.\n Display only, registration will not be updated in CustusX (Debug)",
384  SLOT(debugInit()), debugLayout);
385  this->createAction(this, QIcon(), "Lin", "Run one Linear step in the V2V algorithm. (Debug)",
386  SLOT(debugRunOneLinearStep()), debugLayout);
387  this->createAction(this, QIcon(), "NL",
388  "Run one Nonlinear step in the V2V algorithm. (Should be one at the end only)(Debug)",
389  SLOT(debugRunOneNonlinearStep()), debugLayout);
390  this->createAction(this, QIcon(), "Apply", "Apply results from the debug iteration", SLOT(debugApply()), debugLayout);
391  this->createAction(this, QIcon(), "Clear", "Clear debugging of the V2V algorithm.", SLOT(debugClear()), debugLayout);
392 
393  return retval;
394 }
395 
396 }//namespace cx
QString qstring_cast(const T &val)
virtual QString defaultWhatsThis() const
Returns a short description of what this widget will do for you.
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:130
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