Index: mitk/Modules/Bundles/org.mitk.gui.qt.imagestatistics/src/internal/QmitkImageStatisticsView.cpp =================================================================== --- mitk/Modules/Bundles/org.mitk.gui.qt.imagestatistics/src/internal/QmitkImageStatisticsView.cpp (revision 27214) +++ mitk/Modules/Bundles/org.mitk.gui.qt.imagestatistics/src/internal/QmitkImageStatisticsView.cpp (working copy) @@ -52,7 +52,61 @@ #include "mitkPlanarFigureInteractor.h" #include +#include +#include +#include +#include "mitkPlanarAngle.h" +#include "mitkPlanarCircle.h" +#include "mitkPlanarCross.h" +#include "mitkPlanarFourPointAngle.h" +#include "mitkPlanarLine.h" +#include "mitkPlanarPolygon.h" +#include "mitkPlanarRectangle.h" +struct QmitkStatisticsBackgroundThread: public QThread +{ + QmitkStatisticsBackgroundThread() + : m_StatisticsChanged(true), + m_TimeStep(0), + m_StatisticsCalculationSuccessful(false) + { + + } + mitk::ImageStatisticsCalculator::Pointer m_ImageStatisticsCalculator; + bool m_StatisticsChanged; + int m_TimeStep; + bool m_StatisticsCalculationSuccessful; + std::string m_Error; + + void run() + { + if( m_ImageStatisticsCalculator.IsNull() ) + { + m_Error = "No ImageStatisticsCalculator set for thread."; + return; + } + + try + { + // Compute statistics + m_StatisticsChanged = + m_ImageStatisticsCalculator->ComputeStatistics( m_TimeStep ); + + m_StatisticsCalculationSuccessful = true; + } + catch ( const std::runtime_error &e ) + { + m_Error = e.what(); + } + catch ( const std::exception &e ) + { + m_Error = e.what(); + } + + this->quit(); + } +}; + class QmitkRequestStatisticsUpdateEvent : public QEvent { public: @@ -83,7 +137,27 @@ return d != d; } +template < typename TPixel, unsigned int VImageDimension > +void CopyItkImage( itk::Image< TPixel, VImageDimension >* itkImage, mitk::Image::Pointer& mitkCopy ) +{ + typedef itk::ImageDuplicator< itk::Image< TPixel, VImageDimension > > DuplicatorType; + DuplicatorType::Pointer duplicator = DuplicatorType::New(); + duplicator->SetInputImage(itkImage); + duplicator->Update(); + itk::Image< TPixel, VImageDimension >::Pointer copy = duplicator->GetOutput(); + mitk::CastToMitkImage( copy, mitkCopy ); + //mitkCopy = mitk::ImportItkImage(copy); +} +mitk::Image::Pointer CopyImage( mitk::Image* img ) +{ + mitk::Image::Pointer copy; + + AccessByItk_1( img, CopyItkImage, copy ); + + return copy; +} + QmitkImageStatistics::QmitkImageStatistics(QObject* /*parent*/, const char* /*name*/) : QmitkFunctionality(), m_Controls( NULL ), @@ -499,6 +573,7 @@ return; } + /* // Retrieve ImageStatisticsCalculator from has map (or create a new one // for this image if non-existant) ImageStatisticsMapType::iterator it = @@ -516,15 +591,22 @@ m_ImageStatisticsMap[m_SelectedImage] = m_CurrentStatisticsCalculator; MITK_INFO << "Creating StatisticsCalculator"; } + */ + mitk::ImageStatisticsCalculator::Pointer imageStatisticsCalculator = mitk::ImageStatisticsCalculator::New(); + mitk::Image::Pointer selectedImageCopy = CopyImage( m_SelectedImage ); + // TODO + imageStatisticsCalculator->SetImage( selectedImageCopy ); + std::string maskName; std::string maskType; unsigned int maskDimension; if ( m_SelectedImageMask != NULL ) { - m_CurrentStatisticsCalculator->SetImageMask( m_SelectedImageMask ); - m_CurrentStatisticsCalculator->SetMaskingModeToImage(); + mitk::Image::Pointer selectedImageMaskCopy = CopyImage( m_SelectedImageMask ); + imageStatisticsCalculator->SetImageMask( selectedImageMaskCopy ); + imageStatisticsCalculator->SetMaskingModeToImage(); maskName = m_SelectedMaskNode->GetName(); maskType = m_SelectedImageMask->GetNameOfClass(); @@ -532,16 +614,48 @@ } else if ( m_SelectedPlanarFigure != NULL ) { - m_CurrentStatisticsCalculator->SetPlanarFigure( m_SelectedPlanarFigure ); - m_CurrentStatisticsCalculator->SetMaskingModeToPlanarFigure(); + mitk::PlanarFigure::Pointer selectedPlanarFigureCopy; + // TODO REWORK THIS + if(strcmp(m_SelectedPlanarFigure->GetNameOfClass(), "PlanarAngle") == 0) + { + selectedPlanarFigureCopy = mitk::PlanarAngle::New(); + } + if(strcmp(m_SelectedPlanarFigure->GetNameOfClass(), "PlanarCircle") == 0) + { + selectedPlanarFigureCopy = mitk::PlanarCircle::New(); + } + if(strcmp(m_SelectedPlanarFigure->GetNameOfClass(), "PlanarLine") == 0) + { + selectedPlanarFigureCopy = mitk::PlanarLine::New(); + } + if(strcmp(m_SelectedPlanarFigure->GetNameOfClass(), "PlanarPolygon") == 0) + { + selectedPlanarFigureCopy = mitk::PlanarPolygon::New(); + } + if(strcmp(m_SelectedPlanarFigure->GetNameOfClass(), "PlanarCross") == 0) + { + selectedPlanarFigureCopy = mitk::PlanarCross::New(); + } + if(strcmp(m_SelectedPlanarFigure->GetNameOfClass(), "PlanarRectangle") == 0) + { + selectedPlanarFigureCopy = mitk::PlanarRectangle::New(); + } + if(strcmp(m_SelectedPlanarFigure->GetNameOfClass(), "PlanarFourPointAngle") == 0) + { + selectedPlanarFigureCopy = mitk::PlanarFourPointAngle::New(); + } + selectedPlanarFigureCopy->DeepCopy( m_SelectedPlanarFigure ); + imageStatisticsCalculator->SetPlanarFigure( selectedPlanarFigureCopy ); + imageStatisticsCalculator->SetMaskingModeToPlanarFigure(); + maskName = m_SelectedMaskNode->GetName(); maskType = m_SelectedPlanarFigure->GetNameOfClass(); maskDimension = 2; } else { - m_CurrentStatisticsCalculator->SetMaskingModeToNone(); + imageStatisticsCalculator->SetMaskingModeToNone(); maskName = "None"; maskType = ""; @@ -557,6 +671,16 @@ m_Controls->m_SelectedMaskLabel->setText( maskLabel.str().c_str() ); + QmitkStatisticsBackgroundThread* backgroundThread = + new QmitkStatisticsBackgroundThread; + backgroundThread->m_ImageStatisticsCalculator = imageStatisticsCalculator; + backgroundThread->m_TimeStep = timeStep; + m_BackgroundThreads.insert( backgroundThread ); + connect( backgroundThread, SIGNAL( finished() ), + this, SLOT( QmitkStatisticsBackgroundThreadFinished() ) ); + backgroundThread->start(); + + /* bool statisticsChanged = false; bool statisticsCalculationSuccessful = false; @@ -608,65 +732,98 @@ // remove wait cursor this->WaitCursorOff(); + */ - if ( statisticsCalculationSuccessful ) - { - if ( statisticsChanged ) - { - // Do not show any error messages - m_Controls->m_ErrorMessageLabel->hide(); + /*this->UpdateGUIFromStatisticsCalculation( m_CurrentStatisticsCalculator, statisticsCalculationSuccessful, statisticsChanged, timeStep );*/ + } +} - m_CurrentStatisticsValid = true; - } +void QmitkImageStatistics::QmitkStatisticsBackgroundThreadFinished() +{ + QmitkStatisticsBackgroundThread* backgroundThread = static_cast( sender() ); + m_BackgroundThreads.erase( backgroundThread ); - m_Controls->m_StatisticsWidgetStack->setCurrentIndex( 0 ); - m_Controls->m_HistogramWidget->SetHistogramModeToDirectHistogram(); - m_Controls->m_HistogramWidget->SetHistogram( - m_CurrentStatisticsCalculator->GetHistogram( timeStep ) ); - m_Controls->m_HistogramWidget->UpdateItemModelFromHistogram(); + if( backgroundThread->m_Error.size() > 0 ) + { + // In case of exception, print error message on GUI + std::stringstream message; + message << "Error in calculating histogram"; + m_Controls->m_ErrorMessageLabel->setText( message.str().c_str() ); + m_Controls->m_ErrorMessageLabel->show(); + } + else + { + this->UpdateGUIFromStatisticsCalculation( backgroundThread->m_ImageStatisticsCalculator, + backgroundThread->m_StatisticsCalculationSuccessful, + backgroundThread->m_StatisticsChanged, + backgroundThread->m_TimeStep ); + } - MITK_INFO << "UpdateItemModelFromHistogram()"; + delete backgroundThread; +} - this->FillStatisticsTableView( - m_CurrentStatisticsCalculator->GetStatistics( timeStep ), - m_SelectedImage ); - } - else +void QmitkImageStatistics::UpdateGUIFromStatisticsCalculation( + mitk::ImageStatisticsCalculator* statisticsCalculator, bool statisticsCalculationSuccessful, bool statisticsChanged, + int timeStep) +{ + if ( statisticsCalculationSuccessful ) + { + if ( statisticsChanged ) { - m_Controls->m_SelectedMaskLabel->setText( "None" ); + // Do not show any error messages + m_Controls->m_ErrorMessageLabel->hide(); - // Clear statistics and histogram - this->InvalidateStatisticsTableView(); - m_Controls->m_HistogramWidget->ClearItemModel(); - m_CurrentStatisticsValid = false; + m_CurrentStatisticsValid = true; + } + m_Controls->m_StatisticsWidgetStack->setCurrentIndex( 0 ); + m_Controls->m_HistogramWidget->SetHistogramModeToDirectHistogram(); + m_Controls->m_HistogramWidget->SetHistogram( + statisticsCalculator->GetHistogram( timeStep ) ); + m_Controls->m_HistogramWidget->UpdateItemModelFromHistogram(); - // If a (non-closed) PlanarFigure is selected, display a line profile widget - if ( m_SelectedPlanarFigure != NULL ) + MITK_INFO << "UpdateItemModelFromHistogram()"; + + this->FillStatisticsTableView( + statisticsCalculator->GetStatistics( timeStep ), + m_SelectedImage ); + } + else + { + m_Controls->m_SelectedMaskLabel->setText( "None" ); + + // Clear statistics and histogram + this->InvalidateStatisticsTableView(); + m_Controls->m_HistogramWidget->ClearItemModel(); + m_CurrentStatisticsValid = false; + + + // If a (non-closed) PlanarFigure is selected, display a line profile widget + if ( m_SelectedPlanarFigure != NULL ) + { + // check whether PlanarFigure is initialized + const mitk::Geometry2D *planarFigureGeometry2D = m_SelectedPlanarFigure->GetGeometry2D(); + if ( planarFigureGeometry2D == NULL ) { - // check whether PlanarFigure is initialized - const mitk::Geometry2D *planarFigureGeometry2D = m_SelectedPlanarFigure->GetGeometry2D(); - if ( planarFigureGeometry2D == NULL ) - { - // Clear statistics, histogram, and GUI - this->InvalidateStatisticsTableView(); - m_Controls->m_HistogramWidget->ClearItemModel(); - m_Controls->m_LineProfileWidget->ClearItemModel(); - m_CurrentStatisticsValid = false; - m_Controls->m_ErrorMessageLabel->hide(); - m_Controls->m_SelectedMaskLabel->setText( "None" ); - return; - } - // TODO: enable line profile widget - m_Controls->m_StatisticsWidgetStack->setCurrentIndex( 1 ); - m_Controls->m_LineProfileWidget->SetImage( m_SelectedImage ); - m_Controls->m_LineProfileWidget->SetPlanarFigure( m_SelectedPlanarFigure ); - m_Controls->m_LineProfileWidget->UpdateItemModelFromPath(); + // Clear statistics, histogram, and GUI + this->InvalidateStatisticsTableView(); + m_Controls->m_HistogramWidget->ClearItemModel(); + m_Controls->m_LineProfileWidget->ClearItemModel(); + m_CurrentStatisticsValid = false; + m_Controls->m_ErrorMessageLabel->hide(); + m_Controls->m_SelectedMaskLabel->setText( "None" ); + return; } + // TODO: enable line profile widget + m_Controls->m_StatisticsWidgetStack->setCurrentIndex( 1 ); + m_Controls->m_LineProfileWidget->SetImage( m_SelectedImage ); + m_Controls->m_LineProfileWidget->SetPlanarFigure( m_SelectedPlanarFigure ); + m_Controls->m_LineProfileWidget->UpdateItemModelFromPath(); } } } + void QmitkImageStatistics::UpdateProgressBar() { mitk::ProgressBar::GetInstance()->Progress(); Index: mitk/Modules/Bundles/org.mitk.gui.qt.imagestatistics/src/internal/QmitkImageStatisticsView.h =================================================================== --- mitk/Modules/Bundles/org.mitk.gui.qt.imagestatistics/src/internal/QmitkImageStatisticsView.h (revision 27214) +++ mitk/Modules/Bundles/org.mitk.gui.qt.imagestatistics/src/internal/QmitkImageStatisticsView.h (working copy) @@ -31,9 +31,8 @@ #include #include "mitkPlanarLine.h" +#include - - /*! \brief QmitkImageStatistics @@ -84,7 +83,12 @@ void ClipboardStatisticsButtonClicked(); + /// + /// called when a background thread finished calculation + /// + void QmitkStatisticsBackgroundThreadFinished(); + protected: void StdMultiWidgetAvailable( QmitkStdMultiWidget& stdMultiWidget ); @@ -105,6 +109,10 @@ /** \brief Recalculate statistics for currently selected image and mask and * update the GUI. */ void UpdateStatistics(); + /// + /// a seperate method to really fill the gui when image statistics calculation is finished + /// + void UpdateGUIFromStatisticsCalculation(mitk::ImageStatisticsCalculator* statisticsCalculator, bool statisticsCalculationSuccessful, bool statisticsChanged, int timeStep); /** \brief Listener for progress events to update progress bar. */ void UpdateProgressBar(); @@ -150,6 +158,11 @@ // if a recalculation is not required) ImageStatisticsMapType m_ImageStatisticsMap; + /// + /// all threads that are started in the background and do some calculation + /// + std::set m_BackgroundThreads; + mitk::ImageStatisticsCalculator::Pointer m_CurrentStatisticsCalculator; bool m_CurrentStatisticsValid;