diff --git a/Modules/ImageStatisticsUI/Qmitk/QmitkIntensityProfileVisualizationWidget.cpp b/Modules/ImageStatisticsUI/Qmitk/QmitkIntensityProfileVisualizationWidget.cpp index 5980d61bbd..9905339eef 100644 --- a/Modules/ImageStatisticsUI/Qmitk/QmitkIntensityProfileVisualizationWidget.cpp +++ b/Modules/ImageStatisticsUI/Qmitk/QmitkIntensityProfileVisualizationWidget.cpp @@ -1,105 +1,135 @@ /*=================================================================== 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 "QmitkIntensityProfileVisualizationWidget.h" -#include +#include QmitkIntensityProfileVisualizationWidget::QmitkIntensityProfileVisualizationWidget(QWidget* parent) : QWidget(parent) { m_Controls.setupUi(this); + #if QT_VERSION < QT_VERSION_CHECK(5, 10, 0) + WarnQtVersionTooLow(); + #else + m_Controls.labelIntensityProfileIsInvisibleWarning->setVisible(false); + m_Controls.checkBoxShowSubchart->setChecked(false); + #endif CreateConnections(); } + + void QmitkIntensityProfileVisualizationWidget::SetIntensityProfile(mitk::IntensityProfile::ConstPointer intensityProfile, const std::string& dataLabel) { if (intensityProfile == nullptr) return; m_IntensityProfileList = mitk::CreateVectorFromIntensityProfile(intensityProfile); if (m_IntensityProfileList.empty()) return; m_Controls.chartWidget->AddData1D(m_IntensityProfileList, dataLabel); m_Controls.chartWidget->SetChartType(dataLabel, QmitkChartWidget::ChartType::line); m_Controls.chartWidget->SetXAxisLabel("Distance"); m_Controls.chartWidget->SetYAxisLabel("Intensity"); - m_Controls.chartWidget->Show(m_Controls.checkBoxShowSubchart->isChecked()); - + #if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) + m_Controls.chartWidget->Show(m_Controls.checkBoxShowSubchart->isChecked()); + #endif SetGUIElementsEnabled(true); } void QmitkIntensityProfileVisualizationWidget::Reset() { - m_Controls.chartWidget->Clear(); + #if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) + m_Controls.chartWidget->Clear(); + #endif SetGUIElementsEnabled(false); m_IntensityProfileList.clear(); } +void QmitkIntensityProfileVisualizationWidget::SetTheme(QmitkChartWidget::ChartStyle style) +{ + m_ChartStyle = style; +} + void QmitkIntensityProfileVisualizationWidget::CreateConnections() { connect(m_Controls.checkBoxShowSubchart, &QCheckBox::clicked, this, &QmitkIntensityProfileVisualizationWidget::OnShowSubchartCheckBoxChanged); connect(m_Controls.buttonCopyToClipboard, &QPushButton::clicked, this, &QmitkIntensityProfileVisualizationWidget::OnClipboardButtonClicked); + connect(m_Controls.chartWidget, &QmitkChartWidget::PageSuccessfullyLoaded, this, &QmitkIntensityProfileVisualizationWidget::OnPageSuccessfullyLoaded); } void QmitkIntensityProfileVisualizationWidget::SetGUIElementsEnabled(bool enabled) { this->setEnabled(enabled); m_Controls.groupBoxIntensityProfile->setEnabled(enabled); m_Controls.groupBoxPlot->setEnabled(enabled); m_Controls.buttonCopyToClipboard->setEnabled(enabled); m_Controls.checkBoxShowSubchart->setEnabled(enabled); m_Controls.chartWidget->setEnabled(enabled); m_Controls.labelIntensityProfileIsInvisibleWarning->setEnabled(enabled); m_Controls.labelInfo->setEnabled(enabled); } std::vector QmitkIntensityProfileVisualizationWidget::ConvertIntensityProfileToVector(mitk::IntensityProfile::ConstPointer intensityProfile) const { std::vector intensityProfileList; if (intensityProfile != nullptr) { auto end = intensityProfile->End(); for (auto it = intensityProfile->Begin(); it != end; ++it) { intensityProfileList.push_back(it.GetMeasurementVector()[0]); } } return intensityProfileList; } void QmitkIntensityProfileVisualizationWidget::OnClipboardButtonClicked() { if (m_IntensityProfileList.empty()) return; QApplication::clipboard()->clear(); QString clipboard("Pixel \t Intensity\n"); for (unsigned int i = 0; i < m_IntensityProfileList.size(); i++) { clipboard = clipboard.append("%L1 \t %L2\n") .arg(QString::number(i)) .arg(QString::number(m_IntensityProfileList.at(i))); } QApplication::clipboard()->setText(clipboard, QClipboard::Clipboard); } void QmitkIntensityProfileVisualizationWidget::OnShowSubchartCheckBoxChanged() { m_Controls.chartWidget->Show(m_Controls.checkBoxShowSubchart->isChecked()); } + +void QmitkIntensityProfileVisualizationWidget::OnPageSuccessfullyLoaded() +{ + m_Controls.chartWidget->SetTheme(m_ChartStyle); +} + +void QmitkIntensityProfileVisualizationWidget::WarnQtVersionTooLow() +{ + m_Controls.labelIntensityProfileIsInvisibleWarning->setVisible(true); + m_Controls.labelIntensityProfileIsInvisibleWarning->setText("Intensity profile is not visible because Qt 5.10 is required for MitkChart. You can use the button Copy to Clipboard below to retrieve values.< / font>"); + m_Controls.groupBoxPlot->setVisible(false); + m_Controls.chartWidget->setVisible(false); +} diff --git a/Modules/ImageStatisticsUI/Qmitk/QmitkIntensityProfileVisualizationWidget.h b/Modules/ImageStatisticsUI/Qmitk/QmitkIntensityProfileVisualizationWidget.h index 5844885f3e..22687716e9 100644 --- a/Modules/ImageStatisticsUI/Qmitk/QmitkIntensityProfileVisualizationWidget.h +++ b/Modules/ImageStatisticsUI/Qmitk/QmitkIntensityProfileVisualizationWidget.h @@ -1,63 +1,69 @@ /*=================================================================== 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 QmitkIntensityProfileVisualizationWidget_H__INCLUDED #define QmitkIntensityProfileVisualizationWidget_H__INCLUDED //Qt #include #include #include //mitk #include /** * \brief Widget for displaying intensity profiles. */ class MITKIMAGESTATISTICSUI_EXPORT QmitkIntensityProfileVisualizationWidget : public QWidget { Q_OBJECT public: QmitkIntensityProfileVisualizationWidget(QWidget* parent = nullptr); - + void SetIntensityProfile(mitk::IntensityProfile::ConstPointer intensityProfile, const std::string& dataLabel); /** \brief Clears the intensity profile and disables all GUI elements. */ void Reset(); + void SetTheme(QmitkChartWidget::ChartStyle style); + private: void CreateConnections(); void SetGUIElementsEnabled(bool enabled); std::vector ConvertIntensityProfileToVector(mitk::IntensityProfile::ConstPointer intensityProfile) const; -//slots /** \brief Saves the intensity profile to the clipboard. */ void OnClipboardButtonClicked(); /** \brief Shows / Hides the subchart. */ void OnShowSubchartCheckBoxChanged(); + void OnPageSuccessfullyLoaded(); + private: + void WarnQtVersionTooLow(); + Ui::QmitkIntensityProfileControls m_Controls; + QmitkChartWidget::ChartStyle m_ChartStyle = QmitkChartWidget::ChartStyle::darkstyle; std::vector m_IntensityProfileList; }; #endif //QmitkIntensityProfileVisualizationWidget_H__INCLUDED \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsReloadedView.cpp b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsReloadedView.cpp index 6dcfcffe35..195de154e2 100644 --- a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsReloadedView.cpp +++ b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsReloadedView.cpp @@ -1,277 +1,301 @@ /*=================================================================== 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 "QmitkImageStatisticsReloadedView.h" // berry includes #include #include #include #include #include #include #include #include #include +#include #include const std::string QmitkImageStatisticsReloadedView::VIEW_ID = "org.mitk.views.imagestatisticsReloaded"; QmitkImageStatisticsReloadedView::QmitkImageStatisticsReloadedView(QObject* /*parent*/, const char* /*name*/) { this->m_CalculationThread = new QmitkImageStatisticsCalculationJob(); } QmitkImageStatisticsReloadedView::~QmitkImageStatisticsReloadedView() { if (m_selectedPlanarFigure) m_selectedPlanarFigure->RemoveObserver(m_PlanarFigureObserverTag); } void QmitkImageStatisticsReloadedView::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); PrepareDataStorageComboBoxes(); CreateConnections(); } void QmitkImageStatisticsReloadedView::CreateConnections() { connect(this->m_CalculationThread, &QmitkImageStatisticsCalculationJob::finished, this, &QmitkImageStatisticsReloadedView::OnStatisticsCalculationEnds, Qt::QueuedConnection); } void QmitkImageStatisticsReloadedView::PartClosed(const berry::IWorkbenchPartReference::Pointer& ) { } void QmitkImageStatisticsReloadedView::FillStatisticsWidget(const std::vector& statistics) { m_Controls.widget_statistics->Reset(); m_Controls.widget_statistics->SetStatistics(statistics); m_Controls.widget_statistics->SetImageNodes({ m_selectedImageNode }); if (m_selectedMaskNode) { m_Controls.widget_statistics->SetMaskNodes({ m_selectedMaskNode }); } m_Controls.widget_statistics->setEnabled(true); } void QmitkImageStatisticsReloadedView::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, &QmitkImageStatisticsReloadedView::OnRequestHistogramUpdate); - } QmitkChartWidget::ChartStyle QmitkImageStatisticsReloadedView::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::ChartStyle::darkstyle; } else { return QmitkChartWidget::ChartStyle::lightstyle; } } return QmitkChartWidget::ChartStyle::darkstyle; } void QmitkImageStatisticsReloadedView::OnImageOrMaskSelectorChanged() { if (this->m_selectedPlanarFigure) { this->m_selectedPlanarFigure->RemoveObserver(this->m_PlanarFigureObserverTag); this->m_selectedPlanarFigure = nullptr; } m_selectedImageNode = m_Controls.imageSelector->GetSelectedNode(); m_selectedMaskNode = m_Controls.maskImageSelector->GetSelectedNode(); + m_Controls.groupBox_intensityProfile->setVisible(false); + if (m_selectedImageNode != nullptr) { auto image = dynamic_cast(m_selectedImageNode->GetData()); mitk::Image::Pointer mask = nullptr; mitk::PlanarFigure::Pointer maskPlanarFigure = nullptr; if (m_selectedMaskNode != nullptr) { mask = dynamic_cast(m_selectedMaskNode->GetData()); if (mask == nullptr) { maskPlanarFigure = dynamic_cast(m_selectedMaskNode->GetData()); } } if (mask) { + //compute statistics with given mask CalculateStatistics(image, mask); } else if (maskPlanarFigure) { m_selectedPlanarFigure = maskPlanarFigure; ITKCommandType::Pointer changeListener = ITKCommandType::New(); changeListener->SetCallbackFunction(this, &QmitkImageStatisticsReloadedView::OnImageOrMaskSelectorChanged); this->m_PlanarFigureObserverTag = m_selectedPlanarFigure->AddObserver(mitk::EndInteractionPlanarFigureEvent(), changeListener); + if (!maskPlanarFigure->IsClosed()) { + //compute line profile and display statistics for voxels on line + auto intensityProfile = mitk::ComputeIntensityProfile(image, 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()); + } + //for all planar figures: compute statistics with planarFigure as mask CalculateStatistics(image, maskPlanarFigure); } else { + //compute statistics with image only CalculateStatistics(image); } } else { ResetGUI(); } } void QmitkImageStatisticsReloadedView::ResetGUI() { m_Controls.widget_statistics->Reset(); m_Controls.widget_statistics->setEnabled(false); m_Controls.widget_histogram->Reset(); m_Controls.widget_histogram->setEnabled(false); } void QmitkImageStatisticsReloadedView::OnStatisticsCalculationEnds() { mitk::StatusBar::GetInstance()->Clear(); if (this->m_CalculationThread->GetStatisticsUpdateSuccessFlag()) { this->FillStatisticsWidget(m_CalculationThread->GetStatisticsData()); - this->FillHistogramWidget({ m_CalculationThread->GetTimeStepHistogram() }, {m_selectedImageNode->GetName()}); + if (!m_selectedPlanarFigure || m_selectedPlanarFigure->IsClosed()) { + this->FillHistogramWidget({ m_CalculationThread->GetTimeStepHistogram() }, { m_selectedImageNode->GetName() }); + } } else { mitk::StatusBar::GetInstance()->DisplayErrorText(m_CalculationThread->GetLastErrorMessage().c_str()); m_Controls.widget_histogram->setEnabled(false); m_Controls.widget_statistics->setEnabled(false); } } void QmitkImageStatisticsReloadedView::OnRequestHistogramUpdate(unsigned int nBins) { m_CalculationThread->SetHistogramNBins(nBins); m_CalculationThread->start(); } void QmitkImageStatisticsReloadedView::CalculateStatistics(mitk::Image::Pointer image, mitk::Image::Pointer mask) { CalculateStatisticsInternal(image, mask); } void QmitkImageStatisticsReloadedView::CalculateStatistics(mitk::Image::Pointer image, mitk::PlanarFigure::Pointer mask) { CalculateStatisticsInternal(image, nullptr, mask); } void QmitkImageStatisticsReloadedView::CalculateStatisticsInternal(mitk::Image::Pointer image, mitk::Image::Pointer mask, mitk::PlanarFigure::Pointer maskPlanarFigure) { this->m_StatisticsUpdatePending = true; this->m_CalculationThread->Initialize(image, mask, maskPlanarFigure); this->m_CalculationThread->SetTimeStep(0); try { // Compute statistics this->m_CalculationThread->start(); } catch (const mitk::Exception& e) { mitk::StatusBar::GetInstance()->DisplayErrorText(e.GetDescription()); this->m_StatisticsUpdatePending = false; } catch (const std::runtime_error &e) { mitk::StatusBar::GetInstance()->DisplayErrorText(e.what()); this->m_StatisticsUpdatePending = false; } catch (const std::exception &e) { mitk::StatusBar::GetInstance()->DisplayErrorText(e.what()); this->m_StatisticsUpdatePending = false; } } void QmitkImageStatisticsReloadedView::OnSelectionChanged( berry::IWorkbenchPart::Pointer /*part*/, const QList &nodes ) { } void QmitkImageStatisticsReloadedView::PrepareDataStorageComboBoxes() { auto isImage = mitk::NodePredicateDataType::New("Image"); auto isBinary = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); auto isNoBinary = mitk::NodePredicateNot::New(isBinary); auto isBinaryImage = mitk::NodePredicateAnd::New(isImage, isBinary); auto isNoBinaryImage = mitk::NodePredicateAnd::New(isImage, isNoBinary); auto isPlanarFigure = GetPlanarFigurePredicate(); auto isBinaryImageOrPlanarFigure = mitk::NodePredicateOr::New(isBinaryImage, isPlanarFigure); m_Controls.imageSelector->SetDataStorage(GetDataStorage()); m_Controls.imageSelector->SetPredicate(isNoBinaryImage); m_Controls.maskImageSelector->SetDataStorage(GetDataStorage()); m_Controls.maskImageSelector->SetPredicate(isBinaryImageOrPlanarFigure); m_Controls.maskImageSelector->SetZeroEntryText(""); } mitk::NodePredicateBase::Pointer QmitkImageStatisticsReloadedView::GetPlanarFigurePredicate() const { auto isPlanarCircle = mitk::NodePredicateDataType::New("PlanarCircle"); auto isPlanarRectangle = mitk::NodePredicateDataType::New("PlanarRectangle"); auto isPlanarEllipse = mitk::NodePredicateDataType::New("PlanarEllipse"); auto isPlanarDoubleEllipse = mitk::NodePredicateDataType::New("PlanarDoubleEllipse"); auto isPlanarPolygon = mitk::NodePredicateDataType::New("PlanarPolygon"); auto isPlanarSubdivisionPolygon = mitk::NodePredicateDataType::New("PlanarSubdivisionPolygon"); + auto isPlanarBezierCurve = mitk::NodePredicateDataType::New("PlanarBezierCurve"); + auto isPlanarLine = mitk::NodePredicateDataType::New("PlanarLine"); auto isPlanarFigure = mitk::NodePredicateOr::New(isPlanarCircle, isPlanarEllipse); isPlanarFigure = mitk::NodePredicateOr::New(isPlanarFigure, isPlanarRectangle); isPlanarFigure = mitk::NodePredicateOr::New(isPlanarFigure, isPlanarDoubleEllipse); isPlanarFigure = mitk::NodePredicateOr::New(isPlanarFigure, isPlanarPolygon); isPlanarFigure = mitk::NodePredicateOr::New(isPlanarFigure, isPlanarSubdivisionPolygon); + isPlanarFigure = mitk::NodePredicateOr::New(isPlanarFigure, isPlanarBezierCurve); + isPlanarFigure = mitk::NodePredicateOr::New(isPlanarFigure, isPlanarLine); return isPlanarFigure.GetPointer(); } void QmitkImageStatisticsReloadedView::Activated() { } void QmitkImageStatisticsReloadedView::Deactivated() { } void QmitkImageStatisticsReloadedView::Visible() { connect(m_Controls.imageSelector, static_cast(&QComboBox::currentIndexChanged), this, &QmitkImageStatisticsReloadedView::OnImageOrMaskSelectorChanged); connect(m_Controls.maskImageSelector, static_cast(&QComboBox::currentIndexChanged), this, &QmitkImageStatisticsReloadedView::OnImageOrMaskSelectorChanged); m_selectedImageNode = m_Controls.imageSelector->GetSelectedNode(); if (m_selectedImageNode) { OnImageOrMaskSelectorChanged(); } else { ResetGUI(); } } void QmitkImageStatisticsReloadedView::Hidden() { m_Controls.imageSelector->disconnect(); m_Controls.maskImageSelector->disconnect(); } void QmitkImageStatisticsReloadedView::SetFocus() { } diff --git a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsReloadedViewControls.ui b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsReloadedViewControls.ui index 0b1522bf3f..762d62d479 100644 --- a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsReloadedViewControls.ui +++ b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsReloadedViewControls.ui @@ -1,233 +1,257 @@ QmitkImageStatisticsReloadedViewControls true 0 0 419 1016 Form QLayout::SetMinimumSize 4 0 0 0 0 0 0 0 0 120 120 120 Mask image: 0 0 0 0 0 0 0 0 120 120 120 Image: 0 0 false 0 0 false 0 200 Statistics 0 200 Histogram + + + + + 0 + 200 + + + + Intensity Profile + + + + + + + + Qt::Vertical 20 40 QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
QmitkHistogramVisualizationWidget QWidget
QmitkHistogramVisualizationWidget.h
1
QmitkImageStatisticsWidget QWidget
QmitkImageStatisticsWidget.h
1
QmitkDataStorageComboBoxWithSelectNone QComboBox
QmitkDataStorageComboBoxWithSelectNone.h
+ + QmitkIntensityProfileVisualizationWidget + QWidget +
QmitkIntensityProfileVisualizationWidget.h
+ 1 +