diff --git a/Plugins/org.mitk.gui.qt.cest/CMakeLists.txt b/Plugins/org.mitk.gui.qt.cest/CMakeLists.txt index e566584d43..02e76db46f 100644 --- a/Plugins/org.mitk.gui.qt.cest/CMakeLists.txt +++ b/Plugins/org.mitk.gui.qt.cest/CMakeLists.txt @@ -1,7 +1,7 @@ project(org_mitk_gui_qt_cest) mitk_create_plugin( EXPORT_DIRECTIVE CEST_EXPORT EXPORTED_INCLUDE_SUFFIXES src - MODULE_DEPENDS MitkQtWidgetsExt MitkImageStatistics MitkPlanarFigure MitkCEST + MODULE_DEPENDS MitkQtWidgetsExt MitkImageStatistics MitkImageStatisticsUI MitkPlanarFigure MitkCEST ) diff --git a/Plugins/org.mitk.gui.qt.cest/files.cmake b/Plugins/org.mitk.gui.qt.cest/files.cmake index 54f1352424..67dcc599ba 100644 --- a/Plugins/org.mitk.gui.qt.cest/files.cmake +++ b/Plugins/org.mitk.gui.qt.cest/files.cmake @@ -1,47 +1,45 @@ set(SRC_CPP_FILES - QmitkImageStatisticsCalculationThread.cpp ) set(INTERNAL_CPP_FILES org_mitk_gui_qt_cest_Activator.cpp QmitkCESTStatisticsView.cpp QmitkCESTNormalizeView.cpp ) set(UI_FILES src/internal/QmitkCESTStatisticsViewControls.ui src/internal/QmitkCESTNormalizeViewControls.ui ) set(MOC_H_FILES src/internal/org_mitk_gui_qt_cest_Activator.h src/internal/QmitkCESTStatisticsView.h src/internal/QmitkCESTNormalizeView.h - src/QmitkImageStatisticsCalculationThread.h ) # list of resource files which can be used by the plug-in # system without loading the plug-ins shared library, # for example the icon used in the menu and tabs for the # plug-in views in the workbench set(CACHED_RESOURCE_FILES resources/icon.svg resources/icon_norm.png plugin.xml ) # list of Qt .qrc files which contain additional resources # specific to this plugin set(QRC_FILES ) set(CPP_FILES ) foreach(file ${SRC_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/${file}) endforeach(file ${SRC_CPP_FILES}) foreach(file ${INTERNAL_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/internal/${file}) endforeach(file ${INTERNAL_CPP_FILES}) diff --git a/Plugins/org.mitk.gui.qt.cest/src/QmitkImageStatisticsCalculationThread.cpp b/Plugins/org.mitk.gui.qt.cest/src/QmitkImageStatisticsCalculationThread.cpp deleted file mode 100644 index b6622bff90..0000000000 --- a/Plugins/org.mitk.gui.qt.cest/src/QmitkImageStatisticsCalculationThread.cpp +++ /dev/null @@ -1,266 +0,0 @@ -/*=================================================================== - -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 -#include -#include -#include - -QmitkImageStatisticsCalculationThread::QmitkImageStatisticsCalculationThread():QThread(), - m_StatisticsImage(nullptr), m_BinaryMask(nullptr), m_PlanarFigureMask(nullptr), m_TimeStep(0), - m_IgnoreZeros(false), m_CalculationSuccessful(false), m_StatisticChanged(false), m_HistogramBinSize(10.0), m_UseDefaultNBins(true), m_nBinsForHistogramStatistics(100), m_prioritizeNBinsOverBinSize(true) -{ -} - -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 = nullptr; - - if( this->m_BinaryMask.IsNotNull() ) - this->m_BinaryMask = nullptr; - - if( this->m_PlanarFigureMask.IsNotNull()) - this->m_PlanarFigureMask = nullptr; - - // 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::SetUseDefaultNBins(bool useDefault) -{ - m_UseDefaultNBins = useDefault; -} - -void QmitkImageStatisticsCalculationThread::SetTimeStep( int times ) -{ - this->m_TimeStep = times; -} - -int QmitkImageStatisticsCalculationThread::GetTimeStep() -{ - return this->m_TimeStep; -} - -std::vector QmitkImageStatisticsCalculationThread::GetStatisticsData() -{ - 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; -} - -void QmitkImageStatisticsCalculationThread::SetHistogramBinSize(double size) -{ - this->m_HistogramBinSize = size; - this->m_prioritizeNBinsOverBinSize = false; -} - -double QmitkImageStatisticsCalculationThread::GetHistogramBinSize() const -{ - return this->m_HistogramBinSize; -} - -void QmitkImageStatisticsCalculationThread::SetHistogramNBins(double size) -{ - this->m_nBinsForHistogramStatistics = size; - this->m_prioritizeNBinsOverBinSize = true; -} - -double QmitkImageStatisticsCalculationThread::GetHistogramNBins() const -{ - return this->m_nBinsForHistogramStatistics; -} - -std::string QmitkImageStatisticsCalculationThread::GetLastErrorMessage() -{ - return m_message; -} - -QmitkImageStatisticsCalculationThread::HistogramType::Pointer -QmitkImageStatisticsCalculationThread::GetTimeStepHistogram(unsigned int t) -{ - if (t >= this->m_HistogramVector.size()) - return nullptr; - - 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->SetInputImage(m_StatisticsImage); - } - 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()) - { - mitk::ImageMaskGenerator::Pointer imgMask = mitk::ImageMaskGenerator::New(); - imgMask->SetImageMask(m_BinaryMask); - calculator->SetMask(imgMask.GetPointer()); - } - if(this->m_PlanarFigureMask.IsNotNull()) - { - mitk::PlanarFigureMaskGenerator::Pointer pfMaskGen = mitk::PlanarFigureMaskGenerator::New(); - pfMaskGen->SetInputImage(m_StatisticsImage); - pfMaskGen->SetPlanarFigure(m_PlanarFigureMask); - calculator->SetMask(pfMaskGen.GetPointer()); - } - } - catch (const mitk::Exception& e) - { - MITK_ERROR << "MITK Exception: " << e.what(); - statisticCalculationSuccessful = false; - } - catch (const itk::ExceptionObject& e) - { - MITK_ERROR << "ITK Exception:" << e.what(); - statisticCalculationSuccessful = false; - } - catch ( const std::runtime_error &e ) - { - 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; - } - - bool statisticChanged = false; - - if (this->m_IgnoreZeros) - { - mitk::IgnorePixelMaskGenerator::Pointer ignorePixelValueMaskGen = mitk::IgnorePixelMaskGenerator::New(); - ignorePixelValueMaskGen->SetIgnoredPixelValue(0); - ignorePixelValueMaskGen->SetInputImage(m_StatisticsImage); - calculator->SetSecondaryMask(ignorePixelValueMaskGen.GetPointer()); - } - else - { - calculator->SetSecondaryMask(nullptr); - } - - if (m_UseDefaultNBins) - { - calculator->SetNBinsForHistogramStatistics(100); - } - else - { - if (!m_prioritizeNBinsOverBinSize) - { - calculator->SetBinSizeForHistogramStatistics(m_HistogramBinSize); - } - else - { - calculator->SetNBinsForHistogramStatistics(100); - } - } - - //calculator->SetHistogramBinSize( m_HistogramBinSize ); - //calculator->SetUseDefaultBinSize( m_UseDefaultBinSize ); - - for (unsigned int i = 0; i < m_StatisticsImage->GetTimeSteps(); i++) - { - try - { - calculator->GetStatistics(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_StatisticsVector.clear(); - this->m_HistogramVector.clear(); - - for (unsigned int i = 0; i < m_StatisticsImage->GetTimeSteps(); i++) - { - this->m_StatisticsVector.push_back(calculator->GetStatistics(i)); - this->m_HistogramVector.push_back((HistogramType*)this->m_StatisticsVector[i]->GetHistogram()); - } - } -} diff --git a/Plugins/org.mitk.gui.qt.cest/src/QmitkImageStatisticsCalculationThread.h b/Plugins/org.mitk.gui.qt.cest/src/QmitkImageStatisticsCalculationThread.h deleted file mode 100644 index e1fe90b7f1..0000000000 --- a/Plugins/org.mitk.gui.qt.cest/src/QmitkImageStatisticsCalculationThread.h +++ /dev/null @@ -1,123 +0,0 @@ -/*=================================================================== - -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 Automatically calculate bin size to obtain 200 bins. */ - void SetUseDefaultNBins(bool useDefault); - /*! - /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. */ - 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 Set bin size for histogram resolution.*/ - void SetHistogramBinSize( double size); - /*! - /brief Get bin size for histogram resolution.*/ - double GetHistogramBinSize() const; - /*! - /brief Set bin size for histogram resolution.*/ - void SetHistogramNBins( double size); - /*! - /brief Get bin size for histogram resolution.*/ - double GetHistogramNBins() const; - /*! - /brief Returns the histogram of the currently selected time step. */ - 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() override; - - 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. - 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_CalculationSuccessful; ///< flag set if statistics calculation was successful - bool m_StatisticChanged; ///< flag set if statistics have changed - double m_HistogramBinSize; ///< member variable holds the bin size for histogram resolution. - std::vector m_HistogramVector; ///< member holds the histograms of all time steps. - std::string m_message; - bool m_UseDefaultNBins; - unsigned int m_nBinsForHistogramStatistics; - bool m_prioritizeNBinsOverBinSize; -}; -#endif // QMITKIMAGESTATISTICSCALCULATIONTHREAD_H_INCLUDED diff --git a/Plugins/org.mitk.gui.qt.cest/src/internal/QmitkCESTStatisticsView.cpp b/Plugins/org.mitk.gui.qt.cest/src/internal/QmitkCESTStatisticsView.cpp index 91805622a3..2de9dfc5cd 100644 --- a/Plugins/org.mitk.gui.qt.cest/src/internal/QmitkCESTStatisticsView.cpp +++ b/Plugins/org.mitk.gui.qt.cest/src/internal/QmitkCESTStatisticsView.cpp @@ -1,896 +1,822 @@ /*=================================================================== 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. ===================================================================*/ -//itk +// itk #include "itksys/SystemTools.hxx" #include #include // Blueberry #include #include // Qmitk #include "QmitkCESTStatisticsView.h" // Qt #include #include // qwt #include // mitk #include #include #include #include #include #include +#include #include +#include +#include +#include #include #include -#include // boost -#include #include +#include -//stl -#include -#include -#include +// stl #include +#include #include +#include +#include #include namespace { template void GetSortPermutation(std::vector &out, const std::vector &determiningVector, Compare compare = std::less()) { out.resize(determiningVector.size()); std::iota(out.begin(), out.end(), 0); std::sort(out.begin(), out.end(), [&](unsigned i, unsigned j) { return compare(determiningVector[i], determiningVector[j]); }); } template void ApplyPermutation(const std::vector &order, std::vector &vectorToSort) { assert(order.size() == vectorToSort.size()); std::vector tempVector(vectorToSort.size()); for (unsigned i = 0; i < vectorToSort.size(); i++) { tempVector[i] = vectorToSort[order[i]]; } vectorToSort = tempVector; } template void ApplyPermutation(const std::vector &order, std::vector ¤tVector, std::vector &... remainingVectors) { ApplyPermutation(order, currentVector); ApplyPermutation(order, remainingVectors...); } template void SortVectors(const std::vector &orderDeterminingVector, Compare comparison, std::vector &... vectorsToBeSorted) { std::vector order; GetSortPermutation(order, orderDeterminingVector, comparison); ApplyPermutation(order, vectorsToBeSorted...); } -} +} // namespace const std::string QmitkCESTStatisticsView::VIEW_ID = "org.mitk.views.ceststatistics"; static const int STAT_TABLE_BASE_HEIGHT = 180; -QmitkCESTStatisticsView::QmitkCESTStatisticsView(QObject* /*parent*/, const char* /*name*/) +QmitkCESTStatisticsView::QmitkCESTStatisticsView(QObject * /*parent*/, const char * /*name*/) { - this->m_CalculatorThread = new QmitkImageStatisticsCalculationThread; + this->m_CalculatorJob = new QmitkImageStatisticsCalculationJob(); m_currentSelectedPosition.Fill(0.0); m_currentSelectedTimeStep = 0; m_CrosshairPointSet = mitk::PointSet::New(); } QmitkCESTStatisticsView::~QmitkCESTStatisticsView() { - while (this->m_CalculatorThread->isRunning()) // wait until thread has finished + while (this->m_CalculatorJob->isRunning()) // wait until thread has finished { itksys::SystemTools::Delay(100); } - delete this->m_CalculatorThread; + delete this->m_CalculatorJob; } void QmitkCESTStatisticsView::SetFocus() { m_Controls.threeDimToFourDimPushButton->setFocus(); } -void QmitkCESTStatisticsView::CreateQtPartControl( QWidget *parent ) +void QmitkCESTStatisticsView::CreateQtPartControl(QWidget *parent) { // create GUI widgets from the Qt Designer's .ui file - m_Controls.setupUi( parent ); - connect(m_Controls.threeDimToFourDimPushButton, SIGNAL(clicked()), this, SLOT(OnThreeDimToFourDimPushButtonClicked())); - connect((QObject*) this->m_CalculatorThread, SIGNAL(finished()), this, SLOT(OnThreadedStatisticsCalculationEnds()), Qt::QueuedConnection); - connect((QObject*)(this->m_Controls.m_CopyStatisticsToClipboardPushButton), SIGNAL(clicked()), (QObject*) this, SLOT(OnCopyStatisticsToClipboardPushButtonClicked())); - connect((QObject*)(this->m_Controls.fixedRangeCheckBox), SIGNAL(toggled(bool)), (QObject*) this, SLOT(OnFixedRangeCheckBoxToggled(bool))); - connect((QObject*)(this->m_Controls.fixedRangeLowerDoubleSpinBox), SIGNAL(editingFinished()), (QObject*) this, SLOT(OnFixedRangeDoubleSpinBoxChanged())); - connect((QObject*)(this->m_Controls.fixedRangeUpperDoubleSpinBox), SIGNAL(editingFinished()), (QObject*) this, SLOT(OnFixedRangeDoubleSpinBoxChanged())); + m_Controls.setupUi(parent); + connect( + m_Controls.threeDimToFourDimPushButton, SIGNAL(clicked()), this, SLOT(OnThreeDimToFourDimPushButtonClicked())); + connect((QObject *)this->m_CalculatorJob, + SIGNAL(finished()), + this, + SLOT(OnThreadedStatisticsCalculationEnds()), + Qt::QueuedConnection); + connect((QObject *)(this->m_Controls.fixedRangeCheckBox), + SIGNAL(toggled(bool)), + (QObject *)this, + SLOT(OnFixedRangeCheckBoxToggled(bool))); + connect((QObject *)(this->m_Controls.fixedRangeLowerDoubleSpinBox), + SIGNAL(editingFinished()), + (QObject *)this, + SLOT(OnFixedRangeDoubleSpinBoxChanged())); + connect((QObject *)(this->m_Controls.fixedRangeUpperDoubleSpinBox), + SIGNAL(editingFinished()), + (QObject *)this, + SLOT(OnFixedRangeDoubleSpinBoxChanged())); m_Controls.threeDimToFourDimPushButton->setEnabled(false); + m_Controls.widget_statistics->SetDataStorage(this->GetDataStorage()); + this->m_SliceChangeListener.RenderWindowPartActivated(this->GetRenderWindowPart()); connect(&m_SliceChangeListener, SIGNAL(SliceChanged()), this, SLOT(OnSliceChanged())); } -void QmitkCESTStatisticsView::RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) +void QmitkCESTStatisticsView::RenderWindowPartActivated(mitk::IRenderWindowPart *renderWindowPart) { this->m_SliceChangeListener.RenderWindowPartActivated(renderWindowPart); } -void QmitkCESTStatisticsView::RenderWindowPartDeactivated( - mitk::IRenderWindowPart* renderWindowPart) +void QmitkCESTStatisticsView::RenderWindowPartDeactivated(mitk::IRenderWindowPart *renderWindowPart) { this->m_SliceChangeListener.RenderWindowPartDeactivated(renderWindowPart); } -void QmitkCESTStatisticsView::OnSelectionChanged( berry::IWorkbenchPart::Pointer /*source*/, - const QList& nodes ) +void QmitkCESTStatisticsView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*source*/, + const QList &nodes) { if (nodes.empty()) { std::stringstream message; message << "Please select an image."; m_Controls.labelWarning->setText(message.str().c_str()); m_Controls.labelWarning->show(); this->Clear(); return; } // iterate all selected objects bool atLeastOneWasCESTImage = false; - foreach( mitk::DataNode::Pointer node, nodes ) + foreach (mitk::DataNode::Pointer node, nodes) { if (node.IsNull()) { continue; } - if( dynamic_cast(node->GetData()) != nullptr ) + if (dynamic_cast(node->GetData()) != nullptr) { - m_Controls.labelWarning->setVisible( false ); + m_Controls.labelWarning->setVisible(false); - bool zSpectrumSet = - SetZSpectrum(dynamic_cast(node->GetData()->GetProperty(mitk::CustomTagParser::m_OffsetsPropertyName.c_str()).GetPointer())); + bool zSpectrumSet = SetZSpectrum(dynamic_cast( + node->GetData()->GetProperty(mitk::CustomTagParser::m_OffsetsPropertyName.c_str()).GetPointer())); atLeastOneWasCESTImage = atLeastOneWasCESTImage || zSpectrumSet; if (zSpectrumSet) { - m_ZImage = dynamic_cast(node->GetData()); + m_ZImage = dynamic_cast(node->GetData()); + m_Controls.widget_statistics->SetImageNodes({node.GetPointer()}); } else { - m_MaskImage = dynamic_cast(node->GetData()); + m_MaskImage = dynamic_cast(node->GetData()); + m_Controls.widget_statistics->SetMaskNodes({node.GetPointer()}); } } - if (dynamic_cast(node->GetData()) != nullptr) + if (dynamic_cast(node->GetData()) != nullptr) { - m_MaskPlanarFigure = dynamic_cast(node->GetData()); + m_MaskPlanarFigure = dynamic_cast(node->GetData()); + m_Controls.widget_statistics->SetMaskNodes({node.GetPointer()}); } - if (dynamic_cast(node->GetData()) != nullptr) + if (dynamic_cast(node->GetData()) != nullptr) { - m_PointSet = dynamic_cast(node->GetData()); + m_PointSet = dynamic_cast(node->GetData()); } } // We only want to offer normalization or timestep copying if one object is selected if (nodes.size() == 1) { - if (dynamic_cast(nodes.front()->GetData()) ) + if (dynamic_cast(nodes.front()->GetData())) { m_Controls.threeDimToFourDimPushButton->setDisabled(atLeastOneWasCESTImage); } else { m_Controls.threeDimToFourDimPushButton->setEnabled(false); std::stringstream message; message << "The selected node is not an image."; m_Controls.labelWarning->setText(message.str().c_str()); m_Controls.labelWarning->show(); } this->Clear(); return; } - - // we always need a mask, either image or planar figure as well as an image for further processing if (nodes.size() != 2) { this->Clear(); return; } m_Controls.threeDimToFourDimPushButton->setEnabled(false); if (!atLeastOneWasCESTImage) { std::stringstream message; message << "None of the selected data nodes contains required CEST meta information"; m_Controls.labelWarning->setText(message.str().c_str()); m_Controls.labelWarning->show(); this->Clear(); return; } bool bothAreImages = (m_ZImage.GetPointer() != nullptr) && (m_MaskImage.GetPointer() != nullptr); if (bothAreImages) { - bool geometriesMatch = mitk::Equal(*(m_ZImage->GetTimeGeometry()), *(m_MaskImage->GetTimeGeometry()), mitk::eps, false); + bool geometriesMatch = + mitk::Equal(*(m_ZImage->GetTimeGeometry()), *(m_MaskImage->GetTimeGeometry()), mitk::eps, false); if (!geometriesMatch) { std::stringstream message; message << "The selected images have different geometries."; m_Controls.labelWarning->setText(message.str().c_str()); m_Controls.labelWarning->show(); this->Clear(); return; } } if (!this->DataSanityCheck()) { this->Clear(); return; } if (m_PointSet.IsNull()) { // initialize thread and trigger it - this->m_CalculatorThread->SetIgnoreZeroValueVoxel(false); - this->m_CalculatorThread->Initialize(m_ZImage, m_MaskImage, m_MaskPlanarFigure); + this->m_CalculatorJob->SetIgnoreZeroValueVoxel(false); + this->m_CalculatorJob->Initialize(m_ZImage.GetPointer(), m_MaskImage.GetPointer(), m_MaskPlanarFigure.GetPointer()); std::stringstream message; message << "Calculating statistics..."; m_Controls.labelWarning->setText(message.str().c_str()); m_Controls.labelWarning->show(); try { // Compute statistics - this->m_CalculatorThread->start(); + this->m_CalculatorJob->start(); } - catch (const mitk::Exception& e) + catch (const mitk::Exception &e) { std::stringstream message; message << "" << e.GetDescription() << ""; m_Controls.labelWarning->setText(message.str().c_str()); m_Controls.labelWarning->show(); } catch (const std::runtime_error &e) { // In case of exception, print error message on GUI std::stringstream message; message << "" << e.what() << ""; m_Controls.labelWarning->setText(message.str().c_str()); m_Controls.labelWarning->show(); } 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.labelWarning->setText(message.str().c_str()); m_Controls.labelWarning->show(); } - while (this->m_CalculatorThread->isRunning()) // wait until thread has finished + while (this->m_CalculatorJob->isRunning()) // wait until thread has finished { itksys::SystemTools::Delay(100); } } if (m_PointSet.IsNotNull()) { if (m_ZImage->GetDimension() == 4) { AccessFixedDimensionByItk(m_ZImage, PlotPointSet, 4); } else { MITK_WARN << "Expecting a 4D image."; } } } void QmitkCESTStatisticsView::OnThreadedStatisticsCalculationEnds() { this->m_Controls.m_DataViewWidget->SetAxisTitle(QwtPlot::Axis::xBottom, "delta w"); this->m_Controls.m_DataViewWidget->SetAxisTitle(QwtPlot::Axis::yLeft, "z"); - const std::vector &statistics = - this->m_CalculatorThread->GetStatisticsData(); + if (this->m_CalculatorJob->GetStatisticsUpdateSuccessFlag()) + { + auto statistics = this->m_CalculatorJob->GetStatisticsData(); - QmitkPlotWidget::DataVector::size_type numberOfSpectra = this->m_zSpectrum.size(); + auto statisticNonConst = statistics->Clone(); + std::string statisticsNodeName = "CEST_statistics"; + auto statisticsNode = mitk::CreateImageStatisticsNode(statisticNonConst, statisticsNodeName); + auto imageRule = mitk::StatisticsToImageRelationRule::New(); + imageRule->Connect(statisticNonConst.GetPointer(), m_CalculatorJob->GetStatisticsImage().GetPointer()); - QmitkPlotWidget::DataVector means(numberOfSpectra); - QmitkPlotWidget::DataVector stdevs(numberOfSpectra); + if (m_CalculatorJob->GetMaskImage()) + { + auto maskRule = mitk::StatisticsToMaskRelationRule::New(); + maskRule->Connect(statisticNonConst.GetPointer(), m_CalculatorJob->GetMaskImage().GetPointer()); + } + else if (m_CalculatorJob->GetPlanarFigure()) + { + auto planarFigureRule = mitk::StatisticsToMaskRelationRule::New(); + planarFigureRule->Connect(statisticNonConst.GetPointer(), m_CalculatorJob->GetPlanarFigure().GetPointer()); + } - for (unsigned int index = 0; index < numberOfSpectra; ++index) - { - means[index] = statistics[index]->GetMean(); - stdevs[index] = statistics[index]->GetStd(); - } + this->GetDataStorage()->Add(statisticsNode); - QmitkPlotWidget::DataVector xValues = this->m_zSpectrum; + QmitkPlotWidget::DataVector::size_type numberOfSpectra = this->m_zSpectrum.size(); - RemoveMZeros(xValues, means, stdevs); - ::SortVectors(xValues, std::less(), xValues, means, stdevs); + QmitkPlotWidget::DataVector means(numberOfSpectra); + QmitkPlotWidget::DataVector stdevs(numberOfSpectra); - unsigned int curveId = this->m_Controls.m_DataViewWidget->InsertCurve("Spectrum"); - this->m_Controls.m_DataViewWidget->SetCurveData(curveId, xValues, means, stdevs, stdevs); - this->m_Controls.m_DataViewWidget->SetErrorPen(curveId, QPen(Qt::blue)); - QwtSymbol* blueSymbol = new QwtSymbol(QwtSymbol::Rect, QColor(Qt::blue), QColor(Qt::blue), - QSize(8, 8)); - this->m_Controls.m_DataViewWidget->SetCurveSymbol(curveId, blueSymbol); - this->m_Controls.m_DataViewWidget->SetLegendAttribute(curveId, QwtPlotCurve::LegendShowSymbol); + for (unsigned int index = 0; index < numberOfSpectra; ++index) + { + means[index] = + statistics->GetStatisticsForTimeStep(index).GetValueConverted( + mitk::ImageStatisticsConstants::MEAN()); + stdevs[index] = + statistics->GetStatisticsForTimeStep(index).GetValueConverted( + mitk::ImageStatisticsConstants::STANDARDDEVIATION()); + } - QwtLegend* legend = new QwtLegend(); - legend->setFrameShape(QFrame::Box); - legend->setFrameShadow(QFrame::Sunken); - legend->setLineWidth(1); - this->m_Controls.m_DataViewWidget->SetLegend(legend, QwtPlot::BottomLegend); + QmitkPlotWidget::DataVector xValues = this->m_zSpectrum; - m_Controls.m_DataViewWidget->GetPlot()->axisScaleEngine(QwtPlot::Axis::xBottom)->setAttributes(QwtScaleEngine::Inverted); + RemoveMZeros(xValues, means, stdevs); + ::SortVectors(xValues, std::less(), xValues, means, stdevs); - this->m_Controls.m_DataViewWidget->Replot(); - m_Controls.labelWarning->setVisible(false); + unsigned int curveId = this->m_Controls.m_DataViewWidget->InsertCurve("Spectrum"); + this->m_Controls.m_DataViewWidget->SetCurveData(curveId, xValues, means, stdevs, stdevs); + this->m_Controls.m_DataViewWidget->SetErrorPen(curveId, QPen(Qt::blue)); + QwtSymbol *blueSymbol = new QwtSymbol(QwtSymbol::Rect, QColor(Qt::blue), QColor(Qt::blue), QSize(8, 8)); + this->m_Controls.m_DataViewWidget->SetCurveSymbol(curveId, blueSymbol); + this->m_Controls.m_DataViewWidget->SetLegendAttribute(curveId, QwtPlotCurve::LegendShowSymbol); - if (this->m_Controls.fixedRangeCheckBox->isChecked()) - { - this->m_Controls.m_DataViewWidget->GetPlot()->setAxisAutoScale(2, false); - this->m_Controls.m_DataViewWidget->GetPlot()->setAxisScale(2, this->m_Controls.fixedRangeLowerDoubleSpinBox->value(), this->m_Controls.fixedRangeUpperDoubleSpinBox->value()); - } - else - { - this->m_Controls.m_DataViewWidget->GetPlot()->setAxisAutoScale(2, true); - } + QwtLegend *legend = new QwtLegend(); + legend->setFrameShape(QFrame::Box); + legend->setFrameShadow(QFrame::Sunken); + legend->setLineWidth(1); + this->m_Controls.m_DataViewWidget->SetLegend(legend, QwtPlot::BottomLegend); - if(this->DataSanityCheck()) - { - this->FillStatisticsTableView(this->m_CalculatorThread->GetStatisticsData(), this->m_CalculatorThread->GetStatisticsImage()); + m_Controls.m_DataViewWidget->GetPlot() + ->axisScaleEngine(QwtPlot::Axis::xBottom) + ->setAttributes(QwtScaleEngine::Inverted); + + this->m_Controls.m_DataViewWidget->Replot(); + m_Controls.labelWarning->setVisible(false); + + m_Controls.m_StatisticsGroupBox->setEnabled(true); + m_Controls.m_StatisticsGroupBox->setEnabled(true); + + if (this->m_Controls.fixedRangeCheckBox->isChecked()) + { + this->m_Controls.m_DataViewWidget->GetPlot()->setAxisAutoScale(2, false); + this->m_Controls.m_DataViewWidget->GetPlot()->setAxisScale( + 2, + this->m_Controls.fixedRangeLowerDoubleSpinBox->value(), + this->m_Controls.fixedRangeUpperDoubleSpinBox->value()); + } + else + { + this->m_Controls.m_DataViewWidget->GetPlot()->setAxisAutoScale(2, true); + } } else { + m_Controls.labelWarning->setText(m_CalculatorJob->GetLastErrorMessage().c_str()); + m_Controls.labelWarning->setVisible(true); this->Clear(); } } void QmitkCESTStatisticsView::OnFixedRangeDoubleSpinBoxChanged() { if (this->m_Controls.fixedRangeCheckBox->isChecked()) { this->m_Controls.m_DataViewWidget->GetPlot()->setAxisAutoScale(2, false); - this->m_Controls.m_DataViewWidget->GetPlot()->setAxisScale(2, this->m_Controls.fixedRangeLowerDoubleSpinBox->value(), this->m_Controls.fixedRangeUpperDoubleSpinBox->value()); + this->m_Controls.m_DataViewWidget->GetPlot()->setAxisScale(2, + this->m_Controls.fixedRangeLowerDoubleSpinBox->value(), + this->m_Controls.fixedRangeUpperDoubleSpinBox->value()); } this->m_Controls.m_DataViewWidget->Replot(); } template -void QmitkCESTStatisticsView::PlotPointSet(itk::Image* image) +void QmitkCESTStatisticsView::PlotPointSet(itk::Image *image) { this->m_Controls.m_DataViewWidget->SetAxisTitle(QwtPlot::Axis::xBottom, "delta w"); this->m_Controls.m_DataViewWidget->SetAxisTitle(QwtPlot::Axis::yLeft, "z"); QmitkPlotWidget::DataVector::size_type numberOfSpectra = this->m_zSpectrum.size(); mitk::PointSet::Pointer internalPointset; if (m_PointSet.IsNotNull()) { internalPointset = m_PointSet; } else { internalPointset = m_CrosshairPointSet; } if (internalPointset.IsNull()) { return; } if (!this->DataSanityCheck()) { m_Controls.labelWarning->setText("Data can not be plotted, internally inconsistent."); m_Controls.labelWarning->show(); return; } auto maxIndex = internalPointset->GetMaxId().Index(); for (std::size_t number = 0; number < maxIndex + 1; ++number) { mitk::PointSet::PointType point; if (!internalPointset->GetPointIfExists(number, &point)) { continue; } if (!this->m_ZImage->GetGeometry()->IsInside(point)) { continue; } itk::Index<3> itkIndex; this->m_ZImage->GetGeometry()->WorldToIndex(point, itkIndex); itk::Index itkIndexTime; itkIndexTime[0] = itkIndex[0]; itkIndexTime[1] = itkIndex[1]; itkIndexTime[2] = itkIndex[2]; QmitkPlotWidget::DataVector values(numberOfSpectra); for (std::size_t step = 0; step < numberOfSpectra; ++step) { - if( VImageDimension == 4 ) + if (VImageDimension == 4) { itkIndexTime[3] = step; } values[step] = image->GetPixel(itkIndexTime); } std::stringstream name; name << "Point " << number; // Qcolor enums go from 0 to 19, but 19 is transparent and 0,1 are for bitmaps // 3 is white and thus not visible QColor color(static_cast(number % 17 + 4)); QmitkPlotWidget::DataVector xValues = this->m_zSpectrum; RemoveMZeros(xValues, values); ::SortVectors(xValues, std::less(), xValues, values); unsigned int curveId = this->m_Controls.m_DataViewWidget->InsertCurve(name.str().c_str()); this->m_Controls.m_DataViewWidget->SetCurveData(curveId, xValues, values); this->m_Controls.m_DataViewWidget->SetCurvePen(curveId, QPen(color)); - QwtSymbol* symbol = new QwtSymbol(QwtSymbol::Rect, color, color, - QSize(8, 8)); + QwtSymbol *symbol = new QwtSymbol(QwtSymbol::Rect, color, color, QSize(8, 8)); this->m_Controls.m_DataViewWidget->SetCurveSymbol(curveId, symbol); this->m_Controls.m_DataViewWidget->SetLegendAttribute(curveId, QwtPlotCurve::LegendShowSymbol); } if (this->m_Controls.fixedRangeCheckBox->isChecked()) { this->m_Controls.m_DataViewWidget->GetPlot()->setAxisAutoScale(2, false); - this->m_Controls.m_DataViewWidget->GetPlot()->setAxisScale(2, this->m_Controls.fixedRangeLowerDoubleSpinBox->value(), this->m_Controls.fixedRangeUpperDoubleSpinBox->value()); + this->m_Controls.m_DataViewWidget->GetPlot()->setAxisScale(2, + this->m_Controls.fixedRangeLowerDoubleSpinBox->value(), + this->m_Controls.fixedRangeUpperDoubleSpinBox->value()); } else { this->m_Controls.m_DataViewWidget->GetPlot()->setAxisAutoScale(2, true); } - QwtLegend* legend = new QwtLegend(); + QwtLegend *legend = new QwtLegend(); legend->setFrameShape(QFrame::Box); legend->setFrameShadow(QFrame::Sunken); legend->setLineWidth(1); this->m_Controls.m_DataViewWidget->SetLegend(legend, QwtPlot::BottomLegend); - m_Controls.m_DataViewWidget->GetPlot()->axisScaleEngine(QwtPlot::Axis::xBottom)->setAttributes(QwtScaleEngine::Inverted); + m_Controls.m_DataViewWidget->GetPlot() + ->axisScaleEngine(QwtPlot::Axis::xBottom) + ->setAttributes(QwtScaleEngine::Inverted); this->m_Controls.m_DataViewWidget->Replot(); m_Controls.labelWarning->setVisible(false); - } void QmitkCESTStatisticsView::OnFixedRangeCheckBoxToggled(bool state) { this->m_Controls.fixedRangeLowerDoubleSpinBox->setEnabled(state); this->m_Controls.fixedRangeUpperDoubleSpinBox->setEnabled(state); } -void QmitkCESTStatisticsView::RemoveMZeros(QmitkPlotWidget::DataVector& xValues, QmitkPlotWidget::DataVector& yValues) +void QmitkCESTStatisticsView::RemoveMZeros(QmitkPlotWidget::DataVector &xValues, QmitkPlotWidget::DataVector &yValues) { QmitkPlotWidget::DataVector tempX; QmitkPlotWidget::DataVector tempY; for (std::size_t index = 0; index < xValues.size(); ++index) { if ((xValues.at(index) < -299) || (xValues.at(index)) > 299) { // do not include } else { tempX.push_back(xValues.at(index)); tempY.push_back(yValues.at(index)); } } xValues = tempX; yValues = tempY; } -void QmitkCESTStatisticsView::RemoveMZeros(QmitkPlotWidget::DataVector& xValues, QmitkPlotWidget::DataVector& yValues, QmitkPlotWidget::DataVector& stdDevs) +void QmitkCESTStatisticsView::RemoveMZeros(QmitkPlotWidget::DataVector &xValues, + QmitkPlotWidget::DataVector &yValues, + QmitkPlotWidget::DataVector &stdDevs) { QmitkPlotWidget::DataVector tempX; QmitkPlotWidget::DataVector tempY; QmitkPlotWidget::DataVector tempDevs; for (std::size_t index = 0; index < xValues.size(); ++index) { if ((xValues.at(index) < -299) || (xValues.at(index)) > 299) { // do not include } else { tempX.push_back(xValues.at(index)); tempY.push_back(yValues.at(index)); tempDevs.push_back(stdDevs.at(index)); } } xValues = tempX; yValues = tempY; stdDevs = tempDevs; } void QmitkCESTStatisticsView::OnThreeDimToFourDimPushButtonClicked() { QList nodes = this->GetDataManagerSelection(); - if (nodes.empty()) return; + if (nodes.empty()) + return; - mitk::DataNode* node = nodes.front(); + mitk::DataNode *node = nodes.front(); if (!node) { // Nothing selected. Inform the user and return - QMessageBox::information( nullptr, "CEST View", "Please load and select an image before starting image processing."); + QMessageBox::information(nullptr, "CEST View", "Please load and select an image before starting image processing."); return; } // here we have a valid mitk::DataNode // a node itself is not very useful, we need its data item (the image) - mitk::BaseData* data = node->GetData(); + mitk::BaseData *data = node->GetData(); if (data) { // test if this data item is an image or not (could also be a surface or something totally different) - mitk::Image* image = dynamic_cast( data ); + mitk::Image *image = dynamic_cast(data); if (image) { if (image->GetDimension() == 4) { AccessFixedDimensionByItk(image, CopyTimesteps, 4); } this->Clear(); } } } template -void QmitkCESTStatisticsView::CopyTimesteps(itk::Image* image) +void QmitkCESTStatisticsView::CopyTimesteps(itk::Image *image) { - typedef itk::Image ImageType; - //typedef itk::PasteImageFilter PasteImageFilterType; + typedef itk::Image ImageType; + // typedef itk::PasteImageFilter PasteImageFilterType; unsigned int numberOfTimesteps = image->GetLargestPossibleRegion().GetSize(3); typename ImageType::RegionType sourceRegion = image->GetLargestPossibleRegion(); sourceRegion.SetSize(3, 1); typename ImageType::RegionType targetRegion = image->GetLargestPossibleRegion(); targetRegion.SetSize(3, 1); for (unsigned int timestep = 1; timestep < numberOfTimesteps; ++timestep) { targetRegion.SetIndex(3, timestep); itk::ImageRegionConstIterator sourceIterator(image, sourceRegion); itk::ImageRegionIterator targetIterator(image, targetRegion); while (!sourceIterator.IsAtEnd()) { targetIterator.Set(sourceIterator.Get()); ++sourceIterator; ++targetIterator; } } } -bool QmitkCESTStatisticsView::SetZSpectrum(mitk::StringProperty* zSpectrumProperty) +bool QmitkCESTStatisticsView::SetZSpectrum(mitk::StringProperty *zSpectrumProperty) { if (zSpectrumProperty == nullptr) { return false; } mitk::LocaleSwitch localeSwitch("C"); std::string zSpectrumString = zSpectrumProperty->GetValueAsString(); std::istringstream iss(zSpectrumString); std::vector zSpectra; - std::copy(std::istream_iterator(iss), - std::istream_iterator(), - std::back_inserter(zSpectra)); + std::copy( + std::istream_iterator(iss), std::istream_iterator(), std::back_inserter(zSpectra)); m_zSpectrum.clear(); m_zSpectrum.resize(0); for (auto const &spectrumString : zSpectra) { m_zSpectrum.push_back(std::stod(spectrumString)); } return (m_zSpectrum.size() > 0); } -void QmitkCESTStatisticsView::FillStatisticsTableView( - const std::vector &s, - const mitk::Image *image) -{ - this->m_Controls.m_StatisticsTable->setColumnCount(image->GetTimeSteps()); - this->m_Controls.m_StatisticsTable->horizontalHeader()->setVisible(image->GetTimeSteps() > 1); - - int decimals = 2; - - mitk::PixelType doublePix = mitk::MakeScalarPixelType< double >(); - mitk::PixelType floatPix = mitk::MakeScalarPixelType< float >(); - if (image->GetPixelType() == doublePix || image->GetPixelType() == floatPix) - { - decimals = 5; - } - - for (unsigned int t = 0; t < image->GetTimeSteps(); t++) - { - this->m_Controls.m_StatisticsTable->setHorizontalHeaderItem(t, - new QTableWidgetItem(QString::number(m_zSpectrum[t]))); - - this->m_Controls.m_StatisticsTable->setItem(0, t, new QTableWidgetItem( - QString("%1").arg(s[t]->GetMean(), 0, 'f', decimals))); - this->m_Controls.m_StatisticsTable->setItem(1, t, new QTableWidgetItem( - QString("%1").arg(s[t]->GetStd(), 0, 'f', decimals))); - - this->m_Controls.m_StatisticsTable->setItem(2, t, new QTableWidgetItem( - QString("%1").arg(s[t]->GetRMS(), 0, 'f', decimals))); - - QString max; max.append(QString("%1").arg(s[t]->GetMax(), 0, 'f', decimals)); - max += " ("; - for (unsigned int i = 0; iGetMaxIndex().size(); i++) - { - max += QString::number(s[t]->GetMaxIndex()[i]); - if (iGetMaxIndex().size() - 1) - max += ","; - } - max += ")"; - this->m_Controls.m_StatisticsTable->setItem(3, t, new QTableWidgetItem(max)); - - QString min; min.append(QString("%1").arg(s[t]->GetMin(), 0, 'f', decimals)); - min += " ("; - for (unsigned int i = 0; iGetMinIndex().size(); i++) - { - min += QString::number(s[t]->GetMinIndex()[i]); - if (iGetMinIndex().size() - 1) - min += ","; - } - min += ")"; - this->m_Controls.m_StatisticsTable->setItem(4, t, new QTableWidgetItem(min)); - - this->m_Controls.m_StatisticsTable->setItem(5, t, new QTableWidgetItem( - QString("%1").arg(s[t]->GetN()))); - - const mitk::BaseGeometry *geometry = image->GetGeometry(); - if (geometry != nullptr) - { - const mitk::Vector3D &spacing = image->GetGeometry()->GetSpacing(); - double volume = spacing[0] * spacing[1] * spacing[2] * (double)s[t]->GetN(); - 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); - this->m_Controls.m_StatisticsGroupBox->setEnabled(true); - this->m_Controls.m_StatisticsTable->setEnabled(true); -} - -void QmitkCESTStatisticsView::InvalidateStatisticsTableView() -{ - this->m_Controls.m_StatisticsTable->horizontalHeader()->setVisible(false); - this->m_Controls.m_StatisticsTable->setColumnCount(1); - - for (int i = 0; i < this->m_Controls.m_StatisticsTable->rowCount(); ++i) - { - { - this->m_Controls.m_StatisticsTable->setItem(i, 0, new QTableWidgetItem("NA")); - } - } - - this->m_Controls.m_StatisticsTable->setMinimumHeight(STAT_TABLE_BASE_HEIGHT); - this->m_Controls.m_StatisticsTable->setEnabled(false); -} - bool QmitkCESTStatisticsView::DataSanityCheck() { QmitkPlotWidget::DataVector::size_type numberOfSpectra = m_zSpectrum.size(); // if we do not have a spectrum, the data can not be processed if (numberOfSpectra == 0) { return false; } // if we do not have CEST image data, the data can not be processed if (m_ZImage.IsNull()) { return false; } // if the CEST image data and the meta information do not match, the data can not be processed if (numberOfSpectra != m_ZImage->GetTimeSteps()) { MITK_INFO << "CEST meta information and number of volumes does not match."; return false; } // if we have neither a mask image, a point set nor a mask planar figure, we can not do statistics // statistics on the whole image would not make sense if (m_MaskImage.IsNull() && m_MaskPlanarFigure.IsNull() && m_PointSet.IsNull() && m_CrosshairPointSet->IsEmpty()) { return false; } // if we have a mask image and a mask planar figure, we can not do statistics // we do not know which one to use if (m_MaskImage.IsNotNull() && m_MaskPlanarFigure.IsNotNull()) { return false; } return true; } void QmitkCESTStatisticsView::Clear() { this->m_zSpectrum.clear(); this->m_zSpectrum.resize(0); this->m_ZImage = nullptr; this->m_MaskImage = nullptr; this->m_MaskPlanarFigure = nullptr; this->m_PointSet = nullptr; this->m_Controls.m_DataViewWidget->Clear(); - this->InvalidateStatisticsTableView(); this->m_Controls.m_StatisticsGroupBox->setEnabled(false); -} - -void QmitkCESTStatisticsView::OnCopyStatisticsToClipboardPushButtonClicked() -{ - QLocale tempLocal; - QLocale::setDefault(QLocale(QLocale::English, QLocale::UnitedStates)); - - const std::vector &statistics = - this->m_CalculatorThread->GetStatisticsData(); - - QmitkPlotWidget::DataVector::size_type size = m_zSpectrum.size(); - - QString clipboard("delta_w \t Mean \t StdDev \t RMS \t Max \t Min \t N\n"); - for (QmitkPlotWidget::DataVector::size_type index = 0; index < size; ++index) - { - // Copy statistics to clipboard ("%Ln" will use the default locale for - // number formatting) - clipboard = clipboard.append("%L1 \t %L2 \t %L3 \t %L4 \t %L5 \t %L6 \t %L7\n") - .arg(m_zSpectrum[index], 0, 'f', 10) - .arg(statistics[index]->GetMean(), 0, 'f', 10) - .arg(statistics[index]->GetStd(), 0, 'f', 10) - .arg(statistics[index]->GetRMS(), 0, 'f', 10) - .arg(statistics[index]->GetMax(), 0, 'f', 10) - .arg(statistics[index]->GetMin(), 0, 'f', 10) - .arg(statistics[index]->GetN()); - } - - QApplication::clipboard()->setText( - clipboard, QClipboard::Clipboard); - - QLocale::setDefault(tempLocal); + this->m_Controls.widget_statistics->SetImageNodes({}); + this->m_Controls.widget_statistics->SetMaskNodes({}); } void QmitkCESTStatisticsView::OnSliceChanged() { mitk::Point3D currentSelectedPosition = this->GetRenderWindowPart()->GetSelectedPosition(nullptr); - unsigned int currentSelectedTimeStep = this->GetRenderWindowPart()->GetTimeNavigationController()->GetTime()->GetPos(); + unsigned int currentSelectedTimeStep = + this->GetRenderWindowPart()->GetTimeNavigationController()->GetTime()->GetPos(); - if (m_currentSelectedPosition != currentSelectedPosition - || m_currentSelectedTimeStep != currentSelectedTimeStep) - //|| m_selectedNodeTime > m_currentPositionTime) + if (m_currentSelectedPosition != currentSelectedPosition || m_currentSelectedTimeStep != currentSelectedTimeStep) + //|| m_selectedNodeTime > m_currentPositionTime) { - //the current position has been changed or the selected node has been changed since the last position validation -> check position + // the current position has been changed or the selected node has been changed since the last position validation -> + // check position m_currentSelectedPosition = currentSelectedPosition; m_currentSelectedTimeStep = currentSelectedTimeStep; m_currentPositionTime.Modified(); m_CrosshairPointSet->Clear(); m_CrosshairPointSet->SetPoint(0, m_currentSelectedPosition); QList nodes = this->GetDataManagerSelection(); - if (nodes.empty() || nodes.size() > 1) return; + if (nodes.empty() || nodes.size() > 1) + return; - mitk::DataNode* node = nodes.front(); + mitk::DataNode *node = nodes.front(); if (!node) { return; } if (dynamic_cast(node->GetData()) != nullptr) { m_Controls.labelWarning->setVisible(false); bool zSpectrumSet = SetZSpectrum(dynamic_cast( node->GetData()->GetProperty(mitk::CustomTagParser::m_OffsetsPropertyName.c_str()).GetPointer())); if (zSpectrumSet) { m_ZImage = dynamic_cast(node->GetData()); } else { return; } } else { return; } this->m_Controls.m_DataViewWidget->Clear(); AccessFixedDimensionByItk(m_ZImage, PlotPointSet, 4); - } } diff --git a/Plugins/org.mitk.gui.qt.cest/src/internal/QmitkCESTStatisticsView.h b/Plugins/org.mitk.gui.qt.cest/src/internal/QmitkCESTStatisticsView.h index eeff6e0780..e9c29ccd3e 100644 --- a/Plugins/org.mitk.gui.qt.cest/src/internal/QmitkCESTStatisticsView.h +++ b/Plugins/org.mitk.gui.qt.cest/src/internal/QmitkCESTStatisticsView.h @@ -1,150 +1,139 @@ /*=================================================================== 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 QmitkCESTStatisticsView_h #define QmitkCESTStatisticsView_h #include #include #include #include "ui_QmitkCESTStatisticsViewControls.h" -#include +#include #include #include /** \brief QmitkCESTStatisticsView \warning Basic statistics view for CEST data. \sa QmitkAbstractView \ingroup ${plugin_target}_internal */ class QmitkCESTStatisticsView : public QmitkAbstractView, public mitk::IRenderWindowPartListener { // this is needed for all Qt objects that should have a Qt meta-object // (everything that derives from QObject and wants to have signal/slots) Q_OBJECT public: static const std::string VIEW_ID; /*! \brief default constructor */ QmitkCESTStatisticsView(QObject *parent = nullptr, const char *name = nullptr); /*! \brief default destructor */ virtual ~QmitkCESTStatisticsView(); protected slots: /// \brief Called when the user clicks the GUI button void OnThreeDimToFourDimPushButtonClicked(); /// \brief takes care of processing the computed data void OnThreadedStatisticsCalculationEnds(); - /// \brief copy statistics to clipboard - void OnCopyStatisticsToClipboardPushButtonClicked(); - /// \brief Toggle whether or not the plot uses a fixed x range void OnFixedRangeCheckBoxToggled(bool state); /// \brief Adapt axis scale when manual ranges are set void OnFixedRangeDoubleSpinBoxChanged(); /// \brief What to do if the crosshair moves void OnSliceChanged(); protected: virtual void CreateQtPartControl(QWidget *parent) override; virtual void SetFocus() override; virtual void RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart); virtual void RenderWindowPartDeactivated(mitk::IRenderWindowPart* renderWindowPart); /// \brief called by QmitkFunctionality when DataManager's selection has changed virtual void OnSelectionChanged( berry::IWorkbenchPart::Pointer source, const QList& nodes ) override; - /** \brief Writes the calculated statistics to the GUI */ - void FillStatisticsTableView(const std::vector &s, - const mitk::Image *image); - - - /** \brief Removes statistics from the GUI */ - void InvalidateStatisticsTableView(); - /// parse string and set data vector returns true if succesfull bool SetZSpectrum(mitk::StringProperty* zSpectrumProperty); /** Checks whether the currently set data appears reasonable */ bool DataSanityCheck(); /** Fills the plot based on a point set * * This will only use the first timestep */ template void PlotPointSet(itk::Image* image); /** Deletes all data */ void Clear(); /** Remove MZeros * * Will remove the data for the M0 images from the given input */ void RemoveMZeros(QmitkPlotWidget::DataVector& xValues, QmitkPlotWidget::DataVector& yValues); void RemoveMZeros(QmitkPlotWidget::DataVector& xValues, QmitkPlotWidget::DataVector& yValues, QmitkPlotWidget::DataVector& stdDevs); /** Copies the first timestep of a segmentation to all others */ template void CopyTimesteps(itk::Image* image); Ui::QmitkCESTStatisticsViewControls m_Controls; - QmitkImageStatisticsCalculationThread* m_CalculatorThread; + QmitkImageStatisticsCalculationJob* m_CalculatorJob; QmitkPlotWidget::DataVector m_zSpectrum; mitk::Image::Pointer m_ZImage; mitk::Image::Pointer m_MaskImage; mitk::PlanarFigure::Pointer m_MaskPlanarFigure; mitk::PointSet::Pointer m_PointSet; mitk::PointSet::Pointer m_CrosshairPointSet; QmitkSliceNavigationListener m_SliceChangeListener; itk::TimeStamp m_selectedNodeTime; itk::TimeStamp m_currentPositionTime; /** @brief currently valid selected position in the inspector*/ mitk::Point3D m_currentSelectedPosition; /** @brief indicates if the currently selected position is valid for the currently selected fit. * This it is within the input image */ unsigned int m_currentSelectedTimeStep; }; #endif // QmitkCESTStatisticsView_h diff --git a/Plugins/org.mitk.gui.qt.cest/src/internal/QmitkCESTStatisticsViewControls.ui b/Plugins/org.mitk.gui.qt.cest/src/internal/QmitkCESTStatisticsViewControls.ui index 6ecd840443..dc3bc4b724 100644 --- a/Plugins/org.mitk.gui.qt.cest/src/internal/QmitkCESTStatisticsViewControls.ui +++ b/Plugins/org.mitk.gui.qt.cest/src/internal/QmitkCESTStatisticsViewControls.ui @@ -1,373 +1,314 @@ QmitkCESTStatisticsViewControls 0 0 696 963 0 0 QmitkTemplate QLabel { color: rgb(255, 0, 0) } Please select an image! Do image processing Copy first time step to rest false + + + 0 + 200 + + Statistics 9 9 9 - - - false - - - - 100 - 180 - - - - - 16777215 - 16777215 - - - - Qt::ScrollBarAsNeeded - - - Qt::ScrollBarAsNeeded - - - true + + + + + + + + 255 + 0 + 0 + + + + + + + 255 + 0 + 0 + + + + + + + 255 + 0 + 0 + + + + + + + + + 255 + 0 + 0 + + + + + + + 255 + 0 + 0 + + + + + + + 255 + 0 + 0 + + + + + + + + + 120 + 120 + 120 + + + + + + + 120 + 120 + 120 + + + + + + + 120 + 120 + 120 + + + + + - - QAbstractItemView::NoEditTriggers - - - 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³) - - - - - 0 - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Copy to Clipboard - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - QLayout::SetDefaultConstraint 0 0 Define manual range Qt::Horizontal 40 20 Lower limit false -299.899999999999977 299.990000000000009 Upper limit false 2 -299.899999999999977 299.990000000000009 Qt::Horizontal 40 20 Plot 0 0 0 400 Qt::Vertical QSizePolicy::Expanding 20 220 QmitkPlotWidget QWidget
QmitkPlotWidget.h
1
+ + QmitkImageStatisticsWidget + QWidget +
QmitkImageStatisticsWidget.h
+ 1 +