From 91342e828163ad49dbed39426ed4521dbfc64629 Mon Sep 17 00:00:00 2001 From: srit Date: Thu, 21 Oct 2010 12:56:57 +0000 Subject: [PATCH] Implemented alternative to former split: split on open. --- vv/qt_ui/vvMainWindow.ui | 16 ++- vv/vvConstants.h | 1 + vv/vvImageReader.cxx | 1 + vv/vvImageReader.h | 4 +- vv/vvImageReader.txx | 39 ++++++- vv/vvMainWindow.cxx | 212 ++++++++++++++++++++++++--------------- vv/vvMainWindow.h | 1 + vv/vvSlicerManager.cxx | 3 +- vv/vvSlicerManager.h | 2 +- 9 files changed, 187 insertions(+), 92 deletions(-) diff --git a/vv/qt_ui/vvMainWindow.ui b/vv/qt_ui/vvMainWindow.ui index 0dffe7b..fb7ff76 100644 --- a/vv/qt_ui/vvMainWindow.ui +++ b/vv/qt_ui/vvMainWindow.ui @@ -773,9 +773,10 @@ + + - @@ -910,7 +911,16 @@ :/common/icons/open.png:/common/icons/open.png - Open several xD images into a single (x+1) D + Merge several xD images into a single (x+1)D image + + + + + + :/common/icons/open.png:/common/icons/open.png + + + Slice a xD image into several (x-1)D images @@ -990,7 +1000,7 @@ :/common/icons/open.png:/common/icons/open.png - Open several xD images into a single xD + t + Open several xD images into a single xD+t images diff --git a/vv/vvConstants.h b/vv/vvConstants.h index be3652b..dfc7b75 100644 --- a/vv/vvConstants.h +++ b/vv/vvConstants.h @@ -25,6 +25,7 @@ typedef enum _IMAGETYPE { IMAGE = 20, DICOM, MERGED, +SLICED, IMAGEWITHTIME, MERGEDWITHTIME, VECTORFIELD, diff --git a/vv/vvImageReader.cxx b/vv/vvImageReader.cxx index 17ed757..8bbdf25 100644 --- a/vv/vvImageReader.cxx +++ b/vv/vvImageReader.cxx @@ -31,6 +31,7 @@ vvImageReader::vvImageReader() mInputFilenames.resize(0); mLastError = ""; mType = UNDEFINEDIMAGETYPE; + mSlice = 0; } //------------------------------------------------------------------------------ diff --git a/vv/vvImageReader.h b/vv/vvImageReader.h index 99d302a..b50d66b 100644 --- a/vv/vvImageReader.h +++ b/vv/vvImageReader.h @@ -42,12 +42,13 @@ public: return mLastError; } + void SetSlice(unsigned int i) { mSlice = i; } + //==================================================================== // Main function void Update(); void Update(LoadedImageType type); void Update(int dim, std::string InputPixelType, LoadedImageType type); - //void Extract(int dim, std::string InputPixelType, int slice); protected: void run(); @@ -55,6 +56,7 @@ protected: std::vector mInputFilenames; ///Method used to load the image, see vvConstants.h for definition LoadedImageType mType; + unsigned int mSlice; itk::Command::Pointer mObserver; std::string mLastError; diff --git a/vv/vvImageReader.txx b/vv/vvImageReader.txx index 75fab2d..31937bf 100644 --- a/vv/vvImageReader.txx +++ b/vv/vvImageReader.txx @@ -75,13 +75,12 @@ void vvImageReader::UpdateWithDimAndInputPixelType() // one at the time to avoid excessive // memory use { - mImage=vvImage::New(); - for (std::vector::const_iterator i=mInputFilenames.begin(); i!=mInputFilenames.end(); i++) { + mImage=vvImage::New(); + for (std::vector::const_iterator i=mInputFilenames.begin(); i!=mInputFilenames.end(); i++) { typedef itk::Image< InputPixelType, VImageDimension-1 > InputImageType; typedef itk::ImageFileReader ReaderType; typename ReaderType::Pointer reader = ReaderType::New(); reader->ReleaseDataFlagOn(); - std::cout << (*i) << std::endl; reader->SetFileName(*i); try { reader->Update(); @@ -95,6 +94,40 @@ void vvImageReader::UpdateWithDimAndInputPixelType() } mImage->AddItkImage(reader->GetOutput()); } + } else if (mType == SLICED) { + mImage=vvImage::New(); + typedef itk::Image< InputPixelType, VImageDimension > InputImageType; + typedef itk::ImageFileReader ReaderType; + typename ReaderType::Pointer reader = ReaderType::New(); + reader->SetFileName(mInputFilenames[0]); + reader->UpdateOutputInformation(); + + typedef itk::Image< InputPixelType, VImageDimension-1 > SlicedImageType; + typedef itk::ExtractImageFilter FilterType; + + typename InputImageType::RegionType inputRegion = reader->GetOutput()->GetLargestPossibleRegion(); + typename InputImageType::SizeType inputSize = inputRegion.GetSize(); + typename InputImageType::IndexType start = inputRegion.GetIndex(); + typename InputImageType::SizeType extractedRegionSize = inputSize; + typename InputImageType::RegionType extractedRegion; + extractedRegionSize[VImageDimension - 1] = 0; + extractedRegion.SetSize(extractedRegionSize); + start[VImageDimension - 1] = mSlice; + extractedRegion.SetIndex(start); + + typename FilterType::Pointer filter = FilterType::New(); + filter->SetExtractionRegion(extractedRegion); + filter->SetInput(reader->GetOutput()); + filter->ReleaseDataFlagOn(); + try { + filter->Update(); + } + catch ( itk::ExceptionObject & err ) { + std::cerr << "Error while slicing " << mInputFilenames[0].c_str() + << "(slice #" << mSlice << ") " << err << std::endl; + return; + } + mImage->AddItkImage(filter->GetOutput()); } else { if (mInputFilenames.size() > 1) { typedef itk::Image< InputPixelType, VImageDimension > InputImageType; diff --git a/vv/vvMainWindow.cxx b/vv/vvMainWindow.cxx index 39a2d9a..89a8884 100644 --- a/vv/vvMainWindow.cxx +++ b/vv/vvMainWindow.cxx @@ -234,6 +234,7 @@ vvMainWindow::vvMainWindow():vvMainWindowBase() 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())); @@ -301,6 +302,7 @@ vvMainWindow::vvMainWindow():vvMainWindowBase() QMenu * rmenu = new QMenu("Recently opened files..."); rmenu->setIcon(QIcon(QString::fromUtf8(":/common/icons/open.png"))); menuFile->insertMenu(actionOpen_Image_With_Time,rmenu); + menuFile->insertSeparator(actionOpen_Image_With_Time); for (std::list::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); @@ -594,6 +596,22 @@ void vvMainWindow::MergeImages() } //------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +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, SLICED); +} +//------------------------------------------------------------------------------ //------------------------------------------------------------------------------ void vvMainWindow::MergeImagesWithTime() @@ -729,6 +747,32 @@ void vvMainWindow::LoadImages(std::vector files, LoadedImageType fi 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 == 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) { @@ -748,93 +792,95 @@ void vvMainWindow::LoadImages(std::vector files, LoadedImageType fi progress.SetProgress(i,fileSize); qApp->processEvents(); - //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]); - - if (filetype == IMAGE || filetype == IMAGEWITHTIME) - SetImageSucceed = imageManager->SetImage(files[i],filetype, number); - else { - SetImageSucceed = imageManager->SetImages(files,filetype, number); - } - if (SetImageSucceed == false) { - 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()); - qApp->processEvents(); - - //Create the buttons for reload and close + for (int j = 0; j < nSlices[i]; j++) { + //read the image and put it in mSlicerManagers + vvSlicerManager* imageManager = new vvSlicerManager(4); 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))); + bool SetImageSucceed=false; - DataTree->addTopLevelItem(item); - DataTree->setItemWidget(item, COLUMN_CLOSE_IMAGE, cButton); - DataTree->setItemWidget(item, COLUMN_RELOAD_IMAGE, rButton); + // Change filename if an image with the same already exist + int number = GetImageDuplicateFilenameNumber(files[i] + std::string("_slice")); - //set the id of the image - QString id = 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(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(UpdateWindows(int, int, int)), - this,SLOT(WindowsChanged(int, int, int))); - connect(mSlicerManagers.back(), SIGNAL(WindowLevelChanged(double, double,int, int)), - this,SLOT(WindowLevelChanged(double, double, int, int))); - 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(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*)), - this,SLOT(UpdateLinkedNavigation(std::string,vvSlicerManager*))); - connect(mSlicerManagers.back(), SIGNAL(ChangeImageWithIndexOffset(vvSlicerManager*,int,int)), - this,SLOT(ChangeImageWithIndexOffset(vvSlicerManager*,int,int))); - connect(mSlicerManagers.back(),SIGNAL(LandmarkAdded()),landmarksPanel,SLOT(AddPoint())); - InitSlicers(); + if (filetype == IMAGE || filetype == IMAGEWITHTIME || filetype == SLICED) + SetImageSucceed = imageManager->SetImage(files[i],filetype, number, j); + else { + SetImageSucceed = imageManager->SetImages(files,filetype, number); + } + if (SetImageSucceed == false) { + 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()); + 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 = 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(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(UpdateWindows(int, int, int)), + this,SLOT(WindowsChanged(int, int, int))); + connect(mSlicerManagers.back(), SIGNAL(WindowLevelChanged(double, double,int, int)), + this,SLOT(WindowLevelChanged(double, double, int, int))); + 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(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*)), + this,SLOT(UpdateLinkedNavigation(std::string,vvSlicerManager*))); + connect(mSlicerManagers.back(), SIGNAL(ChangeImageWithIndexOffset(vvSlicerManager*,int,int)), + this,SLOT(ChangeImageWithIndexOffset(vvSlicerManager*,int,int))); + connect(mSlicerManagers.back(),SIGNAL(LandmarkAdded()),landmarksPanel,SLOT(AddPoint())); + InitSlicers(); + } numberofsuccesulreads++; } } diff --git a/vv/vvMainWindow.h b/vv/vvMainWindow.h index 8f218a2..c219397 100644 --- a/vv/vvMainWindow.h +++ b/vv/vvMainWindow.h @@ -72,6 +72,7 @@ public slots: void OpenRecentImage(); void OpenImageWithTime(); void MergeImages(); + void SliceImages(); void MergeImagesWithTime(); void OpenDicom(); ///Open a vtkPolyData surface mesh and display it over the current image diff --git a/vv/vvSlicerManager.cxx b/vv/vvSlicerManager.cxx index 913ede7..46e7764 100644 --- a/vv/vvSlicerManager.cxx +++ b/vv/vvSlicerManager.cxx @@ -146,7 +146,7 @@ void vvSlicerManager::ToggleContourSuperposition() //---------------------------------------------------------------------------- -bool vvSlicerManager::SetImage(std::string filename, LoadedImageType type, int n) +bool vvSlicerManager::SetImage(std::string filename, LoadedImageType type, int n, unsigned int slice) { mType = type; if (mReader == NULL) @@ -154,6 +154,7 @@ bool vvSlicerManager::SetImage(std::string filename, LoadedImageType type, int n std::vector filenames; filenames.push_back(filename); mReader->SetInputFilenames(filenames); + mReader->SetSlice(slice); // Only used for SLICED type mReader->Update(type); SetFilename(filename, n); diff --git a/vv/vvSlicerManager.h b/vv/vvSlicerManager.h index 431f1a0..ed118f5 100644 --- a/vv/vvSlicerManager.h +++ b/vv/vvSlicerManager.h @@ -58,7 +58,7 @@ class vvSlicerManager : public QObject { return mLastError; } - bool SetImage(std::string filename,LoadedImageType type, int n=0); + bool SetImage(std::string filename,LoadedImageType type, int n=0, unsigned int slice=0); void SetImage(vvImage::Pointer image); bool SetImages(std::vector filenames, LoadedImageType type, int n=0); -- 2.47.1