From: rblanc Date: Mon, 7 Jan 2013 16:26:07 +0000 (+0100) Subject: continued the fusion sequence visualization mode X-Git-Tag: v1.4.0~260^2~3 X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?a=commitdiff_plain;h=9ac2232043d7a08735edf00572ccb6565919fd3d;p=clitk.git continued the fusion sequence visualization mode trying to improve display and window behavior and preparing ground for temporal synchronization seems broken however... as loading an image causes a crash... --- diff --git a/vv/qt_ui/vvOverlayPanel.ui b/vv/qt_ui/vvOverlayPanel.ui index b7f73a2..8143521 100644 --- a/vv/qt_ui/vvOverlayPanel.ui +++ b/vv/qt_ui/vvOverlayPanel.ui @@ -50,7 +50,7 @@ p, li { white-space: pre-wrap; } 0 - 70 + 90 @@ -65,8 +65,8 @@ p, li { white-space: pre-wrap; } - 270 - 10 + 220 + 60 80 17 @@ -78,7 +78,7 @@ p, li { white-space: pre-wrap; } - 210 + 220 10 61 17 @@ -90,6 +90,9 @@ p, li { white-space: pre-wrap; } true + + true + @@ -138,7 +141,7 @@ p, li { white-space: pre-wrap; } 130 36 - 181 + 151 20 @@ -146,6 +149,19 @@ p, li { white-space: pre-wrap; } Qt::Horizontal + + + + 20 + 60 + 131 + 23 + + + + Load Fused Seq. Signal + + diff --git a/vv/vvMainWindow.cxx b/vv/vvMainWindow.cxx index 9f7d75c..cde6d50 100644 --- a/vv/vvMainWindow.cxx +++ b/vv/vvMainWindow.cxx @@ -292,6 +292,8 @@ vvMainWindow::vvMainWindow():vvMainWindowBase() connect(actionDocumentation,SIGNAL(triggered()),this,SLOT(ShowDocumentation())); connect(actionRegister_vv,SIGNAL(triggered()),this,SLOT(PopupRegisterForm())); + connect(overlayPanel, SIGNAL(FusionSequenceSignalButtonPressed()), this, SLOT(SelectFusionSequenceTemporalSignal())); + /////////////////////////////////////////////// connect(actionSegmentation,SIGNAL(triggered()),this,SLOT(SegmentationOnCurrentImage())); @@ -333,8 +335,8 @@ vvMainWindow::vvMainWindow():vvMainWindowBase() this,SLOT(SetFusionProperty(int,int,int,double,double, bool))); connect(landmarksPanel,SIGNAL(UpdateRenderWindows()),this,SLOT(UpdateRenderWindows())); - connect(overlayPanel,SIGNAL(FusionSequencePropertyUpdated(int, bool, unsigned int)), - this,SLOT(SetFusionSequenceProperty(int, bool,unsigned int))); + connect(overlayPanel,SIGNAL(FusionSequencePropertyUpdated(int, bool, unsigned int, bool)), + this,SLOT(SetFusionSequenceProperty(int, bool,unsigned int, bool))); playMode = 0;//pause @@ -838,12 +840,11 @@ void vvMainWindow::LoadImages(std::vector files, vvImageReader::Loa int numberofsuccesulreads=0; //open images as 1 or multiples for (int i = 0; i < fileSize; i++) { - progress.SetText("Opening " + files[i]); progress.SetProgress(i,fileSize); qApp->processEvents(); - for (unsigned int j = 0; j < nSlices[i]; j++) { + for (unsigned int j = 0; j < nSlices[i]; j++) { //read the image and put it in mSlicerManagers vvSlicerManager* imageManager = new vvSlicerManager(4); qApp->processEvents(); @@ -858,7 +859,8 @@ void vvMainWindow::LoadImages(std::vector files, vvImageReader::Loa else { SetImageSucceed = imageManager->SetImages(files,filetype, number); } - if (!SetImageSucceed) { + + if (!SetImageSucceed) { QApplication::restoreOverrideCursor(); QString error = "Cannot open file \n"; error += imageManager->GetLastError().c_str(); @@ -876,7 +878,7 @@ void vvMainWindow::LoadImages(std::vector files, vvImageReader::Loa item->setToolTip(COLUMN_IMAGE_NAME, imageManager->GetListOfAbsoluteFilePathInOneString("image").c_str()); qApp->processEvents(); - //Create the buttons for reload and close + //Create the buttons for reload and close qApp->processEvents(); QTreePushButton* cButton = new QTreePushButton; cButton->setItem(item); @@ -905,7 +907,7 @@ void vvMainWindow::LoadImages(std::vector files, vvImageReader::Loa linkPanel->addImage(imageManager->GetFileName(), id.toStdString()); - connect(mSlicerManagers.back(), SIGNAL(currentImageChanged(std::string)), + connect(mSlicerManagers.back(), SIGNAL(currentImageChanged(std::string)), this,SLOT(CurrentImageChanged(std::string))); connect(mSlicerManagers.back(), SIGNAL(currentPickedImageChanged(std::string)), this, SLOT(CurrentPickedImageChanged(std::string))); @@ -917,8 +919,6 @@ void vvMainWindow::LoadImages(std::vector files, vvImageReader::Loa this, SLOT(OverlayChanged(int,double,double))); connect(mSlicerManagers.back(), SIGNAL(UpdateFusion(int, double)), this, SLOT(FusionChanged(int,double))); - //connect(mSlicerManagers.back(), SIGNAL(UpdateFusionSequence(int, bool, unsigned int)), - // this, SLOT(FusionSequenceChanged(int, bool, unsigned int))); connect(mSlicerManagers.back(), SIGNAL(WindowLevelChanged()), this,SLOT(WindowLevelChanged())); connect(mSlicerManagers.back(), SIGNAL(UpdateSlice(int,int)), @@ -936,7 +936,8 @@ void vvMainWindow::LoadImages(std::vector files, vvImageReader::Loa connect(mSlicerManagers.back(), SIGNAL(ChangeImageWithIndexOffset(vvSlicerManager*,int,int)), this,SLOT(ChangeImageWithIndexOffset(vvSlicerManager*,int,int))); connect(mSlicerManagers.back(),SIGNAL(LandmarkAdded()),landmarksPanel,SLOT(AddPoint())); - InitSlicers(); + + InitSlicers(); numberofsuccesulreads++; } } @@ -1388,6 +1389,7 @@ QString vvMainWindow::GetVectorIntAsString(std::vector vectorInt) //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ +//this actually returns the SlicerManager index! int vvMainWindow::GetSlicerIndexFromItem(QTreeWidgetItem* item) { QString id = item->data(COLUMN_IMAGE_NAME,Qt::UserRole).toString(); @@ -1506,13 +1508,13 @@ void vvMainWindow::InitDisplay() for (int i = 0; i < DataTree->topLevelItemCount(); i++) { mSlicerManagers[i]->SetInteractorStyleNavigator(j,style); - //select the image only if previous are not selected + //select the image only if previous are not selected if (DataTree->topLevelItem(i)->data(j+1,Qt::CheckStateRole).toInt() > 1) { mSlicerManagers[i]->UpdateSlicer(j,1); - AlreadySelected = true; + AlreadySelected = true; } else if (i == DataTree->topLevelItemCount()-1 && !AlreadySelected) { if (DataTree->selectedItems().size() == 0) - DataTree->topLevelItem(i)->setSelected(1); + DataTree->topLevelItem(i)->setSelected(1); //RB: crash here when loading an image... DataTree->topLevelItem(i)->setData(j+1,Qt::CheckStateRole,2); mSlicerManagers[i]->UpdateSlicer(j,1); DisplaySliders(i,j); @@ -1577,6 +1579,16 @@ void vvMainWindow::CloseImage(QTreeWidgetItem* item, int column) overlay_index++; if (DataTree->topLevelItem(index)->child(child) == item) break; } + if (overlay_type=="fusionSequence") { + //removing the overlay sequence in a fusion sequence visualization mode + //TODO: remove the synchronization (transform matrices, etc...) + + //=> unlink and untie the slicer managers + mSlicerManagers[index]->SetFusionSequenceInvolvmentCode(-1); + mSlicerManagers[mSlicerManagers[index]->GetFusionSequenceIndexOfLinkedManager()]->SetFusionSequenceInvolvmentCode(-1); + RemoveLink(mSlicerManagers[index]->GetId().c_str(), mSlicerManagers[mSlicerManagers[index]->GetFusionSequenceIndexOfLinkedManager()]->GetId().c_str()); + + } mSlicerManagers[index]->RemoveActor(overlay_type, overlay_index-1); mSlicerManagers[index]->SetColorMap(0); DataTree->topLevelItem(index)->takeChild(DataTree->topLevelItem(index)->indexOfChild(item)); @@ -1612,6 +1624,17 @@ void vvMainWindow::CloseImage(QTreeWidgetItem* item, int column) } linkPanel->removeImage(index); mSlicerManagers[index]->RemoveActors(); + + //if the slicer manager was involved in a fusion sequence visualization... + if ( item->data(1,Qt::UserRole).toString().toStdString() == "fusionSequence" ) { + //TODO + //make sure both SlicerManager exit the FusionSequence visualization mode + //disable the temporal and spatial sync? make sure we reset the spatial transforms to their initial states... + mSlicerManagers[index]->SetFusionSequenceInvolvmentCode(-1); + mSlicerManagers[mSlicerManagers[index]->GetFusionSequenceIndexOfLinkedManager()]->SetFusionSequenceInvolvmentCode(-1); + } + + //remove the slicer manager delete mSlicerManagers[index]; mSlicerManagers.erase(Manageriter); @@ -1637,20 +1660,24 @@ void vvMainWindow::ReloadImage(QTreeWidgetItem* item, int column) int index = GetSlicerIndexFromItem(item); QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); QString role=item->data(1,Qt::UserRole).toString(); - if ( role == "vector"){ + if ( role == "vector") { mSlicerManagers[index]->ReloadVF(); } - else if (role == "overlay"){ + else if (role == "overlay") { mSlicerManagers[index]->ReloadOverlay(); } - else if (role == "fusion"){ + else if (role == "fusion") { mSlicerManagers[index]->ReloadFusion(); } - else if (role == "fusionSequence"){ - mSlicerManagers[index]->ReloadFusionSequence(); //same as for standard fusion + else if (role == "fusionSequence") { + //both versions of the secondary sequence must be updated. + mSlicerManagers[index]->ReloadFusionSequence(); + mSlicerManagers[mSlicerManagers[index]->GetFusionSequenceIndexOfLinkedManager()]->Reload(); } - else{ + else { mSlicerManagers[index]->Reload(); + //if we update the secondary sequence, then the overlay of the main sequence should also be updated + if (mSlicerManagers[index]->IsSecondarySequenceOfFusionSequence()) mSlicerManagers[mSlicerManagers[index]->GetFusionSequenceIndexOfLinkedManager()]->ReloadFusionSequence(); } // Update view and info ImageInfoChanged(); @@ -1714,26 +1741,30 @@ void vvMainWindow::WindowLevelChanged() mSlicerManagers[index]->GetFusionColorMap(), mSlicerManagers[index]->GetFusionWindow(), mSlicerManagers[index]->GetFusionLevel()); - overlayPanel->getFusionSequenceProperty(mSlicerManagers[index]->GetFusionSequenceFrameIndex(), - mSlicerManagers[index]->GetFusionSequenceSpatialSyncFlag(), - mSlicerManagers[index]->GetFusionSequenceNbFrames()); - } - else if ( mSlicerManagers[index]->GetFusionSequenceIndexOfLinkedManager()>=0 ) { + if (mSlicerManagers[index]->IsMainSequenceOfFusionSequence()) { + overlayPanel->getFusionSequenceProperty(mSlicerManagers[index]->GetFusionSequenceFrameIndex(), + mSlicerManagers[index]->GetFusionSequenceSpatialSyncFlag(), + mSlicerManagers[index]->GetFusionSequenceNbFrames(), + mSlicerManagers[index]->GetFusionSequenceTemporalSyncFlag()); + } + } + else if ( mSlicerManagers[index]->IsSecondarySequenceOfFusionSequence() ) { //if the image is involved in a fusion sequence, preserve the overlay panel! int ind = mSlicerManagers[index]->GetFusionSequenceIndexOfLinkedManager(); - overlayPanel->getFusionProperty(mSlicerManagers[index]->GetFusionOpacity(), + overlayPanel->getFusionProperty(mSlicerManagers[ind]->GetFusionOpacity(), mSlicerManagers[ind]->GetFusionThresholdOpacity(), mSlicerManagers[ind]->GetFusionColorMap(), mSlicerManagers[ind]->GetFusionWindow(), mSlicerManagers[ind]->GetFusionLevel()); overlayPanel->getFusionSequenceProperty(mSlicerManagers[ind]->GetFusionSequenceFrameIndex(), mSlicerManagers[ind]->GetFusionSequenceSpatialSyncFlag(), - mSlicerManagers[ind]->GetFusionSequenceNbFrames()); + mSlicerManagers[ind]->GetFusionSequenceNbFrames(), + mSlicerManagers[ind]->GetFusionSequenceTemporalSyncFlag()); } else { overlayPanel->getFusionProperty(-1, -1, -1, -1, -1); - overlayPanel->getFusionSequenceProperty(-1, false, 0); + overlayPanel->getFusionSequenceProperty(-1, false, 0, false); } } //------------------------------------------------------------------------------ @@ -1851,17 +1882,13 @@ void vvMainWindow::ApplyLevelToSetOfImages(double level, unsigned int indexMin, //------------------------------------------------------------------------------ void vvMainWindow::UpdateLinkManager(std::string id, int slicer, double x, double y, double z, int temps) { - for (unsigned int i = 0; i < mSlicerManagers.size(); i++) { - if (mSlicerManagers[i]->GetId() == id) { - //mSlicerManagers[i]->SetTSlice(temps); - if (temps<0) { //for fusionSequence, special input used to avoid any automatic time synchronization... - mSlicerManagers[i]->GetSlicer(slicer)->SetCurrentPosition( x,y,z, mSlicerManagers[i]->GetSlicer(slicer)->GetTSlice() ); + for (unsigned int i = 0; i < mSlicerManagers.size(); i++) { + if (mSlicerManagers[i]->GetId() == id) { + mSlicerManagers[i]->GetSlicer(slicer)->SetCurrentPosition(x,y,z,temps); + mSlicerManagers[i]->UpdateViews(0,slicer); + break; } - else mSlicerManagers[i]->GetSlicer(slicer)->SetCurrentPosition(x,y,z,temps); - mSlicerManagers[i]->UpdateViews(0,slicer); - break; - } - } + } } //------------------------------------------------------------------------------ @@ -2352,8 +2379,9 @@ void vvMainWindow::SetFusionProperty(int opacity, int thresOpacity, int colormap //------------------------------------------------------------------------------ void vvMainWindow::SelectFusionSequence() { + //get the index of the slicer manager of the main sequence (CT) int index = GetSlicerIndexFromItem(DataTree->selectedItems()[0]); - //check if one overlay image is added + //check if one overlay image is already associated for (int child = 0; child < DataTree->topLevelItem(index)->childCount(); child++) if ( (DataTree->topLevelItem(index)->child(child)->data(1,Qt::UserRole).toString() == "fusion") || (DataTree->topLevelItem(index)->child(child)->data(1,Qt::UserRole).toString() == "fusionSequence") ) { @@ -2375,11 +2403,61 @@ void vvMainWindow::SelectFusionSequence() vecFileNames.push_back(files[i].toStdString()); } + //associate the secondary sequence (US) to the main one AddFusionSequence(index,vecFileNames,vvImageReader::MERGEDWITHTIME); } //------------------------------------------------------------------------------ + //------------------------------------------------------------------------------ +void vvMainWindow::SelectFusionSequenceTemporalSignal() { + + //make sure the index is right? + //in the end, I should attach the temporal data to the right sequence! + int index = GetSlicerIndexFromItem(DataTree->selectedItems()[0]); + //in case the other sequence got selected, make sure we select the primary sequence + if ( (!mSlicerManagers[index]->GetSlicer(0)->GetFusion()) && mSlicerManagers[index]->GetFusionSequenceIndexOfLinkedManager()>=0 ) { + index = mSlicerManagers[index]->GetFusionSequenceIndexOfLinkedManager(); + } + + //open a dialog box to find a file + QString Extensions = EXTENSIONS; + Extensions += ";;All Files (*)"; + QString fileName = QFileDialog::getOpenFileName(this,tr("Load respiratory signal for fused sequence"),mInputPathName,Extensions); + if (fileName.isNull()) + return; + + //read it as a vector of values + std::vector signal; + //...TODO, look for itk functions that can do that... vnl in the worst case. + signal.push_back(1);signal.push_back(2); + + //TODO: instead: if the loaded signal is longer, just crop it... + //this allows loading only the first few frames when testing. + //->maybe raise a message that this behavior may be unsafe... + + //if compatible with the fused image sequence (number of images = number of entries), enable the temporalSync + if ( signal.size() >= mSlicerManagers[index]->GetFusionSequenceNbFrames()) { + //for convenience, associate this sequence to both the current slicer manager, and to the linked one + mSlicerManagers[index]->SetFusionSequenceTemporalSignal(signal); + mSlicerManagers[ mSlicerManagers[index]->GetFusionSequenceIndexOfLinkedManager() ]->SetFusionSequenceTemporalSignal(signal); + overlayPanel->enableFusionSequenceTemporalSync(); + QMessageBox::information(this,tr("Adding signal"),"would add the signal from file: "+ fileName); + } + else {//else, send a message to signal the failure... + QString error = "The provided signal doesn't have the same duration as the sequence\n"; + error += "Ignoring file: " + fileName; + QMessageBox::information(this,tr("Problem adding signal!"),error); + return; + } + +} +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +//when this function is called index is the slicer manager index corresponding to the main sequence (CT) +//the files behind fileNames points to the data for the secondary sequence void vvMainWindow::AddFusionSequence(int index, std::vector fileNames, vvImageReader::LoadedImageType type) { QString file(fileNames[0].c_str()); @@ -2453,7 +2531,7 @@ void vvMainWindow::AddFusionSequence(int index, std::vector fileNam DisplaySliders(index, i); - //TEST: also add the image as normal image, link it, and store its index in the SlicerManagersArray for tying it to the fusionSequence + //This loads the secondary sequence (US) as an independent sequence LoadImages(fileNames, type); //reset the transforms to identiy for (unsigned i=0 ; iGetImage()->GetTransform().size() ; i++) { @@ -2464,10 +2542,11 @@ void vvMainWindow::AddFusionSequence(int index, std::vector fileNam //automatically link both images... AddLink(mSlicerManagers[indexParent]->GetId().c_str(), mSlicerManagers.back()->GetId().c_str(), false); - //store the index ; this is also used as a flag to indicate that the images are involved in a fusionSequence... - //TODO: reset these when exiting the visualization mode (unloading one of the images) + //tie the main and secondary sequences by raising flags and informing each another of their respective SlicerManager indices mSlicerManagers[indexParent]->SetFusionSequenceIndexOfLinkedManager(mSlicerManagers.size()-1); + mSlicerManagers[indexParent]->SetFusionSequenceInvolvmentCode(0); //main sequence mSlicerManagers.back()->SetFusionSequenceIndexOfLinkedManager(indexParent); + mSlicerManagers.back()->SetFusionSequenceInvolvmentCode(1); //secondary sequence } else { QApplication::restoreOverrideCursor(); @@ -2487,44 +2566,74 @@ void vvMainWindow::AddFusionSequence(int index, std::vector fileNam //------------------------------------------------------------------------------ -void vvMainWindow::SetFusionSequenceProperty(int fusionSequenceFrameIndex, bool spatialSyncFlag, unsigned int fusionSequenceNbFrames) +//fusionSequenceFrameIndex and fusionSequenceNbFrames are relative to the secondary sequence (US) +void vvMainWindow::SetFusionSequenceProperty(int fusionSequenceFrameIndex, bool spatialSyncFlag, unsigned int fusionSequenceNbFrames, bool temporalSyncFlag) { int index = GetSlicerIndexFromItem(DataTree->selectedItems()[0]); //check if the focus moved to the linked sequence, and in this case, select the master sequence instead - if ( (!mSlicerManagers[index]->GetSlicer(0)->GetFusion()) && mSlicerManagers[index]->GetFusionSequenceIndexOfLinkedManager()>=0 ) { + if (!mSlicerManagers[index]->IsMainSequenceOfFusionSequence()) { index = mSlicerManagers[index]->GetFusionSequenceIndexOfLinkedManager(); } - if (mSlicerManagers[index]->GetSlicer(0)->GetFusion()) { - int indexParent = GetSlicerIndexFromItem( DataTree->topLevelItem(index) ); + int secondaryIndex = mSlicerManagers[index]->GetFusionSequenceIndexOfLinkedManager(); + if ( (!mSlicerManagers[index]->IsMainSequenceOfFusionSequence()) || + (!mSlicerManagers[secondaryIndex]->IsSecondarySequenceOfFusionSequence()) ) + {return;} //this should never happen, raise an exception? - //if the button is unchecked, then reposition the parent sequence (CT) in its original coordinate frame - if ( (!spatialSyncFlag) && (mSlicerManagers[index]->GetFusionSequenceSpatialSyncFlag()) ) { - for ( unsigned i=0 ; iGetSlicer(0)->GetImage()->GetTransform().size() ; i++ ) { - mSlicerManagers[indexParent]->GetSlicer(0)->GetImage()->GetTransform()[i]->SetMatrix( mSlicerManagers[index]->GetFusionSequenceMainTransformMatrix() ); - mSlicerManagers[indexParent]->GetSlicer(0)->GetImage()->GetTransform()[i]->Update(); - } + if (mSlicerManagers[index]->GetSlicer(0)->GetFusion()) { + int indexParent = GetSlicerIndexFromItem( DataTree->topLevelItem(index) ); +//check whether this really makes sense to look at 'parentIndex'... +std::cout<<"index = "< +#include + +// VV include +#include "vvMainWindow.h" +#include "vvHelpDialog.h" +#include "vvRegisterForm.h" +#include "vvDocumentation.h" +#include "vvProgressDialog.h" +#include "vvQDicomSeriesSelector.h" +#include "vvSlicerManager.h" +#include "clitkImageCommon.h" +#include "vvSlicer.h" +#include "vvInteractorStyleNavigator.h" +#include "vvImageWriter.h" +#include "vvSegmentationDialog.h" +#include "vvSurfaceViewerDialog.h" +#include "vvDeformationDialog.h" +#include "vvImageWarp.h" +#include "vvUtils.h" +#include "vvMidPosition.h" +#include "vvMesh.h" +#include "vvStructSelector.h" +#include "vvMeshReader.h" +#include "vvSaveState.h" +#include "vvReadState.h" +#include "clitkConfiguration.h" + +// ITK include +#include +#include +#include +#include +#include + +// VTK include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CLITK_EXPERIMENTAL +# include +#endif +#ifdef VTK_USE_VIDEO_FOR_WINDOWS +# include +#endif +#ifdef VTK_USE_FFMPEG_ENCODER +# include +#endif +#ifdef VTK_USE_MPEG2_ENCODER +# include +#endif +#include +#include + +// Standard includes +#include +#include +#include + +#define COLUMN_TREE 0 +#define COLUMN_UL_VIEW 1 +#define COLUMN_UR_VIEW 2 +#define COLUMN_DL_VIEW 3 +#define COLUMN_DR_VIEW 4 +#define COLUMN_CLOSE_IMAGE 5 +#define COLUMN_RELOAD_IMAGE 6 +#define COLUMN_IMAGE_NAME 7 + +#ifdef CLITK_PRIVATE_FEATURES +#define EXTENSIONS "Images ( *.bmp *.png *.jpeg *.jpg *.tif *.mhd *.mha *.hdr *.vox *.his *.xdr *.SCAN *.nii *.nrrd *.nhdr *.refscan *.nii.gz *.usf)" +#else +#define EXTENSIONS "Images ( *.bmp *.png *.jpeg *.jpg *.tif *.mhd *.mha *.hdr *.vox *.his *.xdr *.SCAN *.nii *.nrrd *.nhdr *.refscan *.nii.gz)" +#endif + + +/*Data Tree values + 0,Qt::UserRole full filename + 1,Qt::CheckStateRole checkbutton UL View + 1,Qt::UserRole overlay, fusion or vector + 2,Qt::CheckStateRole checkbutton UR View + 3,Qt::CheckStateRole checkbutton DL View + 4,Qt::CheckStateRole checkbutton DR View + 5,0 short filename + 5,Qt::UserRole mSlicerManager id*/ + +//------------------------------------------------------------------------------ +vvMainWindow::vvMainWindow():vvMainWindowBase() +{ + setupUi(this); // this sets up the GUI + + mInputPathName = ""; + mMenuTools = menuTools; + // mMenuSegmentation = menuSegmentation; + mContextMenu = &contextMenu; + mMenuExperimentalTools = menuExperimental; + mMainWidget = this; + mCurrentTime = -1; + mCurrentSelectedImageId = ""; + mCurrentPickedImageId = ""; + mCurrentPickedImageIndex = 0; + + //Init the contextMenu + this->setContextMenuPolicy(Qt::CustomContextMenu); + contextActions.resize(0); + QAction* actionOpen_new_image = contextMenu.addAction(QIcon(QString::fromUtf8(":/common/icons/fileopen.png")), + tr("O&pen new Image")); + actionOpen_new_image->setShortcut(QKeySequence(tr("Ctrl+O"))); + connect(actionOpen_new_image,SIGNAL(triggered()),this,SLOT(OpenImages())); + contextActions.push_back(actionOpen_new_image); + contextMenu.addSeparator(); + + QAction* actionClose_Image = contextMenu.addAction(QIcon(QString::fromUtf8(":/common/icons/exit.png")), + tr("Close Current Image")); + connect(actionClose_Image,SIGNAL(triggered()),this,SLOT(CloseImage())); + contextActions.push_back(actionClose_Image); + + QAction* actionReload_image = contextMenu.addAction(QIcon(QString::fromUtf8(":/common/icons/rotateright.png")), + tr("Reload Current Image")); + connect(actionReload_image,SIGNAL(triggered()),this,SLOT(ReloadImage())); + contextActions.push_back(actionReload_image); + + QAction* actionSave_image = contextMenu.addAction(QIcon(QString::fromUtf8(":/common/icons/filesave.png")), + tr("Save Current Image")); + connect(actionSave_image,SIGNAL(triggered()),this,SLOT(SaveAs())); + contextActions.push_back(actionSave_image); + + QAction* actionSave_state = contextMenu.addAction(QIcon(QString::fromUtf8(":/common/icons/filesave.png")), + tr("Save Current State")); + connect(actionSave_state,SIGNAL(triggered()),this,SLOT(SaveCurrentState())); + contextActions.push_back(actionSave_state); + + QAction* actionRead_state = contextMenu.addAction(QIcon(QString::fromUtf8(":/common/icons/filesave.png")), + tr("Read Saved State")); + connect(actionRead_state,SIGNAL(triggered()),this,SLOT(ReadSavedState())); + contextActions.push_back(actionRead_state); + + contextMenu.addSeparator(); + + contextMenu.addAction(actionAdd_VF_to_current_Image); + contextActions.push_back(actionAdd_VF_to_current_Image); + + //QAction* actionAdd_Overlay_to_current_Image = menuOverlay->addAction(QIcon(QString::fromUtf8(":/common/icons/GPSup.png")), + // tr("Add overlay image to current image")); + contextMenu.addAction(actionAdd_overlay_image_to_current_image); + contextActions.push_back(actionAdd_overlay_image_to_current_image); + + contextMenu.addAction(actionAdd_fusion_image); + contextActions.push_back(actionAdd_fusion_image); + + contextMenu.addAction(actionAdd_USSequence_toCT); + contextActions.push_back(actionAdd_USSequence_toCT); + + + contextMenu.addSeparator(); + QAction* actionResetMatrix = contextMenu.addAction(QIcon(QString::fromUtf8(":/common/icons/identity.png")), + tr("Reset transformation to identity")); + connect(actionResetMatrix, SIGNAL(triggered()), this,SLOT(ResetTransformationToIdentity())); + + // TRIAL DS + /* + QMenu * m = new QMenu(menubar); + m->setTitle("TOTO"); + // m->setObjectName(QString::fromUtf8("TOTOTO")); + contextMenu.addMenu(m); + QAction * a = m->addAction(QIcon(QString::fromUtf8(":/common/icons/GPSup.png")), + tr("BIDON")); + QAction * b = m->addAction(QIcon(QString::fromUtf8(":/common/icons/GPSup.png")), + tr("BIDON2")); + m->addAction(a); + m->addAction(b); + connect(a,SIGNAL(triggered()),this,SLOT(AddFusionImage())); + */ + + //init the DataTree + mSlicerManagers.resize(0); + + QStringList header; + header.append(""); + header.append("TL"); + header.append("TR"); + header.append("BL"); + header.append("BR"); + header.append(""); + header.append(""); + header.append("Name"); + + DataTree->setHeaderLabels(header); + DataTree->resizeColumnToContents(COLUMN_TREE); + DataTree->resizeColumnToContents(COLUMN_UL_VIEW); + DataTree->resizeColumnToContents(COLUMN_UR_VIEW); + DataTree->resizeColumnToContents(COLUMN_DL_VIEW); + DataTree->resizeColumnToContents(COLUMN_DR_VIEW); + DataTree->resizeColumnToContents(COLUMN_CLOSE_IMAGE); + DataTree->resizeColumnToContents(COLUMN_RELOAD_IMAGE); + DataTree->resizeColumnToContents(COLUMN_IMAGE_NAME); + + viewMode = 1; + documentation = new vvDocumentation(); + help_dialog = new vvHelpDialog(); + dicomSeriesSelector = new vvDicomSeriesSelector(); + + inverseButton->setEnabled(0); + actionAdd_overlay_image_to_current_image->setEnabled(0); + actionSave_As->setEnabled(0); + actionAdd_VF_to_current_Image->setEnabled(0); + actionAdd_fusion_image->setEnabled(0); + actionAdd_USSequence_toCT->setEnabled(0); + + //init the sliders + verticalSliders.push_back(NOVerticalSlider); + verticalSliders.push_back(NEVerticalSlider); + verticalSliders.push_back(SOVerticalSlider); + verticalSliders.push_back(SEVerticalSlider); + + for (int i =0; i < 4; i++) + verticalSliders[i]->hide(); + + horizontalSliders.push_back(NOHorizontalSlider); + horizontalSliders.push_back(NEHorizontalSlider); + horizontalSliders.push_back(SOHorizontalSlider); + horizontalSliders.push_back(SEHorizontalSlider); + + for (int i =0; i < 4; i++) + horizontalSliders[i]->hide(); + + + connect(NOVerticalSlider,SIGNAL(valueChanged(int)),this,SLOT(NOVerticalSliderChanged())); + connect(NEVerticalSlider,SIGNAL(valueChanged(int)),this,SLOT(NEVerticalSliderChanged())); + connect(SOVerticalSlider,SIGNAL(valueChanged(int)),this,SLOT(SOVerticalSliderChanged())); + connect(SEVerticalSlider,SIGNAL(valueChanged(int)),this,SLOT(SEVerticalSliderChanged())); + + connect(NOHorizontalSlider,SIGNAL(valueChanged(int)),this,SLOT(NOHorizontalSliderMoved())); + connect(NEHorizontalSlider,SIGNAL(valueChanged(int)),this,SLOT(NEHorizontalSliderMoved())); + connect(SOHorizontalSlider,SIGNAL(valueChanged(int)),this,SLOT(SOHorizontalSliderMoved())); + connect(SEHorizontalSlider,SIGNAL(valueChanged(int)),this,SLOT(SEHorizontalSliderMoved())); + + //connect everything + connect(actionCompute_mid_position_image,SIGNAL(triggered()),this,SLOT(ComputeMidPosition())); + connect(actionDeformable_Registration,SIGNAL(triggered()),this,SLOT(ComputeDeformableRegistration())); + connect(actionWarp_image_with_vector_field,SIGNAL(triggered()),this,SLOT(WarpImage())); + connect(actionLoad_images,SIGNAL(triggered()),this,SLOT(OpenImages())); + connect(actionOpen_Dicom,SIGNAL(triggered()),this,SLOT(OpenDicom())); + connect(actionOpen_Dicom_Struct,SIGNAL(triggered()),this,SLOT(OpenDCStructContour())); + connect(actionOpen_VTK_contour,SIGNAL(triggered()),this,SLOT(OpenVTKContour())); + connect(actionOpen_Multiple_Images_As_One,SIGNAL(triggered()),this,SLOT(MergeImages())); + connect(actionSlice_Image_As_Multiple_Images,SIGNAL(triggered()),this,SLOT(SliceImages())); + connect(actionOpen_Image_With_Time,SIGNAL(triggered()),this,SLOT(OpenImageWithTime())); + connect(actionMerge_images_as_n_dim_t, SIGNAL(triggered()), this, SLOT(MergeImagesWithTime())); + connect(actionSave_As,SIGNAL(triggered()),this,SLOT(SaveAs())); + connect(actionSave_current_state,SIGNAL(triggered()),this,SLOT(SaveCurrentState())); + connect(actionRead_saved_state,SIGNAL(triggered()),this,SLOT(ReadSavedState())); + connect(actionExit,SIGNAL(triggered()),this,SLOT(close())); + connect(actionAdd_VF_to_current_Image,SIGNAL(triggered()),this,SLOT(OpenField())); + connect(actionAdd_fusion_image,SIGNAL(triggered()),this,SLOT(SelectFusionImage())); + connect(actionAdd_overlay_image_to_current_image,SIGNAL(triggered()), this,SLOT(SelectOverlayImage())); + connect(actionAdd_USSequence_toCT,SIGNAL(triggered()), this,SLOT(SelectFusionSequence())); + connect(actionNavigation_Help,SIGNAL(triggered()),this,SLOT(ShowHelpDialog())); + connect(actionDocumentation,SIGNAL(triggered()),this,SLOT(ShowDocumentation())); + connect(actionRegister_vv,SIGNAL(triggered()),this,SLOT(PopupRegisterForm())); + + + /////////////////////////////////////////////// + connect(actionSegmentation,SIGNAL(triggered()),this,SLOT(SegmentationOnCurrentImage())); + connect(actionSurface_Viewer,SIGNAL(triggered()),this,SLOT(SurfaceViewerLaunch())); + /////////////////////////////////////////////// + + actionNorth_East_Window->setEnabled(0); + actionNorth_West_Window->setEnabled(0); + actionSouth_East_Window->setEnabled(0); + actionSouth_West_Window->setEnabled(0); + + connect(actionNorth_East_Window,SIGNAL(triggered()),this,SLOT(SaveNEScreenshot())); + connect(actionNorth_West_Window,SIGNAL(triggered()),this,SLOT(SaveNOScreenshot())); + connect(actionSouth_East_Window,SIGNAL(triggered()),this,SLOT(SaveSEScreenshot())); + connect(actionSouth_West_Window,SIGNAL(triggered()),this,SLOT(SaveSOScreenshot())); + connect(actionSave_all_slices,SIGNAL(triggered()),this,SLOT(SaveScreenshotAllSlices())); + + connect(DataTree,SIGNAL(itemSelectionChanged()),this,SLOT(ImageInfoChanged())); + connect(DataTree,SIGNAL(itemClicked(QTreeWidgetItem*, int)),this, + SLOT(DisplayChanged(QTreeWidgetItem*, int))); + + connect(viewButton,SIGNAL(clicked()),this, SLOT(ChangeViewMode()) ); + connect(windowSpinBox,SIGNAL(editingFinished()),this,SLOT(WindowLevelEdited())); + connect(levelSpinBox,SIGNAL(editingFinished()),this,SLOT(WindowLevelEdited())); + connect(colorMapComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(UpdateColorMap())); + connect(presetComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(UpdateWindowLevel())); + connect(slicingPresetComboBox, SIGNAL(currentIndexChanged(int)),this,SLOT(UpdateSlicingPreset())); + connect(inverseButton,SIGNAL(clicked()),this,SLOT(SwitchWindowLevel())); + connect(applyWindowLevelToAllButton,SIGNAL(clicked()),this,SLOT(ApplyWindowLevelToAllImages())); + + connect(this,SIGNAL(customContextMenuRequested(QPoint)),this,SLOT(ShowContextMenu(QPoint))); + + connect(linkPanel,SIGNAL(addLink(QString,QString,bool)),this,SLOT(AddLink(QString,QString,bool))); + connect(linkPanel,SIGNAL(removeLink(QString,QString)),this,SLOT(RemoveLink(QString,QString))); + connect(overlayPanel,SIGNAL(VFPropertyUpdated(int,int,int,int,double,double,double)),this,SLOT(SetVFProperty(int,int,int,int,double,double,double))); + connect(overlayPanel,SIGNAL(OverlayPropertyUpdated(int,int,double,double)), + this,SLOT(SetOverlayProperty(int,int,double,double))); + connect(overlayPanel,SIGNAL(FusionPropertyUpdated(int,int,int,double,double, bool)), + this,SLOT(SetFusionProperty(int,int,int,double,double, bool))); + connect(landmarksPanel,SIGNAL(UpdateRenderWindows()),this,SLOT(UpdateRenderWindows())); + + connect(overlayPanel,SIGNAL(FusionSequencePropertyUpdated(int, bool, unsigned int)), + this,SLOT(SetFusionSequenceProperty(int, bool,unsigned int))); + + + playMode = 0;//pause + mFrameRate = 10; + playButton->setEnabled(0); + frameRateLabel->setEnabled(0); + frameRateSpinBox->setEnabled(0); + connect(playButton, SIGNAL(clicked()),this,SLOT(PlayPause())); + connect(frameRateSpinBox, SIGNAL(valueChanged(int)),this,SLOT(ChangeFrameRate(int))); + + goToCursorPushButton->setEnabled(0); + connect(goToCursorPushButton, SIGNAL(clicked()),this,SLOT(GoToCursor())); + + NOViewWidget->hide(); + NEViewWidget->hide(); + SOViewWidget->hide(); + SEViewWidget->hide(); + + //Recently opened files + std::list recent_files = GetRecentlyOpenedImages(); + recentlyOpenedFilesMenu=NULL; + if ( !recent_files.empty() ) { + createRecentlyOpenedFilesMenu(); + updateRecentlyOpenedFilesMenu(recent_files); + } + + // Adding all new tools (insertion in the menu) + vvToolManager::GetInstance()->InsertToolsInMenu(this); + vvToolManager::GetInstance()->EnableToolsInMenu(this, false); + + if (!CLITK_EXPERIMENTAL) + menuExperimental->menuAction()->setVisible(false); + + + QTimer * timerMemory = new QTimer(this); + //timerMemory->setInterval(5); + connect(timerMemory, SIGNAL(timeout()), this, SLOT(UpdateMemoryUsage())); + timerMemory->start(2000); + +} +//------------------------------------------------------------------------------ +void vvMainWindow::show() +{ + vvMainWindowBase::show(); + PopupRegisterForm(true); +} +//------------------------------------------------------------------------------ +void vvMainWindow::UpdateMemoryUsage() +{ + // clitk::PrintMemory(true); + if (clitk::GetMemoryUsageInMb() == 0) infoPanel->setMemoryInMb("NA"); + else infoPanel->setMemoryInMb(QString::number(clitk::GetMemoryUsageInMb())+" MiB"); +} +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +void vvMainWindow::createRecentlyOpenedFilesMenu() +{ + recentlyOpenedFilesMenu = new QMenu("Recently opened files..."); + recentlyOpenedFilesMenu->setIcon(QIcon(QString::fromUtf8(":/common/icons/open.png"))); + menuFile->insertMenu(actionOpen_Image_With_Time,recentlyOpenedFilesMenu); + menuFile->insertSeparator(actionOpen_Image_With_Time); +} +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ + +void vvMainWindow::updateRecentlyOpenedFilesMenu(const std::list &recent_files) +{ + if(recentlyOpenedFilesMenu==NULL) { + createRecentlyOpenedFilesMenu(); + } else { + recentlyOpenedFilesMenu->clear(); + } + for (std::list::const_iterator i = recent_files.begin(); i!=recent_files.end(); i++) { + QAction* current=new QAction(QIcon(QString::fromUtf8(":/common/icons/open.png")), i->c_str(),this); + recentlyOpenedFilesMenu->addAction(current); + connect(current,SIGNAL(triggered()),this,SLOT(OpenRecentImage())); + } +} +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +void vvMainWindow::ComputeMidPosition() +{ + bool ok; + int index=GetSlicerIndexFromItem(DataTree->selectedItems()[0]); + int ref = QInputDialog::getInteger(this,"Chose reference phase","Reference phase",0,0,\ + mSlicerManagers[index]->GetImage()->GetVTKImages().size()-1,1,&ok); + if (ok) { + vvMidPosition midp; + midp.slicer_manager = mSlicerManagers[index]; + midp.reference_image_index = ref; + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + midp.Update(); + if (midp.error) + QMessageBox::warning(this, "Error computing midposition image",midp.error_message.c_str()); + else { + QFileInfo info(midp.slicer_manager->GetFileName().c_str()); + AddImage(midp.output,info.path().toStdString()+"/"+info.completeBaseName().toStdString()+"_midposition.mhd"); + } + QApplication::restoreOverrideCursor(); + } +} +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +void vvMainWindow::AddContour(int image_index, vvMesh::Pointer contour, bool propagation) +{ + QTreeWidgetItem *item = new QTreeWidgetItem(); + item->setData(0,Qt::UserRole,"filename.vtk"); + item->setData(1,Qt::UserRole,tr("contour")); + QBrush brush; + brush.setColor(QColor(contour->r*255,contour->g*255,contour->b*255)); + brush.setStyle(Qt::SolidPattern); + item->setData(COLUMN_IMAGE_NAME,Qt::BackgroundRole,brush); + item->setData(COLUMN_IMAGE_NAME,Qt::DisplayRole,contour->structure_name.c_str()); + + for (int j = 1; j <= 4; j++) + item->setData(j,Qt::CheckStateRole,DataTree->topLevelItem(image_index)->data(j,Qt::CheckStateRole)); + + QTreePushButton* cButton = new QTreePushButton; + cButton->setItem(item); + cButton->setColumn(COLUMN_CLOSE_IMAGE); + cButton->setToolTip(tr("close image")); + cButton->setIcon(QIcon(QString::fromUtf8(":/common/icons/exit.png"))); + connect(cButton,SIGNAL(clickedInto(QTreeWidgetItem*, int)), + this,SLOT(CloseImage(QTreeWidgetItem*, int))); + + QTreePushButton* rButton = new QTreePushButton; + rButton->setItem(item); + rButton->setColumn(COLUMN_RELOAD_IMAGE); + rButton->setToolTip(tr("reload image")); + rButton->setIcon(QIcon(QString::fromUtf8(":/common/icons/rotateright.png"))); + rButton->setEnabled(false); + //Not implemented + //connect(rButton,SIGNAL(clickedInto(QTreeWidgetItem*, int)), + //this,SLOT(ReloadImage(QTreeWidgetItem*, int))); + + DataTree->topLevelItem(image_index)->setExpanded(1); + DataTree->topLevelItem(image_index)->addChild(item); + DataTree->setItemWidget(item, COLUMN_CLOSE_IMAGE, cButton); + DataTree->setItemWidget(item, COLUMN_RELOAD_IMAGE, rButton); + QString id = DataTree->topLevelItem(image_index)->data(COLUMN_IMAGE_NAME,Qt::UserRole).toString(); + item->setData(COLUMN_IMAGE_NAME,Qt::UserRole,id.toStdString().c_str()); + + UpdateTree(); + mSlicerManagers[image_index]->AddContour(contour,propagation); + mSlicerManagers[image_index]->Render(); +} +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +void vvMainWindow::OpenVTKContour() +{ + if (mSlicerManagers.size() > 0) { + QString Extensions = "Images ( *.vtk *.obj)"; + Extensions += ";;All Files (*)"; + QString file = QFileDialog::getOpenFileName(this,tr("Open vtkPolyData"),mInputPathName,Extensions); + if (file.isNull()) + return; + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + int index = GetSlicerIndexFromItem(DataTree->selectedItems()[0]); + vvMeshReader reader; + reader.SetImage(mSlicerManagers[index]->GetImage()); + reader.SetModeToVTK(); + reader.SetFilename(file.toStdString()); + reader.Update(); + AddContour(index,reader.GetOutput()[0],false); + QApplication::restoreOverrideCursor(); + } +} +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +void vvMainWindow::AddDCStructContour(int index, QString file) +{ + vvMeshReader reader; + reader.SetFilename(file.toStdString()); + vvStructSelector selector; + selector.SetStructures(reader.GetROINames()); + if (!mSlicerManagers[index]->GetVF().IsNull()) + selector.EnablePropagationCheckBox(); + if (selector.exec()) { + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + reader.SetSelectedItems(selector.getSelectedItems()); + reader.SetImage(mSlicerManagers[index]->GetImage()); + if (selector.PropagationEnabled()) + reader.SetPropagationVF(mSlicerManagers[index]->GetVF()); + reader.Update(); + std::vector contours=reader.GetOutput(); + for (std::vector::iterator i=contours.begin(); + i!=contours.end(); i++) + AddContour(index,*i,selector.PropagationEnabled()); + QApplication::restoreOverrideCursor(); + } +} + +//------------------------------------------------------------------------------ +void vvMainWindow::OpenDCStructContour() +{ + if (mSlicerManagers.size() > 0) { + QString Extensions = "Dicom Files ( *.dcm RS*)"; + Extensions += ";;All Files (*)"; + QString file = QFileDialog::getOpenFileName(this,tr("Merge Images"),mInputPathName,Extensions); + if (file.isNull()) + return; + int index = GetSlicerIndexFromItem(DataTree->selectedItems()[0]); + AddDCStructContour(index, file); + } +} +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +void vvMainWindow::ComputeDeformableRegistration() +{ + if (mSlicerManagers.size() > 0) { + int index = GetSlicerIndexFromItem(DataTree->selectedItems()[0]); + vvDeformationDialog dialog(index,mSlicerManagers); + if (dialog.exec()) { + std::string base_name=itksys::SystemTools::GetFilenameWithoutExtension(mSlicerManagers[dialog.GetInputFileIndex()]->GetFileName()); + AddField(dialog.GetOutput(),dialog.getFieldFile(),dialog.GetInputFileIndex()); + WarpImage(dialog.GetSelectedSlicer(),dialog.GetReferenceFrameIndex()); + } else + std::cout << "Error or user cancellation while computing deformation field..." << std::endl; + } else QMessageBox::information(this, "Need to open image","You must open an image first."); +} +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +void vvMainWindow::WarpImage() +{ + int index = GetSlicerIndexFromItem(DataTree->selectedItems()[0]); + if (!mSlicerManagers[index]->GetVF().IsNull()) { + bool ok; + int ref = QInputDialog::getInteger(this,"Chose reference phase","Reference phase",0,0,\ + mSlicerManagers[index]->GetImage()->GetVTKImages().size()-1,1,&ok); + if (ok) { + WarpImage(mSlicerManagers[index],ref); + } + } else + QMessageBox::warning(this,tr("No vector field"),tr("Sorry, can't warp without a vector field")); +} +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +void vvMainWindow::WarpImage(vvSlicerManager* selected_slicer,int reference_phase) +{ + if (!selected_slicer->GetVF().IsNull()) { + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + QFileInfo info(selected_slicer->GetFileName().c_str()); + vvImageWarp warp(selected_slicer->GetImage(),selected_slicer->GetVF(), + reference_phase,this); + if (warp.ComputeWarpedImage()) { + AddImage(warp.GetWarpedImage(),info.path().toStdString()+"/"+info.completeBaseName().toStdString()+"_warped.mhd"); + AddImage(warp.GetDiffImage() ,info.path().toStdString()+"/"+info.completeBaseName().toStdString()+"_diff.mhd"); + AddImage(warp.GetJacobianImage() ,info.path().toStdString()+"/"+info.completeBaseName().toStdString()+"_jacobian.mhd"); + QApplication::restoreOverrideCursor(); + } else { + QApplication::restoreOverrideCursor(); + QMessageBox::warning(this,tr("Different spacings"),tr("The vector field and image spacings must be the same in order to warp.")); + } + } else + QMessageBox::warning(this,tr("No vector field"),tr("Sorry, can't warp without a vector field.")); +} +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +vvMainWindow::~vvMainWindow() +{ + for (unsigned int i = 0; i < mSlicerManagers.size(); i++) { + if (mSlicerManagers[i] != NULL) + delete mSlicerManagers[i]; + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +QTabWidget * vvMainWindow::GetTab() +{ + return tabWidget; +} +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +void vvMainWindow::MergeImages() +{ + QString Extensions = EXTENSIONS; + Extensions += ";;All Files (*)"; + QStringList files = QFileDialog::getOpenFileNames(this,tr("Merge Images"),mInputPathName,Extensions); + if (files.isEmpty()) + return; + mInputPathName = itksys::SystemTools::GetFilenamePath(files[0].toStdString()).c_str(); + std::vector vector; + + unsigned int currentDim = 0; + std::vector currentSpacing; + std::vector currentSize; + std::vector currentOrigin; + + for (int i = 0; i < files.size(); i++) { + itk::ImageIOBase::Pointer reader = itk::ImageIOFactory::CreateImageIO( + files[i].toStdString().c_str(), itk::ImageIOFactory::ReadMode); + reader->SetFileName(files[i].toStdString().c_str()); + reader->ReadImageInformation(); + if (reader) { + //NOViewWidget->hide(); + //NEViewWidget->hide(); + //SOViewWidget->hide(); + //SEViewWidget->hide(); + if (i == 0) + currentDim = reader->GetNumberOfDimensions(); + bool IsOk = true; + for (unsigned int j = 0; j < currentDim; j++) { + if (i == 0) { + if (j == 0) { + currentSpacing.resize(currentDim); + currentSize.resize(currentDim); + currentOrigin.resize(currentDim); + } + currentOrigin[j] = reader->GetOrigin(j); + currentSpacing[j] = reader->GetSpacing(j); + currentSize[j] = reader->GetDimensions(j); + } else if (currentDim != reader->GetNumberOfDimensions() + || currentSpacing[j] != reader->GetSpacing(j) + || currentSize[j] != (int)reader->GetDimensions(j) + || currentOrigin[j] != reader->GetOrigin(j)) { + QString error = "Cannot read file (too different from others "; + error += files[i].toStdString().c_str(); + QMessageBox::information(this,tr("Reading problem"),error); + IsOk = false; + break; + } + } + if (IsOk) + vector.push_back(files[i].toStdString()); + } + } + if (vector.size() > 0) + LoadImages(vector, vvImageReader::MERGED); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void vvMainWindow::SliceImages() +{ + QString Extensions = EXTENSIONS; + Extensions += ";;All Files (*)"; + + QStringList files = QFileDialog::getOpenFileNames(this,tr("Slice Images"),mInputPathName,Extensions); + if (files.isEmpty()) + return; + mInputPathName = itksys::SystemTools::GetFilenamePath(files[0].toStdString()).c_str(); + std::vector vector; + for (int i = 0; i < files.size(); i++) + vector.push_back(files[i].toStdString()); + LoadImages(vector, vvImageReader::SLICED); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void vvMainWindow::MergeImagesWithTime() +{ + QString Extensions = EXTENSIONS; + Extensions += ";;All Files (*)"; + QStringList files = QFileDialog::getOpenFileNames(this,tr("Merge Images With Time"),mInputPathName,Extensions); + if (files.isEmpty()) + return; + mInputPathName = itksys::SystemTools::GetFilenamePath(files[0].toStdString()).c_str(); + std::vector vector; + + for (int i = 0; i < files.size(); i++) + vector.push_back(files[i].toStdString()); + sort(vector.begin(),vector.end()); + if (vector.size() > 1) + LoadImages(vector, vvImageReader::MERGEDWITHTIME); + else + QMessageBox::warning(this,tr("Reading problem"),"You need to select at least two images to merge images with time.\nIf you only want to open one image, please use the \"Open Image\" function."); +} +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +void vvMainWindow::OpenDicom() +{ + std::vector files; + + std::cout << "dicomSeriesSelector " << std::endl; + if (dicomSeriesSelector->exec() == QDialog::Accepted) { + files = *(dicomSeriesSelector->GetFilenames()); + LoadImages(files, vvImageReader::DICOM); + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void vvMainWindow::OpenImages() +{ + QString Extensions = EXTENSIONS; + Extensions += ";;All Files (*)"; + + QStringList files = QFileDialog::getOpenFileNames(this,tr("Load Images"),mInputPathName,Extensions); + if (files.isEmpty()) + return; + mInputPathName = itksys::SystemTools::GetFilenamePath(files[0].toStdString()).c_str(); + std::vector vector; + for (int i = 0; i < files.size(); i++) + vector.push_back(files[i].toStdString()); + LoadImages(vector, vvImageReader::IMAGE); +} +//------------------------------------------------------------------------------ +void vvMainWindow::OpenRecentImage() +{ + QAction * caller = qobject_cast(sender()); + std::vector images; + images.push_back(caller->text().toStdString()); + mInputPathName = itksys::SystemTools::GetFilenamePath(images[0]).c_str(); + LoadImages(images, vvImageReader::IMAGE); +} +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +void vvMainWindow::OpenImageWithTime() +{ + QString Extensions = EXTENSIONS; + Extensions += ";;All Files (*)"; + + QStringList files = QFileDialog::getOpenFileNames(this,tr("Load Images With Time"),mInputPathName,Extensions); + if (files.isEmpty()) + return; + mInputPathName = itksys::SystemTools::GetFilenamePath(files[0].toStdString()).c_str(); + std::vector vector; + for (int i = 0; i < files.size(); i++) { + vector.push_back(files[i].toStdString()); + } + LoadImages(vector, vvImageReader::IMAGEWITHTIME); +} +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +void vvMainWindow::LoadImages(std::vector files, vvImageReader::LoadedImageType filetype) +{ + //Separate the way to open images and dicoms + int fileSize; + if (filetype == vvImageReader::IMAGE || filetype == vvImageReader::IMAGEWITHTIME) + fileSize = files.size(); + else + fileSize = 1; + + // For SLICED, we need the number of slices (ndim and #slices) + std::vector nSlices; + nSlices.resize(files.size()); + std::fill(nSlices.begin(), nSlices.end(), 1); + if (filetype == vvImageReader::SLICED) { + for (int i = 0; i < fileSize; i++) { + itk::ImageIOBase::Pointer header = clitk::readImageHeader(files[i]); + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + if (!header) { + nSlices[i] = 0; + QString error = "Cannot open file \n"; + error += files[i].c_str(); + QMessageBox::information(this,tr("Reading problem"),error); + return; + } + if (header->GetNumberOfDimensions() < 3) { + nSlices[i] = 0; + QString error = "Dimension problem. Cannot slice \n"; + error += files[i].c_str(); + QMessageBox::information(this,tr("Reading problem"),error); + return; + } + nSlices[i] = header->GetDimensions( header->GetNumberOfDimensions()-1 ); + } + } + + //Only add to the list of recently opened files when a single file is opened, + //to avoid polluting the list of recently opened files + if (files.size() == 1) { + QFileInfo finfo=tr(files[0].c_str()); + AddToRecentlyOpenedImages(finfo.absoluteFilePath().toStdString()); + updateRecentlyOpenedFilesMenu(GetRecentlyOpenedImages()); + } + //init the progress events + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + vvProgressDialog progress("Opening " + files[0],fileSize>1); + qApp->processEvents(); + + int numberofsuccesulreads=0; + //open images as 1 or multiples + for (int i = 0; i < fileSize; i++) { + + progress.SetText("Opening " + files[i]); + progress.SetProgress(i,fileSize); + qApp->processEvents(); + + for (unsigned int j = 0; j < nSlices[i]; j++) { + //read the image and put it in mSlicerManagers + vvSlicerManager* imageManager = new vvSlicerManager(4); + qApp->processEvents(); + + bool SetImageSucceed=false; + + // Change filename if an image with the same already exist + int number = GetImageDuplicateFilenameNumber(files[i] + std::string("_slice")); + + if (filetype == vvImageReader::IMAGE || filetype == vvImageReader::IMAGEWITHTIME || filetype == vvImageReader::SLICED) + SetImageSucceed = imageManager->SetImage(files[i],filetype, number, j); + else { + SetImageSucceed = imageManager->SetImages(files,filetype, number); + } + if (!SetImageSucceed) { + QApplication::restoreOverrideCursor(); + QString error = "Cannot open file \n"; + error += imageManager->GetLastError().c_str(); + QMessageBox::information(this,tr("Reading problem"),error); + delete imageManager; + } else { + mSlicerManagers.push_back(imageManager); + + //create an item in the tree with good settings + QTreeWidgetItem *item = new QTreeWidgetItem(); + item->setData(0,Qt::UserRole,files[i].c_str()); + QFileInfo fileinfo(imageManager->GetFileName().c_str()); //Do not show the path + item->setData(COLUMN_IMAGE_NAME,Qt::DisplayRole,fileinfo.fileName()); + item->setData(1,Qt::UserRole,tr("image")); + item->setToolTip(COLUMN_IMAGE_NAME, imageManager->GetListOfAbsoluteFilePathInOneString("image").c_str()); + qApp->processEvents(); + + //Create the buttons for reload and close + qApp->processEvents(); + QTreePushButton* cButton = new QTreePushButton; + cButton->setItem(item); + cButton->setColumn(COLUMN_CLOSE_IMAGE); + cButton->setToolTip(tr("close image")); + cButton->setIcon(QIcon(QString::fromUtf8(":/common/icons/exit.png"))); + connect(cButton,SIGNAL(clickedInto(QTreeWidgetItem*, int)), + this,SLOT(CloseImage(QTreeWidgetItem*, int))); + + QTreePushButton* rButton = new QTreePushButton; + rButton->setItem(item); + rButton->setColumn(COLUMN_RELOAD_IMAGE); + rButton->setToolTip(tr("reload image")); + rButton->setIcon(QIcon(QString::fromUtf8(":/common/icons/rotateright.png"))); + connect(rButton,SIGNAL(clickedInto(QTreeWidgetItem*, int)), + this,SLOT(ReloadImage(QTreeWidgetItem*, int))); + + DataTree->addTopLevelItem(item); + DataTree->setItemWidget(item, COLUMN_CLOSE_IMAGE, cButton); + DataTree->setItemWidget(item, COLUMN_RELOAD_IMAGE, rButton); + + //set the id of the image + QString id = QDir::current().absoluteFilePath(files[i].c_str()) + QString::number(mSlicerManagers.size()-1); + item->setData(COLUMN_IMAGE_NAME,Qt::UserRole,id.toStdString().c_str()); + mSlicerManagers.back()->SetId(id.toStdString()); + + linkPanel->addImage(imageManager->GetFileName(), id.toStdString()); + + connect(mSlicerManagers.back(), SIGNAL(currentImageChanged(std::string)), + this,SLOT(CurrentImageChanged(std::string))); + connect(mSlicerManagers.back(), SIGNAL(currentPickedImageChanged(std::string)), + this, SLOT(CurrentPickedImageChanged(std::string))); + connect(mSlicerManagers.back(), SIGNAL(UpdatePosition(int, double, double, double, double, double, double, double)), + this,SLOT(MousePositionChanged(int,double, double, double, double, double, double, double))); + connect(mSlicerManagers.back(), SIGNAL(UpdateVector(int, double, double, double, double)), + this, SLOT(VectorChanged(int,double,double,double, double))); + connect(mSlicerManagers.back(), SIGNAL(UpdateOverlay(int, double, double)), + this, SLOT(OverlayChanged(int,double,double))); + connect(mSlicerManagers.back(), SIGNAL(UpdateFusion(int, double)), + this, SLOT(FusionChanged(int,double))); + //connect(mSlicerManagers.back(), SIGNAL(UpdateFusionSequence(int, bool, unsigned int)), + // this, SLOT(FusionSequenceChanged(int, bool, unsigned int))); + connect(mSlicerManagers.back(), SIGNAL(WindowLevelChanged()), + this,SLOT(WindowLevelChanged())); + connect(mSlicerManagers.back(), SIGNAL(UpdateSlice(int,int)), + this,SLOT(UpdateSlice(int,int))); + connect(mSlicerManagers.back(), SIGNAL(UpdateTSlice(int, int)), + this,SLOT(UpdateTSlice(int, int))); + connect(mSlicerManagers.back(), SIGNAL(UpdateTSlice(int, int)), + this,SLOT(ImageInfoChanged())); + connect(mSlicerManagers.back(), SIGNAL(UpdateSliceRange(int,int,int,int,int)), + this,SLOT(UpdateSliceRange(int,int,int,int,int))); + connect(mSlicerManagers.back(), SIGNAL(UpdateLinkManager(std::string,int,double,double,double,int)), + this,SLOT(UpdateLinkManager(std::string,int,double,double,double,int))); + connect(mSlicerManagers.back(), SIGNAL(UpdateLinkedNavigation(std::string,vvSlicerManager*,vvSlicer*)), + this,SLOT(UpdateLinkedNavigation(std::string,vvSlicerManager*,vvSlicer*))); + connect(mSlicerManagers.back(), SIGNAL(ChangeImageWithIndexOffset(vvSlicerManager*,int,int)), + this,SLOT(ChangeImageWithIndexOffset(vvSlicerManager*,int,int))); + connect(mSlicerManagers.back(),SIGNAL(LandmarkAdded()),landmarksPanel,SLOT(AddPoint())); + InitSlicers(); + numberofsuccesulreads++; + } + } + } + if (numberofsuccesulreads) { + NOViewWidget->show(); + NEViewWidget->show(); + SOViewWidget->show(); + SEViewWidget->show(); + UpdateTree(); + InitDisplay(); + ShowLastImage(); + + // Try to guess default WindowLevel + double range[2]; + mSlicerManagers.back()->GetImage()->GetFirstVTKImageData()->GetScalarRange(range); + if ((range[0] == 0) && (range[1] == 1)) { + presetComboBox->setCurrentIndex(5);// binary + } else { + // TODO + } + } + QApplication::restoreOverrideCursor(); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void vvMainWindow::UpdateTree() +{ + DataTree->resizeColumnToContents(COLUMN_TREE); + DataTree->resizeColumnToContents(COLUMN_UL_VIEW); + DataTree->resizeColumnToContents(COLUMN_UR_VIEW); + DataTree->resizeColumnToContents(COLUMN_DL_VIEW); + DataTree->resizeColumnToContents(COLUMN_DR_VIEW); + DataTree->resizeColumnToContents(COLUMN_IMAGE_NAME); + DataTree->resizeColumnToContents(COLUMN_CLOSE_IMAGE); + DataTree->resizeColumnToContents(COLUMN_RELOAD_IMAGE); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void vvMainWindow::CurrentImageChanged(std::string id) +{ + if (id == mCurrentSelectedImageId) return; // Do nothing + int selected = 0; + for (int i = 0; i < DataTree->topLevelItemCount(); i++) { + if (DataTree->topLevelItem(i)->data(COLUMN_IMAGE_NAME,Qt::UserRole).toString().toStdString() == id) { + selected = i; + } else { + DataTree->topLevelItem(i)->setSelected(0); + } + for (int child = 0; child < DataTree->topLevelItem(i)->childCount(); child++) + DataTree->topLevelItem(i)->child(child)->setSelected(0); + + } + DataTree->topLevelItem(selected)->setSelected(1); + mCurrentSelectedImageId = id; + emit SelectedImageHasChanged(mSlicerManagers[selected]); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void vvMainWindow::CurrentPickedImageChanged(std::string id) +{ + if (id == mCurrentPickedImageId) return; // Do nothing + int selected = 0; + for (int i = 0; i < DataTree->topLevelItemCount(); i++) { + if (DataTree->topLevelItem(i)->data(COLUMN_IMAGE_NAME,Qt::UserRole).toString().toStdString() == id) { + selected = i; + } else { + DataTree->topLevelItem(i)->setSelected(0); + } + for (int child = 0; child < DataTree->topLevelItem(i)->childCount(); child++) + DataTree->topLevelItem(i)->child(child)->setSelected(0); + + } + DataTree->topLevelItem(selected)->setSelected(1); + mCurrentPickedImageId = id; + mCurrentPickedImageIndex = selected; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void vvMainWindow::ImageInfoChanged() +{ + contextActions[6]->setEnabled(1); + contextActions[5]->setEnabled(1); + actionSave_As->setEnabled(1); + actionAdd_VF_to_current_Image->setEnabled(1); + actionAdd_fusion_image->setEnabled(1); + actionAdd_overlay_image_to_current_image->setEnabled(1); + actionAdd_USSequence_toCT->setEnabled(1); + actionNorth_East_Window->setEnabled(1); + actionNorth_West_Window->setEnabled(1); + actionSouth_East_Window->setEnabled(1); + actionSouth_West_Window->setEnabled(1); + vvToolManager::GetInstance()->EnableToolsInMenu(this, true); + inverseButton->setEnabled(1); + + goToCursorPushButton->setEnabled(1); + + if (DataTree->selectedItems().size()) { + int index = GetSlicerIndexFromItem(DataTree->selectedItems()[0]); + + colorMapComboBox->setEnabled(1); + for (int i = 0; i < DataTree->topLevelItem(index)->childCount(); i++) { + if (DataTree->topLevelItem(index)->child(i)->data(1,Qt::UserRole).toString() == "overlay" || + DataTree->topLevelItem(index)->child(i)->data(1,Qt::UserRole).toString() == "fusion" || + DataTree->topLevelItem(index)->child(i)->data(1,Qt::UserRole).toString() == "fusionSequence") { + colorMapComboBox->setEnabled(0); + break; + } + } + + std::vector origin; + std::vector inputSpacing; + std::vector inputSize; + std::vector sizeMM; + vtkSmartPointer transformation; + int dimension=0; + QString pixelType; + QString inputSizeInBytes; + QString image = DataTree->selectedItems()[0]->data(COLUMN_IMAGE_NAME,Qt::DisplayRole).toString(); + + int nframes = mSlicerManagers[index]->GetSlicer(0)->GetTMax(); + + if (nframes > 1 || playMode == 1) { + playButton->setEnabled(1); + frameRateLabel->setEnabled(1); + frameRateSpinBox->setEnabled(1); + } else { + playButton->setEnabled(0); + frameRateLabel->setEnabled(0); + frameRateSpinBox->setEnabled(0); + } + + //read image header + int NPixel = 1; + + int tSlice = 0; + vvImage::Pointer imageSelected; + if (DataTree->topLevelItem(index) == DataTree->selectedItems()[0]) { + imageSelected = mSlicerManagers[index]->GetSlicer(0)->GetImage(); + tSlice = mSlicerManagers[index]->GetSlicer(0)->GetTSlice(); + } else if (DataTree->selectedItems()[0]->data(1,Qt::UserRole).toString() == "vector") { + imageSelected = mSlicerManagers[index]->GetSlicer(0)->GetVF(); + tSlice = mSlicerManagers[index]->GetSlicer(0)->GetOverlayTSlice(); + } else if (DataTree->selectedItems()[0]->data(1,Qt::UserRole).toString() == "overlay") { + imageSelected = mSlicerManagers[index]->GetSlicer(0)->GetOverlay(); + tSlice = mSlicerManagers[index]->GetSlicer(0)->GetOverlayTSlice(); + } else if (DataTree->selectedItems()[0]->data(1,Qt::UserRole).toString() == "fusion") { + imageSelected = mSlicerManagers[index]->GetSlicer(0)->GetFusion(); + tSlice = mSlicerManagers[index]->GetSlicer(0)->GetFusionTSlice(); + } + else if (DataTree->selectedItems()[0]->data(1,Qt::UserRole).toString() == "fusionSequence") { + imageSelected = mSlicerManagers[index]->GetSlicer(0)->GetFusion(); + tSlice = mSlicerManagers[index]->GetSlicer(0)->GetFusionTSlice(); + } + else if (DataTree->selectedItems()[0]->data(1,Qt::UserRole).toString() == "contour") { + imageSelected = mSlicerManagers[index]->GetSlicer(0)->GetImage(); + tSlice = mSlicerManagers[index]->GetSlicer(0)->GetTSlice(); + } + else { + imageSelected = mSlicerManagers[index]->GetSlicer(0)->GetImage(); + tSlice = mSlicerManagers[index]->GetSlicer(0)->GetTSlice(); + } + + dimension = imageSelected->GetNumberOfDimensions(); + origin.resize(dimension); + inputSpacing.resize(dimension); + inputSize.resize(dimension); + sizeMM.resize(dimension); + pixelType = mSlicerManagers[index]->GetImage()->GetScalarTypeAsITKString().c_str(); + for (int i = 0; i < dimension; i++) { + origin[i] = imageSelected->GetOrigin()[i]; + inputSpacing[i] = imageSelected->GetSpacing()[i]; + inputSize[i] = imageSelected->GetSize()[i]; + sizeMM[i] = inputSize[i]*inputSpacing[i]; + NPixel *= inputSize[i]; + } + inputSizeInBytes = GetSizeInBytes(imageSelected->GetActualMemorySize()*1000); + + QString dim = QString::number(dimension) + " ("; + dim += pixelType + ")"; + + infoPanel->setFileName(image); + infoPanel->setDimension(dim); + infoPanel->setSizePixel(GetVectorIntAsString(inputSize)); + infoPanel->setSizeMM(GetVectorDoubleAsString(sizeMM)); + infoPanel->setOrigin(GetVectorDoubleAsString(origin)); + infoPanel->setSpacing(GetVectorDoubleAsString(inputSpacing)); + infoPanel->setNPixel(QString::number(NPixel)+" ("+inputSizeInBytes+")"); + + transformation = imageSelected->GetTransform()[tSlice]->GetMatrix(); + infoPanel->setTransformation(Get4x4MatrixDoubleAsString(transformation)); + + landmarksPanel->SetCurrentLandmarks(mSlicerManagers[index]->GetLandmarks(), + mSlicerManagers[index]->GetSlicer(0)->GetImage()->GetVTKImages().size()); + landmarksPanel->SetCurrentPath(mInputPathName.toStdString()); + landmarksPanel->SetCurrentImage(mSlicerManagers[index]->GetFileName().c_str()); + + overlayPanel->getCurrentImageName(mSlicerManagers[index]->GetFileName().c_str()); + for (int i = 0; i < 4; i++) { + if (DataTree->selectedItems()[0]->data(i+1,Qt::CheckStateRole).toInt() > 0 || i == 3) { + mSlicerManagers[index]->UpdateInfoOnCursorPosition(i); + break; + } + } + + infoPanel->setFileName(image); + infoPanel->setDimension(dim); + infoPanel->setSizePixel(GetVectorIntAsString(inputSize)); + infoPanel->setSizeMM(GetVectorDoubleAsString(sizeMM)); + infoPanel->setOrigin(GetVectorDoubleAsString(origin)); + infoPanel->setSpacing(GetVectorDoubleAsString(inputSpacing)); + infoPanel->setNPixel(QString::number(NPixel)+" ("+inputSizeInBytes+")"); + + landmarksPanel->SetCurrentLandmarks(mSlicerManagers[index]->GetLandmarks(), + mSlicerManagers[index]->GetSlicer(0)->GetImage()->GetVTKImages().size()); + landmarksPanel->SetCurrentPath(mInputPathName.toStdString()); + landmarksPanel->SetCurrentImage(mSlicerManagers[index]->GetFileName().c_str()); + + overlayPanel->getCurrentImageName(mSlicerManagers[index]->GetFileName().c_str()); + for (int i = 0; i < 4; i++) { + if (DataTree->selectedItems()[0]->data(i+1,Qt::CheckStateRole).toInt() > 0 || i == 3) { + mSlicerManagers[index]->UpdateInfoOnCursorPosition(i); + break; + } + } + WindowLevelChanged(); + + slicingPresetComboBox->setCurrentIndex(mSlicerManagers[index]->GetSlicingPreset()); + + if (mSlicerManagers[index]->GetSlicer(0)->GetVF()) { + overlayPanel->getVFName(mSlicerManagers[index]->GetVFName().c_str()); + overlayPanel->getVFProperty(mSlicerManagers[index]->GetSlicer(0)->GetVFSubSampling(), + mSlicerManagers[index]->GetSlicer(0)->GetVFScale(), + mSlicerManagers[index]->GetSlicer(0)->GetVFLog()); + } else { + overlayPanel->getVFName(mSlicerManagers[index]->GetVFName().c_str()); + overlayPanel->getVFProperty(-1,-1,-1); + } + if (mSlicerManagers[index]->GetSlicer(0)->GetOverlay()) { + overlayPanel->getOverlayName(mSlicerManagers[index]->GetOverlayName().c_str()); + } else { + overlayPanel->getOverlayName(mSlicerManagers[index]->GetOverlayName().c_str()); + } + + if (mSlicerManagers[index]->GetSlicer(0)->GetFusion()) { + overlayPanel->getFusionName(mSlicerManagers[index]->GetFusionName().c_str()); + } else { + overlayPanel->getFusionName(mSlicerManagers[index]->GetFusionName().c_str()); + } + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void vvMainWindow::ShowDocumentation() +{ + documentation->show(); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void vvMainWindow::PopupRegisterForm(bool checkCanPush) +{ + vvRegisterForm* registerForm = new vvRegisterForm(QUrl("http://www.creatis.insa-lyon.fr/~dsarrut/vvregister/write.php"), getVVSettingsPath(), getSettingsOptionFormat()); + if(!checkCanPush) { + registerForm->show(); + } else { + if(registerForm->canPush()) { + registerForm->show(); + registerForm->acquitPushed();//too bad if there is not internet connection anymore. + } + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void vvMainWindow::ShowHelpDialog() +{ + help_dialog->show(); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void vvMainWindow::ChangeViewMode() +{ + typedef struct _SIZE{ + QSplitter* splitter; + QList size1, size2; + int cols[3]; + }SplitterSize; + SplitterSize sizes[4]; + sizes[0].splitter = OSplitter; + sizes[0].size1.push_back(1); + sizes[0].size1.push_back(0); + sizes[0].size2.push_back(1); + sizes[0].size2.push_back(0); + sizes[0].cols[0] = 2; + sizes[0].cols[1] = 3; + sizes[0].cols[2] = 4; + + sizes[1].splitter = ESplitter; + sizes[1].size1.push_back(0); + sizes[1].size1.push_back(1); + sizes[1].size2.push_back(1); + sizes[1].size2.push_back(0); + sizes[1].cols[0] = 1; + sizes[1].cols[1] = 3; + sizes[1].cols[2] = 4; + + sizes[2].splitter = OSplitter; + sizes[2].size1.push_back(1); + sizes[2].size1.push_back(0); + sizes[2].size2.push_back(0); + sizes[2].size2.push_back(1); + sizes[2].cols[0] = 1; + sizes[2].cols[1] = 2; + sizes[2].cols[2] = 4; + + sizes[3].splitter = ESplitter; + sizes[3].size1.push_back(0); + sizes[3].size1.push_back(1); + sizes[3].size2.push_back(0); + sizes[3].size2.push_back(1); + sizes[3].cols[0] = 1; + sizes[3].cols[1] = 2; + sizes[3].cols[2] = 3; + + int slicer = mSlicerManagers[mCurrentPickedImageIndex]->GetSelectedSlicer(); + if (viewMode == 1) { + if (slicer >= 0) { + viewMode = 0; + splitter_3->setSizes(sizes[slicer].size1); + sizes[slicer].splitter->setSizes(sizes[slicer].size2); + DataTree->setColumnHidden(sizes[slicer].cols[0],1); + DataTree->setColumnHidden(sizes[slicer].cols[1],1); + DataTree->setColumnHidden(sizes[slicer].cols[2],1); + } + } else { + QList size; + if (slicer >= 0) { + viewMode = 1; + size.push_back(1); + size.push_back(1); + splitter_3->setSizes(size); + sizes[slicer].splitter->setSizes(size); + DataTree->setColumnHidden(sizes[slicer].cols[0],0); + DataTree->setColumnHidden(sizes[slicer].cols[1],0); + DataTree->setColumnHidden(sizes[slicer].cols[2],0); + } + } + UpdateRenderWindows(); + /* + ** I don't know why but for both resized QVTKWidget we also need to render + ** the associated Slicer to redraw crosses. + */ + for (unsigned int i = 0; i < mSlicerManagers.size(); i++) { +// if (DataTree->topLevelItem(i)->data(COLUMN_UL_VIEW,Qt::CheckStateRole).toInt() > 1) + mSlicerManagers[i]->GetSlicer(0)->Render(); + mSlicerManagers[i]->GetSlicer(1)->Render(); +// if (DataTree->topLevelItem(i)->data(COLUMN_DL_VIEW,Qt::CheckStateRole).toInt() > 1) + mSlicerManagers[i]->GetSlicer(2)->Render(); + mSlicerManagers[i]->GetSlicer(3)->Render(); + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +QString vvMainWindow::GetSizeInBytes(unsigned long size) +{ + QString result = "";// QString::number(size); + //result += " bytes ("; + if (size > 1000000000) { + size /= 1000000000; + result += QString::number(size); + result += "Gb";//)"; + } else if (size > 1000000) { + size /= 1000000; + result += QString::number(size); + result += "Mb";//)"; + } else if (size > 1000) { + size /= 1000; + result += QString::number(size); + result += "kb";//)"; + } + return result; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +QString vvMainWindow::Get4x4MatrixDoubleAsString(vtkSmartPointer matrix, const int precision) +{ + std::ostringstream strmatrix; + + // Figure out the number of digits of the integer part of the largest absolute value + // for each column + unsigned width[4]; + for (unsigned int j = 0; j < 4; j++){ + double absmax = 0.; + for (unsigned int i = 0; i < 4; i++) + absmax = std::max(absmax, vnl_math_abs(matrix->GetElement(i, j))); + unsigned ndigits = (unsigned)std::max(0.,std::log10(absmax))+1; + width[j] = precision+ndigits+3; + } + + // Output with correct width, aligned to the right + for (unsigned int i = 0; i < 4; i++) { + for (unsigned int j = 0; j < 4; j++) { + strmatrix.setf(ios::fixed,ios::floatfield); + strmatrix.precision(precision); + strmatrix.fill(' '); + strmatrix.width(width[j]); + strmatrix << std::right << matrix->GetElement(i, j); + } + strmatrix << std::endl; + } + QString result = strmatrix.str().c_str(); + return result; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +QString vvMainWindow::GetVectorDoubleAsString(std::vector vectorDouble) +{ + QString result; + for (unsigned int i= 0; i < vectorDouble.size(); i++) { + if (i != 0) + result += " "; + result += QString::number(vectorDouble[i]); + } + return result; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +QString vvMainWindow::GetVectorIntAsString(std::vector vectorInt) +{ + QString result; + for (unsigned int i= 0; i < vectorInt.size(); i++) { + if (i != 0) + result += " "; + result += QString::number(vectorInt[i]); + } + return result; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +int vvMainWindow::GetSlicerIndexFromItem(QTreeWidgetItem* item) +{ + QString id = item->data(COLUMN_IMAGE_NAME,Qt::UserRole).toString(); + for (int i = 0; i < DataTree->topLevelItemCount(); i++) { + if (DataTree->topLevelItem(i)->data(COLUMN_IMAGE_NAME,Qt::UserRole).toString() == id) + return i; + } + return -1; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +QTreeWidgetItem* vvMainWindow::GetItemFromSlicerManager(vvSlicerManager* sm) +{ + QString id = sm->GetId().c_str(); + for (int i = 0; i < DataTree->topLevelItemCount(); i++) { + if (DataTree->topLevelItem(i)->data(COLUMN_IMAGE_NAME,Qt::UserRole).toString() == id) + return DataTree->topLevelItem(i); + } + return NULL; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void vvMainWindow::DisplayChanged(QTreeWidgetItem *clickedItem, int column) +{ + if ( column >= COLUMN_CLOSE_IMAGE || column <= 0) + return; + + // Get parent information (might be the same item) + int slicerManagerIndex = GetSlicerIndexFromItem(clickedItem); + QTreeWidgetItem* clickedParentItem = DataTree->topLevelItem(slicerManagerIndex); + vvSlicer* clickedSlicer = mSlicerManagers[slicerManagerIndex]->GetSlicer(column-1); + + // Go over the complete item tree (only 2 levels, parents and children) + for (unsigned int i = 0; i < mSlicerManagers.size(); i++) { + // Trick to avoid redoing twice the job for a key (sr) + mSlicerManagers[i]->GetSlicer(column-1)->GetRenderWindow()->GetInteractor()->SetKeySym("Crap"); + + QTreeWidgetItem* currentParentItem = DataTree->topLevelItem(i); + if(currentParentItem != clickedParentItem) { + // Not the branch of the clicked item, uncheck all + + // Parent + currentParentItem->setData(column,Qt::CheckStateRole, 0); + mSlicerManagers[i]->UpdateSlicer(column-1, false); + + // Children + for (int iChild = 0; iChild < currentParentItem->childCount(); iChild++) { + currentParentItem->child(iChild)->setData(column,Qt::CheckStateRole, 0); + } + } + else { + // Branch of the clicked one: get check status from actor visibility in slicer + // and toggle the clicked one + + // Parent + bool vis = clickedSlicer->GetActorVisibility("image", 0); + bool draw = clickedSlicer->GetRenderer()->GetDraw(); + + // Update slicer (after getting visibility) + mSlicerManagers[slicerManagerIndex]->UpdateSlicer(column-1, true); + mSlicerManagers[slicerManagerIndex]->UpdateInfoOnCursorPosition(column-1); + DisplaySliders(slicerManagerIndex, column-1); + if(clickedParentItem == clickedItem) { + // Toggle + vis = !draw || !vis; + } + clickedSlicer->SetActorVisibility("image", 0, vis); + clickedParentItem->setData(column, Qt::CheckStateRole, vis?2:0); + + // Children + std::map actorTypeCounts; + for (int iChild = 0; iChild < clickedParentItem->childCount(); iChild++) { + QTreeWidgetItem* currentChildItem = clickedParentItem->child(iChild); + std::string actorType = currentChildItem->data(1,Qt::UserRole).toString().toStdString(); + vis = clickedSlicer->GetActorVisibility(actorType, actorTypeCounts[actorType]); + if(currentChildItem == clickedItem) { + // Toggle or force visibility if it was not on this branch so far + vis = !draw || !vis; + clickedSlicer->SetActorVisibility(actorType, actorTypeCounts[actorType], vis); + } + currentChildItem->setData(column, Qt::CheckStateRole, vis?2:0); + actorTypeCounts[actorType]++; + } + } + } + + clickedSlicer->Render(); +} +//------------------------------------------------------------------------------ + +void vvMainWindow::InitSlicers() +{ + if (mSlicerManagers.size()) { + mSlicerManagers.back()->GenerateDefaultLookupTable(); + + mSlicerManagers.back()->SetSlicerWindow(0,NOViewWidget->GetRenderWindow()); + mSlicerManagers.back()->SetSlicerWindow(1,NEViewWidget->GetRenderWindow()); + mSlicerManagers.back()->SetSlicerWindow(2,SOViewWidget->GetRenderWindow()); + mSlicerManagers.back()->SetSlicerWindow(3,SEViewWidget->GetRenderWindow()); + } +} + +//------------------------------------------------------------------------------ +void vvMainWindow::InitDisplay() +{ + if (mSlicerManagers.size()) { + //BE CAREFUL : this is absolutely necessary to set the interactor style + //in order to have the same style instanciation for all SlicerManagers in + // a same window + for (int j = 0; j < 4; j++) { + vvInteractorStyleNavigator* style = vvInteractorStyleNavigator::New(); + style->SetAutoAdjustCameraClippingRange(1); + bool AlreadySelected = false; + for (int i = 0; i < DataTree->topLevelItemCount(); i++) { + mSlicerManagers[i]->SetInteractorStyleNavigator(j,style); + + //select the image only if previous are not selected + if (DataTree->topLevelItem(i)->data(j+1,Qt::CheckStateRole).toInt() > 1) { + mSlicerManagers[i]->UpdateSlicer(j,1); + AlreadySelected = true; + } else if (i == DataTree->topLevelItemCount()-1 && !AlreadySelected) { + if (DataTree->selectedItems().size() == 0) + DataTree->topLevelItem(i)->setSelected(1); + DataTree->topLevelItem(i)->setData(j+1,Qt::CheckStateRole,2); + mSlicerManagers[i]->UpdateSlicer(j,1); + DisplaySliders(i,j); + } else { + DataTree->topLevelItem(i)->setData(j+1,Qt::CheckStateRole,0); + mSlicerManagers[i]->UpdateSlicer(j,0); + } + } + style->Delete(); + } + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void vvMainWindow::DisplaySliders(int slicer, int window) +{ + if(!mSlicerManagers[slicer]->GetSlicer(window)->GetRenderer()->GetDraw()) + return; + + int range[2]; + mSlicerManagers[slicer]->GetSlicer(window)->GetSliceRange(range); + int position = mSlicerManagers[slicer]->GetSlicer(window)->GetSlice(); + if (range[1]>0) + verticalSliders[window]->show(); + else + verticalSliders[window]->hide(); + verticalSliders[window]->setRange(range[0],range[1]); + verticalSliders[window]->setValue(position); + + int tRange[2]; + tRange[0] = 0; + tRange[1] = mSlicerManagers[slicer]->GetSlicer(window)->GetTMax(); + if (tRange[1]>0) + horizontalSliders[window]->show(); + else + horizontalSliders[window]->hide(); + horizontalSliders[window]->setRange(tRange[0],tRange[1]); + int tPosition = mSlicerManagers[slicer]->GetSlicer(window)->GetMaxCurrentTSlice(); + horizontalSliders[window]->setValue(tPosition); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void vvMainWindow::CloseImage(QTreeWidgetItem* item, int column) +{ + int index = GetSlicerIndexFromItem(item); + + if (DataTree->topLevelItem(index) != item) { + QString warning = "Do you really want to close the overlay : "; + warning += item->data(COLUMN_IMAGE_NAME,Qt::DisplayRole).toString(); + QMessageBox msgBox(QMessageBox::Warning, tr("Close Overlay"), + warning, 0, this); + msgBox.addButton(tr("Close"), QMessageBox::AcceptRole); + msgBox.addButton(tr("Cancel"), QMessageBox::RejectRole); + if (msgBox.exec() == QMessageBox::AcceptRole) { + std::string overlay_type=item->data(1,Qt::UserRole).toString().toStdString(); + int overlay_index=0; + for (int child = 0; child < DataTree->topLevelItem(index)->childCount(); child++) { + if (DataTree->topLevelItem(index)->\ + child(child)->data(1,Qt::UserRole).toString().toStdString() == overlay_type) + overlay_index++; + if (DataTree->topLevelItem(index)->child(child) == item) break; + } + mSlicerManagers[index]->RemoveActor(overlay_type, overlay_index-1); + mSlicerManagers[index]->SetColorMap(0); + DataTree->topLevelItem(index)->takeChild(DataTree->topLevelItem(index)->indexOfChild(item)); + mSlicerManagers[index]->Render(); + } + } else if (DataTree->topLevelItemCount() <= 1) { + QString warning = "Do you really want to close the image : "; + warning += item->data(COLUMN_IMAGE_NAME,Qt::DisplayRole).toString(); + warning += "\nThis is the last image, you're about to close vv !!!"; + QMessageBox msgBox(QMessageBox::Warning, tr("Close Image"), + warning, 0, this); + msgBox.addButton(tr("Close vv"), QMessageBox::AcceptRole); + msgBox.addButton(tr("Cancel"), QMessageBox::RejectRole); + if (msgBox.exec() == QMessageBox::AcceptRole) { + this->close(); + } + } else { + QString warning = "Do you really want to close the image : "; + warning += item->data(COLUMN_IMAGE_NAME,Qt::DisplayRole).toString(); + QMessageBox msgBox(QMessageBox::Warning, tr("Close Image"), + warning, 0, this); + msgBox.addButton(tr("Close"), QMessageBox::AcceptRole); + msgBox.addButton(tr("Cancel"), QMessageBox::RejectRole); + if (msgBox.exec() == QMessageBox::AcceptRole) { + + // Tell tools that we close an image + emit AnImageIsBeingClosed(mSlicerManagers[index]); + + std::vector::iterator Manageriter = mSlicerManagers.begin(); + DataTree->takeTopLevelItem(index); + for (int i = 0; i < index; i++) { + Manageriter++; + } + linkPanel->removeImage(index); + mSlicerManagers[index]->RemoveActors(); + delete mSlicerManagers[index]; + mSlicerManagers.erase(Manageriter); + + // + InitDisplay(); + } + } + ImageInfoChanged(); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void vvMainWindow::ReloadImage(QTreeWidgetItem* item, int column) +{ + // int index = GetSlicerIndexFromItem(item); + // QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + // if (item->data(1,Qt::UserRole).toString() == "vector") + // mSlicerManagers[index]->ReloadVF(); + // else + // mSlicerManagers[index]->Reload(); + + // QApplication::restoreOverrideCursor(); + int index = GetSlicerIndexFromItem(item); + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + QString role=item->data(1,Qt::UserRole).toString(); + if ( role == "vector"){ + mSlicerManagers[index]->ReloadVF(); + } + else if (role == "overlay"){ + mSlicerManagers[index]->ReloadOverlay(); + } + else if (role == "fusion"){ + mSlicerManagers[index]->ReloadFusion(); + } + else if (role == "fusionSequence"){ + mSlicerManagers[index]->ReloadFusionSequence(); //same as for standard fusion + } + else{ + mSlicerManagers[index]->Reload(); + } + // Update view and info + ImageInfoChanged(); + mSlicerManagers[index]->Render(); + QApplication::restoreOverrideCursor(); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void vvMainWindow::MousePositionChanged(int visibility,double x, double y, double z, double X, double Y, double Z , double value) +{ + infoPanel->setCurrentInfo(visibility,x,y,z,X,Y,Z,value); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void vvMainWindow::VectorChanged(int visibility,double x, double y, double z, double value) +{ + overlayPanel->getCurrentVectorInfo(visibility,x,y,z,value); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void vvMainWindow::OverlayChanged(int visibility, double valueOver, double valueRef) +{ + overlayPanel->getCurrentOverlayInfo(visibility,valueOver, valueRef); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void vvMainWindow::FusionChanged(int visibility, double value) +{ + overlayPanel->getCurrentFusionInfo(visibility,value); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void vvMainWindow::WindowLevelChanged() +{ + // Base image + int index = GetSlicerIndexFromItem(DataTree->selectedItems()[0]); + if(index==-1) return; + windowSpinBox->setValue(mSlicerManagers[index]->GetColorWindow()); + levelSpinBox->setValue(mSlicerManagers[index]->GetColorLevel()); + colorMapComboBox->setCurrentIndex(mSlicerManagers[index]->GetColorMap()); + presetComboBox->setCurrentIndex(mSlicerManagers[index]->GetPreset()); + + // Overlay image + if (mSlicerManagers[index]->GetSlicer(0)->GetOverlay()) + overlayPanel->getOverlayProperty(mSlicerManagers[index]->GetOverlayColor(), + mSlicerManagers[index]->GetLinkOverlayWindowLevel(), + mSlicerManagers[index]->GetOverlayColorWindow(), + mSlicerManagers[index]->GetOverlayColorLevel()); + else + overlayPanel->getOverlayProperty(-1,0,0.,0.); + + // Fusion & SequenceFusion image + if (mSlicerManagers[index]->GetSlicer(0)->GetFusion()) { + overlayPanel->getFusionProperty(mSlicerManagers[index]->GetFusionOpacity(), + mSlicerManagers[index]->GetFusionThresholdOpacity(), + mSlicerManagers[index]->GetFusionColorMap(), + mSlicerManagers[index]->GetFusionWindow(), + mSlicerManagers[index]->GetFusionLevel()); + overlayPanel->getFusionSequenceProperty(mSlicerManagers[index]->GetFusionSequenceFrameIndex(), + mSlicerManagers[index]->GetFusionSequenceSpatialSyncFlag(), + mSlicerManagers[index]->GetFusionSequenceNbFrames()); + } + else if ( mSlicerManagers[index]->GetFusionSequenceIndexOfLinkedManager()>=0 ) { + //if the image is involved in a fusion sequence, preserve the overlay panel! + int ind = mSlicerManagers[index]->GetFusionSequenceIndexOfLinkedManager(); + overlayPanel->getFusionProperty(mSlicerManagers[index]->GetFusionOpacity(), + mSlicerManagers[ind]->GetFusionThresholdOpacity(), + mSlicerManagers[ind]->GetFusionColorMap(), + mSlicerManagers[ind]->GetFusionWindow(), + mSlicerManagers[ind]->GetFusionLevel()); + overlayPanel->getFusionSequenceProperty(mSlicerManagers[ind]->GetFusionSequenceFrameIndex(), + mSlicerManagers[ind]->GetFusionSequenceSpatialSyncFlag(), + mSlicerManagers[ind]->GetFusionSequenceNbFrames()); + } + else + { + overlayPanel->getFusionProperty(-1, -1, -1, -1, -1); + overlayPanel->getFusionSequenceProperty(-1, false, 0); + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void vvMainWindow::WindowLevelEdited() +{ + presetComboBox->setCurrentIndex(6); + UpdateWindowLevel(); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void vvMainWindow::SetWindowLevel(double w, double l) +{ + windowSpinBox->setValue(w); + levelSpinBox->setValue(l); + presetComboBox->setCurrentIndex(6); + colorMapComboBox->setCurrentIndex(0); + UpdateWindowLevel(); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void vvMainWindow::UpdateWindowLevel() +{ + if (DataTree->selectedItems().size()) { + if (presetComboBox->currentIndex() == 7) //For ventilation + colorMapComboBox->setCurrentIndex(5); + int index = GetSlicerIndexFromItem(DataTree->selectedItems()[0]); + mSlicerManagers[index]->SetColorWindow(windowSpinBox->value()); + mSlicerManagers[index]->SetColorLevel(levelSpinBox->value()); + mSlicerManagers[index]->SetPreset(presetComboBox->currentIndex()); + mSlicerManagers[index]->Render(); + WindowLevelChanged(); + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void vvMainWindow::UpdateSlicingPreset() +{ + if (DataTree->selectedItems().size()) { + int index = GetSlicerIndexFromItem(DataTree->selectedItems()[0]); + mSlicerManagers[index]->SetSlicingPreset(vvSlicerManager::SlicingPresetType(slicingPresetComboBox->currentIndex())); + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void vvMainWindow::UpdateColorMap() +{ + if (DataTree->selectedItems().size()) { + int index = GetSlicerIndexFromItem(DataTree->selectedItems()[0]); + mSlicerManagers[index]->SetColorMap(colorMapComboBox->currentIndex()); + mSlicerManagers[index]->Render(); + } +} +//------------------------------------------------------------------------------ +void vvMainWindow::SwitchWindowLevel() +{ + int index = GetSlicerIndexFromItem(DataTree->selectedItems()[0]); + int window = mSlicerManagers[index]->GetColorWindow(); + presetComboBox->setCurrentIndex(6); + windowSpinBox->setValue(-window); + UpdateWindowLevel(); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void vvMainWindow::ApplyWindowLevelToAllImages() +{ + int index = GetSlicerIndexFromItem(DataTree->selectedItems()[0]); + if(index==-1) return; + double window = mSlicerManagers[index]->GetColorWindow(); + double level = mSlicerManagers[index]->GetColorLevel(); + + for (unsigned int i = 0; i < mSlicerManagers.size(); i++) { + if (mSlicerManagers[i] == NULL) + continue; + mSlicerManagers[i]->SetColorWindow(window); + mSlicerManagers[i]->SetColorLevel(level); + mSlicerManagers[i]->SetPreset(6); + mSlicerManagers[i]->Render(); + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void vvMainWindow::ApplyWindowToSetOfImages(double window, unsigned int indexMin, unsigned int indexMax) +{ + for (unsigned int i = indexMin; i <= indexMax && i < mSlicerManagers.size(); i++) { + if (mSlicerManagers[i] == NULL) + continue; + mSlicerManagers[i]->SetColorWindow(window); + mSlicerManagers[i]->SetPreset(6); + mSlicerManagers[i]->Render(); + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void vvMainWindow::ApplyLevelToSetOfImages(double level, unsigned int indexMin, unsigned int indexMax) +{ + for (unsigned int i = indexMin; i <= indexMax && i < mSlicerManagers.size(); i++) { + if (mSlicerManagers[i] == NULL) + continue; + mSlicerManagers[i]->SetColorLevel(level); + mSlicerManagers[i]->SetPreset(6); + mSlicerManagers[i]->Render(); + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void vvMainWindow::UpdateLinkManager(std::string id, int slicer, double x, double y, double z, int temps) +{ + for (unsigned int i = 0; i < mSlicerManagers.size(); i++) { + if (mSlicerManagers[i]->GetId() == id) { + //mSlicerManagers[i]->SetTSlice(temps); + if (temps<0) { //for fusionSequence, special input used to avoid any automatic time synchronization... + mSlicerManagers[i]->GetSlicer(slicer)->SetCurrentPosition( x,y,z, mSlicerManagers[i]->GetSlicer(slicer)->GetTSlice() ); + } + else mSlicerManagers[i]->GetSlicer(slicer)->SetCurrentPosition(x,y,z,temps); + mSlicerManagers[i]->UpdateViews(0,slicer); + break; + } + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void vvMainWindow::UpdateLinkedNavigation(std::string id, vvSlicerManager * sm, vvSlicer* refSlicer) +{ + for (unsigned int i = 0; i < mSlicerManagers.size(); i++) { + if (id == mSlicerManagers[i]->GetId()) { + mSlicerManagers[i]->UpdateLinkedNavigation(refSlicer); + } + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void vvMainWindow::ShowContextMenu(QPoint point) +{ + if (!DataTree->selectedItems().size()) { + contextActions[1]->setEnabled(0); + contextActions[2]->setEnabled(0); + contextActions[3]->setEnabled(0); + contextActions[4]->setEnabled(0); + contextActions[5]->setEnabled(0); + contextActions[6]->setEnabled(0); + } else { + int index = GetSlicerIndexFromItem(DataTree->selectedItems()[0]); + contextActions[1]->setEnabled(1); + contextActions[2]->setEnabled( + DataTree->itemWidget(DataTree->selectedItems()[0], + COLUMN_RELOAD_IMAGE)->isEnabled()); + contextActions[3]->setEnabled(1); + contextActions[5]->setEnabled(1); + contextActions[6]->setEnabled(1); + + if (mSlicerManagers[index]->GetDimension() < 3) + contextActions[4]->setEnabled(0); + else + contextActions[4]->setEnabled(1); + } + contextMenu.exec(QCursor::pos()); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void vvMainWindow::CloseImage() +{ + CloseImage(DataTree->selectedItems()[0],0); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void vvMainWindow::ReloadImage() +{ + ReloadImage(DataTree->selectedItems()[0],0); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void vvMainWindow::SelectOverlayImage() +{ + int index = GetSlicerIndexFromItem(DataTree->selectedItems()[0]); + + //check if one overlay image is added + for (int child = 0; child < DataTree->topLevelItem(index)->childCount(); child++) + if (DataTree->topLevelItem(index)->child(child)->data(1,Qt::UserRole).toString() == "overlay") { + QString error = "Cannot add more than one compared image\n"; + error += "Please remove first "; + error += DataTree->topLevelItem(index)->child(child)->data(COLUMN_IMAGE_NAME,Qt::DisplayRole).toString(); + QMessageBox::information(this,tr("Problem adding compared image !"),error); + return; + } + + QString Extensions = EXTENSIONS; + Extensions += ";;All Files (*)"; + QStringList files = QFileDialog::getOpenFileNames(this,tr("Load Overlay image"),mInputPathName,Extensions); + if (files.isEmpty()) + return; + + std::vector vecFileNames; + for (int i = 0; i < files.size(); i++) { + vecFileNames.push_back(files[i].toStdString()); + } + AddOverlayImage(index,vecFileNames,vvImageReader::IMAGE); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void vvMainWindow::AddOverlayImage(int index, std::vector fileNames, vvImageReader::LoadedImageType type) +{ + QString file(fileNames[0].c_str()); + if (QFile::exists(file)) + { + mInputPathName = itksys::SystemTools::GetFilenamePath(file.toStdString()).c_str(); + itk::ImageIOBase::Pointer reader = itk::ImageIOFactory::CreateImageIO( + file.toStdString().c_str(), itk::ImageIOFactory::ReadMode); + reader->SetFileName(fileNames[0].c_str()); + reader->ReadImageInformation(); + std::string component = reader->GetComponentTypeAsString(reader->GetComponentType()); + int dimension = reader->GetNumberOfDimensions(); + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + vvProgressDialog progress("Opening " + file.toStdString()); + qApp->processEvents(); + + std::string filename = itksys::SystemTools::GetFilenameWithoutExtension(file.toStdString()).c_str(); + if (mSlicerManagers[index]->SetOverlay(fileNames,dimension, component,type)) { + //create an item in the tree with good settings + QTreeWidgetItem *item = new QTreeWidgetItem(); + item->setData(0,Qt::UserRole,file.toStdString().c_str()); + item->setData(1,Qt::UserRole,tr("overlay")); + QFileInfo fileinfo(file); //Do not show the path + item->setData(COLUMN_IMAGE_NAME,Qt::DisplayRole,fileinfo.fileName()); + item->setToolTip(COLUMN_IMAGE_NAME, mSlicerManagers[index]->GetListOfAbsoluteFilePathInOneString("overlay").c_str()); + qApp->processEvents(); + + for (int j = 1; j <= 4; j++) { + item->setData(j,Qt::CheckStateRole,DataTree->topLevelItem(index)->data(j,Qt::CheckStateRole)); + } + + //Create the buttons for reload and close + qApp->processEvents(); + QTreePushButton* cButton = new QTreePushButton; + cButton->setItem(item); + cButton->setColumn(COLUMN_CLOSE_IMAGE); + cButton->setToolTip(tr("close image")); + cButton->setIcon(QIcon(QString::fromUtf8(":/common/icons/exit.png"))); + connect(cButton,SIGNAL(clickedInto(QTreeWidgetItem*, int)), + this,SLOT(CloseImage(QTreeWidgetItem*, int))); + + QTreePushButton* rButton = new QTreePushButton; + rButton->setItem(item); + rButton->setColumn(COLUMN_RELOAD_IMAGE); + rButton->setToolTip(tr("reload image")); + rButton->setIcon(QIcon(QString::fromUtf8(":/common/icons/rotateright.png"))); + connect(rButton,SIGNAL(clickedInto(QTreeWidgetItem*, int)), + this,SLOT(ReloadImage(QTreeWidgetItem*, int))); + + DataTree->topLevelItem(index)->setExpanded(1); + DataTree->topLevelItem(index)->addChild(item); + DataTree->setItemWidget(item, COLUMN_CLOSE_IMAGE, cButton); + DataTree->setItemWidget(item, COLUMN_RELOAD_IMAGE, rButton); + + //set the id of the image + QString id = DataTree->topLevelItem(index)->data(COLUMN_IMAGE_NAME,Qt::UserRole).toString(); + item->setData(COLUMN_IMAGE_NAME,Qt::UserRole,id.toStdString().c_str()); + UpdateTree(); + qApp->processEvents(); + ImageInfoChanged(); + QApplication::restoreOverrideCursor(); + + // Update the display to update, e.g., the sliders + for(int i=0; i<4; i++) + DisplaySliders(index, i); + } else { + QApplication::restoreOverrideCursor(); + QString error = "Cannot import the new image.\n"; + error += mSlicerManagers[index]->GetLastError().c_str(); + QMessageBox::information(this,tr("Problem reading image !"),error); + } + WindowLevelChanged(); + } + else + QMessageBox::information(this,tr("Problem reading Overlay !"),"File doesn't exist!"); +} +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +void vvMainWindow::AddROI(int index, QString file) +{ + /* + // Get slice manager + + // Load image + + vvImageReader * mReader = new vvImageReader; + mReader->SetInputFilename(filename.toStdString()); + mReader->Update(IMAGE); + if (mReader->GetLastError().size() != 0) { + std::cerr << "Error while reading " << filename.toStdString() << std::endl; + QString error = "Cannot open file \n"; + error += mReader->GetLastError().c_str(); + QMessageBox::information(this,tr("Reading problem"),error); + delete mReader; + return; + } + vvImage::Pointer roi = mReader->GetOutput(); + + // Create roi in new tool + vvToolStructureSetManager::AddImage(mCurrentSlicerManager, roi); + */ +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void vvMainWindow::SelectFusionImage() +{ + int index = GetSlicerIndexFromItem(DataTree->selectedItems()[0]); + + //check if one fusion image is added + for (int child = 0; child < DataTree->topLevelItem(index)->childCount(); child++) + if ( (DataTree->topLevelItem(index)->child(child)->data(1,Qt::UserRole).toString() == "fusion") || + (DataTree->topLevelItem(index)->child(child)->data(1,Qt::UserRole).toString() == "fusionSequence") ) { + QString error = "Cannot add more than one fusion image\n"; + error += "Please remove first "; + error += DataTree->topLevelItem(index)->child(child)->data(COLUMN_IMAGE_NAME,Qt::DisplayRole).toString(); + QMessageBox::information(this,tr("Problem adding fusion image !"),error); + return; + } + + QString Extensions = EXTENSIONS; + Extensions += ";;All Files (*)"; + QString file = QFileDialog::getOpenFileName(this,tr("Load Fusion image"),mInputPathName,Extensions); + if (!file.isEmpty()) + AddFusionImage(index,file); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void vvMainWindow::ResetTransformationToIdentity() +{ + std::string actorType = DataTree->selectedItems()[0]->data(1,Qt::UserRole).toString().toStdString(); + int index = GetSlicerIndexFromItem(DataTree->selectedItems()[0]); + mSlicerManagers[index]->ResetTransformationToIdentity(actorType); + ImageInfoChanged(); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void vvMainWindow::AddFusionImage(int index, QString file) +{ + if (QFile::exists(file)) + { + mInputPathName = itksys::SystemTools::GetFilenamePath(file.toStdString()).c_str(); + itk::ImageIOBase::Pointer reader = itk::ImageIOFactory::CreateImageIO( + file.toStdString().c_str(), itk::ImageIOFactory::ReadMode); + reader->SetFileName(file.toStdString().c_str()); + reader->ReadImageInformation(); + std::string component = reader->GetComponentTypeAsString(reader->GetComponentType()); + if (reader) { + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + vvProgressDialog progress("Opening fusion"); + qApp->processEvents(); + + std::string filename = itksys::SystemTools::GetFilenameWithoutExtension(file.toStdString()).c_str(); + if (mSlicerManagers[index]->SetFusion(file.toStdString(), + reader->GetNumberOfDimensions(), component)) { + //create an item in the tree with good settings + QTreeWidgetItem *item = new QTreeWidgetItem(); + item->setData(0,Qt::UserRole,file.toStdString().c_str()); + item->setData(1,Qt::UserRole,tr("fusion")); + QFileInfo fileinfo(filename.c_str()); //Do not show the path + item->setData(COLUMN_IMAGE_NAME,Qt::DisplayRole,fileinfo.fileName()); + item->setToolTip(COLUMN_IMAGE_NAME, mSlicerManagers[index]->GetListOfAbsoluteFilePathInOneString("fusion").c_str()); + qApp->processEvents(); + + for (int j = 1; j <= 4; j++) { + item->setData(j,Qt::CheckStateRole,DataTree->topLevelItem(index)->data(j,Qt::CheckStateRole)); + } + + //Create the buttons for reload and close + qApp->processEvents(); + QTreePushButton* cButton = new QTreePushButton; + cButton->setItem(item); + cButton->setColumn(COLUMN_CLOSE_IMAGE); + cButton->setToolTip(tr("close image")); + cButton->setIcon(QIcon(QString::fromUtf8(":/common/icons/exit.png"))); + connect(cButton,SIGNAL(clickedInto(QTreeWidgetItem*, int)), + this,SLOT(CloseImage(QTreeWidgetItem*, int))); + + QTreePushButton* rButton = new QTreePushButton; + rButton->setItem(item); + rButton->setColumn(COLUMN_RELOAD_IMAGE); + rButton->setToolTip(tr("reload image")); + rButton->setIcon(QIcon(QString::fromUtf8(":/common/icons/rotateright.png"))); + connect(rButton,SIGNAL(clickedInto(QTreeWidgetItem*, int)), + this,SLOT(ReloadImage(QTreeWidgetItem*, int))); + + DataTree->topLevelItem(index)->setExpanded(1); + DataTree->topLevelItem(index)->addChild(item); + DataTree->setItemWidget(item, COLUMN_CLOSE_IMAGE, cButton); + DataTree->setItemWidget(item, COLUMN_RELOAD_IMAGE, rButton); + + //set the id of the image + QString id = DataTree->topLevelItem(index)->data(COLUMN_IMAGE_NAME,Qt::UserRole).toString(); + item->setData(COLUMN_IMAGE_NAME,Qt::UserRole,id.toStdString().c_str()); + UpdateTree(); + qApp->processEvents(); + ImageInfoChanged(); + QApplication::restoreOverrideCursor(); + } else { + QApplication::restoreOverrideCursor(); + QString error = "Cannot import the new image.\n"; + error += mSlicerManagers[index]->GetLastError().c_str(); + QMessageBox::information(this,tr("Problem reading image !"),error); + } + } else { + QString error = "Cannot import the new image.\n"; + QMessageBox::information(this,tr("Problem reading image !"),error); + } + } + else + QMessageBox::information(this,tr("Problem reading Fusion !"),"File doesn't exist!"); +} +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +void vvMainWindow::OpenField() +{ + int index = GetSlicerIndexFromItem(DataTree->selectedItems()[0]); + //check if a vector field has already been added + for (int child = 0; child < DataTree->topLevelItem(index)->childCount(); child++) + if (DataTree->topLevelItem(index)->child(child)->data(1,Qt::UserRole).toString() == "vector") { + QString error = "Cannot add more than one vector field\n"; + error += "Please remove first "; + error += DataTree->topLevelItem(index)->child(child)->data(COLUMN_IMAGE_NAME,Qt::DisplayRole).toString(); + QMessageBox::information(this,tr("Problem adding vector field!"),error); + return; + } + + QString Extensions = "Images ( *.mhd)"; + Extensions += ";;Images ( *.mha)"; + Extensions += ";;VF Images ( *.vf)"; + Extensions += ";;nii Images ( *.nii)"; + Extensions += ";;nrrd Images ( *.nrrd)"; + Extensions += ";;nhdr Images ( *.nhdr)"; + Extensions += ";;All Files (*)"; + QString file = QFileDialog::getOpenFileName(this,tr("Load deformation field"),mInputPathName,Extensions); + if (!file.isEmpty()) + AddField(file,index); +} +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +void vvMainWindow::AddFieldEntry(QString filename,int index,bool from_disk) +{ + //create an item in the tree with good settings + QTreeWidgetItem *item = new QTreeWidgetItem(); + item->setData(0,Qt::UserRole,filename.toStdString().c_str()); + item->setData(1,Qt::UserRole,tr("vector")); + QFileInfo fileinfo(filename); //Do not show the path + item->setData(COLUMN_IMAGE_NAME,Qt::DisplayRole,fileinfo.fileName()); + item->setToolTip(COLUMN_IMAGE_NAME, mSlicerManagers[index]->GetListOfAbsoluteFilePathInOneString("vector").c_str()); + qApp->processEvents(); + + for (int j = 1; j <= 4; j++) { + item->setData(j,Qt::CheckStateRole,DataTree->topLevelItem(index)->data(j,Qt::CheckStateRole)); + } + + //Create the buttons for reload and close + qApp->processEvents(); + QTreePushButton* cButton = new QTreePushButton; + cButton->setItem(item); + cButton->setColumn(COLUMN_CLOSE_IMAGE); + cButton->setToolTip(tr("close vector field")); + cButton->setIcon(QIcon(QString::fromUtf8(":/common/icons/exit.png"))); + connect(cButton,SIGNAL(clickedInto(QTreeWidgetItem*, int)), + this,SLOT(CloseImage(QTreeWidgetItem*, int))); + + QTreePushButton* rButton = new QTreePushButton; + rButton->setItem(item); + rButton->setColumn(COLUMN_RELOAD_IMAGE); + rButton->setToolTip(tr("reload vector field")); + rButton->setEnabled(from_disk); + rButton->setIcon(QIcon(QString::fromUtf8(":/common/icons/rotateright.png"))); + connect(rButton,SIGNAL(clickedInto(QTreeWidgetItem*, int)), + this,SLOT(ReloadImage(QTreeWidgetItem*, int))); + + DataTree->topLevelItem(index)->setExpanded(1); + DataTree->topLevelItem(index)->addChild(item); + DataTree->setItemWidget(item, COLUMN_RELOAD_IMAGE, rButton); + DataTree->setItemWidget(item, COLUMN_CLOSE_IMAGE, cButton); + + //set the id of the image + QString id = DataTree->topLevelItem(index)->data(COLUMN_IMAGE_NAME,Qt::UserRole).toString(); + item->setData(COLUMN_IMAGE_NAME,Qt::UserRole,id.toStdString().c_str()); + UpdateTree(); + qApp->processEvents(); + ImageInfoChanged(); + QApplication::restoreOverrideCursor(); +} +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +void vvMainWindow::AddField(vvImage::Pointer vf,QString file,int index) +{ + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + vvSlicerManager* imageManager = mSlicerManagers[index]; + if (imageManager->SetVF(vf,file.toStdString())) { + AddFieldEntry(file,index,false); + } else { + QString error = "Cannot import the vector field for this image.\n"; + error += imageManager->GetLastError().c_str(); + QMessageBox::information(this,tr("Problem reading VF !"),error); + } + QApplication::restoreOverrideCursor(); +} +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +void vvMainWindow::AddField(QString file,int index) +{ + if (QFile::exists(file)) { + mInputPathName = itksys::SystemTools::GetFilenamePath(file.toStdString()).c_str(); + + //init the progress events + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + vvProgressDialog progress("Opening " + file.toStdString()); + qApp->processEvents(); + + //read the vector and put it in the current mSlicerManager + vvSlicerManager* imageManager = mSlicerManagers[index]; + qApp->processEvents(); + + std::string filename = itksys::SystemTools::GetFilenameWithoutExtension(file.toStdString()).c_str(); + if (imageManager->SetVF(file.toStdString())) { + imageManager->Render(); + AddFieldEntry(file,index,true); + } else { + QApplication::restoreOverrideCursor(); + QString error = "Cannot import the vector field for this image.\n"; + error += imageManager->GetLastError().c_str(); + QMessageBox::information(this,tr("Problem reading VF !"),error); + } + } else + QMessageBox::information(this,tr("Problem reading VF !"),"File doesn't exist!"); + +} +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +void vvMainWindow::SetVFProperty(int subsampling, int scale, int log, int width, double r, double g, double b) +{ + int index = GetSlicerIndexFromItem(DataTree->selectedItems()[0]); + if (mSlicerManagers[index]->GetSlicer(0)->GetVF()) { + for (int i = 0; i < 4; i++) { + mSlicerManagers[index]->GetSlicer(i)->SetVFSubSampling(subsampling); + mSlicerManagers[index]->GetSlicer(i)->SetVFScale(scale); + mSlicerManagers[index]->GetSlicer(i)->SetVFWidth(width); + mSlicerManagers[index]->GetSlicer(i)->SetVFColor(r,g,b); + if (log > 0) + mSlicerManagers[index]->GetSlicer(i)->SetVFLog(1); + else + mSlicerManagers[index]->GetSlicer(i)->SetVFLog(0); + } + } +} +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +void vvMainWindow::SetOverlayProperty(int color, int linked, double window, double level) +{ + int index = GetSlicerIndexFromItem(DataTree->selectedItems()[0]); + if (mSlicerManagers[index]->GetSlicer(0)->GetOverlay()) { + mSlicerManagers[index]->SetOverlayColor(color); + mSlicerManagers[index]->SetColorMap(0); + mSlicerManagers[index]->SetLinkOverlayWindowLevel(linked); + mSlicerManagers[index]->SetOverlayColorWindow(window); + mSlicerManagers[index]->SetOverlayColorLevel(level); + mSlicerManagers[index]->Render(); + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void vvMainWindow::SetFusionProperty(int opacity, int thresOpacity, int colormap,double window, double level, bool showLegend) +{ + int index = GetSlicerIndexFromItem(DataTree->selectedItems()[0]); + if (mSlicerManagers[index]->GetSlicer(0)->GetFusion()) { + mSlicerManagers[index]->SetFusionColorMap(colormap); + mSlicerManagers[index]->SetFusionOpacity(opacity); + mSlicerManagers[index]->SetFusionThresholdOpacity(thresOpacity); + mSlicerManagers[index]->SetFusionWindow(window); + mSlicerManagers[index]->SetFusionLevel(level); + mSlicerManagers[index]->SetFusionShowLegend(showLegend); + mSlicerManagers[index]->SetColorMap(0); + mSlicerManagers[index]->Render(); + } +} +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +void vvMainWindow::SelectFusionSequence() +{ + int index = GetSlicerIndexFromItem(DataTree->selectedItems()[0]); + //check if one overlay image is added + for (int child = 0; child < DataTree->topLevelItem(index)->childCount(); child++) + if ( (DataTree->topLevelItem(index)->child(child)->data(1,Qt::UserRole).toString() == "fusion") || + (DataTree->topLevelItem(index)->child(child)->data(1,Qt::UserRole).toString() == "fusionSequence") ) { + QString error = "Cannot add more than one compared image\n"; + error += "Please remove first "; + error += DataTree->topLevelItem(index)->child(child)->data(COLUMN_IMAGE_NAME,Qt::DisplayRole).toString(); + QMessageBox::information(this,tr("Problem adding compared image !"),error); + return; + } + + QString Extensions = EXTENSIONS; + Extensions += ";;All Files (*)"; + QStringList files = QFileDialog::getOpenFileNames(this,tr("Load Overlay image sequence"),mInputPathName,Extensions); + if (files.isEmpty()) + return; + + std::vector vecFileNames; + for (int i = 0; i < files.size(); i++) { + vecFileNames.push_back(files[i].toStdString()); + } + + AddFusionSequence(index,vecFileNames,vvImageReader::MERGEDWITHTIME); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void vvMainWindow::AddFusionSequence(int index, std::vector fileNames, vvImageReader::LoadedImageType type) +{ + QString file(fileNames[0].c_str()); + if (QFile::exists(file)) + { + mInputPathName = itksys::SystemTools::GetFilenamePath(file.toStdString()).c_str(); + itk::ImageIOBase::Pointer reader = itk::ImageIOFactory::CreateImageIO( + file.toStdString().c_str(), itk::ImageIOFactory::ReadMode); + reader->SetFileName(fileNames[0].c_str()); + reader->ReadImageInformation(); + std::string component = reader->GetComponentTypeAsString(reader->GetComponentType()); + int dimension = reader->GetNumberOfDimensions(); + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + vvProgressDialog progress("Opening " + file.toStdString()); + qApp->processEvents(); + + std::string filename = itksys::SystemTools::GetFilenameWithoutExtension(file.toStdString()).c_str(); + + if (mSlicerManagers[index]->SetFusionSequence(fileNames,dimension, component,type)) { + //create an item in the tree with good settings + QTreeWidgetItem *item = new QTreeWidgetItem(); + item->setData(0,Qt::UserRole,file.toStdString().c_str()); + item->setData(1,Qt::UserRole,tr("fusionSequence")); + + QFileInfo fileinfo(file); //Do not show the path + item->setData(COLUMN_IMAGE_NAME,Qt::DisplayRole,fileinfo.fileName()); + item->setToolTip(COLUMN_IMAGE_NAME, mSlicerManagers[index]->GetListOfAbsoluteFilePathInOneString("fusionSequence").c_str()); + qApp->processEvents(); + for (int j = 1; j <= 4; j++) { + item->setData(j,Qt::CheckStateRole,DataTree->topLevelItem(index)->data(j,Qt::CheckStateRole)); + } + + //Create the buttons for reload and close + qApp->processEvents(); + QTreePushButton* cButton = new QTreePushButton; + cButton->setItem(item); + cButton->setColumn(COLUMN_CLOSE_IMAGE); + cButton->setToolTip(tr("close image")); + cButton->setIcon(QIcon(QString::fromUtf8(":/common/icons/exit.png"))); + connect(cButton,SIGNAL(clickedInto(QTreeWidgetItem*, int)), + this,SLOT(CloseImage(QTreeWidgetItem*, int))); + + QTreePushButton* rButton = new QTreePushButton; + rButton->setItem(item); + rButton->setColumn(COLUMN_RELOAD_IMAGE); + rButton->setToolTip(tr("reload image")); + rButton->setIcon(QIcon(QString::fromUtf8(":/common/icons/rotateright.png"))); + connect(rButton,SIGNAL(clickedInto(QTreeWidgetItem*, int)), + this,SLOT(ReloadImage(QTreeWidgetItem*, int))); + + DataTree->topLevelItem(index)->setExpanded(1); + DataTree->topLevelItem(index)->addChild(item); + DataTree->setItemWidget(item, COLUMN_CLOSE_IMAGE, cButton); + DataTree->setItemWidget(item, COLUMN_RELOAD_IMAGE, rButton); + + //store the original transform matrix + int indexParent = GetSlicerIndexFromItem( DataTree->topLevelItem(index) ); + mSlicerManagers[indexParent]->SetFusionSequenceMainTransformMatrix( mSlicerManagers[indexParent]->GetSlicer(0)->GetImage()->GetTransform()[0]->GetMatrix() ); + + //set the id of the image + QString id = DataTree->topLevelItem(index)->data(COLUMN_IMAGE_NAME,Qt::UserRole).toString(); + item->setData(COLUMN_IMAGE_NAME,Qt::UserRole,id.toStdString().c_str()); + UpdateTree(); + qApp->processEvents(); + + ImageInfoChanged(); + + QApplication::restoreOverrideCursor(); + // Update the display to update, e.g., the sliders + for(int i=0; i<4; i++) + DisplaySliders(index, i); + + + //TEST: also add the image as normal image, link it, and store its index in the SlicerManagersArray for tying it to the fusionSequence + LoadImages(fileNames, type); + //reset the transforms to identiy + for (unsigned i=0 ; iGetImage()->GetTransform().size() ; i++) { + mSlicerManagers.back()->GetImage()->GetTransform()[i]->Identity(); + mSlicerManagers.back()->GetImage()->GetTransform()[i]->Update(); + } + + //automatically link both images... + AddLink(mSlicerManagers[indexParent]->GetId().c_str(), mSlicerManagers.back()->GetId().c_str(), false); + + //store the index ; this is also used as a flag to indicate that the images are involved in a fusionSequence... + //TODO: reset these when exiting the visualization mode (unloading one of the images) + mSlicerManagers[indexParent]->SetFusionSequenceIndexOfLinkedManager(mSlicerManagers.size()-1); + mSlicerManagers.back()->SetFusionSequenceIndexOfLinkedManager(indexParent); + + } else { + QApplication::restoreOverrideCursor(); + QString error = "Cannot import the new image.\n"; + error += mSlicerManagers[index]->GetLastError().c_str(); + QMessageBox::information(this,tr("Problem reading image !"),error); + } + WindowLevelChanged(); + } + else { + QMessageBox::information(this,tr("Problem reading fusion sequence !"),"File doesn't exist!"); + return; + } + +} +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +void vvMainWindow::SetFusionSequenceProperty(int fusionSequenceFrameIndex, bool spatialSyncFlag, unsigned int fusionSequenceNbFrames) +{ + int index = GetSlicerIndexFromItem(DataTree->selectedItems()[0]); + + //check if the focus moved to the linked sequence, and in this case, select the master sequence instead + if ( (!mSlicerManagers[index]->GetSlicer(0)->GetFusion()) && mSlicerManagers[index]->GetFusionSequenceIndexOfLinkedManager()>=0 ) { + index = mSlicerManagers[index]->GetFusionSequenceIndexOfLinkedManager(); + } + + if (mSlicerManagers[index]->GetSlicer(0)->GetFusion()) { + int indexParent = GetSlicerIndexFromItem( DataTree->topLevelItem(index) ); + + //if the button is unchecked, then reposition the parent sequence (CT) in its original coordinate frame + if ( (!spatialSyncFlag) && (mSlicerManagers[index]->GetFusionSequenceSpatialSyncFlag()) ) { + for ( unsigned i=0 ; iGetSlicer(0)->GetImage()->GetTransform().size() ; i++ ) { + mSlicerManagers[indexParent]->GetSlicer(0)->GetImage()->GetTransform()[i]->SetMatrix( mSlicerManagers[index]->GetFusionSequenceMainTransformMatrix() ); + mSlicerManagers[indexParent]->GetSlicer(0)->GetImage()->GetTransform()[i]->Update(); + } + + for (int i=0; iGetNumberOfSlicers(); i++) { + mSlicerManagers[indexParent]->GetSlicer(i)->ForceUpdateDisplayExtent(); + mSlicerManagers[indexParent]->GetSlicer(i)->Render(); + } + } + + //update the property values in the slicer manager + mSlicerManagers[index]->SetFusionSequenceLength(fusionSequenceNbFrames); + mSlicerManagers[index]->SetFusionSequenceSpatialSyncFlag(spatialSyncFlag); + mSlicerManagers[index]->SetFusionSequenceFrameIndex(fusionSequenceFrameIndex); + + //show the right frame of the US sequence + mSlicerManagers[index]->SetFusionSequenceTSlice(fusionSequenceFrameIndex); + //update the linked sequence if possible + if (mSlicerManagers[index]->GetFusionSequenceIndexOfLinkedManager()>0) { + mSlicerManagers[ mSlicerManagers[index]->GetFusionSequenceIndexOfLinkedManager() ]->SetTSlice(fusionSequenceFrameIndex, false); + } + + if (spatialSyncFlag) { //reslice the CT + + //Set the transform matrix of the parent sequence (typically CT / 4DCT) + vtkSmartPointer tmpMat = vtkSmartPointer::New(); + vtkMatrix4x4::Invert( mSlicerManagers[index]->GetFusionSequenceInitialTransformMatrixAtFrame(fusionSequenceFrameIndex), tmpMat ); + for ( unsigned i=0 ; iGetSlicer(0)->GetImage()->GetTransform().size() ; i++ ) { + mSlicerManagers[indexParent]->GetSlicer(0)->GetImage()->GetTransform()[i]->SetMatrix( mSlicerManagers[index]->GetFusionSequenceMainTransformMatrix() ); + mSlicerManagers[indexParent]->GetSlicer(0)->GetImage()->GetTransform()[i]->PreMultiply(); + mSlicerManagers[indexParent]->GetSlicer(0)->GetImage()->GetTransform()[i]->Concatenate( tmpMat ); + mSlicerManagers[indexParent]->GetSlicer(0)->GetImage()->GetTransform()[i]->Update(); + } + + for (int i=0; iGetNumberOfSlicers(); i++) { + mSlicerManagers[indexParent]->GetSlicer(i)->ForceUpdateDisplayExtent(); + mSlicerManagers[indexParent]->GetSlicer(i)->Render(); + } + } + + } +} +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +void vvMainWindow::SaveAs() +{ + if (DataTree->selectedItems()[0]->data(1,Qt::UserRole).toString() == "vector") { + QMessageBox::warning(this,tr("Unsupported type"),tr("Sorry, saving a vector field is unsupported for the moment")); + return; + } + + int index = GetSlicerIndexFromItem(DataTree->selectedItems()[0]); + int dimension = mSlicerManagers[index]->GetDimension(); + QStringList OutputListeFormat; + OutputListeFormat.clear(); + if (dimension == 1) { + OutputListeFormat.push_back(".mhd"); + OutputListeFormat.push_back(".mha"); + } + if (dimension == 2) { + OutputListeFormat.push_back(".bmp"); + OutputListeFormat.push_back(".png"); + OutputListeFormat.push_back(".jpeg"); + OutputListeFormat.push_back(".tif"); + OutputListeFormat.push_back(".mhd"); + OutputListeFormat.push_back(".mha"); + OutputListeFormat.push_back(".hdr"); + OutputListeFormat.push_back(".vox"); + } else if (dimension == 3) { + OutputListeFormat.push_back(".mhd"); + OutputListeFormat.push_back(".mha"); + OutputListeFormat.push_back(".nii"); + OutputListeFormat.push_back(".nrrd"); + OutputListeFormat.push_back(".nhdr"); + OutputListeFormat.push_back(".hdr"); + OutputListeFormat.push_back(".vox"); + } else if (dimension == 4) { + OutputListeFormat.push_back(".mhd"); + OutputListeFormat.push_back(".mha"); + OutputListeFormat.push_back(".nii"); + OutputListeFormat.push_back(".nrrd"); + OutputListeFormat.push_back(".nhdr"); + } + QString Extensions = "AllFiles(*.*)"; + for (int i = 0; i < OutputListeFormat.count(); i++) { + Extensions += ";;Images ( *"; + Extensions += OutputListeFormat[i]; + Extensions += ")"; + } + QString fileName = QFileDialog::getSaveFileName(this, + tr("Save As"), + mSlicerManagers[index]->GetFileName().c_str(), + Extensions); + if (!fileName.isEmpty()) { + std::string fileformat = itksys::SystemTools::GetFilenameLastExtension(fileName.toStdString()); + if (OutputListeFormat.contains( + fileformat.c_str())) { + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + std::string action = "Saving"; + vvProgressDialog progress("Saving "+fileName.toStdString()); + qApp->processEvents(); + vvImageWriter::Pointer writer = vvImageWriter::New(); + writer->SetOutputFileName(fileName.toStdString()); + writer->SetInput(mSlicerManagers[index]->GetImage()); + + // Check on transform and prompt user + writer->SetSaveTransform(false); + bool bId = true; + for(int i=0; i<4; i++) + for(int j=0; j<4; j++) { + // TODO SR and BP: check on the list of transforms and not the first only + double elt = mSlicerManagers[index]->GetImage()->GetTransform()[0]->GetMatrix()->GetElement(i,j); + if(i==j && elt!=1.) + bId = false; + if(i!=j && elt!=0.) + bId = false; + } + if( !bId ) { + QString warning = "The image has an associated linear transform. Do you want to save it along?"; + QMessageBox msgBox(QMessageBox::Warning, tr("Save transform"), warning, 0, this); + msgBox.addButton(tr("Yes"), QMessageBox::AcceptRole); + msgBox.addButton(tr("No"), QMessageBox::RejectRole); + if (msgBox.exec() == QMessageBox::AcceptRole) + writer->SetSaveTransform(true); + } + + writer->Update(); + QApplication::restoreOverrideCursor(); + if (writer->GetLastError().size()) { + QString error = "Saving did not succeed\n"; + error += writer->GetLastError().c_str(); + QMessageBox::information(this,tr("Saving Problem"),error); + SaveAs(); + } + } else { + QString error = fileformat.c_str(); + if (error.isEmpty()) + error += "no file format specified !"; + else + error += " format unknown !!!\n"; + QMessageBox::information(this,tr("Saving Problem"),error); + SaveAs(); + } + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void vvMainWindow::SaveCurrentState() +{ + QString Extensions = "XML Files(*.xml)"; + QString fileName = QFileDialog::getSaveFileName(this, + tr("Save Current Window State"), + "", + Extensions); + + SaveCurrentStateAs(fileName.toStdString()); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void vvMainWindow::SaveCurrentStateAs(const std::string& stateFile) +{ + vvSaveState save_state; + save_state.Run(this, stateFile); +} + +//------------------------------------------------------------------------------ +void vvMainWindow::ReadSavedState() +{ + QString Extensions = "XML Files(*.xml)"; + QString fileName = QFileDialog::getOpenFileName(this, + tr("Load Window State"), + "", + Extensions); + + ReadSavedStateFile(fileName.toStdString()); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void vvMainWindow::ReadSavedStateFile(const std::string& stateFile) +{ + vvReadState read_state; + read_state.Run(this, stateFile); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void vvMainWindow::LinkAllImages() +{ + linkPanel->linkAll(); +} + +//------------------------------------------------------------------------------ +void vvMainWindow::AddLink(QString image1,QString image2,bool fromPanel) +{ + if (!fromPanel) { + // delegate to linkPanel if call came from elsewhere... + linkPanel->addLinkFromIds(image1, image2); + return; + } + + unsigned int sm1 = 0; + unsigned int sm2 = 0; + + for (unsigned int i = 0; i < mSlicerManagers.size(); i++) { + if (image1.toStdString() == mSlicerManagers[i]->GetId()) { + mSlicerManagers[i]->AddLink(image2.toStdString()); + sm1 = i; + } + if (image2.toStdString() == mSlicerManagers[i]->GetId()) { + mSlicerManagers[i]->AddLink(image1.toStdString()); + sm2 = i; + } + } + + if (linkPanel->isLinkAll()) { + emit UpdateLinkedNavigation(mSlicerManagers[sm1]->GetId(), mSlicerManagers[mCurrentPickedImageIndex], mSlicerManagers[mCurrentPickedImageIndex]->GetSlicer(0)); + emit UpdateLinkedNavigation(mSlicerManagers[sm2]->GetId(), mSlicerManagers[mCurrentPickedImageIndex], mSlicerManagers[mCurrentPickedImageIndex]->GetSlicer(0)); + } else { + emit UpdateLinkedNavigation(mSlicerManagers[sm2]->GetId(), mSlicerManagers[sm1], mSlicerManagers[sm1]->GetSlicer(0)); + } +} + +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +void vvMainWindow::RemoveLink(QString image1,QString image2) +{ + for (unsigned int i = 0; i < mSlicerManagers.size(); i++) { + if (image1.toStdString() == mSlicerManagers[i]->GetId()) { + mSlicerManagers[i]->RemoveLink(image2.toStdString()); + } + if (image2.toStdString() == mSlicerManagers[i]->GetId()) { + mSlicerManagers[i]->RemoveLink(image1.toStdString()); + } + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void vvMainWindow::ChangeImageWithIndexOffset(vvSlicerManager *sm, int slicer, int offset) +{ + if(mSlicerManagers.size()==1) + return; + + int index = 0; + while(sm != mSlicerManagers[index]) + index++; + index = (index+offset+mSlicerManagers.size()) % mSlicerManagers.size(); + + QTreeWidgetItem* item = GetItemFromSlicerManager(mSlicerManagers[index]); + item->setData(slicer+1,Qt::CheckStateRole,2); //change checkbox + CurrentImageChanged(mSlicerManagers[index]->GetId()); //select new image + DisplayChanged(item,slicer+1); +} +//------------------------------------------------------------------------------ + +void vvMainWindow::HorizontalSliderMoved(int value,int column, int slicer_index) +{ + for (unsigned int i = 0; i < mSlicerManagers.size(); i++) { + if (DataTree->topLevelItem(i)->data(column,Qt::CheckStateRole).toInt() > 1) { + for (int j = 0; j < 4; j++) { + mSlicerManagers[i]->SetTSliceInSlicer(value,j); + //if (mSlicerManagers[i]->GetSlicer(j)->GetImageActor()->GetVisibility()) + //UpdateTSlice(j,value); + } + mSlicerManagers[i]->GetSlicer(slicer_index)->Render(); + break; + } + } +} +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +void vvMainWindow::NOHorizontalSliderMoved() +{ + // if (mCurrentTime == NOHorizontalSlider->value()) return; + HorizontalSliderMoved(NOHorizontalSlider->value(),COLUMN_UL_VIEW,0); +// mCurrentTime = NOHorizontalSlider->value(); +} +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +void vvMainWindow::NEHorizontalSliderMoved() +{ + // if (mCurrentTime == NEHorizontalSlider->value()) return; + HorizontalSliderMoved(NEHorizontalSlider->value(),COLUMN_UR_VIEW,1); +// mCurrentTime = NEHorizontalSlider->value(); +} +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +void vvMainWindow::SOHorizontalSliderMoved() +{ + // if (mCurrentTime == SOHorizontalSlider->value()) return; + HorizontalSliderMoved(SOHorizontalSlider->value(),COLUMN_DL_VIEW,2); + // mCurrentTime = SOHorizontalSlider->value(); +} +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +void vvMainWindow::SEHorizontalSliderMoved() +{ + // if (mCurrentTime == SEHorizontalSlider->value()) return; + HorizontalSliderMoved(SEHorizontalSlider->value(),COLUMN_DR_VIEW,3); + // mCurrentTime = SEHorizontalSlider->value(); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void vvMainWindow::NOVerticalSliderChanged() +{ + static int value=-1; + if (value == NOVerticalSlider->value()) return; + else value = NOVerticalSlider->value(); + // int value = NOVerticalSlider->value(); + for (unsigned int i = 0; i < mSlicerManagers.size(); i++) { + if (DataTree->topLevelItem(i)->data(COLUMN_UL_VIEW,Qt::CheckStateRole).toInt() > 1) { + if (mSlicerManagers[i]->GetSlicer(0)->GetSlice() != value) { + mSlicerManagers[i]->GetSlicer(0)->SetSlice(value); + mSlicerManagers[i]->VerticalSliderHasChanged(0, value); + + // If nor Update/Render -> slider not work + // only render = ok navigation, but for contour Update needed but slower ? + + mSlicerManagers[i]->UpdateSlice(0); // <-- DS add this. Not too much update ? YES. but needed for ImageContour ... + //mSlicerManagers[i]->GetSlicer(0)->Render(); // <-- DS add this, needed for contour, seems ok ? not too slow ? + } + break; + } + } +} +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +void vvMainWindow::NEVerticalSliderChanged() +{ + static int value=-1; + if (value == NEVerticalSlider->value()) return; + else value = NEVerticalSlider->value(); + // int value = NEVerticalSlider->value(); + for (unsigned int i = 0; i < mSlicerManagers.size(); i++) { + if (DataTree->topLevelItem(i)->data(COLUMN_UR_VIEW,Qt::CheckStateRole).toInt() > 1) { + if (mSlicerManagers[i]->GetSlicer(1)->GetSlice() != value) { + mSlicerManagers[i]->GetSlicer(1)->SetSlice(value); + mSlicerManagers[i]->VerticalSliderHasChanged(1, value); + mSlicerManagers[i]->UpdateSlice(1); + //mSlicerManagers[i]->GetSlicer(1)->Render(); // <-- DS add this, needed for contour, seems ok ? not too slow ? + } + break; + } + } +} +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +void vvMainWindow::SOVerticalSliderChanged() +{ + static int value=-1; + if (value == SOVerticalSlider->value()) return; + else value = SOVerticalSlider->value(); + //int value = SOVerticalSlider->value(); + for (unsigned int i = 0; i < mSlicerManagers.size(); i++) { + if (DataTree->topLevelItem(i)->data(COLUMN_DL_VIEW,Qt::CheckStateRole).toInt() > 1) { + if (mSlicerManagers[i]->GetSlicer(2)->GetSlice() != value) { + mSlicerManagers[i]->GetSlicer(2)->SetSlice(value); + mSlicerManagers[i]->VerticalSliderHasChanged(2, value); + mSlicerManagers[i]->UpdateSlice(2); + //mSlicerManagers[i]->GetSlicer(2)->Render(); // <-- DS add this, needed for contour, seems ok ? not too slow ? + } + // else { DD("avoid SOVerticalSlider slicer update"); } + break; + } + } +} +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +void vvMainWindow::SEVerticalSliderChanged() +{ + static int value=-1; + if (value == SEVerticalSlider->value()) return; + else value = SEVerticalSlider->value(); + // int value = SEVerticalSlider->value(); + for (unsigned int i = 0; i < mSlicerManagers.size(); i++) { + if (DataTree->topLevelItem(i)->data(COLUMN_DR_VIEW,Qt::CheckStateRole).toInt() > 1) { + if (mSlicerManagers[i]->GetSlicer(3)->GetSlice() != value) { + mSlicerManagers[i]->GetSlicer(3)->SetSlice(value); + mSlicerManagers[i]->VerticalSliderHasChanged(3, value); + mSlicerManagers[i]->UpdateSlice(3); + //mSlicerManagers[i]->GetSlicer(3)->Render(); // <-- DS add this, needed for contour, seems ok ? not too slow ? + } + break; + } + } +} +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +void vvMainWindow::UpdateSlice(int slicer, int slice) +{ + // DD("vvMainWindow::UpdateSlice"); +// DD(slicer); +// DD(slice); + if (slicer == 0) { + // if (slice != NOVerticalSlider->value()) + NOVerticalSlider->setValue(slice); + } else { + if (slicer == 1) + NEVerticalSlider->setValue(slice); + else { + if (slicer == 2) + SOVerticalSlider->setValue(slice); + else { + if (slicer == 3) + SEVerticalSlider->setValue(slice); + } + } + } + // DD("vvMainWindow:UpdateSlice END"); +} +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +void vvMainWindow::UpdateTSlice(int slicer, int slice) +{ + switch (slicer) { + case 0: + NOHorizontalSlider->setValue(slice); + break; + case 1: + NEHorizontalSlider->setValue(slice); + break; + case 2: + SOHorizontalSlider->setValue(slice); + break; + case 3: + SEHorizontalSlider->setValue(slice); + break; + } +} +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +void vvMainWindow::UpdateSliceRange(int slicer, int min, int max, int tmin, int tmax) +{ + //int position = int((min+max)/2); + int position = mSlicerManagers[mCurrentPickedImageIndex]->GetSlicer(slicer)->GetSlice(); + if (slicer == 0) { + NOVerticalSlider->setRange(min,max); + NOHorizontalSlider->setRange(tmin,tmax); + NOVerticalSlider->setValue(position); + } else if (slicer == 1) { + NEVerticalSlider->setRange(min,max); + NEHorizontalSlider->setRange(tmin,tmax); + NEVerticalSlider->setValue(position); + } else if (slicer == 2) { + SOVerticalSlider->setRange(min,max); + SOHorizontalSlider->setRange(tmin,tmax); + SOVerticalSlider->setValue(position); + } else if (slicer == 3) { + SEVerticalSlider->setRange(min,max); + SEHorizontalSlider->setRange(tmin,tmax); + SEVerticalSlider->setValue(position); + } +} +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +void vvMainWindow::SaveNOScreenshot() +{ + SaveScreenshot(NOViewWidget); +} +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +void vvMainWindow::SaveNEScreenshot() +{ + SaveScreenshot(NEViewWidget); +} +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +void vvMainWindow::SaveSOScreenshot() +{ + SaveScreenshot(SOViewWidget); +} +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +void vvMainWindow::SaveSEScreenshot() +{ + SaveScreenshot(SEViewWidget); +} +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +void vvMainWindow::SaveScreenshotAllSlices() +{ + QVTKWidget *widget = NOViewWidget; + + int index = 0;// GetSlicerIndexFromItem(DataTree->selectedItems()[0]); + vvSlicerManager * SM = mSlicerManagers[index]; + vvImage * image = SM->GetImage(); + vvSlicer * slicer = SM->GetSlicer(0); + int orientation = slicer->GetOrientation(); + int nbSlices = image->GetSize()[orientation]; + vtkSmartPointer renderWindow = widget->GetRenderWindow(); + + // Select filename base + QString filename = QFileDialog::getSaveFileName(this, + tr("Save As (filename will be completed by slice number)"), + itksys::SystemTools::GetFilenamePath(mSlicerManagers[index]->GetFileName()).c_str(), + "Images( *.png);;Images( *.jpg)"); + + // Loop on slices + for(int i=0; iSetSlice(i); // -> change the slice of the current slicer + SM->UpdateSlice(0); // --> this one emit UpdateSlice + QCoreApplication::flush(); // -> needed to force display of contours + + // Screenshot + vtkSmartPointer windowToImageFilter = vtkSmartPointer::New(); + windowToImageFilter->SetInput(renderWindow); + windowToImageFilter->SetMagnification(1); + windowToImageFilter->SetInputBufferTypeToRGBA(); //also record the alpha (transparency) channel + windowToImageFilter->Update(); + + vtkSmartPointer writer = vtkSmartPointer::New(); + std::string fn = itksys::SystemTools::GetFilenameWithoutLastExtension(filename.toStdString()); + std::string num = clitk::toString(i); + if (i<10) num = "0"+num; + if (i<100) num = "0"+num; + if (i<1000) num = "0"+num; + + fn = itksys::SystemTools::GetFilenamePath(filename.toStdString()) + "/"+ fn + + "_" + num + itksys::SystemTools::GetFilenameLastExtension(filename.toStdString()); + writer->SetFileName(fn.c_str()); + writer->SetInput(windowToImageFilter->GetOutput()); + writer->Write(); + } +} +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +void vvMainWindow::SaveScreenshot(QVTKWidget *widget) +{ + QString Extensions = "Images( *.png);;"; + Extensions += "Images( *.jpg);;"; + Extensions += "Images( *.bmp);;"; + Extensions += "Images( *.tif);;"; + Extensions += "Images( *.ppm)"; +#if defined(VTK_USE_FFMPEG_ENCODER) || defined(VTK_USE_VIDEO_FOR_WINDOWS) + Extensions += ";;Video( *.avi)"; +#endif +#ifdef VTK_USE_MPEG2_ENCODER + Extensions += ";;Video( *.mpg)"; +#endif +#ifdef CLITK_EXPERIMENTAL + Extensions += ";;Video( *.gif)"; +#endif + + int smIndex=GetSlicerIndexFromItem(DataTree->selectedItems()[0]); + QString fileName = QFileDialog::getSaveFileName(this, + tr("Save As"), + itksys::SystemTools::GetFilenamePath(mSlicerManagers[smIndex]->GetFileName()).c_str(), + Extensions); + + if (!fileName.isEmpty()) { + vtkSmartPointer w2i = vtkSmartPointer::New(); + w2i->SetInput(widget->GetRenderWindow()); + w2i->Update(); + vtkImageData *image = w2i->GetOutput(); + + std::string ext(itksys::SystemTools::GetFilenameLastExtension(fileName.toStdString())); + + // Image + vtkImageWriter *imgwriter = NULL; + if (ext==".bmp") + imgwriter = vtkBMPWriter::New(); + else if (ext==".tif") + imgwriter = vtkTIFFWriter::New(); + else if (ext==".ppm") + imgwriter = vtkPNMWriter::New(); + else if (ext==".png") + imgwriter = vtkPNGWriter::New(); + else if (ext==".jpg") + imgwriter = vtkJPEGWriter::New(); + + // Snapshot image if not null + if(imgwriter!=NULL) { + imgwriter->SetInput(image); + imgwriter->SetFileName(fileName.toStdString().c_str()); + imgwriter->Write(); + return; + } + + // Video + vtkGenericMovieWriter *vidwriter = NULL; +#if CLITK_EXPERIMENTAL == 1 + if (ext==".gif") { + vvAnimatedGIFWriter *gif = vvAnimatedGIFWriter::New(); + vidwriter = gif; + + // FPS + bool ok; + int fps = QInputDialog::getInteger(this, tr("Number of frames per second"), + tr("FPS:"), 5, 0, 1000, 1, &ok); + if(ok) + gif->SetRate(fps); + + // Loops + int loops = QInputDialog::getInteger(this, tr("Loops"), + tr("Number of loops (0 means infinite):"), 0, 0, 1000000000, 1, &ok); + if(ok) + gif->SetLoops(loops); + + // Dithering + QString msg = "Would you like to activate dithering?"; + QMessageBox msgBox(QMessageBox::Question, tr("Dithering"),msg, 0, this); + msgBox.addButton(tr("Yes"), QMessageBox::AcceptRole); + msgBox.addButton(tr("No"), QMessageBox::RejectRole); + gif->SetDither(msgBox.exec() == QMessageBox::AcceptRole); + } +#endif +#ifdef VTK_USE_VIDEO_FOR_WINDOWS + if (ext==".avi") { + vtkAVIWriter *mpg = vtkAVIWriter::New(); + vidwriter = mpg; + mpg->SetQuality(2); + bool ok; + int fps = QInputDialog::getInteger(this, tr("Number of frames per second"), + tr("FPS:"), 5, 0, 1024, 1, &ok); + if(!ok) + fps = 5; + mpg->SetRate(fps); + } +#endif +#ifdef VTK_USE_FFMPEG_ENCODER + if (ext==".avi") { + vtkFFMPEGWriter *mpg = vtkFFMPEGWriter::New(); + vidwriter = mpg; + mpg->SetQuality(2); + bool ok; + int fps = QInputDialog::getInteger(this, tr("Number of frames per second"), + tr("FPS:"), 5, 0, 1024, 1, &ok); + if(!ok) + fps = 5; + mpg->SetRate(fps); + mpg->SetBitRateTolerance(int(ceil(12.0*1024*1024/fps))); + } +#endif +#ifdef VTK_USE_MPEG2_ENCODER + if (ext==".mpg") { + vtkMPEG2Writer *mpg = vtkMPEG2Writer::New(); + vidwriter = mpg; + } +#endif + + // Take video if not null + if(vidwriter!=NULL){ + vidwriter->SetInput(image); + vidwriter->SetFileName(fileName.toStdString().c_str()); + vidwriter->Start(); + int nSlice = mSlicerManagers[smIndex]->GetSlicer(0)->GetTMax(); + for(int i=0; i<=nSlice; i++) { + mSlicerManagers[smIndex]->SetNextTSlice(0); + vtkSmartPointer w2i = vtkSmartPointer::New(); + w2i->SetInput(widget->GetRenderWindow()); + w2i->Update(); + vidwriter->SetInput(w2i->GetOutput()); + vidwriter->Write(); + } + vidwriter->End(); + vidwriter->Delete(); + return; + } + + QMessageBox::information(this,tr("Problem saving screenshot !"),tr("Cannot save image.\nPlease set a file extension !!!")); + } +} +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +void vvMainWindow::GoToCursor() +{ + int index = GetSlicerIndexFromItem(DataTree->selectedItems()[0]); + for (int column = 1; column < 5; column++) { + if (DataTree->selectedItems()[0]->data(column,Qt::CheckStateRole).toInt() > 1) { + double* cursorPos = mSlicerManagers[index]->GetSlicer(column-1)->GetCursorPosition(); + mSlicerManagers[index]->GetSlicer(column-1)->SetCurrentPosition( + cursorPos[0],cursorPos[1],cursorPos[2],cursorPos[3]); + mSlicerManagers[index]->UpdateViews(1,column-1); + mSlicerManagers[index]->UpdateLinked(column-1); + break; + } + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void vvMainWindow::PlayPause() +{ + if (playMode) { + playMode = 0; + playButton->setIcon(QIcon(QString::fromUtf8(":/common/icons/player_play.png"))); + ImageInfoChanged(); + return; + } else { + int image_number=DataTree->topLevelItemCount(); + bool has_temporal; + for (int i=0; iGetSlicer(0)->GetTMax() > 0) { + has_temporal=true; + break; + } + if (has_temporal) { + playMode = 1; + playButton->setIcon(QIcon(QString::fromUtf8(":/common/icons/player_pause.png"))); + QTimer::singleShot(1000/mFrameRate, this, SLOT(PlayNext())); + } + } +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void vvMainWindow::PlayNext() +{ + if (playMode && !this->isHidden()) { + int image_number=DataTree->topLevelItemCount(); + ///Only play one slicer per SM, and only if the SM is being displayed + for (int i=0; iGetSlicer(0)->GetTMax() > 0 && + DataTree->topLevelItem(i)->data(j+1,Qt::CheckStateRole).toInt() > 0) { + mSlicerManagers[i]->SetNextTSlice(j); + break; + } + QTimer::singleShot(1000/mFrameRate, this, SLOT(PlayNext())); + } +} +//------------------------------------------------------------------------------ + +void vvMainWindow::ShowLastImage() +{ + if (mSlicerManagers.size() > 1) { + QTreeWidgetItem * item=DataTree->topLevelItem(DataTree->topLevelItemCount()-1); + CurrentImageChanged(mSlicerManagers.back()->GetId()); //select new image + item->setData(1,Qt::CheckStateRole,2); //show the new image in the first panel + DisplayChanged(item,1); + } +} + +//------------------------------------------------------------------------------ +void vvMainWindow::UpdateRenderWindows() +{ + for (unsigned int i = 0; i < mSlicerManagers.size(); i++) { + mSlicerManagers[i]->GetSlicer(0)->UpdateLandmarks(); + mSlicerManagers[i]->GetSlicer(1)->UpdateLandmarks(); + mSlicerManagers[i]->GetSlicer(2)->UpdateLandmarks(); + mSlicerManagers[i]->GetSlicer(3)->UpdateLandmarks(); + } + if (NOViewWidget->GetRenderWindow()) NOViewWidget->GetRenderWindow()->Render(); + if (NEViewWidget->GetRenderWindow()) NEViewWidget->GetRenderWindow()->Render(); + if (SOViewWidget->GetRenderWindow()) SOViewWidget->GetRenderWindow()->Render(); + if (SEViewWidget->GetRenderWindow()) SEViewWidget->GetRenderWindow()->Render(); +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +void vvMainWindow::SegmentationOnCurrentImage() +{ + int index = GetSlicerIndexFromItem(DataTree->selectedItems()[0]); + + vvSegmentationDialog segmentation; + segmentation.SetImage(mSlicerManagers[index]->GetSlicer(0)->GetImage()); + segmentation.exec(); +} +//------------------------------------------------------------------------------ + +void vvMainWindow::SurfaceViewerLaunch() +{ + vvSurfaceViewerDialog surfaceViewer; + surfaceViewer.exec(); +} +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +int vvMainWindow::GetImageDuplicateFilenameNumber(std::string filename) +{ + int number=0; + for(unsigned int l=0; lGetBaseFileName() == + vtksys::SystemTools::GetFilenameName(vtksys::SystemTools::GetFilenameWithoutLastExtension(filename))) { + number = std::max(number, v->GetBaseFileNameNumber()+1); + } + } + return number; +} +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +vvSlicerManager* vvMainWindow::AddImage(vvImage::Pointer image,std::string filename) +{ + // Change filename if another image exist with the same name + int number = GetImageDuplicateFilenameNumber(filename); + + // Create new SliceManager + vvSlicerManager* slicer_manager = new vvSlicerManager(4); + slicer_manager->SetImage(image);//, IMAGE, number); + // filename = filename+"_"+clitk::toString(number); + slicer_manager->SetFilename(filename, number); + mSlicerManagers.push_back(slicer_manager); + + //create an item in the tree with good settings + QTreeWidgetItem *item = new QTreeWidgetItem(); + item->setData(0,Qt::UserRole,slicer_manager->GetFileName().c_str());//files[i].c_str()); + item->setData(1,Qt::UserRole,tr("image")); + item->setData(COLUMN_IMAGE_NAME,Qt::DisplayRole,slicer_manager->GetFileName().c_str());//filename.c_str()); + qApp->processEvents(); + + for (int j = 1; j <= 4; j++) item->setData(j,Qt::CheckStateRole,1); + + //Create the buttons for reload and close + qApp->processEvents(); + QTreePushButton* cButton = new QTreePushButton; + cButton->setItem(item); + cButton->setColumn(COLUMN_CLOSE_IMAGE); + cButton->setIcon(QIcon(QString::fromUtf8(":/common/icons/exit.png"))); + connect(cButton,SIGNAL(clickedInto(QTreeWidgetItem*, int)), + this,SLOT(CloseImage(QTreeWidgetItem*, int))); + + QTreePushButton* rButton = new QTreePushButton; + rButton->setItem(item); + rButton->setColumn(COLUMN_RELOAD_IMAGE); + rButton->setIcon(QIcon(QString::fromUtf8(":/common/icons/rotateright.png"))); + rButton->setEnabled(0); + connect(rButton,SIGNAL(clickedInto(QTreeWidgetItem*, int)), + this,SLOT(ReloadImage(QTreeWidgetItem*, int))); + + DataTree->addTopLevelItem(item); + DataTree->setItemWidget(item, COLUMN_CLOSE_IMAGE, cButton); + DataTree->setItemWidget(item, COLUMN_RELOAD_IMAGE, rButton); + + //set the id of the image + QString id = QDir::current().absoluteFilePath(slicer_manager->GetFileName().c_str()) + QString::number(mSlicerManagers.size()-1); + item->setData(COLUMN_IMAGE_NAME,Qt::UserRole,id.toStdString().c_str()); + mSlicerManagers.back()->SetId(id.toStdString()); + + linkPanel->addImage(slicer_manager->GetFileName().c_str()// filename + , id.toStdString()); + + connect(mSlicerManagers.back(), SIGNAL(currentImageChanged(std::string)), + this, SLOT(CurrentImageChanged(std::string))); + connect(mSlicerManagers.back(), SIGNAL(currentPickedImageChanged(std::string)), + this, SLOT(CurrentPickedImageChanged(std::string))); + connect(mSlicerManagers.back(), SIGNAL(UpdatePosition(int, double, double, double, double, double, double, double)), + this, SLOT(MousePositionChanged(int,double, double, double, double, double, double, double))); + connect(mSlicerManagers.back(), SIGNAL(UpdateVector(int, double, double, double, double)), + this, SLOT(VectorChanged(int,double,double,double, double))); + connect(mSlicerManagers.back(), SIGNAL(UpdateOverlay(int, double, double)), + this, SLOT(OverlayChanged(int,double,double))); + connect(mSlicerManagers.back(), SIGNAL(UpdateFusion(int, double)), + this, SLOT(FusionChanged(int,double))); + //connect(mSlicerManagers.back(), SIGNAL(UpdateFusionSequence(int, bool, unsigned int)), + // this, SLOT(FusionSequenceChanged(int, bool, unsigned int))); + connect(mSlicerManagers.back(), SIGNAL(WindowLevelChanged()), + this,SLOT(WindowLevelChanged())); + connect(mSlicerManagers.back(), SIGNAL(UpdateSlice(int,int)), + this,SLOT(UpdateSlice(int,int))); + connect(mSlicerManagers.back(), SIGNAL(UpdateTSlice(int, int)), + this,SLOT(UpdateTSlice(int, int))); + connect(mSlicerManagers.back(), SIGNAL(UpdateTSlice(int, int)), + this,SLOT(ImageInfoChanged())); + connect(mSlicerManagers.back(), SIGNAL(UpdateSliceRange(int,int,int,int,int)), + this,SLOT(UpdateSliceRange(int,int,int,int,int))); + connect(mSlicerManagers.back(), SIGNAL(UpdateLinkManager(std::string,int,double,double,double,int)), + this,SLOT(UpdateLinkManager(std::string,int,double,double,double,int))); + connect(mSlicerManagers.back(), SIGNAL(UpdateLinkedNavigation(std::string,vvSlicerManager*,vvSlicer*)), + this,SLOT(UpdateLinkedNavigation(std::string,vvSlicerManager*,vvSlicer*))); + connect(mSlicerManagers.back(), SIGNAL(ChangeImageWithIndexOffset(vvSlicerManager*,int,int)), + this,SLOT(ChangeImageWithIndexOffset(vvSlicerManager*,int,int))); + connect(mSlicerManagers.back(), SIGNAL(LandmarkAdded()),landmarksPanel,SLOT(AddPoint())); + UpdateTree(); + qApp->processEvents(); + InitSlicers(); + ShowLastImage(); + InitDisplay(); + qApp->processEvents(); + + // End + ImageInfoChanged(); + return slicer_manager; +} +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +void vvMainWindow::UpdateCurrentSlicer() +{ + int index = -1; + if (DataTree->selectedItems().size() > 0) { + index = GetSlicerIndexFromItem(DataTree->selectedItems()[0]); + } + mSlicerManagerCurrentIndex = index; +} +//------------------------------------------------------------------------------ + diff --git a/vv/vvMainWindow.h b/vv/vvMainWindow.h index f9e18b1..7933b16 100644 --- a/vv/vvMainWindow.h +++ b/vv/vvMainWindow.h @@ -159,13 +159,14 @@ public slots: void SelectFusionImage(); //select the file(s) from the disk containing the image sequence to fuse void SelectFusionSequence(); + void SelectFusionSequenceTemporalSignal(); void ResetTransformationToIdentity(); void SetVFProperty(int subsampling,int scale,int lut, int width, double r, double g, double b); void SetOverlayProperty(int color, int linked, double window, double level); void SetFusionProperty(int opacity, int tresOpacity, int colormap,double window,double level, bool showLegend); - void SetFusionSequenceProperty(int fusionSequenceFrameIndex, bool spatialSyncFlag, unsigned int fusionSequenceNbFrames); + void SetFusionSequenceProperty(int fusionSequenceFrameIndex, bool spatialSyncFlag, unsigned int fusionSequenceNbFrames, bool temporalSyncFlag); void GoToCursor(); void PlayPause(); @@ -206,7 +207,7 @@ private: QString GetSizeInBytes(unsigned long size); QString GetVectorDoubleAsString(std::vector vectorDouble); QString GetVectorIntAsString(std::vector vectorInt); - int GetSlicerIndexFromItem(QTreeWidgetItem* item); + int GetSlicerIndexFromItem(QTreeWidgetItem* item); //this actually returns the SlicerManager index TODO: rename it to GetSlicerManagerIndexFromItem QTreeWidgetItem* GetItemFromSlicerManager(vvSlicerManager* sm); void SaveScreenshot(QVTKWidget *widget); int GetImageDuplicateFilenameNumber(std::string filename); diff --git a/vv/vvOverlayPanel.cxx b/vv/vvOverlayPanel.cxx index e205c87..f32357b 100644 --- a/vv/vvOverlayPanel.cxx +++ b/vv/vvOverlayPanel.cxx @@ -62,6 +62,8 @@ vvOverlayPanel::vvOverlayPanel(QWidget * parent):QWidget(parent) connect(fCTUSSlider,SIGNAL(valueChanged(int)),this,SLOT(setFusionSequenceProperty())); connect(fCTUSActivateSpaceSyncCheckBox,SIGNAL(stateChanged(int)),this,SLOT(setFusionSequenceProperty())); + connect(fCTUSActivateTimeSyncCheckBox,SIGNAL(stateChanged(int)),this,SLOT(setFusionSequenceProperty())); + connect(fCTUSLoadSignalPushButton,SIGNAL(clicked()),this,SIGNAL(FusionSequenceSignalButtonPressed())); disableFusionSignals = false; disableFusionSequenceSignals = false; @@ -255,7 +257,7 @@ void vvOverlayPanel::getCurrentFusionInfo(int visibility,double value) } -void vvOverlayPanel::getFusionSequenceProperty(int sequenceFrameIndex, bool spatialSync, unsigned int sequenceLenth) +void vvOverlayPanel::getFusionSequenceProperty(int sequenceFrameIndex, bool spatialSync, unsigned int sequenceLenth, bool temporalSync) { if (sequenceFrameIndex > -1) { disableFusionSequenceSignals = true; @@ -265,7 +267,11 @@ void vvOverlayPanel::getFusionSequenceProperty(int sequenceFrameIndex, bool spat fCTUSSlider->setValue(sequenceFrameIndex); fCTUSSlider->setMaximum(sequenceLenth); if (spatialSync) fCTUSActivateSpaceSyncCheckBox->setCheckState(Qt::Checked); - else fCTUSActivateSpaceSyncCheckBox->setCheckState(Qt::Unchecked); + else fCTUSActivateSpaceSyncCheckBox->setCheckState(Qt::Unchecked); + if (fCTUSActivateTimeSyncCheckBox->isEnabled()) { + if ( temporalSync ) fCTUSActivateTimeSyncCheckBox->setCheckState(Qt::Checked); + else fCTUSActivateTimeSyncCheckBox->setCheckState(Qt::Unchecked); + } disableFusionSequenceSignals = false; setFusionSequenceProperty(); } else { @@ -275,6 +281,7 @@ void vvOverlayPanel::getFusionSequenceProperty(int sequenceFrameIndex, bool spat fCTUSSlider->setValue(0); fCTUSSlider->setMaximum(0); fCTUSActivateSpaceSyncCheckBox->setCheckState(Qt::Unchecked); + fCTUSActivateTimeSyncCheckBox->setCheckState(Qt::Unchecked); } } @@ -284,10 +291,21 @@ void vvOverlayPanel::setFusionSequenceProperty() if (disableFusionSequenceSignals) return; - emit FusionSequencePropertyUpdated(fCTUSSlider->value(), fCTUSActivateSpaceSyncCheckBox->isChecked(), fCTUSSlider->maximum()); + emit FusionSequencePropertyUpdated(fCTUSSlider->value(), fCTUSActivateSpaceSyncCheckBox->isChecked(), fCTUSSlider->maximum(), fCTUSActivateTimeSyncCheckBox->isChecked()); } +void vvOverlayPanel::enableFusionSequenceTemporalSync() { + fCTUSActivateTimeSyncCheckBox->setEnabled(1); + fCTUSActivateTimeSyncCheckBox->setChecked(true); + + if (disableFusionSequenceSignals) return; + emit FusionSequencePropertyUpdated(fCTUSSlider->value(), fCTUSActivateSpaceSyncCheckBox->isChecked(), fCTUSSlider->maximum(), fCTUSActivateTimeSyncCheckBox->isChecked()); +} +void vvOverlayPanel::updateFusionSequenceSliderValueFromWindow(int val, bool updateVisualization) { + fCTUSSlider->setValue(val); + if (updateVisualization) emit FusionSequencePropertyUpdated(fCTUSSlider->value(), fCTUSActivateSpaceSyncCheckBox->isChecked(), fCTUSSlider->maximum(), fCTUSActivateTimeSyncCheckBox->isChecked()); +} void vvOverlayPanel::VFColorChangeRequest() { diff --git a/vv/vvOverlayPanel.h b/vv/vvOverlayPanel.h index 69abbc2..1b3f914 100644 --- a/vv/vvOverlayPanel.h +++ b/vv/vvOverlayPanel.h @@ -44,15 +44,16 @@ public: void getFusionProperty(int opacity, int thresOpacity, int colormap, double window, double level); void getFusionName(QString name); - void getFusionSequenceProperty(int sequenceFrameIndex, bool spatialSync, unsigned int sequenceLength); + void getFusionSequenceProperty(int sequenceFrameIndex, bool spatialSync, unsigned int sequenceLength, bool temporalSync); void getCurrentVectorInfo(int visibility, double x, double y, double z, double value); void getCurrentOverlayInfo(int visibility,double valueOver, double valueRef); void getCurrentFusionInfo(int visibility,double value); - //void getCurrentFusionSequenceInfo(int visibility,double value); bool getShowLegend(); + void updateFusionSequenceSliderValueFromWindow(int val, bool updateVisualization); + public slots: void setVFProperty(); void setOverlayProperty(); @@ -60,13 +61,14 @@ public slots: void setFusionSpinProperty(); void VFColorChangeRequest(); void setFusionSequenceProperty(); + void enableFusionSequenceTemporalSync(); signals: void VFPropertyUpdated(int subsampling, int scale, int log, int width, double r, double g, double b); void OverlayPropertyUpdated(int color, int linked, double window, double level); void FusionPropertyUpdated(int opacity, int thresOpacity, int colormap, double window, double level, bool showLegend); - void FusionSequencePropertyUpdated(int sequenceFrameIndex, bool spatialSync, unsigned int sequenceLength); - + void FusionSequencePropertyUpdated(int sequenceFrameIndex, bool spatialSync, unsigned int sequenceLength, bool temporalSync); + void FusionSequenceSignalButtonPressed(); private: bool disableFusionSignals; diff --git a/vv/vvSlicer.cxx b/vv/vvSlicer.cxx index eafc3fa..4f66ee0 100644 --- a/vv/vvSlicer.cxx +++ b/vv/vvSlicer.cxx @@ -81,7 +81,7 @@ static void copyExtent(int* in, int* to){ //------------------------------------------------------------------------------ vvSlicer::vvSlicer() { - mFusionSequenceFlag = false; + mFusionSequenceCode = -1; this->UnInstallPipeline(); mImage = NULL; mReducedExtent = new int[6]; @@ -312,7 +312,7 @@ void vvSlicer::SetCurrentPosition(double x, double y, double z, int t) mCurrentBeforeSlicingTransform[1]=y; mCurrentBeforeSlicingTransform[2]=z; mSlicingTransform->GetInverse()->TransformPoint(mCurrentBeforeSlicingTransform,mCurrent); - SetTSlice(t); + if (t>=0) SetTSlice(t); } //------------------------------------------------------------------------------ @@ -415,9 +415,9 @@ void vvSlicer::SetOverlay(vvImage::Pointer overlay) //------------------------------------------------------------------------------ -void vvSlicer::SetFusion(vvImage::Pointer fusion, bool fusionSequenceFlag) +void vvSlicer::SetFusion(vvImage::Pointer fusion, int fusionSequenceCode) { - mFusionSequenceFlag = fusionSequenceFlag; + mFusionSequenceCode = fusionSequenceCode; if (fusion->GetVTKImages().size()) { mFusion = fusion; @@ -755,7 +755,7 @@ void vvSlicer::SetTSlice(int t, bool updateLinkedImages) } } //update the fusion ; except in case this is a fusionSequence, in which case both 'times' should be independent. - if (mFusion && mFusionActor->GetVisibility() && !mFusionSequenceFlag) { + if (mFusion && mFusionActor->GetVisibility() && (mFusionSequenceCode<0)) { if (mFusion->GetVTKImages().size() > (unsigned int)t) { mCurrentFusionTSlice = t; mFusionReslice->SetInput( mFusion->GetVTKImages()[mCurrentFusionTSlice]); @@ -778,7 +778,7 @@ void vvSlicer::SetTSlice(int t, bool updateLinkedImages) //------------------------------------------------------------------------------ void vvSlicer::SetFusionSequenceTSlice(int t) { - if (mFusion && mFusionActor->GetVisibility() && mFusionSequenceFlag) { + if (mFusion && mFusionActor->GetVisibility() && (mFusionSequenceCode>=0)) { if (mFusion->GetVTKImages().size() > (unsigned int)t) { mCurrentFusionTSlice = t; mFusionReslice->SetInput( mFusion->GetVTKImages()[mCurrentFusionTSlice] ); @@ -807,7 +807,7 @@ int vvSlicer::GetMaxCurrentTSlice() int t = mCurrentTSlice; if(mOverlay) t = std::max(t, mCurrentOverlayTSlice); - if(mFusion&& (!mFusionSequenceFlag)) //ignore fusionSequence data: for these, the times are not to be related (this way) + if(mFusion&& (mFusionSequenceCode<0)) //ignore fusionSequence data: for these, the times are not to be related (this way) t = std::max(t, mCurrentFusionTSlice); return t; } @@ -1183,9 +1183,8 @@ void vvSlicer::ResetCamera() //---------------------------------------------------------------------------- void vvSlicer::SetDisplayMode(bool i) { - this->GetRenderer()->SetDraw(i); - if (i) - UpdateDisplayExtent(); + this->GetRenderer()->SetDraw(i); + if (i) UpdateDisplayExtent(); } //---------------------------------------------------------------------------- @@ -1361,8 +1360,6 @@ double vvSlicer::GetScalarComponentAsDouble(vtkImageData *image, double X, doubl iy = lrint(Y); iz = lrint(Z); - image->UpdateInformation(); - if (ix < image->GetWholeExtent()[0] || ix > image->GetWholeExtent()[1] || iy < image->GetWholeExtent()[2] || diff --git a/vv/vvSlicer.h b/vv/vvSlicer.h index e647a19..7cb4036 100644 --- a/vv/vvSlicer.h +++ b/vv/vvSlicer.h @@ -81,7 +81,7 @@ public: vtkActor* GetVFActor() ; vtkCornerAnnotation* GetAnnotation(); - void SetFusion(vvImage::Pointer inputFusion, bool fusionSequenceFlag = false); + void SetFusion(vvImage::Pointer inputFusion, int fusionSequenceCode = -1); vvImage::Pointer GetFusion() { return mFusion; } @@ -218,7 +218,7 @@ protected: vvLandmarks* mLandmarks; - bool mFusionSequenceFlag; //flag used to indicate whether the 'fusion' data is actually a 'fusionSequence' + int mFusionSequenceCode; //-1: not involved in a fusion sequence, 0: main sequence (CT), 1: secondary sequence (US) // __________ Image coordinates accounting for spacing and origin // Λ Λ diff --git a/vv/vvSlicerManager.cxx b/vv/vvSlicerManager.cxx index 6f5c55a..01821d9 100644 --- a/vv/vvSlicerManager.cxx +++ b/vv/vvSlicerManager.cxx @@ -40,6 +40,7 @@ #include #include +#include //---------------------------------------------------------------------------- vvSlicerManager::vvSlicerManager(int numberOfSlicers) { @@ -62,10 +63,12 @@ vvSlicerManager::vvSlicerManager(int numberOfSlicers) mFusionLevel = 1000; mFusionShowLegend = true; + mFusionSequenceInvolvementCode = -1; + mFusionSequenceIndexLinkedManager = -1; mFusionSequenceFrameIndex = -1; - mFusionSequenceSpatialSyncFlag = false; mFusionSequenceNbFrames = 0; - mFusionSequenceIndexLinkedManager = -1; + mFusionSequenceSpatialSyncFlag = false; + mFusionSequenceTemporalSyncFlag = false; mLandmarks = NULL; mLinkedId.resize(0); @@ -307,8 +310,11 @@ bool vvSlicerManager::SetFusion(std::string filename,int dim, std::string compon //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- -bool vvSlicerManager::SetFusionSequence(std::vector filenames,int dim, std::string component, vvImageReader::LoadedImageType type) +//this function is called by vvMainWindow::AddFusionSequence for the primary sequence (CT), while the given files constitute the secondary sequence. +bool vvSlicerManager::SetFusionSequence(std::vector filenames, int dim, std::string component, vvImageReader::LoadedImageType type) { + mFusionSequenceInvolvementCode = 0; + mFusionName = filenames[0]; mFusionComponent = component; @@ -326,7 +332,7 @@ bool vvSlicerManager::SetFusionSequence(std::vector filenames,int d if (mFusionSequenceReader->GetLastError().size() == 0) { for ( unsigned int i = 0; i < mSlicers.size(); i++) { - mSlicers[i]->SetFusion(mFusionSequenceReader->GetOutput(), true); + mSlicers[i]->SetFusion(mFusionSequenceReader->GetOutput(), mFusionSequenceInvolvementCode); } } else { mLastError = mFusionSequenceReader->GetLastError(); @@ -411,8 +417,9 @@ vvSlicer* vvSlicerManager::GetSlicer(int i) //---------------------------------------------------------------------------- void vvSlicerManager::UpdateSlicer(int num, bool state) { - if (mSlicers[num]->GetImage()) + if (mSlicers[num]->GetImage()) { mSlicers[num]->SetDisplayMode(state); + } } //---------------------------------------------------------------------------- @@ -777,8 +784,9 @@ void vvSlicerManager::UpdateLinked(int slicer) z >= mSlicers[slicer]->GetInput()->GetWholeExtent()[4]-0.5 && z <= mSlicers[slicer]->GetInput()->GetWholeExtent()[5]+0.5) { for (std::list::const_iterator i = mLinkedId.begin(); i != mLinkedId.end(); i++) { - if (mFusionSequenceIndexLinkedManager>0) { + if (this->IsInvolvedInFusionSequence()) { //this SlicerManager is involved in fusionSequence => do not synchronize the times + //TODO: check is something more specific should be done ... emit UpdateLinkManager(*i, slicer, p[0], p[1], p[2], -1); } else { @@ -935,8 +943,8 @@ void vvSlicerManager::Reload() mSlicers[i]->SetImage(mImage); } - //check if this image is involved in a fusion sequence, then the main transform matrix should be updated. - if (mFusionSequenceReader.IsNotNull()) { + //if this image is the primary sequence of a fusion sequence, then the main transform matrix should be updated. + if (this->IsMainSequenceOfFusionSequence()) { SetFusionSequenceMainTransformMatrix( mImage->GetTransform()[0]->GetMatrix() ); } } @@ -956,12 +964,13 @@ void vvSlicerManager::ReloadFusion() //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- +//the secondary sequence is being reloaded. void vvSlicerManager::ReloadFusionSequence() { mFusionSequenceReader->Update(mImage->GetNumberOfDimensions(),mFusionComponent.c_str(),vvImageReader::MERGEDWITHTIME); for ( unsigned int i = 0; i < mSlicers.size(); i++) { - mSlicers[i]->SetFusion(mFusionSequenceReader->GetOutput(), true); + mSlicers[i]->SetFusion(mFusionSequenceReader->GetOutput(), 1); mSlicers[i]->Render(); } @@ -972,7 +981,6 @@ void vvSlicerManager::ReloadFusionSequence() } //Update the list of initial transforms - //Warning, the main transform will not be updated on reload......... mFusionSequenceListInitialTransformMatrices.clear(); for (unsigned i=0 ; iAddFusionSequenceInitialTransformMatrices( mFusionSequenceReader->GetOutput()->GetTransform()[i]->GetMatrix() ); @@ -1113,7 +1121,9 @@ void vvSlicerManager::UpdateInfoOnCursorPosition(int slicer) double Zover = (z - fusion->GetOrigin()[2]) / fusion->GetSpacing()[2]; valueFus = this->GetScalarComponentAsDouble(fusion, Xover, Yover, Zover); } - else if (mFusionSequenceIndexLinkedManager>=0) { + else if (this->IsInvolvedInFusionSequence()) { + //if the cursor moves over the 'independent' version of the secondary sequence + //do not update the panel, just keep it as it is. displayFus = 1; valueFus = std::numeric_limits::quiet_NaN(); } @@ -1171,9 +1181,9 @@ void vvSlicerManager::UpdateSlice(int slicer) void vvSlicerManager::UpdateTSlice(int slicer) { int slice = mSlicers[slicer]->GetSlice(); + int tslice = mSlicers[slicer]->GetMaxCurrentTSlice(); - - if (mFusionSequenceIndexLinkedManager>=0) tslice = mSlicers[slicer]->GetTSlice(); + if (this->IsInvolvedInFusionSequence()) tslice = mSlicers[slicer]->GetTSlice(); if (mPreviousSlice[slicer] == slice) { if (mPreviousTSlice[slicer] == tslice) { @@ -1184,8 +1194,6 @@ void vvSlicerManager::UpdateTSlice(int slicer) mPreviousSlice[slicer] = slice; mPreviousTSlice[slicer] = tslice; - if (mFusionSequenceIndexLinkedManager>=0) return; - emit UpdateTSlice(slicer, tslice); } //---------------------------------------------------------------------------- @@ -1392,18 +1400,22 @@ void vvSlicerManager::SetColorMap(int colormap) LUT->Build(); } vtkWindowLevelLookupTable* fusLUT = NULL; + + //FUSION / FUSION SEQUENCE if (mSlicers[0]->GetFusion()) { // && mFusionColorMap >= 0) { - fusLUT = vtkWindowLevelLookupTable::New(); + fusLUT = vtkWindowLevelLookupTable::New(); double fusRange [2]; fusRange[0] = mFusionLevel - mFusionWindow/2; fusRange[1] = mFusionLevel + mFusionWindow/2; - //check whether it is actually a fusionSequence or a fusion, before invoking mFusionReader... - double* frange; - if (mFusionReader.IsNull()) frange = mFusionSequenceReader->GetOutput()->GetVTKImages()[0]->GetScalarRange(); - else frange = mFusionReader->GetOutput()->GetVTKImages()[0]->GetScalarRange(); + //check whether it is actually a fusionSequence or a fusion, before invoking mFusionReader... + double* frange; + if (this->IsInvolvedInFusionSequence()) + frange = mFusionSequenceReader->GetOutput()->GetVTKImages()[0]->GetScalarRange(); + else + frange = mFusionReader->GetOutput()->GetVTKImages()[0]->GetScalarRange(); - fusLUT->SetTableRange(frange); + fusLUT->SetTableRange(frange); fusLUT->SetValueRange(1,1); fusLUT->SetSaturationRange(1,1); fusLUT->SetAlphaRange(1, 1); @@ -1425,10 +1437,10 @@ void vvSlicerManager::SetColorMap(int colormap) fusLUT->SetValueRange(0,1); fusLUT->SetSaturationRange(0,0); } - + fusLUT->ForceBuild(); double v[4]; - + // set color table transparency //double alpha_range=(double)mFusionThresOpacity/10; double range_end = fusRange[0] + (double)mFusionThresOpacity*(fusRange[1] - fusRange[0])/100; @@ -1444,7 +1456,7 @@ void vvSlicerManager::SetColorMap(int colormap) } } for ( unsigned int i = 0; i < mSlicers.size(); i++) { - + if (mSlicers[i]->GetOverlay()) { vtkLookupTable* supLUT = vtkLookupTable::New(); supLUT->SetTableRange(range[0],range[1]); @@ -1467,7 +1479,7 @@ void vvSlicerManager::SetColorMap(int colormap) } else { mSlicers[i]->GetWindowLevel()->SetLookupTable(LUT); } - + if (mSlicers[i]->GetFusion()) { mSlicers[i]->ShowFusionLegend(mFusionShowLegend); mSlicers[i]->GetFusionMapper()->SetLookupTable(fusLUT); diff --git a/vv/vvSlicerManager.h b/vv/vvSlicerManager.h index e6c3505..527078a 100644 --- a/vv/vvSlicerManager.h +++ b/vv/vvSlicerManager.h @@ -153,6 +153,7 @@ class vvSlicerManager : public QObject { //set/get fusionSequence related data void SetFusionSequenceFrameIndex(int sequenceFrameIndex) { mFusionSequenceFrameIndex = sequenceFrameIndex; } void SetFusionSequenceSpatialSyncFlag(bool spatialSync) { mFusionSequenceSpatialSyncFlag = spatialSync; } + void SetFusionSequenceTemporalSyncFlag(bool temporalSync) { mFusionSequenceTemporalSyncFlag = temporalSync; } void SetFusionSequenceLength(unsigned int fusionSequenceNbFrames) { mFusionSequenceNbFrames = fusionSequenceNbFrames; } void SetFusionSequenceMainTransformMatrix(vtkSmartPointer mat) { mFusionSequenceMainTransform = vtkSmartPointer::New(); @@ -164,16 +165,25 @@ class vvSlicerManager : public QObject { mFusionSequenceListInitialTransformMatrices.push_back( tmpMat ); } void SetFusionSequenceIndexOfLinkedManager(int index) { mFusionSequenceIndexLinkedManager = index; } + void SetFusionSequenceTemporalSignal(std::vector s) { mFusionSequenceTemporalSignal = s; } + + void SetFusionSequenceInvolvmentCode(int code) { mFusionSequenceInvolvementCode=code; } + int GetFusionSequenceInvolvmentCode() { return mFusionSequenceInvolvementCode;} + bool IsInvolvedInFusionSequence() {return (!(mFusionSequenceInvolvementCode==-1));} + bool IsMainSequenceOfFusionSequence() {return (mFusionSequenceInvolvementCode==0);} + bool IsSecondarySequenceOfFusionSequence() {return (mFusionSequenceInvolvementCode==1);} int GetFusionSequenceIndexOfLinkedManager() { return mFusionSequenceIndexLinkedManager; } int GetFusionSequenceFrameIndex() { return mFusionSequenceFrameIndex; } bool GetFusionSequenceSpatialSyncFlag() { return mFusionSequenceSpatialSyncFlag; } + bool GetFusionSequenceTemporalSyncFlag() { return mFusionSequenceTemporalSyncFlag; } unsigned int GetFusionSequenceNbFrames() { return mFusionSequenceNbFrames; } const vtkSmartPointer& GetFusionSequenceMainTransformMatrix() {return mFusionSequenceMainTransform;} const std::vector< vtkSmartPointer >& GetFusionSequenceInitialTransformMatrices() {return mFusionSequenceListInitialTransformMatrices;} const vtkSmartPointer& GetFusionSequenceInitialTransformMatrixAtFrame(unsigned i) { return mFusionSequenceListInitialTransformMatrices[i]; } + const std::vector& GetFusionSequenceTemporalSignal() {return mFusionSequenceTemporalSignal;} double GetColorWindow() const; double GetColorLevel() const; @@ -302,13 +312,15 @@ protected: double mFusionLevel; bool mFusionShowLegend; - //fusionSequence related data - int mFusionSequenceIndexLinkedManager; - int mFusionSequenceFrameIndex; - bool mFusionSequenceSpatialSyncFlag; - unsigned int mFusionSequenceNbFrames; + //Fusion of sequences related data + int mFusionSequenceInvolvementCode; //-1: not involved, 0: main sequence(CT), 1: secondary sequence (US) + int mFusionSequenceIndexLinkedManager; //index of the other sequence involved in the visualization + int mFusionSequenceFrameIndex; //temporal index of the current image in the sequence (<->TSlice) + unsigned int mFusionSequenceNbFrames; //number of frames in the temporal sequence + bool mFusionSequenceSpatialSyncFlag, mFusionSequenceTemporalSyncFlag; //flags indicating whether the spatial/temporal synchronization are actives vtkSmartPointer mFusionSequenceMainTransform; std::vector< vtkSmartPointer > mFusionSequenceListInitialTransformMatrices; + std::vector mFusionSequenceTemporalSignal; int mPreset; SlicingPresetType mSlicingPreset;