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 "vvToolROIManager.h"
21 #include "vvImageReader.h"
22 #include "vvROIActor.h"
24 #include "vvROIActor.h"
27 #include <QFileDialog>
28 #include <QMessageBox>
29 #include <QColorDialog>
30 #include <QAbstractEventDispatcher>
33 #include <vtkLookupTable.h>
34 #include <vtkRenderWindow.h>
36 //------------------------------------------------------------------------------
37 // Create the tool and automagically (I like this word) insert it in
38 // the main window menu.
39 ADD_TOOL(vvToolROIManager);
40 //------------------------------------------------------------------------------
42 //------------------------------------------------------------------------------
43 vvToolROIManager::vvToolROIManager(vvMainWindowBase * parent, Qt::WindowFlags f):
44 QWidget(parent->GetTab()),
45 vvToolBase<vvToolROIManager>(parent),
46 Ui::vvToolROIManager()
51 // Assume the initial tab ROI index is 2
55 QWidget * tab = qFindChild<QWidget*>(parent->GetTab(), "ROItab");
58 parent->GetTab()->setCurrentIndex(mIndexFirstTab);
60 // Check if widget already used
61 if (tab->layout()->isEmpty()) {
62 tab->layout()->addWidget(this);
70 Ui_vvToolROIManager::setupUi(this);
71 setAttribute(Qt::WA_DeleteOnClose);
73 mTree->header()->resizeSection(0, 30);
76 mDefaultLUTColor = vtkSmartPointer<vtkLookupTable>::New();
77 for(int i=0; i<mDefaultLUTColor->GetNumberOfTableValues(); i++) {
78 double r = (rand()/(RAND_MAX+1.0));
79 double v = (rand()/(RAND_MAX+1.0));
80 double b = (rand()/(RAND_MAX+1.0));
81 mDefaultLUTColor->SetTableValue(i, r, v, b);
83 #include "vvDefaultLut.h"
86 mNumberOfVisibleROI = 0;
87 mNumberOfVisibleContourROI = 0;
89 // Select the current image as the target
90 int i = parent->GetSlicerManagerCurrentIndex();
91 InputIsSelected(parent->GetSlicerManagers()[i]);
93 // Connect event from mainwindow to this widget
94 connect(parent, SIGNAL(AnImageIsBeingClosed(vvSlicerManager *)),
95 this, SLOT(AnImageIsBeingClosed(vvSlicerManager *)));
96 connect(parent, SIGNAL(SelectedImageHasChanged(vvSlicerManager *)),
97 this, SLOT(SelectedImageHasChanged(vvSlicerManager *)));
98 connect(mOpenBinaryButton, SIGNAL(clicked()), this, SLOT(OpenBinaryImage()));
99 connect(mTree, SIGNAL(itemSelectionChanged()), this, SLOT(SelectedItemChangedInTree()));
100 connect(mCheckBoxShow, SIGNAL(toggled(bool)), this, SLOT(VisibleROIToggled(bool)));
101 connect(mOpacitySlider, SIGNAL(valueChanged(int)), this, SLOT(OpacityChanged(int)));
102 connect(mChangeColorButton, SIGNAL(clicked()), this, SLOT(ChangeColor()));
103 connect(mContourCheckBoxShow, SIGNAL(toggled(bool)), this, SLOT(VisibleContourROIToggled(bool)));
104 connect(mChangeContourColorButton, SIGNAL(clicked()), this, SLOT(ChangeContourColor()));
105 connect(mContourWidthSpinBox, SIGNAL(valueChanged(int)), this, SLOT(ChangeContourWidth(int)));
106 connect(mDepthSpinBox, SIGNAL(valueChanged(int)), this, SLOT(ChangeDepth(int)));
107 connect(mReloadButton, SIGNAL(clicked()), this, SLOT(ReloadCurrentROI()));
108 connect(mCheckBoxShowAll, SIGNAL(stateChanged(int)), this, SLOT(AllVisibleROIToggled(int)));
109 connect(mContourCheckBoxShowAll, SIGNAL(toggled(bool)), this, SLOT(AllVisibleContourROIToggled(bool)));
110 connect(mCloseButton, SIGNAL(clicked()), this, SLOT(close()));
112 //------------------------------------------------------------------------------
115 //------------------------------------------------------------------------------
116 vvToolROIManager::~vvToolROIManager()
118 std::cout << "vvToolROIManager::~vvToolROIManager()" << std::endl;
120 //------------------------------------------------------------------------------
123 //------------------------------------------------------------------------------
125 void vvToolROIManager::Initialize() {
126 SetToolName("ROIManager");
127 SetToolMenuName("Display ROI (binary image)");
128 SetToolIconFilename(":/common/icons/tool-roi.png");
129 SetToolTip("Display ROI from a binary image.");
130 SetToolExperimental(true);
132 //------------------------------------------------------------------------------
135 //------------------------------------------------------------------------------
136 void vvToolROIManager::InputIsSelected(vvSlicerManager *m)
142 mCurrentImage = mSlicerManager->GetImage();
145 if (mCurrentImage->GetNumberOfDimensions() != 3) {
146 QMessageBox::information(this,tr("Sorry only 3D yet"), tr("Sorry only 3D yet"));
152 mLabelInputInfo->setText(QString("%1").arg(m->GetFileName().c_str()));
154 // Auto display browser to select new contours
157 //------------------------------------------------------------------------------
160 //------------------------------------------------------------------------------
161 void vvToolROIManager::AnImageIsBeingClosed(vvSlicerManager * m)
163 DD("AnImageIsBeingClosed");
164 if (m == mSlicerManager) {
169 //------------------------------------------------------------------------------
172 //------------------------------------------------------------------------------
173 void vvToolROIManager::close()
178 //------------------------------------------------------------------------------
181 //------------------------------------------------------------------------------
182 void vvToolROIManager::SelectedImageHasChanged(vvSlicerManager * m) {
183 DD("SelectedImageHasChanged");
184 if (m != mSlicerManager) hide();
189 //------------------------------------------------------------------------------
192 //------------------------------------------------------------------------------
193 void vvToolROIManager::OpenBinaryImage()
196 QString Extensions = "Images files ( *.mha *.mhd *.hdr *.his)";
197 Extensions += ";;All Files (*)";
198 QStringList filename =
199 QFileDialog::getOpenFileNames(this,tr("Open binary image"),
200 mMainWindowBase->GetInputPathName(),Extensions);
201 if (filename.size() == 0) return;
203 // For each selected file, open the image
204 for(int i=0; i<filename.size(); i++) {
206 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
207 vvImageReader::Pointer reader = vvImageReader::New();
208 std::vector<std::string> filenames;
209 filenames.push_back(filename[i].toStdString());
210 reader->SetInputFilenames(filenames);
211 reader->Update(vvImageReader::IMAGE);
212 QApplication::restoreOverrideCursor();
214 if (reader->GetLastError().size() != 0) {
215 std::cerr << "Error while reading " << filename[i].toStdString() << std::endl;
216 QString error = "Cannot open file \n";
217 error += reader->GetLastError().c_str();
218 QMessageBox::information(this,tr("Reading problem"),error);
221 vvImage::Pointer binaryImage = reader->GetOutput();
222 AddImage(binaryImage, filename[i].toStdString(), mBackgroundValueSpinBox->value(),
223 (!mBGModeCheckBox->isChecked()));
224 mOpenedBinaryImage.push_back(binaryImage);
227 // Update the contours
230 //------------------------------------------------------------------------------
233 //------------------------------------------------------------------------------
234 void vvToolROIManager::AddImage(vvImage * binaryImage, std::string filename,
235 double BG, bool modeBG)
238 int dim = mCurrentImage->GetNumberOfDimensions();
239 int bin_dim = binaryImage->GetNumberOfDimensions();
241 std::ostringstream os;
242 os << "Error. Loaded binary image is " << bin_dim
243 << "D while selected image is " << dim << "D" << std::endl;
244 QMessageBox::information(this,tr("Reading problem"),os.str().c_str());
249 int n = mROIList.size();
251 // Compute the name of the new ROI
252 std::ostringstream oss;
253 oss << vtksys::SystemTools::GetFilenameName(vtksys::SystemTools::GetFilenameWithoutLastExtension(filename));
254 std::string name = oss.str();
257 std::vector<double> color;
263 clitk::DicomRT_ROI::Pointer roi = clitk::DicomRT_ROI::New();
264 roi->SetFromBinaryImage(binaryImage, n, name, color, filename);
266 // Add a new roi to the list
267 mROIList.push_back(roi);
271 roi->SetBackgroundValueLabelImage(BG);
273 roi->SetForegroundValueLabelImage(BG);
276 if (n<mDefaultLUTColor->GetNumberOfTableValues ()) {
277 double * color = mDefaultLUTColor->GetTableValue(n % mDefaultLUTColor->GetNumberOfTableValues ());
278 roi->SetDisplayColor(color[0], color[1], color[2]);
281 // Add a new roi actor
282 QSharedPointer<vvROIActor> actor = QSharedPointer<vvROIActor>(new vvROIActor);
283 actor->SetBGMode(modeBG);
285 actor->SetSlicerManager(mSlicerManager);
286 actor->Initialize(n+1); // depth is n+1 to start at 1
287 mROIActorsList.push_back(actor);
289 // CheckBox for "All"
290 if (actor->IsVisible()) mNumberOfVisibleROI++;
291 if (actor->IsContourVisible()) mNumberOfVisibleContourROI++;
294 mTreeWidgetList.push_back(QSharedPointer<QTreeWidgetItem>(new QTreeWidgetItem(mTree)));
295 QTreeWidgetItem * w = mTreeWidgetList.back().data();
296 w->setText(0, QString("%1").arg(roi->GetROINumber()));
297 w->setText(1, QString("%1").arg(roi->GetName().c_str()));
298 w->setText(3, QString("%1").arg(actor->GetDepth()));
299 QBrush brush(QColor(roi->GetDisplayColor()[0]*255,
300 roi->GetDisplayColor()[1]*255,
301 roi->GetDisplayColor()[2]*255));
302 brush.setStyle(Qt::SolidPattern);
303 w->setBackground(2, brush);
304 mMapROIToTreeWidget[roi] = w;
305 mMapTreeWidgetToROI[w] = roi;
306 mTree->resizeColumnToContents(0);
307 mTree->resizeColumnToContents(1);
310 UpdateAllROIStatus();
312 //------------------------------------------------------------------------------
315 //------------------------------------------------------------------------------
316 void vvToolROIManager::UpdateAllContours()
318 // Render loaded ROIs (the first is sufficient)
319 for(unsigned int i=0; i<mROIList.size(); i++) {
320 mROIActorsList[i]->Update();
322 for(int i=0; i<mSlicerManager->GetNumberOfSlicers(); i++) {
323 mSlicerManager->GetSlicer(i)->Render();
326 //------------------------------------------------------------------------------
329 //------------------------------------------------------------------------------
330 void vvToolROIManager::UpdateAllROIStatus() {
332 int nb = mROIList.size();
333 for(int i=0; i<nb; i++) {
334 if (mROIActorsList[i]->IsVisible()) {
340 disconnect(mCheckBoxShowAll, SIGNAL(stateChanged(int)), this, SLOT(AllVisibleROIToggled(int)));
341 disconnect(mContourCheckBoxShowAll, SIGNAL(toggled(bool)), this, SLOT(AllVisibleContourROIToggled(bool)));
342 if (nbVisible == nb) mCheckBoxShowAll->setCheckState(Qt::Checked);
344 if (nbVisible == 0) mCheckBoxShowAll->setCheckState(Qt::Unchecked);
345 else mCheckBoxShowAll->setCheckState(Qt::PartiallyChecked);
347 connect(mContourCheckBoxShowAll, SIGNAL(toggled(bool)), this, SLOT(AllVisibleContourROIToggled(bool)));
348 connect(mCheckBoxShowAll, SIGNAL(stateChanged(int)), this, SLOT(AllVisibleROIToggled(int)));
350 //------------------------------------------------------------------------------
353 //------------------------------------------------------------------------------
354 void vvToolROIManager::SelectedItemChangedInTree() {
356 // Search which roi is selected
357 QList<QTreeWidgetItem *> l = mTree->selectedItems();
359 // mCurrentROIActor = 0;
361 mGroupBoxROI->setEnabled(false);
364 QTreeWidgetItem * w = l[0];
365 if (mMapTreeWidgetToROI.find(w) == mMapTreeWidgetToROI.end()) {
366 // mCurrentROIActor = 0;
368 mGroupBoxROI->setEnabled(false);
371 clitk::DicomRT_ROI * roi = mMapTreeWidgetToROI[w];
372 // Get selected roi actor
373 QSharedPointer<vvROIActor> actor = mROIActorsList[roi->GetROINumber()];
375 mCurrentROIActor = actor;
377 // Warning -> avoid unuseful Render here by disconnect slider
379 disconnect(mTree, SIGNAL(itemSelectionChanged()), this, SLOT(SelectedItemChangedInTree()));
380 disconnect(mCheckBoxShow, SIGNAL(toggled(bool)), this, SLOT(VisibleROIToggled(bool)));
381 disconnect(mOpacitySlider, SIGNAL(valueChanged(int)), this, SLOT(OpacityChanged(int)));
382 disconnect(mChangeColorButton, SIGNAL(clicked()), this, SLOT(ChangeColor()));
383 disconnect(mContourCheckBoxShow, SIGNAL(toggled(bool)), this, SLOT(VisibleContourROIToggled(bool)));
384 disconnect(mChangeContourColorButton, SIGNAL(clicked()), this, SLOT(ChangeContourColor()));
385 disconnect(mContourWidthSpinBox, SIGNAL(valueChanged(int)), this, SLOT(ChangeContourWidth(int)));
386 disconnect(mDepthSpinBox, SIGNAL(valueChanged(int)), this, SLOT(ChangeDepth(int)));
388 mGroupBoxROI->setEnabled(true);
389 mROInameLabel->setText(roi->GetName().c_str());
390 mCheckBoxShow->setChecked(actor->IsVisible());
391 mContourCheckBoxShow->setChecked(actor->IsContourVisible());
392 mContourWidthSpinBox->setValue(actor->GetContourWidth());
393 mDepthSpinBox->setValue(actor->GetDepth());
394 w->setText(3, QString("%1").arg(actor->GetDepth()));
395 mOpacitySlider->setValue((int)lrint(actor->GetOpacity()*100));
396 mOpacitySpinBox->setValue((int)lrint(actor->GetOpacity()*100));
398 connect(mTree, SIGNAL(itemSelectionChanged()), this, SLOT(SelectedItemChangedInTree()));
399 connect(mCheckBoxShow, SIGNAL(toggled(bool)), this, SLOT(VisibleROIToggled(bool)));
400 connect(mOpacitySlider, SIGNAL(valueChanged(int)), this, SLOT(OpacityChanged(int)));
401 connect(mChangeColorButton, SIGNAL(clicked()), this, SLOT(ChangeColor()));
402 connect(mContourCheckBoxShow, SIGNAL(toggled(bool)), this, SLOT(VisibleContourROIToggled(bool)));
403 connect(mChangeContourColorButton, SIGNAL(clicked()), this, SLOT(ChangeContourColor()));
404 connect(mContourWidthSpinBox, SIGNAL(valueChanged(int)), this, SLOT(ChangeContourWidth(int)));
405 connect(mDepthSpinBox, SIGNAL(valueChanged(int)), this, SLOT(ChangeDepth(int)));
408 // Set the current color to the selected ROI name
409 mROInameLabel->setAutoFillBackground(true);// # This is important!!
410 mROInameLabel->setStyleSheet("QLabel { background-color : red; color : blue; }");
411 QColor color = QColor(mCurrentROI->GetDisplayColor()[0]*255,
412 mCurrentROI->GetDisplayColor()[1]*255,
413 mCurrentROI->GetDisplayColor()[2]*255);
414 QString values = QString("%1, %2, %3").arg(color.red()).arg(color.green()).arg(color.blue());
415 mROInameLabel->setStyleSheet("QLabel { background-color: rgb("+values+"); }");
420 // mCurrentSlicerManager->Render();
422 //------------------------------------------------------------------------------
425 //------------------------------------------------------------------------------
426 void vvToolROIManager::VisibleROIToggled(bool b) {
427 if (mCurrentROIActor == NULL) return;
428 if (b == mCurrentROIActor->IsVisible()) return; // nothing to do
429 mCurrentROIActor->SetVisible(b);
430 UpdateAllROIStatus();
431 mSlicerManager->Render();
433 //------------------------------------------------------------------------------
436 //------------------------------------------------------------------------------
437 void vvToolROIManager::VisibleContourROIToggled(bool b) {
438 if (mCurrentROIActor == NULL) return;
439 if (mCurrentROIActor->IsContourVisible() == b) return; // nothing to do
440 mCurrentROIActor->SetContourVisible(b);
441 mCurrentROIActor->UpdateColor();
442 mSlicerManager->Render();
444 //------------------------------------------------------------------------------
447 //------------------------------------------------------------------------------
448 void vvToolROIManager::OpacityChanged(int v) {
449 if (mCurrentROIActor == NULL) return;
450 mCurrentROIActor->SetOpacity((double)v/100.0);
451 mCurrentROIActor->UpdateColor();
452 mSlicerManager->Render();
454 //------------------------------------------------------------------------------
457 //------------------------------------------------------------------------------
458 void vvToolROIManager::AllVisibleROIToggled(int b) {
460 if ((mCheckBoxShowAll->checkState() == Qt::Checked) ||
461 (mCheckBoxShowAll->checkState() == Qt::PartiallyChecked)) status = true;
463 for(uint i=0; i<mROIList.size(); i++) {
464 mROIActorsList[i]->SetVisible(status);
466 if (status) mCheckBoxShowAll->setCheckState(Qt::Checked);
467 else mCheckBoxShowAll->setCheckState(Qt::Unchecked);
468 mCheckBoxShow->setChecked(status);
469 mSlicerManager->Render();
471 //------------------------------------------------------------------------------
474 //------------------------------------------------------------------------------
475 void vvToolROIManager::AllVisibleContourROIToggled(bool b) {
477 if ((mContourCheckBoxShowAll->checkState() == Qt::Checked) ||
478 (mContourCheckBoxShowAll->checkState() == Qt::PartiallyChecked)) status = true;
480 for(uint i=0; i<mROIActorsList.size(); i++) {
481 mROIActorsList[i]->SetContourVisible(status);
483 // Update current selection
484 if (status) mContourCheckBoxShowAll->setCheckState(Qt::Checked);
485 else mContourCheckBoxShowAll->setCheckState(Qt::Unchecked);
486 mContourCheckBoxShow->setChecked(status);
487 mSlicerManager->Render();
489 //------------------------------------------------------------------------------
492 //------------------------------------------------------------------------------
493 void vvToolROIManager::ChangeColor() {
495 color.setRgbF(mCurrentROIActor->GetROI()->GetDisplayColor()[0],
496 mCurrentROIActor->GetROI()->GetDisplayColor()[1],
497 mCurrentROIActor->GetROI()->GetDisplayColor()[2]);
498 QColor c = QColorDialog::getColor(color, this, "Choose the ROI color");
499 mCurrentROIActor->GetROI()->SetDisplayColor(c.redF(), c.greenF(), c.blueF());
500 mCurrentROIActor->UpdateColor();
502 QTreeWidgetItem * w = mMapROIToTreeWidget[mCurrentROI];
503 QBrush brush(QColor(mCurrentROI->GetDisplayColor()[0]*255,
504 mCurrentROI->GetDisplayColor()[1]*255,
505 mCurrentROI->GetDisplayColor()[2]*255));
506 brush.setStyle(Qt::SolidPattern);
507 w->setBackground(2, brush);
509 mSlicerManager->Render();
511 //------------------------------------------------------------------------------
514 //------------------------------------------------------------------------------
515 void vvToolROIManager::ChangeContourColor() {
517 color.setRgbF(mCurrentROIActor->GetContourColor()[0],
518 mCurrentROIActor->GetContourColor()[1],
519 mCurrentROIActor->GetContourColor()[2]);
520 QColor c = QColorDialog::getColor(color, this, "Choose the contour color");
521 mCurrentROIActor->SetContourColor(c.redF(), c.greenF(), c.blueF());
522 mCurrentROIActor->UpdateColor();
523 mSlicerManager->Render();
525 //------------------------------------------------------------------------------
528 //------------------------------------------------------------------------------
529 void vvToolROIManager::ChangeContourWidth(int n) {
530 mCurrentROIActor->SetContourWidth(n);
531 mCurrentROIActor->UpdateColor();
532 mSlicerManager->Render();
534 //------------------------------------------------------------------------------
537 //------------------------------------------------------------------------------
538 void vvToolROIManager::ChangeDepth(int n) {
539 mCurrentROIActor->SetDepth(n);
540 mCurrentROIActor->UpdateImage();
541 mSlicerManager->Render();
542 QList<QTreeWidgetItem *> l = mTree->selectedItems();
543 QTreeWidgetItem * w = l[0];
544 w->setText(3, QString("%1").arg(mCurrentROIActor->GetDepth()));
546 //------------------------------------------------------------------------------
549 //------------------------------------------------------------------------------
550 void vvToolROIManager::ReloadCurrentROI() {
552 vvImageReader::Pointer reader = vvImageReader::New();
553 reader->SetInputFilename(mCurrentROI->GetFilename());
554 reader->Update(vvImageReader::IMAGE);
555 if (reader->GetLastError() != "") {
556 QMessageBox::information(mMainWindowBase, tr("Sorry, error. Could not reload"),
557 reader->GetLastError().c_str());
560 mCurrentROI->GetImage()->GetFirstVTKImageData()->ReleaseData();
561 mCurrentROI->SetImage(reader->GetOutput());
564 mCurrentROIActor->UpdateImage();
565 mSlicerManager->Render();
567 //------------------------------------------------------------------------------