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"
25 #include "vvMeshReader.h"
26 #include "vvStructSelector.h"
29 #include <QFileDialog>
30 #include <QMessageBox>
31 #include <QColorDialog>
32 #include <QAbstractEventDispatcher>
35 #include <vtkLookupTable.h>
36 #include <vtkRenderWindow.h>
38 //------------------------------------------------------------------------------
39 // Create the tool and automagically (I like this word) insert it in
40 // the main window menu.
41 ADD_TOOL(vvToolROIManager);
42 //------------------------------------------------------------------------------
44 //------------------------------------------------------------------------------
45 vvToolROIManager::vvToolROIManager(vvMainWindowBase * parent, Qt::WindowFlags f):
46 QWidget(parent->GetTab()),
47 vvToolBase<vvToolROIManager>(parent),
48 Ui::vvToolROIManager()
53 // Assume the initial tab ROI index is 2
57 QWidget * tab = qFindChild<QWidget*>(parent->GetTab(), "ROItab");
60 parent->GetTab()->setCurrentIndex(mIndexFirstTab);
62 // Check if widget already used
63 if (tab->layout()->isEmpty()) {
64 tab->layout()->addWidget(this);
72 Ui_vvToolROIManager::setupUi(this);
73 setAttribute(Qt::WA_DeleteOnClose);
75 mTree->header()->resizeSection(0, 30);
76 mGroupBoxROI->setEnabled(false);
78 // Temporary disable "Load dicom" button
82 mDefaultLUTColor = vtkSmartPointer<vtkLookupTable>::New();
83 for(int i=0; i<mDefaultLUTColor->GetNumberOfTableValues(); i++) {
84 double r = (rand()/(RAND_MAX+1.0));
85 double v = (rand()/(RAND_MAX+1.0));
86 double b = (rand()/(RAND_MAX+1.0));
87 mDefaultLUTColor->SetTableValue(i, r, v, b);
89 #include "vvDefaultLut.h"
92 mNumberOfVisibleROI = 0;
93 mNumberOfVisibleContourROI = 0;
95 // Select the current image as the target
96 int i = parent->GetSlicerManagerCurrentIndex();
97 InputIsSelected(parent->GetSlicerManagers()[i]);
99 // Connect event from mainwindow to this widget
100 connect(parent, SIGNAL(AnImageIsBeingClosed(vvSlicerManager *)),
101 this, SLOT(AnImageIsBeingClosed(vvSlicerManager *)));
102 connect(parent, SIGNAL(SelectedImageHasChanged(vvSlicerManager *)),
103 this, SLOT(SelectedImageHasChanged(vvSlicerManager *)));
104 connect(mOpenBinaryButton, SIGNAL(clicked()), this, SLOT(OpenBinaryImage()));
105 connect(mOpenDicomButton, SIGNAL(clicked()), this, SLOT(OpenDicomImage()));
106 connect(mTree, SIGNAL(itemSelectionChanged()), this, SLOT(SelectedItemChangedInTree()));
107 connect(mCheckBoxShow, SIGNAL(toggled(bool)), this, SLOT(VisibleROIToggled(bool)));
108 connect(mOpacitySlider, SIGNAL(valueChanged(int)), this, SLOT(OpacityChanged(int)));
109 connect(mChangeColorButton, SIGNAL(clicked()), this, SLOT(ChangeColor()));
110 connect(mContourCheckBoxShow, SIGNAL(toggled(bool)), this, SLOT(VisibleContourROIToggled(bool)));
111 connect(mChangeContourColorButton, SIGNAL(clicked()), this, SLOT(ChangeContourColor()));
112 connect(mContourWidthSpinBox, SIGNAL(valueChanged(int)), this, SLOT(ChangeContourWidth(int)));
113 connect(mDepthSpinBox, SIGNAL(valueChanged(int)), this, SLOT(ChangeDepth(int)));
114 connect(mReloadButton, SIGNAL(clicked()), this, SLOT(ReloadCurrentROI()));
115 connect(mCheckBoxShowAll, SIGNAL(stateChanged(int)), this, SLOT(AllVisibleROIToggled(int)));
116 connect(mContourCheckBoxShowAll, SIGNAL(toggled(bool)), this, SLOT(AllVisibleContourROIToggled(bool)));
117 connect(mCloseButton, SIGNAL(clicked()), this, SLOT(close()));
119 //------------------------------------------------------------------------------
122 //------------------------------------------------------------------------------
123 vvToolROIManager::~vvToolROIManager()
126 //------------------------------------------------------------------------------
129 //------------------------------------------------------------------------------
131 void vvToolROIManager::Initialize() {
132 SetToolName("ROIManager");
133 SetToolMenuName("Display ROI (binary image)");
134 SetToolIconFilename(":/common/icons/tool-roi.png");
135 SetToolTip("Display ROI from a binary image.");
136 SetToolExperimental(true);
138 //------------------------------------------------------------------------------
141 //------------------------------------------------------------------------------
142 void vvToolROIManager::InputIsSelected(vvSlicerManager *m)
148 mCurrentImage = mSlicerManager->GetImage();
151 if (mCurrentImage->GetNumberOfDimensions() != 3) {
152 QMessageBox::information(this,tr("Sorry only 3D yet"), tr("Sorry only 3D yet"));
158 mLabelInputInfo->setText(QString("%1").arg(m->GetFileName().c_str()));
160 // Auto display browser to select new contours
163 //------------------------------------------------------------------------------
166 //------------------------------------------------------------------------------
167 void vvToolROIManager::AnImageIsBeingClosed(vvSlicerManager * m)
169 if (m == mSlicerManager) {
174 //------------------------------------------------------------------------------
177 //------------------------------------------------------------------------------
178 void vvToolROIManager::close()
180 // Update to delete actors
184 //------------------------------------------------------------------------------
187 //------------------------------------------------------------------------------
188 void vvToolROIManager::SelectedImageHasChanged(vvSlicerManager * m) {
189 if (m != mSlicerManager) hide();
194 //------------------------------------------------------------------------------
197 //------------------------------------------------------------------------------
198 void vvToolROIManager::OpenBinaryImage()
201 QString Extensions = "Images files ( *.mha *.mhd *.hdr *.his)";
202 Extensions += ";;All Files (*)";
203 QStringList filename =
204 QFileDialog::getOpenFileNames(this,tr("Open binary image"),
205 mMainWindowBase->GetInputPathName(),Extensions);
206 if (filename.size() == 0) return;
208 // For each selected file, open the image
209 for(int i=0; i<filename.size(); i++) {
211 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
212 vvImageReader::Pointer reader = vvImageReader::New();
213 std::vector<std::string> filenames;
214 filenames.push_back(filename[i].toStdString());
215 reader->SetInputFilenames(filenames);
216 reader->Update(vvImageReader::IMAGE);
217 QApplication::restoreOverrideCursor();
219 if (reader->GetLastError().size() != 0) {
220 std::cerr << "Error while reading " << filename[i].toStdString() << std::endl;
221 QString error = "Cannot open file \n";
222 error += reader->GetLastError().c_str();
223 QMessageBox::information(this,tr("Reading problem"),error);
226 vvImage::Pointer binaryImage = reader->GetOutput();
227 AddImage(binaryImage, filename[i].toStdString(), mBackgroundValueSpinBox->value(),
228 (!mBGModeCheckBox->isChecked()));
229 mOpenedBinaryImage.push_back(binaryImage);
232 // Update the contours
235 //------------------------------------------------------------------------------
238 //------------------------------------------------------------------------------
239 void vvToolROIManager::OpenDicomImage()
241 DD("OpenDicomImage");
242 QString Extensions = "Dicom Files ( *.dcm RS*)";
243 Extensions += ";;All Files (*)";
244 QString file = QFileDialog::getOpenFileName(this,tr("Merge Images"),
245 mMainWindow->GetInputPathName(),
247 if (file.isNull()) return;
249 // AddDCStructContour(index, file);
251 reader.SetFilename(file.toStdString());
252 vvStructSelector selector;
253 selector.SetStructures(reader.GetROINames());
254 // selector.EnablePropagationCheckBox(); FIXME Disable
256 // FIXME : change text -> allow to save binary image
258 if (selector.exec()) {
259 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
260 reader.SetSelectedItems(selector.getSelectedItems());
261 reader.SetImage(mSlicerManager->GetImage());
264 // std::vector<vvMesh::Pointer> contours=reader.GetOutput();
265 // for (std::vector<vvMesh::Pointer>::iterator i=contours.begin();
266 // i!=contours.end(); i++)
267 // AddContour(index,*i,selector.PropagationEnabled());
268 QApplication::restoreOverrideCursor();
274 //------------------------------------------------------------------------------
277 //------------------------------------------------------------------------------
278 void vvToolROIManager::AddImage(vvImage * binaryImage, std::string filename,
279 double BG, bool modeBG)
282 int dim = mCurrentImage->GetNumberOfDimensions();
283 int bin_dim = binaryImage->GetNumberOfDimensions();
285 std::ostringstream os;
286 os << "Error. Loaded binary image is " << bin_dim
287 << "D while selected image is " << dim << "D" << std::endl;
288 QMessageBox::information(this,tr("Reading problem"),os.str().c_str());
293 int n = mROIList.size();
295 // Compute the name of the new ROI
296 std::ostringstream oss;
297 oss << vtksys::SystemTools::GetFilenameName(vtksys::SystemTools::GetFilenameWithoutLastExtension(filename));
298 std::string name = oss.str();
301 std::vector<double> color;
307 clitk::DicomRT_ROI::Pointer roi = clitk::DicomRT_ROI::New();
308 roi->SetFromBinaryImage(binaryImage, n, name, color, filename);
310 // Add a new roi to the list
311 mROIList.push_back(roi);
315 roi->SetBackgroundValueLabelImage(BG);
317 roi->SetForegroundValueLabelImage(BG);
320 if (n<mDefaultLUTColor->GetNumberOfTableValues ()) {
321 double * color = mDefaultLUTColor->GetTableValue(n % mDefaultLUTColor->GetNumberOfTableValues ());
322 roi->SetDisplayColor(color[0], color[1], color[2]);
325 // Add a new roi actor
326 QSharedPointer<vvROIActor> actor = QSharedPointer<vvROIActor>(new vvROIActor);
327 actor->SetBGMode(modeBG);
329 actor->SetSlicerManager(mSlicerManager);
330 actor->Initialize(n+1); // depth is n+1 to start at 1
331 mROIActorsList.push_back(actor);
333 // CheckBox for "All"
334 if (actor->IsVisible()) mNumberOfVisibleROI++;
335 if (actor->IsContourVisible()) mNumberOfVisibleContourROI++;
338 mTreeWidgetList.push_back(QSharedPointer<QTreeWidgetItem>(new QTreeWidgetItem(mTree)));
339 QTreeWidgetItem * w = mTreeWidgetList.back().data();
340 w->setText(0, QString("%1").arg(roi->GetROINumber()));
341 w->setText(1, QString("%1").arg(roi->GetName().c_str()));
342 w->setText(3, QString("%1").arg(actor->GetDepth()));
343 QBrush brush(QColor(roi->GetDisplayColor()[0]*255,
344 roi->GetDisplayColor()[1]*255,
345 roi->GetDisplayColor()[2]*255));
346 brush.setStyle(Qt::SolidPattern);
347 w->setBackground(2, brush);
348 mMapROIToTreeWidget[roi] = w;
349 mMapTreeWidgetToROI[w] = roi;
350 mTree->resizeColumnToContents(0);
351 mTree->resizeColumnToContents(1);
354 UpdateAllROIStatus();
356 //------------------------------------------------------------------------------
359 //------------------------------------------------------------------------------
360 void vvToolROIManager::UpdateAllContours()
362 // Render loaded ROIs (the first is sufficient)
363 for(unsigned int i=0; i<mROIList.size(); i++) {
364 mROIActorsList[i]->Update();
366 for(int i=0; i<mSlicerManager->GetNumberOfSlicers(); i++) {
367 mSlicerManager->GetSlicer(i)->Render();
370 //------------------------------------------------------------------------------
373 //------------------------------------------------------------------------------
374 void vvToolROIManager::UpdateAllROIStatus() {
376 int nb = mROIList.size();
377 for(int i=0; i<nb; i++) {
378 if (mROIActorsList[i]->IsVisible()) {
384 disconnect(mCheckBoxShowAll, SIGNAL(stateChanged(int)), this, SLOT(AllVisibleROIToggled(int)));
385 disconnect(mContourCheckBoxShowAll, SIGNAL(toggled(bool)), this, SLOT(AllVisibleContourROIToggled(bool)));
386 if (nbVisible == nb) mCheckBoxShowAll->setCheckState(Qt::Checked);
388 if (nbVisible == 0) mCheckBoxShowAll->setCheckState(Qt::Unchecked);
389 else mCheckBoxShowAll->setCheckState(Qt::PartiallyChecked);
391 connect(mContourCheckBoxShowAll, SIGNAL(toggled(bool)), this, SLOT(AllVisibleContourROIToggled(bool)));
392 connect(mCheckBoxShowAll, SIGNAL(stateChanged(int)), this, SLOT(AllVisibleROIToggled(int)));
394 //------------------------------------------------------------------------------
397 //------------------------------------------------------------------------------
398 void vvToolROIManager::SelectedItemChangedInTree() {
399 // Search which roi is selected
400 QList<QTreeWidgetItem *> l = mTree->selectedItems();
402 // mCurrentROIActor = 0;
404 mGroupBoxROI->setEnabled(false);
407 QTreeWidgetItem * w = l[0];
408 if (mMapTreeWidgetToROI.find(w) == mMapTreeWidgetToROI.end()) {
409 // mCurrentROIActor = 0;
411 mGroupBoxROI->setEnabled(false);
414 if (w == NULL) return;
415 clitk::DicomRT_ROI * roi = mMapTreeWidgetToROI[w];
416 if (roi == NULL) return; // sometimes it is called while there is no roi anymore
417 // Get selected roi actor
418 int n = roi->GetROINumber();
419 QSharedPointer<vvROIActor> actor = mROIActorsList[n];
421 mCurrentROIActor = actor;
423 // Warning -> avoid unuseful Render here by disconnect slider
425 disconnect(mTree, SIGNAL(itemSelectionChanged()), this, SLOT(SelectedItemChangedInTree()));
426 disconnect(mCheckBoxShow, SIGNAL(toggled(bool)), this, SLOT(VisibleROIToggled(bool)));
427 disconnect(mOpacitySlider, SIGNAL(valueChanged(int)), this, SLOT(OpacityChanged(int)));
428 disconnect(mChangeColorButton, SIGNAL(clicked()), this, SLOT(ChangeColor()));
429 disconnect(mContourCheckBoxShow, SIGNAL(toggled(bool)), this, SLOT(VisibleContourROIToggled(bool)));
430 disconnect(mChangeContourColorButton, SIGNAL(clicked()), this, SLOT(ChangeContourColor()));
431 disconnect(mContourWidthSpinBox, SIGNAL(valueChanged(int)), this, SLOT(ChangeContourWidth(int)));
432 disconnect(mDepthSpinBox, SIGNAL(valueChanged(int)), this, SLOT(ChangeDepth(int)));
434 mGroupBoxROI->setEnabled(true);
435 mROInameLabel->setText(roi->GetName().c_str());
436 mCheckBoxShow->setChecked(actor->IsVisible());
437 mContourCheckBoxShow->setChecked(actor->IsContourVisible());
438 mContourWidthSpinBox->setValue(actor->GetContourWidth());
439 mDepthSpinBox->setValue(actor->GetDepth());
440 w->setText(3, QString("%1").arg(actor->GetDepth()));
441 mOpacitySlider->setValue((int)lrint(actor->GetOpacity()*100));
442 mOpacitySpinBox->setValue((int)lrint(actor->GetOpacity()*100));
444 connect(mTree, SIGNAL(itemSelectionChanged()), this, SLOT(SelectedItemChangedInTree()));
445 connect(mCheckBoxShow, SIGNAL(toggled(bool)), this, SLOT(VisibleROIToggled(bool)));
446 connect(mOpacitySlider, SIGNAL(valueChanged(int)), this, SLOT(OpacityChanged(int)));
447 connect(mChangeColorButton, SIGNAL(clicked()), this, SLOT(ChangeColor()));
448 connect(mContourCheckBoxShow, SIGNAL(toggled(bool)), this, SLOT(VisibleContourROIToggled(bool)));
449 connect(mChangeContourColorButton, SIGNAL(clicked()), this, SLOT(ChangeContourColor()));
450 connect(mContourWidthSpinBox, SIGNAL(valueChanged(int)), this, SLOT(ChangeContourWidth(int)));
451 connect(mDepthSpinBox, SIGNAL(valueChanged(int)), this, SLOT(ChangeDepth(int)));
454 // Set the current color to the selected ROI name
455 mROInameLabel->setAutoFillBackground(true);// # This is important!!
456 mROInameLabel->setStyleSheet("QLabel { background-color : red; color : blue; }");
457 QColor color = QColor(mCurrentROI->GetDisplayColor()[0]*255,
458 mCurrentROI->GetDisplayColor()[1]*255,
459 mCurrentROI->GetDisplayColor()[2]*255);
460 QString values = QString("%1, %2, %3").arg(color.red()).arg(color.green()).arg(color.blue());
461 mROInameLabel->setStyleSheet("QLabel { background-color: rgb("+values+"); }");
464 mGroupBoxROI->setEnabled(true);
468 // mCurrentSlicerManager->Render();
470 //------------------------------------------------------------------------------
473 //------------------------------------------------------------------------------
474 void vvToolROIManager::VisibleROIToggled(bool b) {
475 if (mCurrentROIActor == NULL) return;
476 if (b == mCurrentROIActor->IsVisible()) return; // nothing to do
477 mCurrentROIActor->SetVisible(b);
478 UpdateAllROIStatus();
479 mSlicerManager->Render();
481 //------------------------------------------------------------------------------
484 //------------------------------------------------------------------------------
485 void vvToolROIManager::VisibleContourROIToggled(bool b) {
486 if (mCurrentROIActor == NULL) return;
487 if (mCurrentROIActor->IsContourVisible() == b) return; // nothing to do
488 mCurrentROIActor->SetContourVisible(b);
489 mCurrentROIActor->UpdateColor();
490 mSlicerManager->Render();
492 //------------------------------------------------------------------------------
495 //------------------------------------------------------------------------------
496 void vvToolROIManager::OpacityChanged(int v) {
497 if (mCurrentROIActor == NULL) return;
498 mCurrentROIActor->SetOpacity((double)v/100.0);
499 mCurrentROIActor->UpdateColor();
500 mSlicerManager->Render();
502 //------------------------------------------------------------------------------
505 //------------------------------------------------------------------------------
506 void vvToolROIManager::AllVisibleROIToggled(int b) {
508 if ((mCheckBoxShowAll->checkState() == Qt::Checked) ||
509 (mCheckBoxShowAll->checkState() == Qt::PartiallyChecked)) status = true;
511 for(uint i=0; i<mROIList.size(); i++) {
512 mROIActorsList[i]->SetVisible(status);
514 if (status) mCheckBoxShowAll->setCheckState(Qt::Checked);
515 else mCheckBoxShowAll->setCheckState(Qt::Unchecked);
516 mCheckBoxShow->setChecked(status);
517 mSlicerManager->Render();
519 //------------------------------------------------------------------------------
522 //------------------------------------------------------------------------------
523 void vvToolROIManager::AllVisibleContourROIToggled(bool b) {
525 if ((mContourCheckBoxShowAll->checkState() == Qt::Checked) ||
526 (mContourCheckBoxShowAll->checkState() == Qt::PartiallyChecked)) status = true;
528 for(uint i=0; i<mROIActorsList.size(); i++) {
529 mROIActorsList[i]->SetContourVisible(status);
531 // Update current selection
532 if (status) mContourCheckBoxShowAll->setCheckState(Qt::Checked);
533 else mContourCheckBoxShowAll->setCheckState(Qt::Unchecked);
534 mContourCheckBoxShow->setChecked(status);
535 mSlicerManager->Render();
537 //------------------------------------------------------------------------------
540 //------------------------------------------------------------------------------
541 void vvToolROIManager::ChangeColor() {
542 if (mCurrentROIActor == NULL) return;
544 color.setRgbF(mCurrentROIActor->GetROI()->GetDisplayColor()[0],
545 mCurrentROIActor->GetROI()->GetDisplayColor()[1],
546 mCurrentROIActor->GetROI()->GetDisplayColor()[2]);
547 QColor c = QColorDialog::getColor(color, this, "Choose the ROI color");
548 mCurrentROIActor->GetROI()->SetDisplayColor(c.redF(), c.greenF(), c.blueF());
549 mCurrentROIActor->UpdateColor();
551 QTreeWidgetItem * w = mMapROIToTreeWidget[mCurrentROI];
552 QBrush brush(QColor(mCurrentROI->GetDisplayColor()[0]*255,
553 mCurrentROI->GetDisplayColor()[1]*255,
554 mCurrentROI->GetDisplayColor()[2]*255));
555 brush.setStyle(Qt::SolidPattern);
556 w->setBackground(2, brush);
558 mSlicerManager->Render();
560 //------------------------------------------------------------------------------
563 //------------------------------------------------------------------------------
564 void vvToolROIManager::ChangeContourColor() {
565 if (mCurrentROIActor == NULL) return;
567 color.setRgbF(mCurrentROIActor->GetContourColor()[0],
568 mCurrentROIActor->GetContourColor()[1],
569 mCurrentROIActor->GetContourColor()[2]);
570 QColor c = QColorDialog::getColor(color, this, "Choose the contour color");
571 mCurrentROIActor->SetContourColor(c.redF(), c.greenF(), c.blueF());
572 mCurrentROIActor->UpdateColor();
573 mSlicerManager->Render();
575 //------------------------------------------------------------------------------
578 //------------------------------------------------------------------------------
579 void vvToolROIManager::ChangeContourWidth(int n) {
580 if (mCurrentROIActor == NULL) return;
581 mCurrentROIActor->SetContourWidth(n);
582 mCurrentROIActor->UpdateColor();
583 mSlicerManager->Render();
585 //------------------------------------------------------------------------------
588 //------------------------------------------------------------------------------
589 void vvToolROIManager::ChangeDepth(int n) {
590 if (mCurrentROIActor == NULL) return;
591 mCurrentROIActor->SetDepth(n);
592 mCurrentROIActor->UpdateImage();
593 mSlicerManager->Render();
594 QList<QTreeWidgetItem *> l = mTree->selectedItems();
595 QTreeWidgetItem * w = l[0];
596 w->setText(3, QString("%1").arg(mCurrentROIActor->GetDepth()));
598 //------------------------------------------------------------------------------
601 //------------------------------------------------------------------------------
602 void vvToolROIManager::ReloadCurrentROI() {
604 // Remove all contours/overlay first
605 bool visible = mCurrentROIActor->IsVisible();
606 bool cvisible = mCurrentROIActor->IsContourVisible();
607 mCurrentROIActor->SetVisible(false);
608 mCurrentROIActor->SetContourVisible(false);
609 mSlicerManager->Render();
612 vvImageReader::Pointer reader = vvImageReader::New();
613 reader->SetInputFilename(mCurrentROI->GetFilename());
614 reader->Update(vvImageReader::IMAGE);
615 if (reader->GetLastError() != "") {
616 QMessageBox::information(mMainWindowBase, tr("Sorry, error. Could not reload"),
617 reader->GetLastError().c_str());
621 mCurrentROI->GetImage()->Reset();//GetFirstVTKImageData()->ReleaseData();
622 mCurrentROI->SetImage(reader->GetOutput());
625 mCurrentROIActor->UpdateImage();
626 mCurrentROIActor->SetVisible(visible);
627 mCurrentROIActor->SetContourVisible(cvisible);
628 mSlicerManager->Render();
630 //------------------------------------------------------------------------------