diff --git a/Modules/ImageStatistics/CMakeLists.txt b/Modules/ImageStatistics/CMakeLists.txt index 850733b3bd..73a49bc11d 100644 --- a/Modules/ImageStatistics/CMakeLists.txt +++ b/Modules/ImageStatistics/CMakeLists.txt @@ -1,12 +1,10 @@ MITK_CREATE_MODULE( DEPENDS MitkImageExtraction MitkPlanarFigure MitkMultilabel PACKAGE_DEPENDS PUBLIC ITK|ITKIOXML PRIVATE ITK|ITKVTK+ITKConvolution ) if(BUILD_TESTING) - add_subdirectory(Testing) - -endif(BUILD_TESTING) +endif() diff --git a/Modules/ImageStatisticsUI/CMakeLists.txt b/Modules/ImageStatisticsUI/CMakeLists.txt index 25f8997e0c..9aefacf838 100644 --- a/Modules/ImageStatisticsUI/CMakeLists.txt +++ b/Modules/ImageStatisticsUI/CMakeLists.txt @@ -1,10 +1,8 @@ MITK_CREATE_MODULE( INCLUDE_DIRS Qmitk DEPENDS MitkCore MitkChart MitkImageStatistics MitkQtWidgets ) if(BUILD_TESTING) - add_subdirectory(test) - -endif(BUILD_TESTING) +endif() diff --git a/Modules/ImageStatisticsUI/Qmitk/QmitkDataGenerationJobBase.cpp b/Modules/ImageStatisticsUI/Qmitk/QmitkDataGenerationJobBase.cpp index c132a2bfc9..8bc428671a 100644 --- a/Modules/ImageStatisticsUI/Qmitk/QmitkDataGenerationJobBase.cpp +++ b/Modules/ImageStatisticsUI/Qmitk/QmitkDataGenerationJobBase.cpp @@ -1,51 +1,51 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "QmitkDataGenerationJobBase.h" std::string QmitkDataGenerationJobBase::GetLastErrorMessage() const { return m_LastErrorMessage; } bool QmitkDataGenerationJobBase::GetComputationSuccessFlag() const { return m_ComputationSuccessful; } void QmitkDataGenerationJobBase::run() { try { m_ComputationSuccessful = this->RunComputation(); if (m_ComputationSuccessful) { emit ResultsAvailable(this->GetResults(), this); } else { - emit Error(QString("Error while running computation. Error description: ") + QString::fromStdString(m_LastErrorMessage), this); + emit Error(QStringLiteral("Error while running computation. Error description: ") + QString::fromStdString(m_LastErrorMessage), this); } } - catch (std::exception& e) + catch (const std::exception& e) { m_LastErrorMessage = e.what(); - emit Error(QString("Error while running computation. Error description: ") + QString::fromStdString(m_LastErrorMessage), this); + emit Error(QStringLiteral("Error while running computation. Error description: ") + QString::fromStdString(m_LastErrorMessage), this); } catch (...) { m_LastErrorMessage = "Unknown exception"; - emit Error(QString("Error while running computation. Error description: ") + QString::fromStdString(m_LastErrorMessage), this); + emit Error(QStringLiteral("Error while running computation. Error description: ") + QString::fromStdString(m_LastErrorMessage), this); } } diff --git a/Modules/ImageStatisticsUI/Qmitk/QmitkDataGenerationJobBase.h b/Modules/ImageStatisticsUI/Qmitk/QmitkDataGenerationJobBase.h index c340091709..a9f1f61401 100644 --- a/Modules/ImageStatisticsUI/Qmitk/QmitkDataGenerationJobBase.h +++ b/Modules/ImageStatisticsUI/Qmitk/QmitkDataGenerationJobBase.h @@ -1,77 +1,74 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ -#ifndef __QMITK_DATA_GENERATION_JOB_BASE_H -#define __QMITK_DATA_GENERATION_JOB_BASE_H +#ifndef QmitkDataGenerationJobBase_h +#define QmitkDataGenerationJobBase_h //QT #include #include #include //MITK #include #include /*! \brief QmitkDataGenerationJobBase Base class for generation jobs used by QmitkDataGenerationBase and derived classes. */ class MITKIMAGESTATISTICSUI_EXPORT QmitkDataGenerationJobBase : public QObject, public QRunnable { Q_OBJECT public: - QmitkDataGenerationJobBase(const QmitkDataGenerationJobBase& other) = delete; - QmitkDataGenerationJobBase& operator=(const QmitkDataGenerationJobBase& other) = delete; - /** Result map that indicates all results generated by the job. The key is a job specific label for the results.*/ using ResultMapType = std::map; virtual ResultMapType GetResults() const = 0; /** Calls RunComputation() and takes care of the error handling and result signalling.*/ void run() final; /*! /brief Returns a flag the indicates if the job computation was successfull.*/ bool GetComputationSuccessFlag() const; std::string GetLastErrorMessage() const; signals: void Error(QString err, const QmitkDataGenerationJobBase* job); /*! @brief Signal is emitted when results are available. @param results produced by the job and ready to be used. @param the job that produced the data */ void ResultsAvailable(ResultMapType results, const QmitkDataGenerationJobBase* job); protected: QmitkDataGenerationJobBase() = default; virtual ~QmitkDataGenerationJobBase() = default; /**Does the real computation. Returns true if there where results produced.*/ virtual bool RunComputation() = 0; std::string m_LastErrorMessage; private: bool m_ComputationSuccessful = false; }; #endif diff --git a/Modules/ImageStatisticsUI/Qmitk/QmitkDataGeneratorBase.h b/Modules/ImageStatisticsUI/Qmitk/QmitkDataGeneratorBase.h index 38dd245159..f3988f0060 100644 --- a/Modules/ImageStatisticsUI/Qmitk/QmitkDataGeneratorBase.h +++ b/Modules/ImageStatisticsUI/Qmitk/QmitkDataGeneratorBase.h @@ -1,174 +1,174 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ -#ifndef __QMITK_DATA_GENERATOR_BASE_H -#define __QMITK_DATA_GENERATOR_BASE_H +#ifndef QmitkDataGeneratorBase_h +#define QmitkDataGeneratorBase_h #include //QT #include //MITK #include #include "QmitkDataGenerationJobBase.h" #include /*! \brief QmitkDataGeneratorBase BaseClass that implements the organisation of (statistic) data generation for pairs of images and ROIs. The key idea is that this class ensures that for vector of given image ROI pairs (defined by derived classes) a result instance (e.g ImageStatisticsContainer) will be calculated, if needed (e.g. because it is missing or not uptodate anymore), and stored in the data storage passed to a generator instance. While derived classes i.a. specify how to generate the image ROI pairs, how to detect latest results, what the next generation step is and how to remove obsolete data from the storage, the base class takes care of the observation of the data storage and orchestrates the whole checking and generation workflow. In all the generation/orchestration process the data storage, passed to the generator, 1) serves as place where the final results are stored and searched and 2) it resembles the state of the genertion process with these final results and WIP place holder nodes that indicate planed or currently processed generation steps. */ class MITKIMAGESTATISTICSUI_EXPORT QmitkDataGeneratorBase : public QObject { Q_OBJECT public: QmitkDataGeneratorBase(const QmitkDataGeneratorBase& other) = delete; QmitkDataGeneratorBase& operator=(const QmitkDataGeneratorBase& other) = delete; - ~QmitkDataGeneratorBase(); + virtual ~QmitkDataGeneratorBase(); using JobResultMapType = QmitkDataGenerationJobBase::ResultMapType; mitk::DataStorage::Pointer GetDataStorage() const; /** Indicates if the generator may trigger the update automatically (true). Reasons for an update are: - Input data has been changed or modified - Generation relevant settings in derived classes have been changed (must be implemented in derived classes) */ bool GetAutoUpdate() const; /** Indicates if there is currently work in progress, thus data generation jobs are running or pending. It is set to true when GenerationStarted is triggered and becomes false as soon as GenerationFinished is triggered. */ bool IsGenerating() const; /** Checks data validity and triggers generation of data, if needed. The generation itselfs will be done with a thread pool and is orchestrated by this class. To learn if the threads are finished and everything is uptodate, listen to the signal GenerationFinished. @return indicates if everything is already valid (true) or if the generation of new data was triggerd (false).*/ bool Generate() const; /** Indicates if for a given image and ROI a valid final result is available.*/ virtual bool IsValidResultAvailable(const mitk::DataNode* imageNode, const mitk::DataNode* roiNode) const = 0; public slots: /** Sets the data storage the generator should monitor and where WIP placeholder nodes and final result nodes should be stored.*/ void SetDataStorage(mitk::DataStorage* storage); void SetAutoUpdate(bool autoUpdate); protected slots: /** Used by QmitkDataGenerationJobBase to signal the generator that an error occured. */ void OnJobError(QString error, const QmitkDataGenerationJobBase* failedJob) const; /** Used by QmitkDataGenerationJobBase to signal and communicate the results of there computation. */ void OnFinalResultsAvailable(JobResultMapType results, const QmitkDataGenerationJobBase *job) const; signals: /*! @brief Signal that is emitted if a data generation job is started to generat outdated/inexistant data. */ void DataGenerationStarted(const mitk::DataNode* imageNode, const mitk::DataNode* roiNode, const QmitkDataGenerationJobBase* job) const; /*! @brief Signal that is emitted if new final data is produced. */ void NewDataAvailable(mitk::DataStorage::SetOfObjects::ConstPointer data) const; /*! @brief Signal that is emitted if all jobs are finished and everything is up to date. */ void GenerationFinished() const; /*! @brief Signal that is emitted in case of job errors. */ void JobError(QString error, const QmitkDataGenerationJobBase* failedJob) const; protected: /*! @brief Constructor @param storage the data storage where all produced data should be stored */ QmitkDataGeneratorBase(mitk::DataStorage::Pointer storage, QObject* parent = nullptr); QmitkDataGeneratorBase(QObject* parent = nullptr); using InputPairVectorType = std::vector>; /** This method must be implemented by derived to indicate if a changed node is relevant and therefore if an update must be triggered.*/ virtual bool ChangedNodeIsRelevant(const mitk::DataNode* changedNode) const = 0; /** This method must be impemented by derived classes to return the pairs of images and ROIs (ROI may be null if no ROI is needed) for which data are needed.*/ virtual InputPairVectorType GetAllImageROICombinations() const = 0; /** This method should indicate all missing and outdated (interim) results in the data storage, with new placeholder nodes and WIP dummy data added to the storage. The placeholder nodes will be replaced by the real results as soon as they are ready. The strategy how to detact which placeholder node is need and how the dummy data should look like must be implemented by derived classes.*/ virtual void IndicateFutureResults(const mitk::DataNode* imageNode, const mitk::DataNode* roiNode) const = 0; /*! @brief Is called to generate the next job instance that needs to be done and is associated dummy node in order to progress the data generation workflow. @remark The method can assume that the caller takes care of the job instance deletion. @return std::pair of job pointer and placeholder node associated with the job. Following combinations are possible: - Both are null: nothing to do; - Both are set: there is something to do for a pending dumme node -> trigger computation; - Job null and node set: a job for this node is already work in progress -> pass on till its finished.*/ virtual std::pair GetNextMissingGenerationJob(const mitk::DataNode* imageNode, const mitk::DataNode* roiNode) const =0; /** Remove all obsolete data nodes for the given image and ROI node from the data storage. Obsolete nodes are (interim) result nodes that are not the most recent any more.*/ virtual void RemoveObsoleteDataNodes(const mitk::DataNode* imageNode, const mitk::DataNode* roiNode) const = 0; /** Prepares result to be added to the storage in an appropriate way and returns the data node for that.*/ virtual mitk::DataNode::Pointer PrepareResultForStorage(const std::string& label, mitk::BaseData* result, const QmitkDataGenerationJobBase* job) const = 0; /*! Creates a data node for WIP place holder results. It can be used by IndicateFutureResults().*/ static mitk::DataNode::Pointer CreateWIPDataNode(mitk::BaseData* dataDummy, const std::string& nodeName); /** Filters a passed pair vector. The returned pair vector only contains pair of nodes that exist in the data storage.*/ InputPairVectorType FilterImageROICombinations(InputPairVectorType&& imageROICombinations) const; /** Return a descriptive label of a passed pair. Used e.g. for some debug log messages.*/ std::string GetPairDescription(const InputPairVectorType::value_type& imageAndSeg) const; /** Internal part of the generation strategy. Here is where the heavy lifting is done.*/ bool DoGenerate() const; /** Methods either directly calls generation or if its allready onging flags to restart the generation.*/ void EnsureRecheckingAndGeneration() const; mitk::WeakPointer m_Storage; bool m_AutoUpdate = false; mutable std::mutex m_DataMutex; private: /** Indicates if we are currently in the Generation() verification and generation of pending jobs triggering loop. Only needed for the internal logic.*/ mutable bool m_InGenerate = false; /** Internal flag that is set if a generation was requested, while one generation loop was already ongoing.*/ mutable bool m_RestartGeneration = false; /** Indicates if there are still jobs pending or computing (true) or if everything is valid (false).*/ mutable bool m_WIP = false; /** Internal flag that indicates that generator is currently in the process of adding results to the storage*/ mutable bool m_AddingToStorage = false; /**Member is called when a node is added to the storage.*/ void NodeAddedOrModified(const mitk::DataNode* node); unsigned long m_DataStorageDeletedTag; }; #endif diff --git a/Modules/ImageStatisticsUI/Qmitk/QmitkImageAndRoiDataGeneratorBase.cpp b/Modules/ImageStatisticsUI/Qmitk/QmitkImageAndRoiDataGeneratorBase.cpp index 38e50a02c9..6b6c95dfd1 100644 --- a/Modules/ImageStatisticsUI/Qmitk/QmitkImageAndRoiDataGeneratorBase.cpp +++ b/Modules/ImageStatisticsUI/Qmitk/QmitkImageAndRoiDataGeneratorBase.cpp @@ -1,103 +1,103 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "QmitkImageAndRoiDataGeneratorBase.h" QmitkImageAndRoiDataGeneratorBase::NodeVectorType QmitkImageAndRoiDataGeneratorBase::GetROINodes() const { return m_ROINodes; } QmitkImageAndRoiDataGeneratorBase::NodeVectorType QmitkImageAndRoiDataGeneratorBase::GetImageNodes() const { return m_ImageNodes; } void QmitkImageAndRoiDataGeneratorBase::SetImageNodes(const NodeVectorType& imageNodes) { if (m_ImageNodes != imageNodes) { { std::lock_guard mutexguard(m_DataMutex); m_ImageNodes = imageNodes; } if (m_AutoUpdate) { this->EnsureRecheckingAndGeneration(); } } } void QmitkImageAndRoiDataGeneratorBase::SetROINodes(const NodeVectorType& roiNodes) { if (m_ROINodes != roiNodes) { { std::lock_guard mutexguard(m_DataMutex); m_ROINodes = roiNodes; } if (m_AutoUpdate) { this->EnsureRecheckingAndGeneration(); } } } bool QmitkImageAndRoiDataGeneratorBase::ChangedNodeIsRelevant(const mitk::DataNode* changedNode) const { if (m_AutoUpdate) { auto finding = std::find(m_ImageNodes.begin(), m_ImageNodes.end(), changedNode); if (finding != m_ImageNodes.end()) { return true; } finding = std::find(m_ROINodes.begin(), m_ROINodes.end(), changedNode); if (finding != m_ROINodes.end()) { return true; } } return false; } QmitkImageAndRoiDataGeneratorBase::InputPairVectorType QmitkImageAndRoiDataGeneratorBase::GetAllImageROICombinations() const { std::lock_guard mutexguard(m_DataMutex); InputPairVectorType allCombinations; - for (auto& imageNode : m_ImageNodes) + for (const auto& imageNode : m_ImageNodes) { if (m_ROINodes.empty()) { allCombinations.emplace_back(imageNode, nullptr); } else { - for (auto& roiNode : m_ROINodes) + for (const auto& roiNode : m_ROINodes) { allCombinations.emplace_back(imageNode, roiNode); } } } return allCombinations; } diff --git a/Modules/ImageStatisticsUI/Qmitk/QmitkImageAndRoiDataGeneratorBase.h b/Modules/ImageStatisticsUI/Qmitk/QmitkImageAndRoiDataGeneratorBase.h index 071931a4b2..164023b752 100644 --- a/Modules/ImageStatisticsUI/Qmitk/QmitkImageAndRoiDataGeneratorBase.h +++ b/Modules/ImageStatisticsUI/Qmitk/QmitkImageAndRoiDataGeneratorBase.h @@ -1,58 +1,58 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ -#ifndef __QMITK_IMAGE_AND_ROI_DATA_GENERATOR_BASE_H -#define __QMITK_IMAGE_AND_ROI_DATA_GENERATOR_BASE_H +#ifndef QmitkImageAndRoiDataGeneratorBase_h +#define QmitkImageAndRoiDataGeneratorBase_h #include "QmitkDataGeneratorBase.h" #include /*! Base class that can be used for generators that should alow the image nodes and the ROI nodes as vectors (like generated by node selection widgets). This class ensures that data for every combination of images and ROIs (basicly a folding) will be processed. @sa QmitkDataGeneratorBase */ class MITKIMAGESTATISTICSUI_EXPORT QmitkImageAndRoiDataGeneratorBase : public QmitkDataGeneratorBase { public: using Superclass = QmitkDataGeneratorBase; using NodeVectorType = std::vector; NodeVectorType GetImageNodes() const; NodeVectorType GetROINodes() const; public slots: /*! @brief Setter for image nodes */ void SetImageNodes(const NodeVectorType& imageNodes); /*! @brief Setter for roi nodes */ void SetROINodes(const NodeVectorType& roiNodes); protected: QmitkImageAndRoiDataGeneratorBase(mitk::DataStorage::Pointer storage, QObject* parent = nullptr) : QmitkDataGeneratorBase(storage, parent) {}; QmitkImageAndRoiDataGeneratorBase(QObject* parent = nullptr) : QmitkDataGeneratorBase(parent) {}; using InputPairVectorType = Superclass::InputPairVectorType; bool ChangedNodeIsRelevant(const mitk::DataNode *changedNode) const override; InputPairVectorType GetAllImageROICombinations() const override; NodeVectorType m_ImageNodes; NodeVectorType m_ROINodes; QmitkImageAndRoiDataGeneratorBase(const QmitkImageAndRoiDataGeneratorBase&) = delete; QmitkImageAndRoiDataGeneratorBase& operator = (const QmitkImageAndRoiDataGeneratorBase&) = delete; }; #endif diff --git a/Modules/ImageStatisticsUI/Qmitk/QmitkImageStatisticsCalculationRunnable.cpp b/Modules/ImageStatisticsUI/Qmitk/QmitkImageStatisticsCalculationRunnable.cpp index e2f309b183..51850b06ed 100644 --- a/Modules/ImageStatisticsUI/Qmitk/QmitkImageStatisticsCalculationRunnable.cpp +++ b/Modules/ImageStatisticsUI/Qmitk/QmitkImageStatisticsCalculationRunnable.cpp @@ -1,216 +1,186 @@ /*=================================================================== 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 "QmitkImageStatisticsCalculationRunnable.h" #include "mitkImageStatisticsCalculator.h" #include #include #include #include "mitkStatisticsToImageRelationRule.h" #include "mitkStatisticsToMaskRelationRule.h" #include "mitkImageStatisticsContainerManager.h" #include "mitkProperties.h" QmitkImageStatisticsCalculationRunnable::QmitkImageStatisticsCalculationRunnable() : QmitkDataGenerationJobBase() , m_StatisticsImage(nullptr) , m_BinaryMask(nullptr) , m_PlanarFigureMask(nullptr) , m_IgnoreZeros(false) , m_HistogramNBins(100) { } QmitkImageStatisticsCalculationRunnable::~QmitkImageStatisticsCalculationRunnable() { } void QmitkImageStatisticsCalculationRunnable::Initialize(const mitk::Image *image, const mitk::Image *binaryImage, const mitk::PlanarFigure *planarFig) { this->m_StatisticsImage = image; this->m_BinaryMask = binaryImage; this->m_PlanarFigureMask = planarFig; } mitk::ImageStatisticsContainer* QmitkImageStatisticsCalculationRunnable::GetStatisticsData() const { return this->m_StatisticsContainer.GetPointer(); } const mitk::Image* QmitkImageStatisticsCalculationRunnable::GetStatisticsImage() const { return this->m_StatisticsImage.GetPointer(); } const mitk::Image* QmitkImageStatisticsCalculationRunnable::GetMaskImage() const { return this->m_BinaryMask.GetPointer(); } const mitk::PlanarFigure* QmitkImageStatisticsCalculationRunnable::GetPlanarFigure() const { return this->m_PlanarFigureMask.GetPointer(); } void QmitkImageStatisticsCalculationRunnable::SetIgnoreZeroValueVoxel(bool _arg) { this->m_IgnoreZeros = _arg; } bool QmitkImageStatisticsCalculationRunnable::GetIgnoreZeroValueVoxel() const { return this->m_IgnoreZeros; } void QmitkImageStatisticsCalculationRunnable::SetHistogramNBins(unsigned int nbins) { this->m_HistogramNBins = nbins; } unsigned int QmitkImageStatisticsCalculationRunnable::GetHistogramNBins() const { return this->m_HistogramNBins; } QmitkDataGenerationJobBase::ResultMapType QmitkImageStatisticsCalculationRunnable::GetResults() const { ResultMapType result; result.emplace("statistics", this->GetStatisticsData()); return result; } bool QmitkImageStatisticsCalculationRunnable::RunComputation() { 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_LastErrorMessage = e.what(); - statisticCalculationSuccessful = false; - } - catch (const itk::ExceptionObject& e) - { - MITK_ERROR << "ITK Exception:" << e.what(); - m_LastErrorMessage = e.what(); - statisticCalculationSuccessful = false; - } - catch (const std::runtime_error &e) - { - MITK_ERROR << "Runtime Exception: " << e.what(); - m_LastErrorMessage = e.what(); - statisticCalculationSuccessful = false; - } catch (const std::exception &e) { - MITK_ERROR << "Standard Exception: " << e.what(); + MITK_ERROR << "Error while configuring the statistics calculator: " << e.what(); m_LastErrorMessage = 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_LastErrorMessage = e.GetDescription(); - MITK_ERROR << "MITK Exception: " << e.what(); - statisticCalculationSuccessful = false; - } - catch (const std::runtime_error &e) - { - m_LastErrorMessage = "Failure: " + std::string(e.what()); - MITK_ERROR << "Runtime Exception: " << e.what(); - statisticCalculationSuccessful = false; - } catch (const std::exception &e) { - m_LastErrorMessage = "Failure: " + std::string(e.what()); - MITK_ERROR << "Standard Exception: " << e.what(); + m_LastErrorMessage = "Failure while calculating the statistics: " + std::string(e.what()); + MITK_ERROR << m_LastErrorMessage; statisticCalculationSuccessful = false; } if (statisticCalculationSuccessful) { m_StatisticsContainer = calculator->GetStatistics(); auto imageRule = mitk::StatisticsToImageRelationRule::New(); imageRule->Connect(m_StatisticsContainer, m_StatisticsImage); if (nullptr != m_PlanarFigureMask) { auto maskRule = mitk::StatisticsToMaskRelationRule::New(); maskRule->Connect(m_StatisticsContainer, m_PlanarFigureMask); } if (nullptr != m_BinaryMask) { auto maskRule = mitk::StatisticsToMaskRelationRule::New(); maskRule->Connect(m_StatisticsContainer, m_BinaryMask); } m_StatisticsContainer->SetProperty(mitk::STATS_HISTOGRAM_BIN_PROPERTY_NAME.c_str(), mitk::UIntProperty::New(m_HistogramNBins)); m_StatisticsContainer->SetProperty(mitk::STATS_IGNORE_ZERO_VOXEL_PROPERTY_NAME.c_str(), mitk::BoolProperty::New(m_IgnoreZeros)); } return statisticCalculationSuccessful; } diff --git a/Modules/ImageStatisticsUI/Qmitk/QmitkImageStatisticsCalculationRunnable.h b/Modules/ImageStatisticsUI/Qmitk/QmitkImageStatisticsCalculationRunnable.h index f253838398..53c0bc182f 100644 --- a/Modules/ImageStatisticsUI/Qmitk/QmitkImageStatisticsCalculationRunnable.h +++ b/Modules/ImageStatisticsUI/Qmitk/QmitkImageStatisticsCalculationRunnable.h @@ -1,86 +1,86 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ -#ifndef QMITKIMAGESTATISTICSCALCULATIONRUNNABLE_H_INCLUDED -#define QMITKIMAGESTATISTICSCALCULATIONRUNNABLE_H_INCLUDED +#ifndef QmitkImageStatisticsCalculationRunnable_h +#define QmitkImageStatisticsCalculationRunnable_h //mitk headers #include "mitkImage.h" #include "mitkPlanarFigure.h" #include "mitkImageStatisticsContainer.h" #include "QmitkDataGenerationJobBase.h" // itk headers #ifndef __itkHistogram_h #include #endif #include /** * /brief This class is executed as background thread for image statistics calculation. * * This class is derived from QRunnable and is intended to be used by QmitkImageStatisticsView * to run the image statistics calculation in a background thread keeping the GUI usable. */ class MITKIMAGESTATISTICSUI_EXPORT QmitkImageStatisticsCalculationRunnable : public QmitkDataGenerationJobBase { Q_OBJECT public: typedef itk::Statistics::Histogram HistogramType; /*! /brief standard constructor. */ QmitkImageStatisticsCalculationRunnable(); /*! /brief standard destructor. */ ~QmitkImageStatisticsCalculationRunnable(); /*! /brief Initializes the object with necessary data. */ void Initialize(const mitk::Image* image, const mitk::Image* binaryImage, const mitk::PlanarFigure* planarFig); /*! /brief returns the calculated image statistics. */ mitk::ImageStatisticsContainer* GetStatisticsData() 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; ResultMapType GetResults() const override; protected: bool RunComputation() override; 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. }; #endif // QMITKIMAGESTATISTICSCALCULATIONRUNNABLE_H_INCLUDED diff --git a/Modules/ImageStatisticsUI/Qmitk/QmitkImageStatisticsDataGenerator.cpp b/Modules/ImageStatisticsUI/Qmitk/QmitkImageStatisticsDataGenerator.cpp index 5cb2cfbd81..70a8da970b 100644 --- a/Modules/ImageStatisticsUI/Qmitk/QmitkImageStatisticsDataGenerator.cpp +++ b/Modules/ImageStatisticsUI/Qmitk/QmitkImageStatisticsDataGenerator.cpp @@ -1,273 +1,273 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "QmitkImageStatisticsDataGenerator.h" #include "mitkImageStatisticsContainer.h" #include "mitkStatisticsToImageRelationRule.h" #include "mitkStatisticsToMaskRelationRule.h" #include "mitkNodePredicateFunction.h" #include "mitkNodePredicateAnd.h" #include "mitkNodePredicateNot.h" #include "mitkNodePredicateDataProperty.h" #include "mitkProperties.h" #include "mitkImageStatisticsContainerManager.h" #include "QmitkImageStatisticsCalculationRunnable.h" void QmitkImageStatisticsDataGenerator::SetIgnoreZeroValueVoxel(bool _arg) { if (m_IgnoreZeroValueVoxel != _arg) { m_IgnoreZeroValueVoxel = _arg; if (m_AutoUpdate) { this->EnsureRecheckingAndGeneration(); } } } bool QmitkImageStatisticsDataGenerator::GetIgnoreZeroValueVoxel() const { return this->m_IgnoreZeroValueVoxel; } void QmitkImageStatisticsDataGenerator::SetHistogramNBins(unsigned int nbins) { if (m_HistogramNBins != nbins) { m_HistogramNBins = nbins; if (m_AutoUpdate) { this->EnsureRecheckingAndGeneration(); } } } unsigned int QmitkImageStatisticsDataGenerator::GetHistogramNBins() const { return this->m_HistogramNBins; } bool QmitkImageStatisticsDataGenerator::ChangedNodeIsRelevant(const mitk::DataNode* changedNode) const { auto result = QmitkImageAndRoiDataGeneratorBase::ChangedNodeIsRelevant(changedNode); if (!result) { if (changedNode->GetProperty(mitk::STATS_GENERATION_STATUS_PROPERTY_NAME.c_str()) == nullptr) { auto stats = dynamic_cast(changedNode->GetData()); result = stats != nullptr; } } return result; } bool QmitkImageStatisticsDataGenerator::IsValidResultAvailable(const mitk::DataNode* imageNode, const mitk::DataNode* roiNode) const { auto resultNode = this->GetLatestResult(imageNode, roiNode, true, true); return resultNode.IsNotNull(); } mitk::DataNode::Pointer QmitkImageStatisticsDataGenerator::GetLatestResult(const mitk::DataNode* imageNode, const mitk::DataNode* roiNode, bool onlyIfUpToDate, bool noWIP) const { auto storage = m_Storage.Lock(); - if (!imageNode || !imageNode->GetData()) + if (imageNode == nullptr || !imageNode->GetData()) { mitkThrow() << "Image is nullptr"; } const auto image = imageNode->GetData(); const mitk::BaseData* mask = nullptr; if (roiNode) { mask = roiNode->GetData(); } std::lock_guard mutexguard(m_DataMutex); return mitk::ImageStatisticsContainerManager::GetImageStatisticsNode(storage, image, mask, m_IgnoreZeroValueVoxel, m_HistogramNBins, onlyIfUpToDate, noWIP); } void QmitkImageStatisticsDataGenerator::IndicateFutureResults(const mitk::DataNode* imageNode, const mitk::DataNode* roiNode) const { - if (!imageNode || !imageNode->GetData()) + if (imageNode == nullptr || !imageNode->GetData()) { mitkThrow() << "Image node is nullptr"; } auto image = dynamic_cast(imageNode->GetData()); if (!image) { mitkThrow() << "Image node date is nullptr or no image."; } const mitk::BaseData* mask = nullptr; - if (roiNode) + if (roiNode != nullptr) { mask = roiNode->GetData(); } auto resultDataNode = this->GetLatestResult(imageNode, roiNode, true, false); if (resultDataNode.IsNull()) { auto dummyStats = mitk::ImageStatisticsContainer::New(); auto imageRule = mitk::StatisticsToImageRelationRule::New(); imageRule->Connect(dummyStats, image); if (nullptr != mask) { auto maskRule = mitk::StatisticsToMaskRelationRule::New(); maskRule->Connect(dummyStats, mask); } dummyStats->SetProperty(mitk::STATS_HISTOGRAM_BIN_PROPERTY_NAME.c_str(), mitk::UIntProperty::New(m_HistogramNBins)); dummyStats->SetProperty(mitk::STATS_IGNORE_ZERO_VOXEL_PROPERTY_NAME.c_str(), mitk::BoolProperty::New(m_IgnoreZeroValueVoxel)); auto dummyNode = CreateWIPDataNode(dummyStats, "WIP_"+GenerateStatisticsNodeName(image, mask)); auto storage = m_Storage.Lock(); - if (storage) + if (storage != nullptr) { std::lock_guard mutexguard(m_DataMutex); storage->Add(dummyNode); } } } std::pair QmitkImageStatisticsDataGenerator::GetNextMissingGenerationJob(const mitk::DataNode* imageNode, const mitk::DataNode* roiNode) const { auto resultDataNode = this->GetLatestResult(imageNode, roiNode, true, false); std::string status; if (resultDataNode.IsNull() || (resultDataNode->GetStringProperty(mitk::STATS_GENERATION_STATUS_PROPERTY_NAME.c_str(), status) && status == mitk::STATS_GENERATION_STATUS_VALUE_PENDING)) { - if (!imageNode || !imageNode->GetData()) + if (imageNode == nullptr || !imageNode->GetData()) { mitkThrow() << "Image node is nullptr"; } auto image = dynamic_cast(imageNode->GetData()); - if (!image) + if (image == nullptr) { mitkThrow() << "Image node date is nullptr or no image."; } const mitk::Image* mask = nullptr; const mitk::PlanarFigure* planar = nullptr; - if (roiNode) + if (roiNode != nullptr) { mask = dynamic_cast(roiNode->GetData()); planar = dynamic_cast(roiNode->GetData()); } auto newJob = new QmitkImageStatisticsCalculationRunnable; newJob->Initialize(image, mask, planar); newJob->SetIgnoreZeroValueVoxel(m_IgnoreZeroValueVoxel); newJob->SetHistogramNBins(m_HistogramNBins); return std::pair(newJob, resultDataNode.GetPointer()); } else if (resultDataNode->GetStringProperty(mitk::STATS_GENERATION_STATUS_PROPERTY_NAME.c_str(), status) && status == mitk::STATS_GENERATION_STATUS_VALUE_WORK_IN_PROGRESS) { return std::pair(nullptr, resultDataNode.GetPointer()); } return std::pair(nullptr, nullptr); } void QmitkImageStatisticsDataGenerator::RemoveObsoleteDataNodes(const mitk::DataNode* imageNode, const mitk::DataNode* roiNode) const { - if (!imageNode || !imageNode->GetData()) + if (imageNode == nullptr || !imageNode->GetData()) { mitkThrow() << "Image is nullptr"; } const auto image = imageNode->GetData(); const mitk::BaseData* mask = nullptr; - if (roiNode) + if (roiNode != nullptr) { mask = roiNode->GetData(); } auto lastResult = this->GetLatestResult(imageNode, roiNode, false, false); auto rulePredicate = mitk::ImageStatisticsContainerManager::GetStatisticsPredicateForSources(image, mask); auto notLatestPredicate = mitk::NodePredicateFunction::New([lastResult](const mitk::DataNode* node) { return node != lastResult; }); auto binPredicate = mitk::NodePredicateDataProperty::New(mitk::STATS_HISTOGRAM_BIN_PROPERTY_NAME.c_str(), mitk::UIntProperty::New(m_HistogramNBins)); auto zeroPredicate = mitk::NodePredicateDataProperty::New(mitk::STATS_IGNORE_ZERO_VOXEL_PROPERTY_NAME.c_str(), mitk::BoolProperty::New(m_IgnoreZeroValueVoxel)); mitk::NodePredicateBase::ConstPointer predicate = mitk::NodePredicateAnd::New(rulePredicate, notLatestPredicate).GetPointer(); predicate = mitk::NodePredicateAnd::New(predicate, binPredicate, zeroPredicate).GetPointer(); auto storage = m_Storage.Lock(); - if (storage) + if (storage != nullptr) { std::lock_guard mutexguard(m_DataMutex); auto oldStatisticContainerNodes = storage->GetSubset(predicate); storage->Remove(oldStatisticContainerNodes); } } mitk::DataNode::Pointer QmitkImageStatisticsDataGenerator::PrepareResultForStorage(const std::string& /*label*/, mitk::BaseData* result, const QmitkDataGenerationJobBase* job) const { auto statsJob = dynamic_cast(job); - if (statsJob) + if (statsJob != nullptr) { auto resultNode = mitk::DataNode::New(); resultNode->SetProperty("helper object", mitk::BoolProperty::New(true)); resultNode->SetVisibility(false); resultNode->SetData(result); const mitk::BaseData* roi = statsJob->GetMaskImage(); - if (!roi) + if (roi == nullptr) { roi = statsJob->GetPlanarFigure(); } resultNode->SetName(this->GenerateStatisticsNodeName(statsJob->GetStatisticsImage(), roi)); return resultNode; } return nullptr; } std::string QmitkImageStatisticsDataGenerator::GenerateStatisticsNodeName(const mitk::Image* image, const mitk::BaseData* roi) const { std::stringstream statisticsNodeName; statisticsNodeName << "statistics_bins-" << m_HistogramNBins <<"_"; if (m_IgnoreZeroValueVoxel) { statisticsNodeName << "noZeros_"; } - if (!image) + if (image == nullptr) { mitkThrow() << "Image is nullptr"; } statisticsNodeName << image->GetUID(); - if (roi) + if (roi != nullptr) { statisticsNodeName << "_" + roi->GetUID(); } return statisticsNodeName.str(); } diff --git a/Modules/ImageStatisticsUI/Qmitk/QmitkImageStatisticsDataGenerator.h b/Modules/ImageStatisticsUI/Qmitk/QmitkImageStatisticsDataGenerator.h index 451def0a65..4d3766e246 100644 --- a/Modules/ImageStatisticsUI/Qmitk/QmitkImageStatisticsDataGenerator.h +++ b/Modules/ImageStatisticsUI/Qmitk/QmitkImageStatisticsDataGenerator.h @@ -1,67 +1,67 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ -#ifndef __QMITK_IMAGE_STATISTICS_DATA_GENERATOR_H -#define __QMITK_IMAGE_STATISTICS_DATA_GENERATOR_H +#ifndef QmitkImageStatisticsDataGenerator_h +#define QmitkImageStatisticsDataGenerator_h #include "QmitkImageAndRoiDataGeneratorBase.h" #include /** Generates ImageStatisticContainers by using QmitkImageStatisticsCalculationRunnables for each pair if image and ROIs and ensures their validity. It also encodes the HistogramNBins and IgnoreZeroValueVoxel as properties to the results as these settings are important criteria for discreminating statistics results. For more details of how the generation is done see QmitkDataGenerationBase. */ class MITKIMAGESTATISTICSUI_EXPORT QmitkImageStatisticsDataGenerator : public QmitkImageAndRoiDataGeneratorBase { public: QmitkImageStatisticsDataGenerator(mitk::DataStorage::Pointer storage, QObject* parent = nullptr) : QmitkImageAndRoiDataGeneratorBase(storage, parent) {}; QmitkImageStatisticsDataGenerator(QObject* parent = nullptr) : QmitkImageAndRoiDataGeneratorBase(parent) {}; - bool IsValidResultAvailable(const mitk::DataNode* imageNode, const mitk::DataNode* roiNode) const final; + bool IsValidResultAvailable(const mitk::DataNode* imageNode, const mitk::DataNode* roiNode) const; /** Returns the latest result for a given image and ROI and the current settings of the generator. @param onlyIfUpToDate Indicates if results should only be returned if the are up to date, thus not older then image and ROI. @param noWIP If noWIP is true, the function only returns valid final result and not just its placeholder (WIP). If noWIP equals false it might also return a WIP, thus the valid result is currently processed/ordered but might not be ready yet.*/ mitk::DataNode::Pointer GetLatestResult(const mitk::DataNode* imageNode, const mitk::DataNode* roiNode, bool onlyIfUpToDate = false, bool noWIP = true) const; std::string GenerateStatisticsNodeName(const mitk::Image* image, const mitk::BaseData* roi) 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; protected: - bool ChangedNodeIsRelevant(const mitk::DataNode* changedNode) const final; - void IndicateFutureResults(const mitk::DataNode* imageNode, const mitk::DataNode* roiNode) const final; - std::pair GetNextMissingGenerationJob(const mitk::DataNode* imageNode, const mitk::DataNode* roiNode) const final; - void RemoveObsoleteDataNodes(const mitk::DataNode* imageNode, const mitk::DataNode* roiNode) const final; - mitk::DataNode::Pointer PrepareResultForStorage(const std::string& label, mitk::BaseData* result, const QmitkDataGenerationJobBase* job) const final; + bool ChangedNodeIsRelevant(const mitk::DataNode* changedNode) const; + void IndicateFutureResults(const mitk::DataNode* imageNode, const mitk::DataNode* roiNode) const; + std::pair GetNextMissingGenerationJob(const mitk::DataNode* imageNode, const mitk::DataNode* roiNode) const; + void RemoveObsoleteDataNodes(const mitk::DataNode* imageNode, const mitk::DataNode* roiNode) const; + mitk::DataNode::Pointer PrepareResultForStorage(const std::string& label, mitk::BaseData* result, const QmitkDataGenerationJobBase* job) const; QmitkImageStatisticsDataGenerator(const QmitkImageStatisticsDataGenerator&) = delete; QmitkImageStatisticsDataGenerator& operator = (const QmitkImageStatisticsDataGenerator&) = delete; bool m_IgnoreZeroValueVoxel = false; unsigned int m_HistogramNBins = 100; }; #endif