diff --git a/Modules/ImageStatisticsUI/Qmitk/QmitkImageStatisticsCalculationJob.cpp b/Modules/ImageStatisticsUI/Qmitk/QmitkImageStatisticsCalculationJob.cpp index 4f208c1921..aa3264614c 100644 --- a/Modules/ImageStatisticsUI/Qmitk/QmitkImageStatisticsCalculationJob.cpp +++ b/Modules/ImageStatisticsUI/Qmitk/QmitkImageStatisticsCalculationJob.cpp @@ -1,227 +1,215 @@ /*=================================================================== 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 "QmitkImageStatisticsCalculationJob.h" #include "mitkImageStatisticsCalculator.h" #include #include #include QmitkImageStatisticsCalculationJob::QmitkImageStatisticsCalculationJob() : QThread() , m_StatisticsImage(nullptr) , m_BinaryMask(nullptr) , m_PlanarFigureMask(nullptr) , m_IgnoreZeros(false) , m_HistogramNBins(100) , m_CalculationSuccessful(false) { } QmitkImageStatisticsCalculationJob::~QmitkImageStatisticsCalculationJob() { } -void QmitkImageStatisticsCalculationJob::Initialize( mitk::Image::ConstPointer image, mitk::Image::ConstPointer binaryImage, mitk::PlanarFigure::ConstPointer planarFig ) +void QmitkImageStatisticsCalculationJob::Initialize(const mitk::Image *image, + const mitk::Image *binaryImage, + const mitk::PlanarFigure *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; - if(binaryImage.IsNotNull()) - this->m_BinaryMask = binaryImage; - if(planarFig.IsNotNull()) - this->m_PlanarFigureMask = planarFig; + this->m_StatisticsImage = image; + this->m_BinaryMask = binaryImage; + this->m_PlanarFigureMask = planarFig; } -mitk::ImageStatisticsContainer::ConstPointer QmitkImageStatisticsCalculationJob::GetStatisticsData() const +mitk::ImageStatisticsContainer* QmitkImageStatisticsCalculationJob::GetStatisticsData() const { - mitk::ImageStatisticsContainer::ConstPointer constContainer = this->m_StatisticsContainer.GetPointer(); - return constContainer; + return this->m_StatisticsContainer.GetPointer(); } -mitk::Image::ConstPointer QmitkImageStatisticsCalculationJob::GetStatisticsImage() const +const mitk::Image* QmitkImageStatisticsCalculationJob::GetStatisticsImage() const { - return this->m_StatisticsImage; + return this->m_StatisticsImage.GetPointer(); } -mitk::Image::ConstPointer QmitkImageStatisticsCalculationJob::GetMaskImage() const +const mitk::Image* QmitkImageStatisticsCalculationJob::GetMaskImage() const { - return this->m_BinaryMask; + return this->m_BinaryMask.GetPointer(); } -mitk::PlanarFigure::ConstPointer QmitkImageStatisticsCalculationJob::GetPlanarFigure() const +const mitk::PlanarFigure* QmitkImageStatisticsCalculationJob::GetPlanarFigure() const { - return this->m_PlanarFigureMask; + return this->m_PlanarFigureMask.GetPointer(); } void QmitkImageStatisticsCalculationJob::SetIgnoreZeroValueVoxel(bool _arg) { this->m_IgnoreZeros = _arg; } bool QmitkImageStatisticsCalculationJob::GetIgnoreZeroValueVoxel() const { return this->m_IgnoreZeros; } void QmitkImageStatisticsCalculationJob::SetHistogramNBins(unsigned int nbins) { this->m_HistogramNBins = nbins; } unsigned int QmitkImageStatisticsCalculationJob::GetHistogramNBins() const { return this->m_HistogramNBins; } std::string QmitkImageStatisticsCalculationJob::GetLastErrorMessage() const { return m_message; } -QmitkImageStatisticsCalculationJob::HistogramType::ConstPointer +const QmitkImageStatisticsCalculationJob::HistogramType* QmitkImageStatisticsCalculationJob::GetTimeStepHistogram(unsigned int t) const { if (t >= this->m_HistogramVector.size()) return nullptr; - return this->m_HistogramVector[t]; -} + return this->m_HistogramVector.at(t).GetPointer(); } bool QmitkImageStatisticsCalculationJob::GetStatisticsUpdateSuccessFlag() const { return m_CalculationSuccessful; } void QmitkImageStatisticsCalculationJob::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->Clone()); calculator->SetMask(imgMask.GetPointer()); } if(this->m_PlanarFigureMask.IsNotNull()) { mitk::PlanarFigureMaskGenerator::Pointer pfMaskGen = mitk::PlanarFigureMaskGenerator::New(); pfMaskGen->SetInputImage(m_StatisticsImage); pfMaskGen->SetPlanarFigure(m_PlanarFigureMask->Clone()); calculator->SetMask(pfMaskGen.GetPointer()); } } catch (const mitk::Exception& e) { MITK_ERROR << "MITK Exception: " << e.what(); m_message = e.what(); statisticCalculationSuccessful = false; } catch( const itk::ExceptionObject& e) { MITK_ERROR << "ITK Exception:" << e.what(); m_message = e.what(); statisticCalculationSuccessful = false; } catch ( const std::runtime_error &e ) { MITK_ERROR<< "Runtime Exception: " << e.what(); m_message = e.what(); statisticCalculationSuccessful = false; } catch ( const std::exception &e ) { MITK_ERROR<< "Standard Exception: " << e.what(); m_message = e.what(); statisticCalculationSuccessful = 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); } calculator->SetNBinsForHistogramStatistics(m_HistogramNBins); try { calculator->GetStatistics(); } 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_CalculationSuccessful = statisticCalculationSuccessful; if(statisticCalculationSuccessful) { m_StatisticsContainer = calculator->GetStatistics(); this->m_HistogramVector.clear(); for (unsigned int i = 0; i < m_StatisticsImage->GetTimeSteps(); i++) { this->m_HistogramVector.push_back(calculator->GetStatistics()->GetStatisticsForTimeStep(i).m_Histogram); } } } diff --git a/Modules/ImageStatisticsUI/Qmitk/QmitkImageStatisticsCalculationJob.h b/Modules/ImageStatisticsUI/Qmitk/QmitkImageStatisticsCalculationJob.h index f1ae06becf..15e21c1a65 100644 --- a/Modules/ImageStatisticsUI/Qmitk/QmitkImageStatisticsCalculationJob.h +++ b/Modules/ImageStatisticsUI/Qmitk/QmitkImageStatisticsCalculationJob.h @@ -1,100 +1,102 @@ /*=================================================================== 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 //mitk headers #include "mitkImage.h" #include "mitkPlanarFigure.h" #include "mitkImageStatisticsContainer.h" #include // 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. + to run the image statistics calculation in a background thread keeping the gui usable. */ class MITKIMAGESTATISTICSUI_EXPORT QmitkImageStatisticsCalculationJob : public QThread { Q_OBJECT public: typedef itk::Statistics::Histogram HistogramType; /*! /brief standard constructor. */ QmitkImageStatisticsCalculationJob(); /*! /brief standard destructor. */ ~QmitkImageStatisticsCalculationJob(); /*! /brief Initializes the object with necessary data. */ - void Initialize( mitk::Image::ConstPointer image, mitk::Image::ConstPointer binaryImage, mitk::PlanarFigure::ConstPointer planarFig ); + void Initialize(const mitk::Image* image, const mitk::Image* binaryImage, const mitk::PlanarFigure* planarFig ); /*! /brief returns the calculated image statistics. */ - mitk::ImageStatisticsContainer::ConstPointer GetStatisticsData() const; + mitk::ImageStatisticsContainer* GetStatisticsData() const; - mitk::Image::ConstPointer GetStatisticsImage() const; - mitk::Image::ConstPointer GetMaskImage() const; - mitk::PlanarFigure::ConstPointer GetPlanarFigure() const; + const mitk::Image* GetStatisticsImage() const; + const mitk::Image* GetMaskImage() const; + const mitk::PlanarFigure* GetPlanarFigure() const; /*! /brief Set flag to ignore zero valued voxels */ void SetIgnoreZeroValueVoxel( bool _arg ); /*! /brief Get status of zero value voxel ignoring. */ bool GetIgnoreZeroValueVoxel() const; /*! /brief Set bin size for histogram resolution.*/ void SetHistogramNBins( unsigned int nbins); /*! /brief Get bin size for histogram resolution.*/ unsigned int GetHistogramNBins() const; /*! /brief Returns the histogram of the currently selected time step. */ + const HistogramType* GetTimeStepHistogram(unsigned int t = 0) const; + /*! /brief Returns a flag the indicates if the statistics are updated successfully */ bool GetStatisticsUpdateSuccessFlag() const; /*! /brief Method called once the thread is executed. */ void run() override; std::string GetLastErrorMessage() const; private: mitk::Image::ConstPointer m_StatisticsImage; ///< member variable holds the input image for which the statistics need to be calculated. mitk::Image::ConstPointer m_BinaryMask; ///< member variable holds the binary mask image for segmentation image statistics calculation. mitk::PlanarFigure::ConstPointer m_PlanarFigureMask; ///< member variable holds the planar figure for segmentation image statistics calculation. mitk::ImageStatisticsContainer::Pointer m_StatisticsContainer; bool m_IgnoreZeros; ///< member variable holds flag to indicate if zero valued voxel should be suppressed unsigned int m_HistogramNBins; ///< member variable holds the bin size for histogram resolution. bool m_CalculationSuccessful; ///< flag set if statistics calculation was successful 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 cfd3758121..f16a8299ee 100644 --- a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsView.cpp +++ b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsView.cpp @@ -1,544 +1,543 @@ /*=================================================================== 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" #include // berry includes #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mitkImageStatisticsContainerManager.h" #include const std::string QmitkImageStatisticsView::VIEW_ID = "org.mitk.views.imagestatistics"; QmitkImageStatisticsView::QmitkImageStatisticsView(QObject * /*parent*/, const char * /*name*/) { this->m_CalculationJob = new QmitkImageStatisticsCalculationJob(); } QmitkImageStatisticsView::~QmitkImageStatisticsView() { if (m_selectedPlanarFigure) m_selectedPlanarFigure->RemoveObserver(m_PlanarFigureObserverTag); } void QmitkImageStatisticsView::CreateQtPartControl(QWidget *parent) { m_Controls.setupUi(parent); m_Controls.widget_histogram->SetTheme(this->GetColorTheme()); m_Controls.widget_intensityProfile->SetTheme(this->GetColorTheme()); m_Controls.groupBox_histogram->setVisible(true); m_Controls.groupBox_intensityProfile->setVisible(false); m_Controls.label_currentlyComputingStatistics->setVisible(false); m_Controls.sliderWidget_histogram->setPrefix("Time: "); m_Controls.sliderWidget_histogram->setDecimals(0); m_Controls.sliderWidget_histogram->setVisible(false); m_Controls.sliderWidget_intensityProfile->setPrefix("Time: "); m_Controls.sliderWidget_intensityProfile->setDecimals(0); m_Controls.sliderWidget_intensityProfile->setVisible(false); ResetGUI(); PrepareDataStorageComboBoxes(); m_Controls.widget_statistics->SetDataStorage(this->GetDataStorage()); CreateConnections(); } void QmitkImageStatisticsView::CreateConnections() { connect(this->m_CalculationJob, &QmitkImageStatisticsCalculationJob::finished, this, &QmitkImageStatisticsView::OnStatisticsCalculationEnds, Qt::QueuedConnection); connect(this->m_Controls.checkBox_ignoreZero, &QCheckBox::stateChanged, this, &QmitkImageStatisticsView::OnCheckBoxIgnoreZeroStateChanged); connect(this->m_Controls.sliderWidget_histogram, &ctkSliderWidget::valueChanged, this, &QmitkImageStatisticsView::OnSliderWidgetHistogramChanged); connect(this->m_Controls.sliderWidget_intensityProfile, &ctkSliderWidget::valueChanged, this, &QmitkImageStatisticsView::OnSliderWidgetIntensityProfileChanged); connect(this->m_Controls.imageSelector, static_cast(&QComboBox::currentIndexChanged), this, &QmitkImageStatisticsView::OnImageSelectorChanged); connect(this->m_Controls.maskImageSelector, static_cast(&QComboBox::currentIndexChanged), this, &QmitkImageStatisticsView::OnMaskSelectorChanged); } void QmitkImageStatisticsView::OnCheckBoxIgnoreZeroStateChanged(int state) { m_ForceRecompute = true; if (state != Qt::Unchecked) { this->m_CalculationJob->SetIgnoreZeroValueVoxel(true); } else { this->m_CalculationJob->SetIgnoreZeroValueVoxel(false); } CalculateOrGetStatistics(); } void QmitkImageStatisticsView::OnSliderWidgetHistogramChanged(double value) { unsigned int timeStep = static_cast(value); auto mask = m_selectedMaskNode ? m_selectedMaskNode->GetData() : nullptr; auto imageStatistics = mitk::ImageStatisticsContainerManager::GetImageStatistics( this->GetDataStorage(), m_selectedImageNode->GetData(), mask); HistogramType::ConstPointer histogram = imageStatistics->GetStatisticsForTimeStep(timeStep).m_Histogram; if (histogram.IsNotNull() && this->m_CalculationJob->GetStatisticsUpdateSuccessFlag()) { this->FillHistogramWidget({histogram}, {m_selectedImageNode->GetName()}); } } void QmitkImageStatisticsView::OnSliderWidgetIntensityProfileChanged() { //intensity profile is always computed on request, not stored as node in DataStorage auto image = dynamic_cast(m_selectedImageNode->GetData()); auto planarFigure = dynamic_cast(m_selectedMaskNode->GetData()); if (image && planarFigure && this->m_CalculationJob->GetStatisticsUpdateSuccessFlag()) { this->ComputeAndDisplayIntensityProfile(image, planarFigure); } } void QmitkImageStatisticsView::PartClosed(const berry::IWorkbenchPartReference::Pointer &) {} void QmitkImageStatisticsView::FillHistogramWidget(const std::vector &histogram, const std::vector &dataLabels) { m_Controls.groupBox_histogram->setVisible(true); m_Controls.widget_histogram->SetTheme(this->GetColorTheme()); m_Controls.widget_histogram->Reset(); m_Controls.widget_histogram->SetHistogram(histogram.front(), dataLabels.front()); connect(m_Controls.widget_histogram, &QmitkHistogramVisualizationWidget::RequestHistogramUpdate, this, &QmitkImageStatisticsView::OnRequestHistogramUpdate); } QmitkChartWidget::ColorTheme QmitkImageStatisticsView::GetColorTheme() const { ctkPluginContext *context = berry::WorkbenchPlugin::GetDefault()->GetPluginContext(); ctkServiceReference styleManagerRef = context->getServiceReference(); if (styleManagerRef) { auto styleManager = context->getService(styleManagerRef); if (styleManager->GetStyle().name == "Dark") { return QmitkChartWidget::ColorTheme::darkstyle; } else { return QmitkChartWidget::ColorTheme::lightstyle; } } return QmitkChartWidget::ColorTheme::darkstyle; } void QmitkImageStatisticsView::OnImageSelectorChanged() { auto selectedImageNode = m_Controls.imageSelector->GetSelectedNode(); if (selectedImageNode != m_selectedImageNode) { m_selectedImageNode = selectedImageNode; if (m_selectedImageNode.IsNotNull()) { ResetGUIDefault(); auto isPlanarFigurePredicate = mitk::GetImageStatisticsPlanarFigurePredicate(); auto isMaskPredicate = mitk::GetImageStatisticsMaskPredicate(); auto hasSameGeometry = mitk::NodePredicateGeometry::New(m_selectedImageNode->GetData()->GetGeometry()); hasSameGeometry->SetCheckPrecision(1e-10); auto isMaskWithGeometryPredicate = mitk::NodePredicateAnd::New(isMaskPredicate, hasSameGeometry); auto isMaskOrPlanarFigureWithGeometryPredicate = mitk::NodePredicateOr::New(isPlanarFigurePredicate, isMaskWithGeometryPredicate); // prevent triggering of computation as the predicate triggers a signalChanged event m_Controls.maskImageSelector->disconnect(); m_Controls.maskImageSelector->SetPredicate(isMaskOrPlanarFigureWithGeometryPredicate); // reset mask to m_Controls.maskImageSelector->SetZeroEntryText(""); m_Controls.checkBox_ignoreZero->setEnabled(true); m_selectedMaskNode = nullptr; m_Controls.widget_statistics->SetMaskNodes({}); CalculateOrGetStatistics(); m_Controls.widget_statistics->SetImageNodes({m_selectedImageNode.GetPointer()}); connect(this->m_Controls.maskImageSelector, static_cast(&QComboBox::currentIndexChanged), this, &QmitkImageStatisticsView::OnMaskSelectorChanged); } else { m_Controls.widget_statistics->SetImageNodes({}); m_Controls.widget_statistics->SetMaskNodes({}); m_Controls.widget_statistics->Reset(); m_Controls.widget_histogram->Reset(); ResetGUI(); } } } void QmitkImageStatisticsView::OnMaskSelectorChanged() { auto selectedMaskNode = m_Controls.maskImageSelector->GetSelectedNode(); if (selectedMaskNode != m_selectedMaskNode) { m_selectedMaskNode = selectedMaskNode; if (m_selectedMaskNode.IsNotNull()) { m_Controls.widget_statistics->SetMaskNodes({m_selectedMaskNode.GetPointer()}); } else { m_Controls.widget_statistics->SetMaskNodes({}); } CalculateOrGetStatistics(); } } void QmitkImageStatisticsView::CalculateOrGetStatistics() { if (this->m_selectedPlanarFigure) { this->m_selectedPlanarFigure->RemoveObserver(this->m_PlanarFigureObserverTag); this->m_selectedPlanarFigure = nullptr; } m_Controls.groupBox_intensityProfile->setVisible(false); m_Controls.widget_statistics->setEnabled(m_selectedImageNode.IsNotNull()); if (m_selectedImageNode != nullptr) { auto image = dynamic_cast(m_selectedImageNode->GetData()); mitk::Image::Pointer mask = nullptr; mitk::PlanarFigure::Pointer maskPlanarFigure = nullptr; if (image->GetDimension() == 4) { m_Controls.sliderWidget_histogram->setVisible(true); unsigned int maxTimestep = image->GetTimeSteps(); m_Controls.sliderWidget_histogram->setMaximum(maxTimestep - 1); } else { m_Controls.sliderWidget_histogram->setVisible(false); } if (m_selectedMaskNode != nullptr) { mask = dynamic_cast(m_selectedMaskNode->GetData()); if (mask == nullptr) { maskPlanarFigure = dynamic_cast(m_selectedMaskNode->GetData()); } } mitk::ImageStatisticsContainer::ConstPointer imageStatistics; if (mask) { imageStatistics = mitk::ImageStatisticsContainerManager::GetImageStatistics(this->GetDataStorage(), image, mask.GetPointer()); } else if (maskPlanarFigure) { m_selectedPlanarFigure = maskPlanarFigure; ITKCommandType::Pointer changeListener = ITKCommandType::New(); changeListener->SetCallbackFunction(this, &QmitkImageStatisticsView::CalculateOrGetStatistics); this->m_PlanarFigureObserverTag = m_selectedPlanarFigure->AddObserver(mitk::EndInteractionPlanarFigureEvent(), changeListener); if (!maskPlanarFigure->IsClosed()) { ComputeAndDisplayIntensityProfile(image, maskPlanarFigure); } imageStatistics = mitk::ImageStatisticsContainerManager::GetImageStatistics( this->GetDataStorage(), image, maskPlanarFigure.GetPointer()); } else { imageStatistics = mitk::ImageStatisticsContainerManager::GetImageStatistics(this->GetDataStorage(), image); } bool imageStatisticsOlderThanInputs = false; if (imageStatistics && (imageStatistics->GetMTime() < image->GetMTime() || (mask && imageStatistics->GetMTime() < mask->GetMTime()) || (maskPlanarFigure && imageStatistics->GetMTime() < maskPlanarFigure->GetMTime()))) { imageStatisticsOlderThanInputs = true; } if (imageStatistics) { // triggers recomputation when switched between images and the newest one has not 100 bins (default) auto calculatedBins = imageStatistics->GetStatisticsForTimeStep(0).m_Histogram.GetPointer()->Size(); if (calculatedBins != 100) { OnRequestHistogramUpdate(m_Controls.widget_histogram->GetBins()); } } // statistics need to be computed if (!imageStatistics || imageStatisticsOlderThanInputs || m_ForceRecompute) { CalculateStatistics(image, mask.GetPointer(), maskPlanarFigure.GetPointer()); } // statistics already computed else { // Not an open planar figure: show histogram (intensity profile already shown) if (!(maskPlanarFigure && !maskPlanarFigure->IsClosed())) { if (imageStatistics->TimeStepExists(0)) { auto histogram = imageStatistics->GetStatisticsForTimeStep(0).m_Histogram.GetPointer(); std::string imageNodeName = m_selectedImageNode->GetName(); this->FillHistogramWidget({histogram}, {imageNodeName}); } } } } else { ResetGUI(); } m_ForceRecompute = false; } void QmitkImageStatisticsView::ComputeAndDisplayIntensityProfile(mitk::Image *image, mitk::PlanarFigure::Pointer maskPlanarFigure) { mitk::Image::Pointer inputImage; if (image->GetDimension() == 4) { m_Controls.sliderWidget_intensityProfile->setVisible(true); unsigned int maxTimestep = image->GetTimeSteps(); m_Controls.sliderWidget_intensityProfile->setMaximum(maxTimestep - 1); //Intensity profile can only be calculated on 3D, so extract if 4D mitk::ImageTimeSelector::Pointer timeSelector = mitk::ImageTimeSelector::New(); int currentTimestep = static_cast(m_Controls.sliderWidget_intensityProfile->value()); timeSelector->SetInput(image); timeSelector->SetTimeNr(currentTimestep); timeSelector->Update(); inputImage = timeSelector->GetOutput(); } else { m_Controls.sliderWidget_intensityProfile->setVisible(false); inputImage = image; } auto intensityProfile = mitk::ComputeIntensityProfile(inputImage, maskPlanarFigure); // Don't show histogram for intensity profiles m_Controls.groupBox_histogram->setVisible(false); m_Controls.groupBox_intensityProfile->setVisible(true); m_Controls.widget_intensityProfile->Reset(); m_Controls.widget_intensityProfile->SetIntensityProfile(intensityProfile.GetPointer(), "Intensity Profile of " + m_selectedImageNode->GetName()); } void QmitkImageStatisticsView::ResetGUI() { m_Controls.widget_statistics->Reset(); m_Controls.widget_statistics->setEnabled(false); m_Controls.widget_histogram->Reset(); m_Controls.widget_histogram->setEnabled(false); m_Controls.checkBox_ignoreZero->setEnabled(false); } void QmitkImageStatisticsView::ResetGUIDefault() { - MITK_INFO << "reset GUI"; m_Controls.widget_histogram->ResetDefault(); m_Controls.checkBox_ignoreZero->setChecked(false); } void QmitkImageStatisticsView::OnStatisticsCalculationEnds() { mitk::StatusBar::GetInstance()->Clear(); if (this->m_CalculationJob->GetStatisticsUpdateSuccessFlag()) { auto statistic = m_CalculationJob->GetStatisticsData(); auto image = m_CalculationJob->GetStatisticsImage(); mitk::BaseData::ConstPointer mask = nullptr; auto imageRule = mitk::StatisticsToImageRelationRule::New(); imageRule->Connect(statistic, image); if (m_CalculationJob->GetMaskImage()) { auto maskRule = mitk::StatisticsToMaskRelationRule::New(); mask = m_CalculationJob->GetMaskImage(); maskRule->Connect(statistic, mask); } else if (m_CalculationJob->GetPlanarFigure()) { auto planarFigureRule = mitk::StatisticsToMaskRelationRule::New(); mask = m_CalculationJob->GetPlanarFigure(); planarFigureRule->Connect(statistic, mask); } auto imageStatistics = mitk::ImageStatisticsContainerManager::GetImageStatistics(this->GetDataStorage(), image, mask); // if statistics base data already exist: add to existing node if (imageStatistics) { auto allDataNodes = this->GetDataStorage()->GetAll()->CastToSTLConstContainer(); for (auto node : allDataNodes) { auto nodeData = node->GetData(); if (nodeData && nodeData->GetUID() == imageStatistics->GetUID()) { node->SetData(statistic); } } } // statistics base data does not exist: add new node else { auto statisticsNodeName = m_selectedImageNode->GetName(); if (m_selectedMaskNode) { statisticsNodeName += "_" + m_selectedMaskNode->GetName(); } statisticsNodeName += "_statistics"; auto statisticsNode = mitk::CreateImageStatisticsNode(statistic, statisticsNodeName); this->GetDataStorage()->Add(statisticsNode); } if (!m_selectedPlanarFigure || m_selectedPlanarFigure->IsClosed()) { this->FillHistogramWidget({m_CalculationJob->GetTimeStepHistogram()}, {m_selectedImageNode->GetName()}); } } else { mitk::StatusBar::GetInstance()->DisplayErrorText(m_CalculationJob->GetLastErrorMessage().c_str()); m_Controls.widget_histogram->setEnabled(false); } m_Controls.label_currentlyComputingStatistics->setVisible(false); } void QmitkImageStatisticsView::OnRequestHistogramUpdate(unsigned int nBins) { m_CalculationJob->SetHistogramNBins(nBins); m_CalculationJob->start(); } void QmitkImageStatisticsView::CalculateStatistics(mitk::Image::ConstPointer image, mitk::Image::ConstPointer mask, mitk::PlanarFigure::ConstPointer maskPlanarFigure) { this->m_CalculationJob->Initialize(image, mask, maskPlanarFigure); try { // Compute statistics this->m_CalculationJob->start(); m_Controls.label_currentlyComputingStatistics->setVisible(true); } catch (const mitk::Exception &e) { mitk::StatusBar::GetInstance()->DisplayErrorText(e.GetDescription()); m_Controls.label_currentlyComputingStatistics->setVisible(false); } catch (const std::runtime_error &e) { mitk::StatusBar::GetInstance()->DisplayErrorText(e.what()); m_Controls.label_currentlyComputingStatistics->setVisible(false); } catch (const std::exception &e) { mitk::StatusBar::GetInstance()->DisplayErrorText(e.what()); m_Controls.label_currentlyComputingStatistics->setVisible(false); } } void QmitkImageStatisticsView::OnSelectionChanged(berry::IWorkbenchPart::Pointer part, const QList &nodes) { Q_UNUSED(part); Q_UNUSED(nodes); } void QmitkImageStatisticsView::PrepareDataStorageComboBoxes() { auto isPlanarFigurePredicate = mitk::GetImageStatisticsPlanarFigurePredicate(); auto isMaskPredicate = mitk::GetImageStatisticsMaskPredicate(); auto isImagePredicate = mitk::GetImageStatisticsImagePredicate(); auto isMaskOrPlanarFigurePredicate = mitk::NodePredicateOr::New(isPlanarFigurePredicate, isMaskPredicate); m_Controls.imageSelector->SetDataStorage(GetDataStorage()); m_Controls.imageSelector->SetPredicate(isImagePredicate); m_Controls.maskImageSelector->SetDataStorage(GetDataStorage()); m_Controls.maskImageSelector->SetPredicate(isMaskOrPlanarFigurePredicate); m_Controls.maskImageSelector->SetZeroEntryText(""); } void QmitkImageStatisticsView::Activated() {} void QmitkImageStatisticsView::Deactivated() {} void QmitkImageStatisticsView::Visible() { connect(this->m_Controls.imageSelector, static_cast(&QComboBox::currentIndexChanged), this, &QmitkImageStatisticsView::OnImageSelectorChanged); connect(this->m_Controls.maskImageSelector, static_cast(&QComboBox::currentIndexChanged), this, &QmitkImageStatisticsView::OnMaskSelectorChanged); OnImageSelectorChanged(); OnMaskSelectorChanged(); } void QmitkImageStatisticsView::Hidden() { m_Controls.imageSelector->disconnect(); m_Controls.maskImageSelector->disconnect(); } 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 ce01fe8004..af02048186 100644 --- a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsView.h +++ b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsView.h @@ -1,112 +1,111 @@ /*=================================================================== 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 #include #include #include #include /*! \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 separate thread to keep the gui accessible during calculation. \ingroup Plugins/org.mitk.gui.qt.measurementtoolbox */ class QmitkImageStatisticsView : public QmitkAbstractView, public mitk::ILifecycleAwarePart, public berry::IPartListener { Q_OBJECT public: using HistogramType = mitk::ImageStatisticsContainer::HistogramType; /*! \brief default constructor */ QmitkImageStatisticsView(QObject *parent = nullptr, const char *name = nullptr); /*! \brief default destructor */ virtual ~QmitkImageStatisticsView(); /*! \brief method for creating the widget containing the application controls, like sliders, buttons etc. */ virtual void CreateQtPartControl(QWidget *parent) override; /*! \brief method for creating the connections of main and control widget */ virtual void CreateConnections(); /*! \brief Is called from the selection mechanism once the data manager selection has changed*/ void OnSelectionChanged(berry::IWorkbenchPart::Pointer part, const QList &selectedNodes) override; void PrepareDataStorageComboBoxes(); static const std::string VIEW_ID; void FillHistogramWidget(const std::vector& histogram, const std::vector& dataLabels); QmitkChartWidget::ColorTheme GetColorTheme() const; protected: virtual void Activated() override; virtual void Deactivated() override; virtual void Visible() override; virtual void Hidden() override; - virtual void SetFocus() override; /** \brief Is called right before the view closes (before the destructor) */ virtual void PartClosed(const berry::IWorkbenchPartReference::Pointer&) override; /** \brief Required for berry::IPartListener */ virtual Events::Types GetPartEventTypes() const override { return Events::CLOSED; } void OnImageSelectorChanged(); void OnMaskSelectorChanged(); void CalculateOrGetStatistics(); void ComputeAndDisplayIntensityProfile(mitk::Image * image, mitk::PlanarFigure::Pointer maskPlanarFigure); void ResetGUI(); void ResetGUIDefault(); void OnStatisticsCalculationEnds(); void OnRequestHistogramUpdate(unsigned int nBins); void OnCheckBoxIgnoreZeroStateChanged(int state); void OnSliderWidgetHistogramChanged(double value); void OnSliderWidgetIntensityProfileChanged(); void CalculateStatistics(mitk::Image::ConstPointer image, mitk::Image::ConstPointer mask=nullptr, mitk::PlanarFigure::ConstPointer maskPlanarFigure = nullptr); // member variables Ui::QmitkImageStatisticsViewControls m_Controls; private: typedef itk::SimpleMemberCommand< QmitkImageStatisticsView > ITKCommandType; QmitkImageStatisticsCalculationJob * m_CalculationJob = nullptr; mitk::DataNode::ConstPointer m_selectedImageNode = nullptr, m_selectedMaskNode = nullptr; mitk::PlanarFigure::Pointer m_selectedPlanarFigure=nullptr; long m_PlanarFigureObserverTag; bool m_ForceRecompute = false; }; #endif // QmitkImageStatisticsView_H__INCLUDED