diff --git a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsCalculationThread.cpp b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsCalculationThread.cpp index 61a069f036..a064aaf3e3 100644 --- a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsCalculationThread.cpp +++ b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsCalculationThread.cpp @@ -1,181 +1,190 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkImageStatisticsCalculationThread.h" //QT headers #include #include QmitkImageStatisticsCalculationThread::QmitkImageStatisticsCalculationThread():QThread(), m_StatisticsImage(NULL), m_BinaryMask(NULL), m_PlanarFigureMask(NULL), m_TimeStep(0), m_IgnoreZeros(false), m_CalculationSuccessful(false), m_StatisticChanged(false) { } QmitkImageStatisticsCalculationThread::~QmitkImageStatisticsCalculationThread() { } void QmitkImageStatisticsCalculationThread::Initialize( mitk::Image::Pointer image, mitk::Image::Pointer binaryImage, mitk::PlanarFigure::Pointer planarFig ) { // reset old values if( this->m_StatisticsImage.IsNotNull() ) this->m_StatisticsImage = 0; if( this->m_BinaryMask.IsNotNull() ) this->m_BinaryMask = 0; if( this->m_PlanarFigureMask.IsNotNull()) this->m_PlanarFigureMask = 0; // set new values if passed in if(image.IsNotNull()) this->m_StatisticsImage = image->Clone(); if(binaryImage.IsNotNull()) this->m_BinaryMask = binaryImage->Clone(); if(planarFig.IsNotNull()) this->m_PlanarFigureMask = planarFig->Clone(); } void QmitkImageStatisticsCalculationThread::SetTimeStep( int times ) { this->m_TimeStep = times; } int QmitkImageStatisticsCalculationThread::GetTimeStep() { return this->m_TimeStep; } -mitk::ImageStatisticsCalculator::Statistics QmitkImageStatisticsCalculationThread::GetStatisticsData() +std::vector QmitkImageStatisticsCalculationThread::GetStatisticsData() { - return this->m_StatisticsStruct; + return this->m_StatisticsVector; } mitk::Image::Pointer QmitkImageStatisticsCalculationThread::GetStatisticsImage() { return this->m_StatisticsImage; } void QmitkImageStatisticsCalculationThread::SetIgnoreZeroValueVoxel(bool _arg) { this->m_IgnoreZeros = _arg; } bool QmitkImageStatisticsCalculationThread::GetIgnoreZeroValueVoxel() { return this->m_IgnoreZeros; } std::string QmitkImageStatisticsCalculationThread::GetLastErrorMessage() { return m_message; } QmitkImageStatisticsCalculationThread::HistogramType::Pointer -QmitkImageStatisticsCalculationThread::GetTimeStepHistogram() +QmitkImageStatisticsCalculationThread::GetTimeStepHistogram(unsigned int t) { - return this->m_TimeStepHistogram; + if (t >= this->m_HistogramVector.size()) + return NULL; + + return this->m_HistogramVector[t]; } bool QmitkImageStatisticsCalculationThread::GetStatisticsChangedFlag() { return m_StatisticChanged; } bool QmitkImageStatisticsCalculationThread::GetStatisticsUpdateSuccessFlag() { return m_CalculationSuccessful; } void QmitkImageStatisticsCalculationThread::run() { bool statisticCalculationSuccessful = true; mitk::ImageStatisticsCalculator::Pointer calculator = mitk::ImageStatisticsCalculator::New(); if(this->m_StatisticsImage.IsNotNull()) { calculator->SetImage(m_StatisticsImage); calculator->SetMaskingModeToNone(); } else { statisticCalculationSuccessful = false; } // Bug 13416 : The ImageStatistics::SetImageMask() method can throw exceptions, i.e. when the dimensionality // of the masked and input image differ, we need to catch them and mark the calculation as failed // the same holds for the ::SetPlanarFigure() try { if(this->m_BinaryMask.IsNotNull()) { calculator->SetImageMask(m_BinaryMask); calculator->SetMaskingModeToImage(); } if(this->m_PlanarFigureMask.IsNotNull()) { calculator->SetPlanarFigure(m_PlanarFigureMask); calculator->SetMaskingModeToPlanarFigure(); } } catch( const itk::ExceptionObject& e) { MITK_ERROR << "ITK Exception:" << e.what(); statisticCalculationSuccessful = false; } bool statisticChanged = false; calculator->SetDoIgnorePixelValue(this->m_IgnoreZeros); calculator->SetIgnorePixelValue(0); - try - { - statisticChanged = calculator->ComputeStatistics(m_TimeStep); - } - catch ( mitk::Exception& e) - { - //m_message = e.GetDescription(); - MITK_ERROR<< "MITK Exception: " << e.what(); - statisticCalculationSuccessful = false; - } - catch ( const std::runtime_error &e ) - { - //m_message = "Failure: " + std::string(e.what()); - MITK_ERROR<< "Runtime Exception: " << e.what(); - statisticCalculationSuccessful = false; - } - catch ( const std::exception &e ) + + for (unsigned int i = 0; i < m_StatisticsImage->GetTimeSteps(); i++) { - //m_message = "Failure: " + std::string(e.what()); - MITK_ERROR<< "Standard Exception: " << e.what(); - statisticCalculationSuccessful = false; + try + { + statisticChanged = calculator->ComputeStatistics(i); + } + catch ( mitk::Exception& e) + { + //m_message = e.GetDescription(); + MITK_ERROR<< "MITK Exception: " << e.what(); + statisticCalculationSuccessful = false; + } + catch ( const std::runtime_error &e ) + { + //m_message = "Failure: " + std::string(e.what()); + MITK_ERROR<< "Runtime Exception: " << e.what(); + statisticCalculationSuccessful = false; + } + catch ( const std::exception &e ) + { + //m_message = "Failure: " + std::string(e.what()); + MITK_ERROR<< "Standard Exception: " << e.what(); + statisticCalculationSuccessful = false; + } } + this->m_StatisticChanged = statisticChanged; this->m_CalculationSuccessful = statisticCalculationSuccessful; if(statisticCalculationSuccessful) { - this->m_StatisticsStruct = calculator->GetStatistics(m_TimeStep); + this->m_StatisticsVector.clear(); + this->m_HistogramVector.clear(); - if(this->m_TimeStepHistogram.IsNotNull()) + for (unsigned int i = 0; i < m_StatisticsImage->GetTimeSteps(); i++) { - this->m_TimeStepHistogram = NULL; + this->m_StatisticsVector.push_back(calculator->GetStatistics(i)); + this->m_HistogramVector.push_back((HistogramType*)calculator->GetHistogram(i)); } - this->m_TimeStepHistogram = (HistogramType*) calculator->GetHistogram(m_TimeStep); } } diff --git a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsCalculationThread.h b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsCalculationThread.h index cf0bb4074a..e97458d351 100644 --- a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsCalculationThread.h +++ b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsCalculationThread.h @@ -1,104 +1,104 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QMITKIMAGESTATISTICSCALCULATIONTHREAD_H_INCLUDED #define QMITKIMAGESTATISTICSCALCULATIONTHREAD_H_INCLUDED //QT headers #include #include //mitk headers #include "mitkImage.h" #include "mitkPlanarFigure.h" #include "mitkImageStatisticsCalculator.h" // itk headers #ifndef __itkHistogram_h #include #endif /** /brief This class is executed as background thread for image statistics calculation. * Documentation: This class is derived from QThread and is intended to be used by QmitkImageStatisticsView to run the image statistics calculation in a background thread keepung the gui usable. * \ingroup Plugins/MeasurementToolbox */ class QmitkImageStatisticsCalculationThread : public QThread { Q_OBJECT public: typedef itk::Statistics::Histogram HistogramType; /*! /brief standard constructor. */ QmitkImageStatisticsCalculationThread(); /*! /brief standard destructor. */ ~QmitkImageStatisticsCalculationThread(); /*! /brief Initializes the object with necessary data. */ void Initialize( mitk::Image::Pointer image, mitk::Image::Pointer binaryImage, mitk::PlanarFigure::Pointer planarFig ); /*! /brief returns the calculated image statistics. */ - mitk::ImageStatisticsCalculator::Statistics GetStatisticsData(); + std::vector GetStatisticsData(); /*! /brief */ mitk::Image::Pointer GetStatisticsImage(); /*! /brief Set the time step of the image you want to process. */ void SetTimeStep( int times ); /*! /brief Get the time step of the image you want to process. */ int GetTimeStep(); /*! /brief Set flag to ignore zero valued voxels */ void SetIgnoreZeroValueVoxel( bool _arg ); /*! /brief Get status of zero value voxel ignoring. */ bool GetIgnoreZeroValueVoxel(); /*! /brief Returns the histogram of the currently selected time step. */ - HistogramType::Pointer GetTimeStepHistogram(); + HistogramType::Pointer GetTimeStepHistogram(unsigned int t = 0); /*! /brief Returns a flag indicating if the statistics have changed during calculation */ bool GetStatisticsChangedFlag(); /*! /brief Returns a flag the indicates if the statistics are updated successfully */ bool GetStatisticsUpdateSuccessFlag(); /*! /brief Method called once the thread is executed. */ void run(); std::string GetLastErrorMessage(); private: //member declaration mitk::Image::Pointer m_StatisticsImage; ///< member variable holds the input image for which the statistics need to be calculated. mitk::Image::Pointer m_BinaryMask; ///< member variable holds the binary mask image for segmentation image statistics calculation. mitk::PlanarFigure::Pointer m_PlanarFigureMask; ///< member variable holds the planar figure for segmentation image statistics calculation. - mitk::ImageStatisticsCalculator::Statistics m_StatisticsStruct; ///< member variable holds the result struct. + std::vector m_StatisticsVector; ///< member variable holds the result structs. int m_TimeStep; ///< member variable holds the time step for statistics calculation bool m_IgnoreZeros; ///< member variable holds flag to indicate if zero valued voxel should be suppressed bool m_StatisticChanged; ///< flag set if statistics have changed bool m_CalculationSuccessful; ///< flag set if statistics calculation was successful - HistogramType::Pointer m_TimeStepHistogram; ///< member holds the histogram of the current time step. + std::vector m_HistogramVector; ///< member holds the histograms of all time steps. std::string m_message; }; #endif // QMITKIMAGESTATISTICSCALCULATIONTHREAD_H_INCLUDED diff --git a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsView.cpp b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsView.cpp index 9e383b06c5..56cd32ee5e 100644 --- a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsView.cpp +++ b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsView.cpp @@ -1,822 +1,897 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkImageStatisticsView.h" // Qt includes #include +#include // berry includes #include // mitk includes #include "mitkNodePredicateDataType.h" #include "mitkPlanarFigureInteractor.h" // itk includes #include "itksys/SystemTools.hxx" #include #include const std::string QmitkImageStatisticsView::VIEW_ID = "org.mitk.views.imagestatistics"; +const int QmitkImageStatisticsView::STAT_TABLE_BASE_HEIGHT = 180; QmitkImageStatisticsView::QmitkImageStatisticsView(QObject* /*parent*/, const char* /*name*/) : m_Controls( NULL ), m_TimeStepperAdapter( NULL ), m_SelectedImage( NULL ), m_SelectedImageMask( NULL ), m_SelectedPlanarFigure( NULL ), m_ImageObserverTag( -1 ), m_ImageMaskObserverTag( -1 ), m_PlanarFigureObserverTag( -1 ), m_TimeObserverTag( -1 ), m_CurrentStatisticsValid( false ), m_StatisticsUpdatePending( false ), m_DataNodeSelectionChanged ( false ), m_Visible(false) { this->m_CalculationThread = new QmitkImageStatisticsCalculationThread; } QmitkImageStatisticsView::~QmitkImageStatisticsView() { if ( m_SelectedImage != NULL ) m_SelectedImage->RemoveObserver( m_ImageObserverTag ); if ( m_SelectedImageMask != NULL ) m_SelectedImageMask->RemoveObserver( m_ImageMaskObserverTag ); if ( m_SelectedPlanarFigure != NULL ) m_SelectedPlanarFigure->RemoveObserver( m_PlanarFigureObserverTag ); while(this->m_CalculationThread->isRunning()) // wait until thread has finished { itksys::SystemTools::Delay(100); } delete this->m_CalculationThread; } void QmitkImageStatisticsView::CreateQtPartControl(QWidget *parent) { if (m_Controls == NULL) { m_Controls = new Ui::QmitkImageStatisticsViewControls; m_Controls->setupUi(parent); this->CreateConnections(); m_Controls->m_ErrorMessageLabel->hide(); m_Controls->m_StatisticsWidgetStack->setCurrentIndex( 0 ); } } void QmitkImageStatisticsView::CreateConnections() { if ( m_Controls ) { connect( (QObject*)(this->m_Controls->m_ButtonCopyHistogramToClipboard), SIGNAL(clicked()),(QObject*) this, SLOT(OnClipboardHistogramButtonClicked()) ); connect( (QObject*)(this->m_Controls->m_ButtonCopyStatisticsToClipboard), SIGNAL(clicked()),(QObject*) this, SLOT(OnClipboardStatisticsButtonClicked()) ); connect( (QObject*)(this->m_Controls->m_IgnoreZerosCheckbox), SIGNAL(clicked()),(QObject*) this, SLOT(OnIgnoreZerosCheckboxClicked()) ); connect( (QObject*) this->m_CalculationThread, SIGNAL(finished()),this, SLOT( OnThreadedStatisticsCalculationEnds()),Qt::QueuedConnection); connect( (QObject*) this, SIGNAL(StatisticsUpdate()),this, SLOT( RequestStatisticsUpdate()), Qt::QueuedConnection); connect( (QObject*) this->m_Controls->m_StatisticsTable, SIGNAL(cellDoubleClicked(int,int)),this, SLOT( JumpToCoordinates(int,int)) ); connect( (QObject*) (this->m_Controls->m_barRadioButton), SIGNAL(clicked()), (QObject*) (this->m_Controls->m_JSHistogram), SLOT(OnBarRadioButtonSelected())); connect( (QObject*) (this->m_Controls->m_lineRadioButton), SIGNAL(clicked()), (QObject*) (this->m_Controls->m_JSHistogram), SLOT(OnLineRadioButtonSelected())); } } void QmitkImageStatisticsView::PartClosed( berry::IWorkbenchPartReference::Pointer ) { } -void QmitkImageStatisticsView::OnTimeChanged(const itk::EventObject&) +void QmitkImageStatisticsView::OnTimeChanged(const itk::EventObject& e) { - if (m_SelectedImage != NULL && !this->m_StatisticsUpdatePending) + if (this->m_SelectedDataNodes.isEmpty() || this->m_SelectedImage == NULL) + return; + + const mitk::SliceNavigationController::GeometryTimeEvent* timeEvent = + dynamic_cast(&e); + assert(timeEvent != NULL); + unsigned int timestep = timeEvent->GetPos(); + + if (this->m_SelectedImage->GetTimeSteps() > 1) { - while( this->m_CalculationThread->isRunning()) // wait until thread has finished + for (unsigned int x = 0; x < this->m_Controls->m_StatisticsTable->columnCount(); x++) { - itksys::SystemTools::Delay(100); - } + for (unsigned int y = 0; y < this->m_Controls->m_StatisticsTable->rowCount(); y++) + { + QTableWidgetItem* item = this->m_Controls->m_StatisticsTable->item(y, x); + if (item == NULL) + break; - if(this->m_SelectedImage != NULL) - { - this->m_SelectedImage->RemoveObserver( this->m_ImageObserverTag); - this->m_SelectedImage = NULL; + if (x == timestep) + { + item->setBackgroundColor(Qt::yellow); + } + else + { + if (y % 2 == 0) + item->setBackground(this->m_Controls->m_StatisticsTable->palette().base()); + else + item->setBackground(this->m_Controls->m_StatisticsTable->palette().alternateBase()); + } + } } - if(this->m_SelectedImageMask != NULL) - { - this->m_SelectedImageMask->RemoveObserver( this->m_ImageMaskObserverTag); - this->m_SelectedImageMask = NULL; - } + this->m_Controls->m_StatisticsTable->viewport()->update(); + } - if(this->m_SelectedPlanarFigure != NULL) - { - this->m_SelectedPlanarFigure->RemoveObserver( this->m_PlanarFigureObserverTag); - this->m_SelectedPlanarFigure = NULL; - } + if ((this->m_SelectedImage->GetTimeSteps() == 1 && timestep == 0) || + this->m_SelectedImage->GetTimeSteps() > 1) + { + // display histogram for selected timestep + this->m_Controls->m_JSHistogram->ClearHistogram(); + QmitkImageStatisticsCalculationThread::HistogramType::Pointer histogram = + this->m_CalculationThread->GetTimeStepHistogram(timestep); - m_Controls->m_ErrorMessageLabel->setText(""); - m_Controls->m_ErrorMessageLabel->hide(); - this->InvalidateStatisticsTableView(); - m_Controls->m_StatisticsWidgetStack->setCurrentIndex(0); + if (histogram.IsNotNull()) + { + this->m_Controls->m_JSHistogram->ComputeHistogram(histogram.GetPointer()); +// this->m_Controls->m_JSHistogram->SignalGraphChanged(); - emit StatisticsUpdate(); + // hacky way to make sure the protected SignalGraphChanged() is called + if (this->m_Controls->m_JSHistogram->GetUseLineGraph()) + { + this->m_Controls->m_JSHistogram->OnBarRadioButtonSelected(); + this->m_Controls->m_JSHistogram->OnLineRadioButtonSelected(); + } + else + { + this->m_Controls->m_JSHistogram->OnLineRadioButtonSelected(); + this->m_Controls->m_JSHistogram->OnBarRadioButtonSelected(); + } + } } } void QmitkImageStatisticsView::JumpToCoordinates(int row ,int col) { if(m_SelectedDataNodes.isEmpty()) { MITK_WARN("QmitkImageStatisticsView") << "No data node selected for statistics calculation." ; return; } mitk::Point3D world; if (row==4) - world = m_WorldMin; + world = m_WorldMinList[col]; else if (row==3) - world = m_WorldMax; + world = m_WorldMaxList[col]; else return; mitk::IRenderWindowPart* part = this->GetRenderWindowPart(); if (part) { part->GetQmitkRenderWindow("axial")->GetSliceNavigationController()->SelectSliceByPoint(world); part->GetQmitkRenderWindow("sagittal")->GetSliceNavigationController()->SelectSliceByPoint(world); part->GetQmitkRenderWindow("coronal")->GetSliceNavigationController()->SelectSliceByPoint(world); + + mitk::SliceNavigationController::GeometryTimeEvent timeEvent(this->m_SelectedImage->GetTimeGeometry(), col); + part->GetQmitkRenderWindow("axial")->GetSliceNavigationController()->SetGeometryTime(timeEvent); } } void QmitkImageStatisticsView::OnIgnoreZerosCheckboxClicked() { emit StatisticsUpdate(); } void QmitkImageStatisticsView::OnClipboardHistogramButtonClicked() { if ( m_CurrentStatisticsValid ) { + const unsigned int t = this->GetRenderWindowPart()->GetTimeNavigationController()->GetTime()->GetPos(); + typedef mitk::ImageStatisticsCalculator::HistogramType HistogramType; - const HistogramType *histogram = this->m_CalculationThread->GetTimeStepHistogram().GetPointer(); + const HistogramType *histogram = this->m_CalculationThread->GetTimeStepHistogram(t).GetPointer(); QString clipboard( "Measurement \t Frequency\n" ); for ( HistogramType::ConstIterator it = histogram->Begin(); it != histogram->End(); ++it ) { clipboard = clipboard.append( "%L1 \t %L2\n" ) .arg( it.GetMeasurementVector()[0], 0, 'f', 2 ) .arg( it.GetFrequency() ); } QApplication::clipboard()->setText( clipboard, QClipboard::Clipboard ); } else { QApplication::clipboard()->clear(); } } void QmitkImageStatisticsView::OnClipboardStatisticsButtonClicked() { QLocale tempLocal; QLocale::setDefault(QLocale(QLocale::English, QLocale::UnitedStates)); if ( this->m_CurrentStatisticsValid ) { - const mitk::ImageStatisticsCalculator::Statistics &statistics = - this->m_CalculationThread->GetStatisticsData(); + const std::vector &statistics = + this->m_CalculationThread->GetStatisticsData(); + const unsigned int t = this->GetRenderWindowPart()->GetTimeNavigationController()->GetTime()-> + GetPos(); // Copy statistics to clipboard ("%Ln" will use the default locale for // number formatting) QString clipboard( "Mean \t StdDev \t RMS \t Max \t Min \t N \t V (mm³)\n" ); clipboard = clipboard.append( "%L1 \t %L2 \t %L3 \t %L4 \t %L5 \t %L6 \t %L7" ) - .arg( statistics.Mean, 0, 'f', 10 ) - .arg( statistics.Sigma, 0, 'f', 10 ) - .arg( statistics.RMS, 0, 'f', 10 ) - .arg( statistics.Max, 0, 'f', 10 ) - .arg( statistics.Min, 0, 'f', 10 ) - .arg( statistics.N ) - .arg( m_Controls->m_StatisticsTable->item( 0, 6 )->text().toDouble(), 0, 'f', 10 ); + .arg( statistics[t].Mean, 0, 'f', 10 ) + .arg( statistics[t].Sigma, 0, 'f', 10 ) + .arg( statistics[t].RMS, 0, 'f', 10 ) + .arg( statistics[t].Max, 0, 'f', 10 ) + .arg( statistics[t].Min, 0, 'f', 10 ) + .arg( statistics[t].N ) + .arg( m_Controls->m_StatisticsTable->item( 0, 6 )->text().toDouble(), 0, 'f', 10 ); QApplication::clipboard()->setText( clipboard, QClipboard::Clipboard ); } else { QApplication::clipboard()->clear(); } QLocale::setDefault(tempLocal); } void QmitkImageStatisticsView::OnSelectionChanged( berry::IWorkbenchPart::Pointer /*part*/, const QList &selectedNodes ) { if (this->m_Visible) { this->SelectionChanged( selectedNodes ); } else { this->m_DataNodeSelectionChanged = true; } } void QmitkImageStatisticsView::SelectionChanged(const QList &selectedNodes) { if( this->m_StatisticsUpdatePending ) { this->m_DataNodeSelectionChanged = true; return; // not ready for new data now! } if (selectedNodes.size() == this->m_SelectedDataNodes.size()) { int i = 0; for (; i < selectedNodes.size(); ++i) { if (selectedNodes.at(i) != this->m_SelectedDataNodes.at(i)) { break; } } // node selection did not change if (i == selectedNodes.size()) return; } this->ReinitData(); if (selectedNodes.isEmpty()) { m_Controls->m_JSHistogram->ClearHistogram(); m_Controls->m_lineRadioButton->setEnabled(true); m_Controls->m_barRadioButton->setEnabled(true); m_Controls->m_InfoLabel->setText(QString("")); // m_Controls->horizontalLayout_3->setEnabled(false); m_Controls->groupBox->setEnabled(false); m_Controls->groupBox_3->setEnabled(false); } else { // m_Controls->horizontalLayout_3->setEnabled(true); m_Controls->groupBox->setEnabled(true); m_Controls->groupBox_3->setEnabled(true); } if(selectedNodes.size() == 1 || selectedNodes.size() == 2) { bool isBinary = false; selectedNodes.value(0)->GetBoolProperty("binary",isBinary); if(isBinary) { m_Controls->m_JSHistogram->ClearHistogram(); m_Controls->m_lineRadioButton->setEnabled(true); m_Controls->m_barRadioButton->setEnabled(true); m_Controls->m_InfoLabel->setText(QString("")); } for (int i= 0; i< selectedNodes.size(); ++i) { this->m_SelectedDataNodes.push_back(selectedNodes.at(i)); } this->m_DataNodeSelectionChanged = false; this->m_Controls->m_ErrorMessageLabel->setText( "" ); this->m_Controls->m_ErrorMessageLabel->hide(); emit StatisticsUpdate(); } else { this->m_DataNodeSelectionChanged = false; } } void QmitkImageStatisticsView::ReinitData() { while( this->m_CalculationThread->isRunning()) // wait until thread has finished { itksys::SystemTools::Delay(100); } if(this->m_SelectedImage != NULL) { this->m_SelectedImage->RemoveObserver( this->m_ImageObserverTag); this->m_SelectedImage = NULL; } if(this->m_SelectedImageMask != NULL) { this->m_SelectedImageMask->RemoveObserver( this->m_ImageMaskObserverTag); this->m_SelectedImageMask = NULL; } if(this->m_SelectedPlanarFigure != NULL) { this->m_SelectedPlanarFigure->RemoveObserver( this->m_PlanarFigureObserverTag); this->m_SelectedPlanarFigure = NULL; } this->m_SelectedDataNodes.clear(); this->m_StatisticsUpdatePending = false; m_Controls->m_ErrorMessageLabel->setText( "" ); m_Controls->m_ErrorMessageLabel->hide(); this->InvalidateStatisticsTableView(); + m_Controls->m_JSHistogram->ClearHistogram(); m_Controls->m_StatisticsWidgetStack->setCurrentIndex( 0 ); } void QmitkImageStatisticsView::OnThreadedStatisticsCalculationEnds() { std::stringstream message; message << ""; m_Controls->m_ErrorMessageLabel->setText( message.str().c_str() ); m_Controls->m_ErrorMessageLabel->hide(); this->WriteStatisticsToGUI(); } void QmitkImageStatisticsView::UpdateStatistics() { mitk::IRenderWindowPart* renderPart = this->GetRenderWindowPart(); if ( renderPart == NULL ) { this->m_StatisticsUpdatePending = false; return; } - m_WorldMin.Fill(-1); - m_WorldMax.Fill(-1); + m_WorldMinList.clear(); + m_WorldMaxList.clear(); // classify selected nodes mitk::NodePredicateDataType::Pointer imagePredicate = mitk::NodePredicateDataType::New("Image"); std::string maskName = std::string(); std::string maskType = std::string(); unsigned int maskDimension = 0; // reset data from last run ITKCommandType::Pointer changeListener = ITKCommandType::New(); changeListener->SetCallbackFunction( this, &QmitkImageStatisticsView::SelectedDataModified ); mitk::DataNode::Pointer planarFigureNode; for( int i= 0 ; i < this->m_SelectedDataNodes.size(); ++i) { mitk::PlanarFigure::Pointer planarFig = dynamic_cast(this->m_SelectedDataNodes.at(i)->GetData()); if( imagePredicate->CheckNode(this->m_SelectedDataNodes.at(i)) ) { bool isMask = false; this->m_SelectedDataNodes.at(i)->GetPropertyValue("binary", isMask); if( this->m_SelectedImageMask == NULL && isMask) { this->m_SelectedImageMask = dynamic_cast(this->m_SelectedDataNodes.at(i)->GetData()); this->m_ImageMaskObserverTag = this->m_SelectedImageMask->AddObserver(itk::ModifiedEvent(), changeListener); maskName = this->m_SelectedDataNodes.at(i)->GetName(); maskType = m_SelectedImageMask->GetNameOfClass(); maskDimension = 3; } else if( !isMask ) { if(this->m_SelectedImage == NULL) { this->m_SelectedImage = static_cast(this->m_SelectedDataNodes.at(i)->GetData()); this->m_ImageObserverTag = this->m_SelectedImage->AddObserver(itk::ModifiedEvent(), changeListener); } } } else if (planarFig.IsNotNull()) { if(this->m_SelectedPlanarFigure == NULL) { this->m_SelectedPlanarFigure = planarFig; this->m_PlanarFigureObserverTag = this->m_SelectedPlanarFigure->AddObserver(mitk::EndInteractionPlanarFigureEvent(), changeListener); maskName = this->m_SelectedDataNodes.at(i)->GetName(); maskType = this->m_SelectedPlanarFigure->GetNameOfClass(); maskDimension = 2; planarFigureNode = m_SelectedDataNodes.at(i); } } else { std::stringstream message; message << "" << "Invalid data node type!" << ""; m_Controls->m_ErrorMessageLabel->setText( message.str().c_str() ); m_Controls->m_ErrorMessageLabel->show(); } } if(maskName == "") { maskName = "None"; maskType = ""; maskDimension = 0; } if (m_SelectedPlanarFigure != NULL && m_SelectedImage == NULL) { mitk::DataStorage::SetOfObjects::ConstPointer parentSet = this->GetDataStorage()->GetSources(planarFigureNode); for (int i=0; iSize(); i++) { mitk::DataNode::Pointer node = parentSet->ElementAt(i); if( imagePredicate->CheckNode(node) ) { bool isMask = false; node->GetPropertyValue("binary", isMask); if( !isMask ) { if(this->m_SelectedImage == NULL) { this->m_SelectedImage = static_cast(node->GetData()); this->m_ImageObserverTag = this->m_SelectedImage->AddObserver(itk::ModifiedEvent(), changeListener); } } } } } unsigned int timeStep = renderPart->GetTimeNavigationController()->GetTime()->GetPos(); if ( m_SelectedImage != NULL && m_SelectedImage->IsInitialized()) { // Check if a the selected image is a multi-channel image. If yes, statistics // cannot be calculated currently. if ( m_SelectedImage->GetPixelType().GetNumberOfComponents() > 1 ) { std::stringstream message; message << "Multi-component images not supported."; m_Controls->m_ErrorMessageLabel->setText( message.str().c_str() ); m_Controls->m_ErrorMessageLabel->show(); this->InvalidateStatisticsTableView(); m_Controls->m_StatisticsWidgetStack->setCurrentIndex( 0 ); m_Controls->m_JSHistogram->ClearHistogram(); m_CurrentStatisticsValid = false; this->m_StatisticsUpdatePending = false; m_Controls->m_lineRadioButton->setEnabled(true); m_Controls->m_barRadioButton->setEnabled(true); m_Controls->m_InfoLabel->setText(QString("")); return; } std::stringstream maskLabel; maskLabel << maskName; if ( maskDimension > 0 ) { maskLabel << " [" << maskDimension << "D " << maskType << "]"; } m_Controls->m_SelectedMaskLabel->setText( maskLabel.str().c_str() ); // check time step validity if(m_SelectedImage->GetDimension() <= 3 && timeStep > m_SelectedImage->GetDimension(3)-1) { timeStep = m_SelectedImage->GetDimension(3)-1; } // Add the used mask time step to the mask label so the user knows which mask time step was used // if the image time step is bigger than the total number of mask time steps (see // ImageStatisticsCalculator::ExtractImageAndMask) if (m_SelectedImageMask != NULL) { unsigned int maskTimeStep = timeStep; if (maskTimeStep >= m_SelectedImageMask->GetTimeSteps()) { maskTimeStep = m_SelectedImageMask->GetTimeSteps() - 1; } m_Controls->m_SelectedMaskLabel->setText(m_Controls->m_SelectedMaskLabel->text() + - QString(" (t=") + - QString::number(maskTimeStep) + - QString(")")); + QString(" (t=") + + QString::number(maskTimeStep) + + QString(")")); } //// initialize thread and trigger it this->m_CalculationThread->SetIgnoreZeroValueVoxel( m_Controls->m_IgnoreZerosCheckbox->isChecked() ); this->m_CalculationThread->Initialize( m_SelectedImage, m_SelectedImageMask, m_SelectedPlanarFigure ); this->m_CalculationThread->SetTimeStep( timeStep ); std::stringstream message; message << "Calculating statistics..."; m_Controls->m_ErrorMessageLabel->setText( message.str().c_str() ); m_Controls->m_ErrorMessageLabel->show(); try { // Compute statistics this->m_CalculationThread->start(); } catch ( const mitk::Exception& e) { std::stringstream message; message << "" << e.GetDescription() << ""; m_Controls->m_ErrorMessageLabel->setText( message.str().c_str() ); m_Controls->m_ErrorMessageLabel->show(); this->m_StatisticsUpdatePending = false; } catch ( const std::runtime_error &e ) { // In case of exception, print error message on GUI std::stringstream message; message << "" << e.what() << ""; m_Controls->m_ErrorMessageLabel->setText( message.str().c_str() ); m_Controls->m_ErrorMessageLabel->show(); this->m_StatisticsUpdatePending = false; } catch ( const std::exception &e ) { MITK_ERROR << "Caught exception: " << e.what(); // In case of exception, print error message on GUI std::stringstream message; message << "Error! Unequal Dimensions of Image and Segmentation. No recompute possible "; m_Controls->m_ErrorMessageLabel->setText( message.str().c_str() ); m_Controls->m_ErrorMessageLabel->show(); this->m_StatisticsUpdatePending = false; } } else { this->m_StatisticsUpdatePending = false; } } void QmitkImageStatisticsView::SelectedDataModified() { if( !m_StatisticsUpdatePending ) { emit StatisticsUpdate(); } } void QmitkImageStatisticsView::NodeRemoved(const mitk::DataNode *node) { while(this->m_CalculationThread->isRunning()) // wait until thread has finished { itksys::SystemTools::Delay(100); } if (node->GetData() == m_SelectedImage) { m_SelectedImage = NULL; } } void QmitkImageStatisticsView::RequestStatisticsUpdate() { if ( !m_StatisticsUpdatePending ) { if(this->m_DataNodeSelectionChanged) { this->SelectionChanged(this->GetCurrentSelection()); } else { this->m_StatisticsUpdatePending = true; this->UpdateStatistics(); } } if (this->GetRenderWindowPart()) this->GetRenderWindowPart()->RequestUpdate(); } void QmitkImageStatisticsView::WriteStatisticsToGUI() { m_Controls->m_lineRadioButton->setEnabled(true); m_Controls->m_barRadioButton->setEnabled(true); m_Controls->m_InfoLabel->setText(QString("")); if(m_DataNodeSelectionChanged) { this->m_StatisticsUpdatePending = false; this->RequestStatisticsUpdate(); return; // stop visualization of results and calculate statistics of new selection } if ( this->m_CalculationThread->GetStatisticsUpdateSuccessFlag()) { if ( this->m_CalculationThread->GetStatisticsChangedFlag() ) { // Do not show any error messages m_Controls->m_ErrorMessageLabel->hide(); m_CurrentStatisticsValid = true; } if (m_Controls->m_barRadioButton->isChecked()) { m_Controls->m_JSHistogram->OnBarRadioButtonSelected(); } m_Controls->m_StatisticsWidgetStack->setCurrentIndex( 0 ); - m_Controls->m_JSHistogram->ComputeHistogram( this->m_CalculationThread->GetTimeStepHistogram().GetPointer() ); + //m_Controls->m_JSHistogram->ComputeHistogram( this->m_CalculationThread->GetTimeStepHistogram(this->m_CalculationThread->GetTimeStep()).GetPointer() ); this->FillStatisticsTableView( this->m_CalculationThread->GetStatisticsData(), this->m_CalculationThread->GetStatisticsImage()); } else { m_Controls->m_SelectedMaskLabel->setText( "None" ); m_Controls->m_ErrorMessageLabel->setText( m_CalculationThread->GetLastErrorMessage().c_str() ); m_Controls->m_ErrorMessageLabel->show(); // Clear statistics and histogram this->InvalidateStatisticsTableView(); m_Controls->m_StatisticsWidgetStack->setCurrentIndex( 0 ); //m_Controls->m_JSHistogram->clearHistogram(); m_CurrentStatisticsValid = false; // If a (non-closed) PlanarFigure is selected, display a line profile widget if ( m_SelectedPlanarFigure != NULL ) { // Check if the (closed) planar figure is out of bounds and so no image mask could be calculated--> Intensity Profile can not be calculated bool outOfBounds = false; if ( m_SelectedPlanarFigure->IsClosed() && m_SelectedImageMask == NULL) { outOfBounds = true; std::stringstream message; message << "Planar figure is outside the images bounds."; m_Controls->m_InfoLabel->setText(message.str().c_str()); } // check whether PlanarFigure is initialized const mitk::Geometry2D *planarFigureGeometry2D = m_SelectedPlanarFigure->GetGeometry2D(); if ( planarFigureGeometry2D == NULL || outOfBounds) { // Clear statistics, histogram, and GUI this->InvalidateStatisticsTableView(); m_Controls->m_StatisticsWidgetStack->setCurrentIndex( 0 ); m_Controls->m_JSHistogram->ClearHistogram(); m_CurrentStatisticsValid = false; m_Controls->m_ErrorMessageLabel->hide(); m_Controls->m_SelectedMaskLabel->setText( "None" ); this->m_StatisticsUpdatePending = false; m_Controls->m_lineRadioButton->setEnabled(true); m_Controls->m_barRadioButton->setEnabled(true); if (!outOfBounds) m_Controls->m_InfoLabel->setText(QString("")); return; } unsigned int timeStep = this->GetRenderWindowPart()->GetTimeNavigationController()->GetTime()->GetPos(); m_Controls->m_JSHistogram->SetImage(this->m_CalculationThread->GetStatisticsImage()); m_Controls->m_JSHistogram->SetPlanarFigure(m_SelectedPlanarFigure); m_Controls->m_JSHistogram->ComputeIntensityProfile(timeStep); m_Controls->m_lineRadioButton->setEnabled(false); m_Controls->m_barRadioButton->setEnabled(false); std::stringstream message; message << "Only linegraph available for an intesityprofile!"; m_Controls->m_InfoLabel->setText(message.str().c_str()); } } this->m_StatisticsUpdatePending = false; } void QmitkImageStatisticsView::FillStatisticsTableView( - const mitk::ImageStatisticsCalculator::Statistics &s, + const std::vector &s, const mitk::Image *image ) { - if (s.MaxIndex.size()==3) + this->m_Controls->m_StatisticsTable->setColumnCount(image->GetTimeSteps()); + this->m_Controls->m_StatisticsTable->horizontalHeader()->setVisible(image->GetTimeSteps() > 1); + + for (unsigned int t = 0; t < image->GetTimeSteps(); t++) { - mitk::Point3D index; - index[0] = s.MaxIndex[0]; - index[1] = s.MaxIndex[1]; - index[2] = s.MaxIndex[2]; - m_SelectedImage->GetGeometry()->IndexToWorld(index, m_WorldMax); - index[0] = s.MinIndex[0]; - index[1] = s.MinIndex[1]; - index[2] = s.MinIndex[2]; - m_SelectedImage->GetGeometry()->IndexToWorld(index, m_WorldMin); - } + this->m_Controls->m_StatisticsTable->setHorizontalHeaderItem(t, + new QTableWidgetItem(QString::number(t))); - int decimals = 2; + if (s[t].MaxIndex.size()==3) + { + mitk::Point3D index, max, min; + index[0] = s[t].MaxIndex[0]; + index[1] = s[t].MaxIndex[1]; + index[2] = s[t].MaxIndex[2]; + m_SelectedImage->GetGeometry()->IndexToWorld(index, max); + this->m_WorldMaxList.push_back(max); + index[0] = s[t].MinIndex[0]; + index[1] = s[t].MinIndex[1]; + index[2] = s[t].MinIndex[2]; + m_SelectedImage->GetGeometry()->IndexToWorld(index, min); + this->m_WorldMinList.push_back(min); + } - mitk::PixelType doublePix = mitk::MakeScalarPixelType< double >(); - mitk::PixelType floatPix = mitk::MakeScalarPixelType< float >(); - if (image->GetPixelType()==doublePix || image->GetPixelType()==floatPix) - decimals = 5; + int decimals = 2; - this->m_Controls->m_StatisticsTable->setItem( 0, 0, new QTableWidgetItem( - QString("%1").arg(s.Mean, 0, 'f', decimals) ) ); - this->m_Controls->m_StatisticsTable->setItem( 0, 1, new QTableWidgetItem( - QString("%1").arg(s.Sigma, 0, 'f', decimals) ) ); + mitk::PixelType doublePix = mitk::MakeScalarPixelType< double >(); + mitk::PixelType floatPix = mitk::MakeScalarPixelType< float >(); + if (image->GetPixelType()==doublePix || image->GetPixelType()==floatPix) + decimals = 5; - this->m_Controls->m_StatisticsTable->setItem( 0, 2, new QTableWidgetItem( - QString("%1").arg(s.RMS, 0, 'f', decimals) ) ); + this->m_Controls->m_StatisticsTable->setItem( 0, t, new QTableWidgetItem( + QString("%1").arg(s[t].Mean, 0, 'f', decimals) ) ); + this->m_Controls->m_StatisticsTable->setItem( 1, t, new QTableWidgetItem( + QString("%1").arg(s[t].Sigma, 0, 'f', decimals) ) ); - QString max; max.append(QString("%1").arg(s.Max, 0, 'f', decimals)); - max += " ("; - for (int i=0; im_Controls->m_StatisticsTable->setItem( 0, 3, new QTableWidgetItem( max ) ); + this->m_Controls->m_StatisticsTable->setItem( 2, t, new QTableWidgetItem( + QString("%1").arg(s[t].RMS, 0, 'f', decimals) ) ); - QString min; min.append(QString("%1").arg(s.Min, 0, 'f', decimals)); - min += " ("; - for (int i=0; im_Controls->m_StatisticsTable->setItem( 0, 4, new QTableWidgetItem( min ) ); + QString max; max.append(QString("%1").arg(s[t].Max, 0, 'f', decimals)); + max += " ("; + for (int i=0; im_Controls->m_StatisticsTable->setItem( 3, t, new QTableWidgetItem( max ) ); - this->m_Controls->m_StatisticsTable->setItem( 0, 5, new QTableWidgetItem( - QString("%1").arg(s.N) ) ); + QString min; min.append(QString("%1").arg(s[t].Min, 0, 'f', decimals)); + min += " ("; + for (int i=0; im_Controls->m_StatisticsTable->setItem( 4, t, new QTableWidgetItem( min ) ); - const mitk::Geometry3D *geometry = image->GetGeometry(); - if ( geometry != NULL ) - { - const mitk::Vector3D &spacing = image->GetGeometry()->GetSpacing(); - double volume = spacing[0] * spacing[1] * spacing[2] * (double) s.N; - this->m_Controls->m_StatisticsTable->setItem( 0, 6, new QTableWidgetItem( - QString("%1").arg(volume, 0, 'f', decimals) ) ); - } - else - { - this->m_Controls->m_StatisticsTable->setItem( 0, 6, new QTableWidgetItem( - "NA" ) ); + this->m_Controls->m_StatisticsTable->setItem( 5, t, new QTableWidgetItem( + QString("%1").arg(s[t].N) ) ); + + const mitk::Geometry3D *geometry = image->GetGeometry(); + if ( geometry != NULL ) + { + const mitk::Vector3D &spacing = image->GetGeometry()->GetSpacing(); + double volume = spacing[0] * spacing[1] * spacing[2] * (double) s[t].N; + this->m_Controls->m_StatisticsTable->setItem( 6, t, new QTableWidgetItem( + QString("%1").arg(volume, 0, 'f', decimals) ) ); + } + else + { + this->m_Controls->m_StatisticsTable->setItem( 6, t, new QTableWidgetItem( + "NA" ) ); + } } + + this->m_Controls->m_StatisticsTable->resizeColumnsToContents(); + int height = STAT_TABLE_BASE_HEIGHT; + + if (this->m_Controls->m_StatisticsTable->horizontalHeader()->isVisible()) + height += this->m_Controls->m_StatisticsTable->horizontalHeader()->height(); + + if (this->m_Controls->m_StatisticsTable->horizontalScrollBar()->isVisible()) + height += this->m_Controls->m_StatisticsTable->horizontalScrollBar()->height(); + + this->m_Controls->m_StatisticsTable->setMinimumHeight(height); + + // make sure the current timestep's column is highlighted (and the correct histogram is displayed) + unsigned int timestep = this->GetRenderWindowPart()->GetTimeNavigationController()->GetTime()-> + GetPos(); + mitk::SliceNavigationController::GeometryTimeEvent timeEvent(this->m_SelectedImage->GetTimeGeometry(), + timestep); + this->OnTimeChanged(timeEvent); } void QmitkImageStatisticsView::InvalidateStatisticsTableView() { - for ( unsigned int i = 0; i < 7; ++i ) + this->m_Controls->m_StatisticsTable->horizontalHeader()->setVisible(false); + this->m_Controls->m_StatisticsTable->setColumnCount(1); + + for ( unsigned int i = 0; i < this->m_Controls->m_StatisticsTable->rowCount(); ++i ) { - this->m_Controls->m_StatisticsTable->setItem( 0, i, new QTableWidgetItem( "NA" ) ); + { + this->m_Controls->m_StatisticsTable->setItem( i, 0, new QTableWidgetItem( "NA" ) ); + } } + + this->m_Controls->m_StatisticsTable->setMinimumHeight(STAT_TABLE_BASE_HEIGHT); } void QmitkImageStatisticsView::Activated() { } void QmitkImageStatisticsView::Deactivated() { } void QmitkImageStatisticsView::Visible() { m_Visible = true; mitk::IRenderWindowPart* renderWindow = GetRenderWindowPart(); if (renderWindow) { itk::ReceptorMemberCommand::Pointer cmdTimeEvent = itk::ReceptorMemberCommand::New(); cmdTimeEvent->SetCallbackFunction(this, &QmitkImageStatisticsView::OnTimeChanged); // It is sufficient to add the observer to the axial render window since the GeometryTimeEvent // is always triggered by all views. m_TimeObserverTag = renderWindow->GetQmitkRenderWindow("axial")-> GetSliceNavigationController()-> AddObserver(mitk::SliceNavigationController::GeometryTimeEvent(NULL, 0), cmdTimeEvent); } if (m_DataNodeSelectionChanged) { if (this->IsCurrentSelectionValid()) { this->SelectionChanged(this->GetCurrentSelection()); } else { this->SelectionChanged(this->GetDataManagerSelection()); } m_DataNodeSelectionChanged = false; } } void QmitkImageStatisticsView::Hidden() { m_Visible = false; // The slice navigation controller observer is removed here instead of in the destructor. // If it was called in the destructor, the application would freeze because the view's // destructor gets called after the render windows have been destructed. if ( m_TimeObserverTag != NULL ) { mitk::IRenderWindowPart* renderWindow = GetRenderWindowPart(); if (renderWindow) { renderWindow->GetQmitkRenderWindow("axial")->GetSliceNavigationController()-> RemoveObserver( m_TimeObserverTag ); } m_TimeObserverTag = NULL; } } void QmitkImageStatisticsView::SetFocus() { } diff --git a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsView.h b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsView.h index 442d36fdee..fbbba0a3f1 100644 --- a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsView.h +++ b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsView.h @@ -1,178 +1,179 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QmitkImageStatisticsView_H__INCLUDED #define QmitkImageStatisticsView_H__INCLUDED #include "ui_QmitkImageStatisticsViewControls.h" // Qmitk includes #include #include "QmitkStepperAdapter.h" #include "QmitkImageStatisticsCalculationThread.h" #include // mitk includes #include "mitkImageStatisticsCalculator.h" #include "mitkILifecycleAwarePart.h" #include "mitkPlanarLine.h" /*! \brief QmitkImageStatisticsView is a bundle that allows statistics calculation from images. Three modes are supported: 1. Statistics of one image, 2. Statistics of an image and a segmentation, 3. Statistics of an image and a Planar Figure. The statistics calculation is realized in a seperate thread to keep the gui accessable during calculation. \ingroup Plugins/org.mitk.gui.qt.measurementtoolbox */ class QmitkImageStatisticsView : public QmitkAbstractView, public mitk::ILifecycleAwarePart, public berry::IPartListener { Q_OBJECT private: /*! \ Convenient typedefs */ typedef mitk::DataStorage::SetOfObjects ConstVector; typedef ConstVector::ConstPointer ConstVectorPointer; typedef ConstVector::ConstIterator ConstVectorIterator; typedef std::map< mitk::Image *, mitk::ImageStatisticsCalculator::Pointer > ImageStatisticsMapType; typedef QList SelectedDataNodeVectorType; typedef itk::SimpleMemberCommand< QmitkImageStatisticsView > ITKCommandType; public: /*! \brief default constructor */ QmitkImageStatisticsView(QObject *parent=0, const char *name=0); /*! \brief default destructor */ virtual ~QmitkImageStatisticsView(); /*! \brief method for creating the widget containing the application controls, like sliders, buttons etc. */ virtual void CreateQtPartControl(QWidget *parent); /*! \brief method for creating the connections of main and control widget */ virtual void CreateConnections(); /*! \brief not implemented*/ //bool IsExclusiveFunctionality() const; /*! \brief Is called from the selection mechanism once the data manager selection has changed*/ void OnSelectionChanged( berry::IWorkbenchPart::Pointer part, const QList &nodes ); static const std::string VIEW_ID; + static const int STAT_TABLE_BASE_HEIGHT; public slots: /** \brief Called when the statistics update is finished, sets the results to GUI.*/ void OnThreadedStatisticsCalculationEnds(); protected slots: /** \brief Saves the histogram to the clipboard */ void OnClipboardHistogramButtonClicked(); /** \brief Saves the statistics to the clipboard */ void OnClipboardStatisticsButtonClicked(); /** \brief Indicates if zeros should be excluded from statistics calculation */ void OnIgnoreZerosCheckboxClicked( ); /** \brief Checks if update is possible and calls StatisticsUpdate() possible */ void RequestStatisticsUpdate(); /** \brief Jump to coordinates stored in the double clicked cell */ void JumpToCoordinates(int row, int col); signals: /** \brief Method to set the data to the member and start the threaded statistics update */ void StatisticsUpdate(); protected: /** \brief Writes the calculated statistics to the GUI */ - void FillStatisticsTableView( const mitk::ImageStatisticsCalculator::Statistics &s, + void FillStatisticsTableView( const std::vector &s, const mitk::Image *image ); /** \brief Removes statistics from the GUI */ void InvalidateStatisticsTableView(); /** \brief Recalculate statistics for currently selected image and mask and * update the GUI. */ void UpdateStatistics(); /** \brief Listener for progress events to update progress bar. */ void UpdateProgressBar(); /** \brief Removes any cached images which are no longer referenced elsewhere. */ void RemoveOrphanImages(); /** \brief Computes an Intensity Profile along line and updates the histogram widget with it. */ void ComputeIntensityProfile( mitk::PlanarLine* line ); /** \brief Removes all Observers to images, masks and planar figures and sets corresponding members to zero */ void ClearObservers(); void Activated(); void Deactivated(); void Visible(); void Hidden(); void SetFocus(); /** \brief Method called when itkModifiedEvent is called by selected data. */ void SelectedDataModified(); /** \brief Method called when the data manager selection changes */ void SelectionChanged(const QList &selectedNodes); /** \brief Method called to remove old selection when a new selection is present */ void ReinitData(); /** \brief writes the statistics to the gui*/ void WriteStatisticsToGUI(); void NodeRemoved(const mitk::DataNode *node); - /** \brief Is called right before the view closes (before the destructor) */ - virtual void PartClosed( berry::IWorkbenchPartReference::Pointer ); - /** \brief Is called from the image navigator once the time step has changed */ - void OnTimeChanged( const itk::EventObject& ); - /** \brief Required for berry::IPartListener */ - virtual const char* GetClassName() const { return "QmitkImageStatisticsView"; } - /** \brief Required for berry::IPartListener */ + /** \brief Is called right before the view closes (before the destructor) */ + virtual void PartClosed( berry::IWorkbenchPartReference::Pointer ); + /** \brief Is called from the image navigator once the time step has changed */ + void OnTimeChanged( const itk::EventObject& ); + /** \brief Required for berry::IPartListener */ + virtual const char* GetClassName() const { return "QmitkImageStatisticsView"; } + /** \brief Required for berry::IPartListener */ virtual Events::Types GetPartEventTypes() const { return Events::CLOSED; } // member variables Ui::QmitkImageStatisticsViewControls *m_Controls; QmitkImageStatisticsCalculationThread* m_CalculationThread; QmitkStepperAdapter* m_TimeStepperAdapter; unsigned int m_CurrentTime; QString m_Clipboard; // Image and mask data mitk::Image* m_SelectedImage; mitk::Image* m_SelectedImageMask; mitk::PlanarFigure* m_SelectedPlanarFigure; // observer tags long m_ImageObserverTag; long m_ImageMaskObserverTag; long m_PlanarFigureObserverTag; long m_TimeObserverTag; SelectedDataNodeVectorType m_SelectedDataNodes; bool m_CurrentStatisticsValid; bool m_StatisticsUpdatePending; bool m_StatisticsIntegrationPending; bool m_DataNodeSelectionChanged; bool m_Visible; - mitk::Point3D m_WorldMin; - mitk::Point3D m_WorldMax; + std::vector m_WorldMinList; + std::vector m_WorldMaxList; }; #endif // QmitkImageStatisticsView_H__INCLUDED diff --git a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsViewControls.ui b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsViewControls.ui index 69496e4766..8d685a8c47 100644 --- a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsViewControls.ui +++ b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsViewControls.ui @@ -1,462 +1,465 @@ QmitkImageStatisticsViewControls true 0 0 465 800 Form 0 0 Mask: None 2 Qt::Horizontal 40 20 color: rgb(255, 0, 0); Error Message Qt::AutoText Ignore zero-valued voxels false Statistics 9 9 9 0 0 100 - 175 + 180 16777215 - 170 + 16777215 Qt::ScrollBarAlwaysOff Qt::ScrollBarAsNeeded true true true Qt::DotLine false + + 7 + false false 80 true 80 false true true false 25 25 false false Mean StdDev RMS Max Min N V (mm³) - Component 1 + 0 0 0 Copy to Clipboard Qt::Horizontal 40 20 false 150 160 Histogram false 0 0 0 0 0 Copy to Clipboard Qt::Horizontal 40 20 0 0 0 50 16777215 16777215 Plot 0 20 411 31 QLayout::SetDefaultConstraint Qt::Horizontal QSizePolicy::Preferred 10 0 0 0 Use barchart true 0 0 0 0 Use linegraph Qt::Horizontal 40 20 Qt::Vertical 20 40 QmitkHistogramJSWidget QWidget
QmitkHistogramJSWidget.h
1