1 /*=========================================================================
2 Program: vv http://www.creatis.insa-lyon.fr/rio/vv
5 - University of LYON http://www.universite-lyon.fr/
6 - Léon Bérard cancer center http://www.centreleonberard.fr
7 - CREATIS CNRS laboratory http://www.creatis.insa-lyon.fr
9 This software is distributed WITHOUT ANY WARRANTY; without even
10 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
11 PURPOSE. See the copyright notices for more information.
13 It is distributed under dual licence
15 - BSD See included LICENSE.txt file
16 - CeCILL-B http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
17 ===========================================================================**/
20 #include "vvToolRigidReg.h"
24 #include <vtkImageData.h>
25 #include <vtkSmartPointer.h>
26 #include <vtkTransform.h>
29 #include <itkEuler3DTransform.h>
32 #include "clitkTransformUtilities.h"
35 #include <QMessageBox>
36 #include <QFileDialog>
37 #include <QTextStream>
40 //------------------------------------------------------------------------------
41 // Create the tool and automagically (I like this word) insert it in
42 // the main window menu.
43 ADD_TOOL(vvToolRigidReg);
44 //------------------------------------------------------------------------------
46 //------------------------------------------------------------------------------
47 vvToolRigidReg::vvToolRigidReg(vvMainWindowBase * parent, Qt::WindowFlags f):
48 vvToolWidgetBase(parent, f),
49 vvToolBase<vvToolRigidReg>(parent),
53 Ui_vvToolRigidReg::setupUi(mToolWidget);
55 // Set how many inputs are needed for this tool
56 AddInputSelector("Select moving image");
58 QFont font = transformationLabel->font();
59 font.setStyleHint(QFont::TypeWriter);
60 transformationLabel->setFont(font);
62 mInitialMatrix = vtkSmartPointer<vtkMatrix4x4>::New();
64 // Set slider ranges, assume degrees, will not be changed for radians
65 std::vector<QSlider *> transSliders, rotSliders;
66 std::vector<QDoubleSpinBox *> transSBs, rotSBs;
67 GetSlidersAndSpinBoxes(transSliders, rotSliders, transSBs, rotSBs);
68 for(int i=0; i<3; i++) {
69 transSliders[i]->setRange(-2000,2000);
70 rotSliders[i]->setRange(-360,360);
71 transSBs[i]->setRange(-2000,2000);
72 transSBs[i]->setDecimals(3);
73 rotSBs[i]->setRange(-360,360);
74 rotSBs[i]->setDecimals(3);
77 //------------------------------------------------------------------------------
79 //------------------------------------------------------------------------------
80 vvToolRigidReg::~vvToolRigidReg()
83 //------------------------------------------------------------------------------
85 //------------------------------------------------------------------------------
86 void vvToolRigidReg::Initialize()
88 SetToolName("Register");
89 SetToolMenuName("Register manually");
90 SetToolIconFilename(":/common/icons/register.png");
91 SetToolTip("Register manually.");
92 SetToolExperimental(false);
94 //------------------------------------------------------------------------------
96 //------------------------------------------------------------------------------
97 void vvToolRigidReg::InputIsSelected(vvSlicerManager *input)
101 QTabWidget * tab = dynamic_cast<vvMainWindow*>(mMainWindow)->GetTab();
102 move(tab->mapToGlobal(tab->pos()));
103 resize(tab->width(), 0);
105 //default image rotation center is the center of the image
106 QString xcord,ycord,zcord;
107 std::vector<double> imageorigin;
108 imageorigin=mInput->GetImage()->GetOrigin();
109 std::vector<int> imageSize = mInput->GetImage()->GetSize();
110 std::vector<double> imageSpacing = mInput->GetImage()->GetSpacing();
111 xcord=xcord.setNum(imageorigin[0]+(imageSize[0]-1)*imageSpacing[0]*0.5, 'g', 3);
112 ycord=ycord.setNum(imageorigin[1]+(imageSize[1]-1)*imageSpacing[1]*0.5, 'g', 3);
113 zcord=zcord.setNum(imageorigin[2]+(imageSize[2]-1)*imageSpacing[2]*0.5, 'g', 3);
114 Xval->setText(xcord);
115 Yval->setText(ycord);
116 Zval->setText(zcord);
118 //backup original matrix
119 for(int j=0; j<4; j++)
120 for(int i=0; i<4; i++)
121 mInitialMatrix->SetElement(i,j, mCurrentSlicerManager->GetImage()->GetTransform()->GetMatrix()->GetElement(i,j));
122 QString origTransformString = dynamic_cast<vvMainWindow*>(mMainWindow)->Get4x4MatrixDoubleAsString(mInitialMatrix);
123 transformationLabel->setText(origTransformString);
124 SetTransform(mInitialMatrix);
126 //connect all sigs to slots
127 connect(resetbutton, SIGNAL(pressed()), this, SLOT(ResetTransform()));
128 connect(loadbutton, SIGNAL(pressed()), this, SLOT(LoadFile()));
129 connect(savebutton, SIGNAL(pressed()), this, SLOT(SaveFile()));
131 connect(xtrans_slider, SIGNAL(valueChanged(int)), this, SLOT(SliderChange(int)));
132 connect(ytrans_slider, SIGNAL(valueChanged(int)), this, SLOT(SliderChange(int)));
133 connect(ztrans_slider, SIGNAL(valueChanged(int)), this, SLOT(SliderChange(int)));
134 connect(xrot_slider, SIGNAL(valueChanged(int)), this, SLOT(SliderChange(int)));
135 connect(yrot_slider, SIGNAL(valueChanged(int)), this, SLOT(SliderChange(int)));
136 connect(zrot_slider, SIGNAL(valueChanged(int)), this, SLOT(SliderChange(int)));
137 connect(xtrans_sb, SIGNAL(valueChanged(double)), this, SLOT(SpinBoxChange(double)));
138 connect(ytrans_sb, SIGNAL(valueChanged(double)), this, SLOT(SpinBoxChange(double)));
139 connect(ztrans_sb, SIGNAL(valueChanged(double)), this, SLOT(SpinBoxChange(double)));
140 connect(xrot_sb, SIGNAL(valueChanged(double)), this, SLOT(SpinBoxChange(double)));
141 connect(yrot_sb, SIGNAL(valueChanged(double)), this, SLOT(SpinBoxChange(double)));
142 connect(zrot_sb, SIGNAL(valueChanged(double)), this, SLOT(SpinBoxChange(double)));
144 connect(stepTransSpinBox, SIGNAL(valueChanged(double)), this, SLOT(SetTranslationStep(double)));
145 connect(stepRotSpinBox, SIGNAL(valueChanged(double)), this, SLOT(SetRotationStep(double)));
147 connect(checkBoxDegrees, SIGNAL(stateChanged(int)), this, SLOT(ToggleSpinBoxAnglesUnit()));
149 connect(Xval, SIGNAL(editingFinished()), this, SLOT(ChangeOfRotationCenter()));
150 connect(Yval, SIGNAL(editingFinished()), this, SLOT(ChangeOfRotationCenter()));
151 connect(Zval, SIGNAL(editingFinished()), this, SLOT(ChangeOfRotationCenter()));
153 // Init step modifiers
154 stepTransSpinBox->setValue(1.);
155 stepRotSpinBox->setValue(1.);
157 //------------------------------------------------------------------------------
159 //------------------------------------------------------------------------------
160 void vvToolRigidReg::apply()
162 vvToolWidgetBase::close();
164 //------------------------------------------------------------------------------
166 //------------------------------------------------------------------------------
167 bool vvToolRigidReg::close()
169 QString warning = "Are you sure you want to reset the original transform?";
170 QMessageBox msgBox(QMessageBox::Warning, tr("Reset transform"),warning, 0, this);
171 msgBox.addButton(tr("Yes"), QMessageBox::AcceptRole);
172 msgBox.addButton(tr("No"), QMessageBox::RejectRole);
173 if (msgBox.exec() == QMessageBox::AcceptRole) {
174 SetTransform(mInitialMatrix);
175 return vvToolWidgetBase::close();
179 //------------------------------------------------------------------------------
181 //------------------------------------------------------------------------------
182 void vvToolRigidReg::reject()
184 return vvToolWidgetBase::reject();
186 //------------------------------------------------------------------------------
188 //------------------------------------------------------------------------------
189 void vvToolRigidReg::SetTranslationStep(double v)
191 xtrans_sb->setSingleStep(v);
192 ytrans_sb->setSingleStep(v);
193 ztrans_sb->setSingleStep(v);
195 //------------------------------------------------------------------------------
197 //------------------------------------------------------------------------------
198 void vvToolRigidReg::SetRotationStep(double v)
200 xrot_sb->setSingleStep(v);
201 yrot_sb->setSingleStep(v);
202 zrot_sb->setSingleStep(v);
204 //------------------------------------------------------------------------------
206 //------------------------------------------------------------------------------
207 void vvToolRigidReg::SliderChange(int newVal)
209 std::vector<QSlider *> transSliders, rotSliders;
210 std::vector<QDoubleSpinBox *> transSBs, rotSBs;
211 GetSlidersAndSpinBoxes(transSliders, rotSliders, transSBs, rotSBs);
212 for(int i=0; i<3; i++) {
213 if(transSliders[i] == QObject::sender()) {
214 transSBs[i]->setValue(newVal);
216 if(rotSliders[i] == QObject::sender()) {
217 double rad = (checkBoxDegrees->checkState()==Qt::Unchecked)?itk::Math::pi/180.:1.;
218 rotSBs[i]->setValue(newVal*rad);
222 //------------------------------------------------------------------------------
224 //------------------------------------------------------------------------------
225 void vvToolRigidReg::SpinBoxChange(double newVal)
227 std::vector<QSlider *> transSliders, rotSliders;
228 std::vector<QDoubleSpinBox *> transSBs, rotSBs;
229 GetSlidersAndSpinBoxes(transSliders, rotSliders, transSBs, rotSBs);
230 for(int i=0; i<3; i++) {
231 if(transSBs[i] == QObject::sender()) {
232 transSliders[i]->blockSignals(true);
233 transSliders[i]->setValue(itk::Math::Round<double,double>(newVal));
234 transSliders[i]->blockSignals(false);
236 if(rotSBs[i] == QObject::sender()) {
237 double rad = (checkBoxDegrees->checkState()==Qt::Unchecked)?180./itk::Math::pi:1.;
238 rotSliders[i]->blockSignals(true);
239 rotSliders[i]->setValue(itk::Math::Round<double,double>(newVal*rad));
240 rotSliders[i]->blockSignals(false);
244 // Compute transform and set
245 vtkSmartPointer<vtkTransform> transform_final=mInput->GetImage()->GetTransform();
246 transform_final->Identity();
247 transform_final->PostMultiply();
250 double x=0, y=0 ,z=0;
251 x= Xval->text().toDouble();
252 y= Yval->text().toDouble();
253 z= Zval->text().toDouble();
254 double rad = (checkBoxDegrees->checkState()==Qt::Unchecked)?180./itk::Math::pi:1.;
255 transform_final->Translate(-x,-y,-z);
256 transform_final->RotateY(yrot_sb->value()*rad);
257 transform_final->RotateX(xrot_sb->value()*rad);
258 transform_final->RotateZ(zrot_sb->value()*rad);
259 transform_final->Translate(x,y,z);
262 transform_final->Translate(xtrans_sb->value(),
265 transform_final->Update();
266 SetTransform(transform_final->GetMatrix());
268 //------------------------------------------------------------------------------
270 //------------------------------------------------------------------------------
271 void vvToolRigidReg::ToggleSpinBoxAnglesUnit()
273 double rad = (checkBoxDegrees->checkState()==Qt::Unchecked)?itk::Math::pi/180.:180./itk::Math::pi;
274 std::vector<QSlider *> transSliders, rotSliders;
275 std::vector<QDoubleSpinBox *> transSBs, rotSBs;
276 GetSlidersAndSpinBoxes(transSliders, rotSliders, transSBs, rotSBs);
277 for(int i=0; i<3; i++) {
278 rotSBs[i]->blockSignals(true);
279 rotSBs[i]->setValue(rotSBs[i]->value()*rad);
280 rotSBs[i]->blockSignals(false);
283 //------------------------------------------------------------------------------
285 //------------------------------------------------------------------------------
286 void vvToolRigidReg::SaveFile()
288 //Write the Transformation Matrix
289 std::string absPath = mCurrentSlicerManager->GetFileName();
290 absPath = itksys::SystemTools::GetFilenameWithoutExtension(absPath) + std::string(".mat");
291 QString filename = QFileDialog::getSaveFileName(this, tr("Save Transformation Matrix File"),
293 tr("Text (*.mat *.txt *.doc *.rtf)"));
295 QFile file(filename);
296 if (file.open(QFile::WriteOnly | QFile::Truncate)) {
297 vtkMatrix4x4* matrix = mCurrentSlicerManager->GetImage()->GetTransform()->GetMatrix();
298 QString matrixStr = dynamic_cast<vvMainWindow*>(mMainWindow)->Get4x4MatrixDoubleAsString(matrix,16);
299 QTextStream out(&file);
304 QMessageBox::information(this,"Error","Unable to open file for writing");
307 //------------------------------------------------------------------------------
309 //------------------------------------------------------------------------------
310 void vvToolRigidReg::LoadFile()
312 //Open File to read the transformation parameters
313 QString file = QFileDialog::getOpenFileName(
315 "Choose the filename for the transformation matrix",
316 vtksys::SystemTools::GetFilenamePath(mCurrentSlicerManager->GetFileName()).c_str(),
317 "Text (*.mat *.txt *.rtf *.doc)");
322 itk::Matrix<double, 4, 4> itkMat = clitk::ReadMatrix3D(file.toStdString());
323 vtkSmartPointer<vtkMatrix4x4> matrix = vtkSmartPointer<vtkMatrix4x4>::New();
325 for(int j=0; j<4; j++)
326 for(int i=0; i<4; i++)
327 matrix->SetElement(j,i,itkMat[j][i]);
328 SetTransform(matrix);
330 //------------------------------------------------------------------------------
332 //------------------------------------------------------------------------------
333 void vvToolRigidReg::ChangeOfRotationCenter()
335 SetTransform(mCurrentSlicerManager->GetImage()->GetTransform()->GetMatrix());
337 //------------------------------------------------------------------------------
339 //------------------------------------------------------------------------------
340 void vvToolRigidReg::ResetTransform()
342 SetTransform(mInitialMatrix);
344 //------------------------------------------------------------------------------
346 //------------------------------------------------------------------------------
347 void vvToolRigidReg::SetTransform(vtkMatrix4x4 *matrix)
349 vtkSmartPointer<vtkTransform> transform=vtkSmartPointer<vtkTransform>::New();
350 mCurrentSlicerManager->GetImage()->GetTransform()->SetMatrix(matrix);
353 dynamic_cast<vvMainWindow*>(mMainWindow)->ImageInfoChanged();
355 // Compute parameters from transfer using itk Euler transform
356 itk::Euler3DTransform<double>::CenterType center;
357 center[0] = Xval->text().toDouble();
358 center[1] = Yval->text().toDouble();
359 center[2] = Zval->text().toDouble();
360 itk::Euler3DTransform<double>::MatrixType rotMat;
361 itk::Euler3DTransform<double>::OutputVectorType transVec;
362 for(int i=0; i<3; i++) {
363 transVec[i] = matrix->GetElement(i,3);
364 for(int j=0; j<3; j++)
365 rotMat[i][j] = matrix->GetElement(i,j);
367 itk::Euler3DTransform<double>::Pointer euler;
368 euler = itk::Euler3DTransform<double>::New();
369 euler->SetCenter(center);
370 euler->SetMatrix(rotMat);
371 euler->SetOffset(transVec);
373 // Modify GUI according to the new parameters
374 std::vector<QSlider *> transSliders, rotSliders;
375 std::vector<QDoubleSpinBox *> transSBs, rotSBs;
376 GetSlidersAndSpinBoxes(transSliders, rotSliders, transSBs, rotSBs);
377 for(int i=0; i<3; i++) {
379 transSBs[i]->blockSignals(true);
380 transSBs[i]->setValue( euler->GetParameters()[i+3] );
381 transSBs[i]->blockSignals(false);
382 transSliders[i]->blockSignals(true);
383 transSliders[i]->setValue( itk::Math::Round<double,double>(euler->GetParameters()[i+3]) );
384 transSliders[i]->blockSignals(false);
387 double rad = (checkBoxDegrees->checkState()==Qt::Checked)?180./itk::Math::pi:1.;
388 double angleDiff = euler->GetParameters()[i]-rotSBs[i]->value()/rad+2*itk::Math::pi;
389 angleDiff = angleDiff - 2*itk::Math::pi*itk::Math::Round<double,double>(angleDiff/(2*itk::Math::pi));
390 if(angleDiff>1.e-4) {
391 rotSBs[i]->blockSignals(true);
392 rotSBs[i]->setValue( euler->GetParameters()[i]*rad );
393 rotSBs[i]->blockSignals(false);
395 int iAngle = itk::Math::Round<int,double>(euler->GetParameters()[i]*180./itk::Math::pi);
396 if((iAngle-rotSliders[i]->value()+360)%360!=0) {
397 rotSliders[i]->blockSignals(true);
398 rotSliders[i]->setValue(iAngle);
399 rotSliders[i]->blockSignals(false);
403 //------------------------------------------------------------------------------
405 //------------------------------------------------------------------------------
406 // Just an helper function to shorten the code with loops on sliders and spinboxes
407 void vvToolRigidReg::GetSlidersAndSpinBoxes(std::vector<QSlider *>&transSliders, std::vector<QSlider *>&rotSliders,
408 std::vector<QDoubleSpinBox *>&transSBs, std::vector<QDoubleSpinBox *>&rotSBs)
410 transSliders.push_back(xtrans_slider);
411 transSliders.push_back(ytrans_slider);
412 transSliders.push_back(ztrans_slider);
414 rotSliders.push_back(xrot_slider);
415 rotSliders.push_back(yrot_slider);
416 rotSliders.push_back(zrot_slider);
418 transSBs.push_back(xtrans_sb);
419 transSBs.push_back(ytrans_sb);
420 transSBs.push_back(ztrans_sb);
422 rotSBs.push_back(xrot_sb);
423 rotSBs.push_back(yrot_sb);
424 rotSBs.push_back(zrot_sb);
426 //------------------------------------------------------------------------------
428 //------------------------------------------------------------------------------
429 void vvToolRigidReg::Render()
431 for (int i=0; i<mCurrentSlicerManager->GetNumberOfSlicers(); i++)
433 mCurrentSlicerManager->GetSlicer(i)->ForceUpdateDisplayExtent();
434 mCurrentSlicerManager->GetSlicer(i)->Render();
437 //------------------------------------------------------------------------------