diff --git a/Documentation/Doxygen/2-UserManual/MITKPluginGeneralManualsList.dox b/Documentation/Doxygen/2-UserManual/MITKPluginGeneralManualsList.dox index 0ec050c887..7d38e016f0 100644 --- a/Documentation/Doxygen/2-UserManual/MITKPluginGeneralManualsList.dox +++ b/Documentation/Doxygen/2-UserManual/MITKPluginGeneralManualsList.dox @@ -1,32 +1,32 @@ /** \page PluginListGeneralPage List of General Purpose Plugins \li \subpage org_mitk_views_basicimageprocessing \li \subpage org_mitk_views_datamanager \li \subpage org_mitk_views_properties \li \subpage org_mitk_editors_dicombrowser - \li \subpage org_mitk_gui_qt_dicominspector + \li \subpage org_mitk_views_dicominspector \li \subpage org_mitk_views_imagecropper \li \subpage org_mitk_views_imagenavigator \li \subpage org_blueberry_views_logview \li \subpage org_mitk_gui_qt_matchpoint_algorithm_batch \li \subpage org_mitk_views_matchpoint_algorithm_browser \li \subpage org_mitk_views_matchpoint_algorithm_control \li \subpage org_mitk_views_matchpoint_evaluator \li \subpage org_mitk_views_matchpoint_framereg \li \subpage org_mitk_views_matchpoint_manipulator \li \subpage org_mitk_views_matchpoint_mapper \li \subpage org_mitk_views_matchpoint_visualizer \li \subpage org_mitk_gui_qt_measurementtoolbox \li \subpage org_mitk_views_moviemaker \li \subpage org_mitk_views_multilabelsegmentation \li \subpage org_mitk_views_pointsetinteraction - \li \subpage org_mitk_gui_qt_python - \li \subpage org_mitk_gui_qt_remeshing + \li \subpage org_mitk_views_python + \li \subpage org_mitk_views_qt_remeshing \li \subpage org_mitk_views_screenshotmaker \li \subpage org_mitk_views_segmentation \li \subpage org_mitk_gui_qt_flow_segmentation - \li \subpage org_mitk_gui_qt_viewnavigator + \li \subpage org_mitk_views_viewnavigatorview \li \subpage org_mitk_views_volumevisualization */ diff --git a/Documentation/Doxygen/2-UserManual/MITKPluginManualsList.dox b/Documentation/Doxygen/2-UserManual/MITKPluginManualsList.dox index 133bb9f5ab..2bcc3ca505 100644 --- a/Documentation/Doxygen/2-UserManual/MITKPluginManualsList.dox +++ b/Documentation/Doxygen/2-UserManual/MITKPluginManualsList.dox @@ -1,84 +1,82 @@ /** \page PluginListPage MITK Plugin Manuals The plugins and bundles provide much of the extended functionality of MITK. Each encapsulates a solution to a problem and associated features. This way one can easily assemble the necessary capabilites for a workflow without adding a lot of bloat, by combining plugins as needed. - \subpage PluginListGeneralPage \subpage PluginListSpecificPage - */ diff --git a/Documentation/Doxygen/2-UserManual/MITKPluginSpecificManualsList.dox b/Documentation/Doxygen/2-UserManual/MITKPluginSpecificManualsList.dox index ebc2b9753a..c30e4932d9 100644 --- a/Documentation/Doxygen/2-UserManual/MITKPluginSpecificManualsList.dox +++ b/Documentation/Doxygen/2-UserManual/MITKPluginSpecificManualsList.dox @@ -1,45 +1,46 @@ /** \page PluginListSpecificPage List of Application-specific Plugins \li \subpage org_mitk_gui_qt_aicpregistration \li \subpage org_mitk_gui_qt_cest \li \subpage org_mitk_gui_qt_classificationsegmentation \li \subpage org_mitk_gui_qt_flowapplication \li \subpage org_mitk_views_cmdlinemodules \li \subpage org_mitk_views_pharmacokinetics_concentration_mri \li \subpage org_mitk_views_pharmacokinetics_mri \li \subpage org_mitk_views_pharmacokinetics_pet + \li \subpage org_mitk_views_pharmacokinetics_simulation \li \subpage org_mitk_gui_qt_eventrecorder \li \subpage org_mitk_gui_qt_examples \li \subpage org_mitk_gui_qt_geometrytools \li \subpage org_mitk_gui_qt_igtexample \li \subpage org_mitk_gui_qt_igtlplugin \li \subpage org_mitk_gui_qt_igttracking \li \subpage org_mitk_views_igttrackingsemiautomaticmeasurement \li \subpage org_mitk_views_imagestatistics \li \subpage org_mitk_gui_qt_lasercontrol \li \subpage org_mitk_views_fit_demo - \li \subpage org_mitk_gui_qt_fit_genericfitting + \li \subpage org_mitk_views_fit_genericfitting \li \subpage org_mitk_views_fit_inspector \li \subpage org_mitkexamplesopencv \li \subpage org_mitk_gui_qt_overlaymanager \li \subpage org_mitk_gui_qt_mitkphenotyping \li \subpage org_mitk_gui_qt_photoacoustics_pausmotioncompensation \li \subpage org_mitk_example_gui_pcaexample \li \subpage org_mitk_gui_qt_preprocessing_resampling \li \subpage org_mitk_views_pharmacokinetics_curvedescriptor \li \subpage org_mitk_views_photoacoustics_imageprocessing \li \subpage org_mitk_gui_qt_pharmacokinetics_simulation \li \subpage org_mitk_gui_qt_pointsetinteractionmultispectrum \li \subpage org_mitk_gui_qt_renderwindowmanager \li \subpage org_mitk_gui_qt_photoacoustics_spectralunmixing \li \subpage org_mitk_gui_qt_spectrocamrecorder \li \subpage org_surfacematerialeditor \li \subpage org_blueberry_ui_qt_objectinspector \li \subpage org_toftutorial \li \subpage org_mitk_gui_qt_ultrasound \li \subpage org_mitk_gui_qt_igt_app_echotrack \li \subpage org_mitk_gui_qt_xnat -*/ \ No newline at end of file +*/ diff --git a/Plugins/org.mitk.gui.qt.cest/src/internal/QmitkCESTNormalizeView.cpp b/Plugins/org.mitk.gui.qt.cest/src/internal/QmitkCESTNormalizeView.cpp index 6ff6b43f96..7a9de6b733 100644 --- a/Plugins/org.mitk.gui.qt.cest/src/internal/QmitkCESTNormalizeView.cpp +++ b/Plugins/org.mitk.gui.qt.cest/src/internal/QmitkCESTNormalizeView.cpp @@ -1,110 +1,110 @@ /*============================================================================ 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 "QmitkCESTNormalizeView.h" #include #include "mitkWorkbenchUtil.h" #include "mitkNodePredicateAnd.h" #include "mitkNodePredicateDataProperty.h" #include "mitkNodePredicateDataType.h" #include "QmitkDataStorageComboBoxWithSelectNone.h" #include #include "mitkCESTImageNormalizationFilter.h" #include "mitkCESTPropertyHelper.h" #include "mitkCESTImageDetectionHelper.h" -const std::string QmitkCESTNormalizeView::VIEW_ID = "org.mitk.gui.qt.cest.normalize"; +const std::string QmitkCESTNormalizeView::VIEW_ID = "org.mitk.views.cest.normalization"; void QmitkCESTNormalizeView::SetFocus() { m_Controls.btnNormalize->setFocus(); } void QmitkCESTNormalizeView::CreateQtPartControl(QWidget* parent) { m_Controls.setupUi(parent); m_Controls.btnNormalize->setEnabled(false); m_Controls.comboCESTImage->SetPredicate(this->m_IsCESTImagePredicate); m_Controls.comboCESTImage->SetDataStorage(this->GetDataStorage()); connect(m_Controls.btnNormalize, SIGNAL(clicked()), this, SLOT(OnNormalizeButtonClicked())); connect(m_Controls.comboCESTImage, SIGNAL(OnSelectionChanged(const mitk::DataNode *)), this, SLOT(UpdateGUIControls())); UpdateGUIControls(); } void QmitkCESTNormalizeView::UpdateGUIControls() { m_Controls.btnNormalize->setEnabled(m_Controls.comboCESTImage->GetSelectedNode().IsNotNull()); } void QmitkCESTNormalizeView::OnNormalizeButtonClicked() { auto selectedImageNode = m_Controls.comboCESTImage->GetSelectedNode(); if (!selectedImageNode) { MITK_ERROR << "Invalid system state. CEST selection is invalid. Selected node is null_ptr."; return; } auto selectedImage = dynamic_cast(selectedImageNode->GetData()); if (!selectedImageNode) { MITK_ERROR << "Invalid system state. CEST selection is invalid. Selected node is not an image."; return; } std::string offsetsStr = ""; bool hasOffsets = selectedImage->GetPropertyList()->GetStringProperty(mitk::CEST_PROPERTY_NAME_OFFSETS().c_str(), offsetsStr); if (!hasOffsets) { QMessageBox::information(nullptr, "CEST normalization", "Selected image was missing CEST offset information."); return; } if (!mitk::IsNotNormalizedCESTImage(selectedImage)) { QMessageBox::information(nullptr, "CEST normalization", "Selected image already seems to be normalized."); return; } if (selectedImage->GetDimension() == 4) { auto normalizationFilter = mitk::CESTImageNormalizationFilter::New(); normalizationFilter->SetInput(selectedImage); normalizationFilter->Update(); auto resultImage = normalizationFilter->GetOutput(); mitk::DataNode::Pointer dataNode = mitk::DataNode::New(); dataNode->SetData(resultImage); std::string normalizedName = selectedImageNode->GetName() + "_normalized"; dataNode->SetName(normalizedName); this->GetDataStorage()->Add(dataNode); } } QmitkCESTNormalizeView::QmitkCESTNormalizeView() { auto isImage = mitk::NodePredicateDataType::New("Image"); this->m_IsCESTImagePredicate = mitk::NodePredicateAnd::New(isImage, mitk::CreateAnyCESTImageNodePredicate()).GetPointer(); } diff --git a/Plugins/org.mitk.gui.qt.cest/src/internal/QmitkCESTStatisticsView.cpp b/Plugins/org.mitk.gui.qt.cest/src/internal/QmitkCESTStatisticsView.cpp index 2b8c2c96bf..5f913cf2a3 100644 --- a/Plugins/org.mitk.gui.qt.cest/src/internal/QmitkCESTStatisticsView.cpp +++ b/Plugins/org.mitk.gui.qt.cest/src/internal/QmitkCESTStatisticsView.cpp @@ -1,815 +1,815 @@ /*============================================================================ 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. ============================================================================*/ // itk #include "itksys/SystemTools.hxx" #include #include // Blueberry #include #include // Qmitk #include "QmitkCESTStatisticsView.h" // Qt #include #include // qwt #include // mitk #include #include #include #include #include #include #include #include #include #include #include #include #include // boost #include #include // stl #include #include #include #include #include #include namespace { template void GetSortPermutation(std::vector &out, const std::vector &determiningVector, Compare compare = std::less()) { out.resize(determiningVector.size()); std::iota(out.begin(), out.end(), 0); std::sort(out.begin(), out.end(), [&](unsigned i, unsigned j) { return compare(determiningVector[i], determiningVector[j]); }); } template void ApplyPermutation(const std::vector &order, std::vector &vectorToSort) { assert(order.size() == vectorToSort.size()); std::vector tempVector(vectorToSort.size()); for (unsigned i = 0; i < vectorToSort.size(); i++) { tempVector[i] = vectorToSort[order[i]]; } vectorToSort = tempVector; } template void ApplyPermutation(const std::vector &order, std::vector ¤tVector, std::vector &... remainingVectors) { ApplyPermutation(order, currentVector); ApplyPermutation(order, remainingVectors...); } template void SortVectors(const std::vector &orderDeterminingVector, Compare comparison, std::vector &... vectorsToBeSorted) { std::vector order; GetSortPermutation(order, orderDeterminingVector, comparison); ApplyPermutation(order, vectorsToBeSorted...); } } // namespace -const std::string QmitkCESTStatisticsView::VIEW_ID = "org.mitk.views.ceststatistics"; +const std::string QmitkCESTStatisticsView::VIEW_ID = "org.mitk.views.cest.statistics"; QmitkCESTStatisticsView::QmitkCESTStatisticsView(QObject * /*parent*/, const char * /*name*/) { this->m_CalculatorJob = new QmitkImageStatisticsCalculationJob(); m_currentSelectedPosition.Fill(0.0); m_currentSelectedTimePoint = 0.; m_CrosshairPointSet = mitk::PointSet::New(); } QmitkCESTStatisticsView::~QmitkCESTStatisticsView() { while (this->m_CalculatorJob->isRunning()) // wait until thread has finished { itksys::SystemTools::Delay(100); } delete this->m_CalculatorJob; } void QmitkCESTStatisticsView::SetFocus() { m_Controls.threeDimToFourDimPushButton->setFocus(); } void QmitkCESTStatisticsView::CreateQtPartControl(QWidget *parent) { // create GUI widgets from the Qt Designer's .ui file m_Controls.setupUi(parent); connect( m_Controls.threeDimToFourDimPushButton, SIGNAL(clicked()), this, SLOT(OnThreeDimToFourDimPushButtonClicked())); connect((QObject *)this->m_CalculatorJob, SIGNAL(finished()), this, SLOT(OnThreadedStatisticsCalculationEnds()), Qt::QueuedConnection); connect((QObject *)(this->m_Controls.fixedRangeCheckBox), SIGNAL(toggled(bool)), (QObject *)this, SLOT(OnFixedRangeCheckBoxToggled(bool))); connect((QObject *)(this->m_Controls.fixedRangeLowerDoubleSpinBox), SIGNAL(editingFinished()), (QObject *)this, SLOT(OnFixedRangeDoubleSpinBoxChanged())); connect((QObject *)(this->m_Controls.fixedRangeUpperDoubleSpinBox), SIGNAL(editingFinished()), (QObject *)this, SLOT(OnFixedRangeDoubleSpinBoxChanged())); m_Controls.threeDimToFourDimPushButton->setEnabled(false); m_Controls.widget_statistics->SetDataStorage(this->GetDataStorage()); this->m_SliceChangeListener.RenderWindowPartActivated(this->GetRenderWindowPart()); connect(&m_SliceChangeListener, SIGNAL(SliceChanged()), this, SLOT(OnSliceChanged())); } void QmitkCESTStatisticsView::RenderWindowPartActivated(mitk::IRenderWindowPart *renderWindowPart) { this->m_SliceChangeListener.RenderWindowPartActivated(renderWindowPart); } void QmitkCESTStatisticsView::RenderWindowPartDeactivated(mitk::IRenderWindowPart *renderWindowPart) { this->m_SliceChangeListener.RenderWindowPartDeactivated(renderWindowPart); } void QmitkCESTStatisticsView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*source*/, const QList &nodes) { if (nodes.empty()) { std::stringstream message; message << "Please select an image."; m_Controls.labelWarning->setText(message.str().c_str()); m_Controls.labelWarning->show(); this->Clear(); return; } // iterate all selected objects bool atLeastOneWasCESTImage = false; foreach (mitk::DataNode::Pointer node, nodes) { if (node.IsNull()) { continue; } if (dynamic_cast(node->GetData()) != nullptr) { m_Controls.labelWarning->setVisible(false); bool zSpectrumSet = SetZSpectrum(dynamic_cast( node->GetData()->GetProperty(mitk::CEST_PROPERTY_NAME_OFFSETS().c_str()).GetPointer())); atLeastOneWasCESTImage = atLeastOneWasCESTImage || zSpectrumSet; if (zSpectrumSet) { m_ZImage = dynamic_cast(node->GetData()); m_Controls.widget_statistics->SetImageNodes({node.GetPointer()}); } else { m_MaskImage = dynamic_cast(node->GetData()); m_Controls.widget_statistics->SetMaskNodes({node.GetPointer()}); } } if (dynamic_cast(node->GetData()) != nullptr) { m_MaskPlanarFigure = dynamic_cast(node->GetData()); m_Controls.widget_statistics->SetMaskNodes({node.GetPointer()}); } if (dynamic_cast(node->GetData()) != nullptr) { m_PointSet = dynamic_cast(node->GetData()); } } // We only want to offer normalization or timestep copying if one object is selected if (nodes.size() == 1) { if (dynamic_cast(nodes.front()->GetData())) { m_Controls.threeDimToFourDimPushButton->setDisabled(atLeastOneWasCESTImage); } else { m_Controls.threeDimToFourDimPushButton->setEnabled(false); std::stringstream message; message << "The selected node is not an image."; m_Controls.labelWarning->setText(message.str().c_str()); m_Controls.labelWarning->show(); } this->Clear(); return; } // we always need a mask, either image or planar figure as well as an image for further processing if (nodes.size() != 2) { this->Clear(); return; } m_Controls.threeDimToFourDimPushButton->setEnabled(false); if (!atLeastOneWasCESTImage) { std::stringstream message; message << "None of the selected data nodes contains required CEST meta information"; m_Controls.labelWarning->setText(message.str().c_str()); m_Controls.labelWarning->show(); this->Clear(); return; } bool bothAreImages = (m_ZImage.GetPointer() != nullptr) && (m_MaskImage.GetPointer() != nullptr); if (bothAreImages) { bool geometriesMatch = mitk::Equal(*(m_ZImage->GetTimeGeometry()), *(m_MaskImage->GetTimeGeometry()), mitk::eps, false); if (!geometriesMatch) { std::stringstream message; message << "The selected images have different geometries."; m_Controls.labelWarning->setText(message.str().c_str()); m_Controls.labelWarning->show(); this->Clear(); return; } } if (!this->DataSanityCheck()) { this->Clear(); return; } if (m_PointSet.IsNull()) { // initialize thread and trigger it this->m_CalculatorJob->SetIgnoreZeroValueVoxel(false); this->m_CalculatorJob->Initialize(m_ZImage.GetPointer(), m_MaskImage.GetPointer(), m_MaskPlanarFigure.GetPointer()); std::stringstream message; message << "Calculating statistics..."; m_Controls.labelWarning->setText(message.str().c_str()); m_Controls.labelWarning->show(); try { // Compute statistics this->m_CalculatorJob->start(); } catch (const mitk::Exception &e) { std::stringstream message; message << "" << e.GetDescription() << ""; m_Controls.labelWarning->setText(message.str().c_str()); m_Controls.labelWarning->show(); } catch (const std::runtime_error &e) { // In case of exception, print error message on GUI std::stringstream message; message << "" << e.what() << ""; m_Controls.labelWarning->setText(message.str().c_str()); m_Controls.labelWarning->show(); } catch (const std::exception &e) { MITK_ERROR << "Caught exception: " << e.what(); // In case of exception, print error message on GUI std::stringstream message; message << "Error! Unequal Dimensions of Image and Segmentation. No recompute possible "; m_Controls.labelWarning->setText(message.str().c_str()); m_Controls.labelWarning->show(); } while (this->m_CalculatorJob->isRunning()) // wait until thread has finished { itksys::SystemTools::Delay(100); } } if (m_PointSet.IsNotNull()) { if (m_ZImage->GetDimension() == 4) { AccessFixedDimensionByItk(m_ZImage, PlotPointSet, 4); } else { MITK_WARN << "Expecting a 4D image."; } } } void QmitkCESTStatisticsView::OnThreadedStatisticsCalculationEnds() { this->m_Controls.m_DataViewWidget->SetAxisTitle(QwtPlot::Axis::xBottom, "delta w"); this->m_Controls.m_DataViewWidget->SetAxisTitle(QwtPlot::Axis::yLeft, "z"); if (this->m_CalculatorJob->GetStatisticsUpdateSuccessFlag()) { auto statistics = this->m_CalculatorJob->GetStatisticsData(); std::string statisticsNodeName = "CEST_statistics"; auto statisticsNode = mitk::CreateImageStatisticsNode(statistics, statisticsNodeName); auto imageRule = mitk::StatisticsToImageRelationRule::New(); imageRule->Connect(statistics, m_CalculatorJob->GetStatisticsImage()); if (m_CalculatorJob->GetMaskImage()) { auto maskRule = mitk::StatisticsToMaskRelationRule::New(); maskRule->Connect(statistics, m_CalculatorJob->GetMaskImage()); } else if (m_CalculatorJob->GetPlanarFigure()) { auto planarFigureRule = mitk::StatisticsToMaskRelationRule::New(); planarFigureRule->Connect(statistics, m_CalculatorJob->GetPlanarFigure()); } this->GetDataStorage()->Add(statisticsNode); QmitkPlotWidget::DataVector::size_type numberOfSpectra = this->m_zSpectrum.size(); QmitkPlotWidget::DataVector means(numberOfSpectra); QmitkPlotWidget::DataVector stdevs(numberOfSpectra); for (unsigned int index = 0; index < numberOfSpectra; ++index) { means[index] = statistics->GetStatisticsForTimeStep(index).GetValueConverted( mitk::ImageStatisticsConstants::MEAN()); stdevs[index] = statistics->GetStatisticsForTimeStep(index).GetValueConverted( mitk::ImageStatisticsConstants::STANDARDDEVIATION()); } QmitkPlotWidget::DataVector xValues = this->m_zSpectrum; RemoveMZeros(xValues, means, stdevs); ::SortVectors(xValues, std::less(), xValues, means, stdevs); unsigned int curveId = this->m_Controls.m_DataViewWidget->InsertCurve("Spectrum"); this->m_Controls.m_DataViewWidget->SetCurveData(curveId, xValues, means, stdevs, stdevs); this->m_Controls.m_DataViewWidget->SetErrorPen(curveId, QPen(Qt::blue)); QwtSymbol *blueSymbol = new QwtSymbol(QwtSymbol::Rect, QColor(Qt::blue), QColor(Qt::blue), QSize(8, 8)); this->m_Controls.m_DataViewWidget->SetCurveSymbol(curveId, blueSymbol); this->m_Controls.m_DataViewWidget->SetLegendAttribute(curveId, QwtPlotCurve::LegendShowSymbol); QwtLegend *legend = new QwtLegend(); legend->setFrameShape(QFrame::Box); legend->setFrameShadow(QFrame::Sunken); legend->setLineWidth(1); this->m_Controls.m_DataViewWidget->SetLegend(legend, QwtPlot::BottomLegend); m_Controls.m_DataViewWidget->GetPlot() ->axisScaleEngine(QwtPlot::Axis::xBottom) ->setAttributes(QwtScaleEngine::Inverted); this->m_Controls.m_DataViewWidget->Replot(); m_Controls.labelWarning->setVisible(false); m_Controls.m_StatisticsGroupBox->setEnabled(true); m_Controls.m_StatisticsGroupBox->setEnabled(true); if (this->m_Controls.fixedRangeCheckBox->isChecked()) { this->m_Controls.m_DataViewWidget->GetPlot()->setAxisAutoScale(2, false); this->m_Controls.m_DataViewWidget->GetPlot()->setAxisScale( 2, this->m_Controls.fixedRangeLowerDoubleSpinBox->value(), this->m_Controls.fixedRangeUpperDoubleSpinBox->value()); } else { this->m_Controls.m_DataViewWidget->GetPlot()->setAxisAutoScale(2, true); } } else { m_Controls.labelWarning->setText(m_CalculatorJob->GetLastErrorMessage().c_str()); m_Controls.labelWarning->setVisible(true); this->Clear(); } } void QmitkCESTStatisticsView::OnFixedRangeDoubleSpinBoxChanged() { if (this->m_Controls.fixedRangeCheckBox->isChecked()) { this->m_Controls.m_DataViewWidget->GetPlot()->setAxisAutoScale(2, false); this->m_Controls.m_DataViewWidget->GetPlot()->setAxisScale(2, this->m_Controls.fixedRangeLowerDoubleSpinBox->value(), this->m_Controls.fixedRangeUpperDoubleSpinBox->value()); } this->m_Controls.m_DataViewWidget->Replot(); } template void QmitkCESTStatisticsView::PlotPointSet(itk::Image *image) { this->m_Controls.m_DataViewWidget->SetAxisTitle(QwtPlot::Axis::xBottom, "delta w"); this->m_Controls.m_DataViewWidget->SetAxisTitle(QwtPlot::Axis::yLeft, "z"); QmitkPlotWidget::DataVector::size_type numberOfSpectra = this->m_zSpectrum.size(); mitk::PointSet::Pointer internalPointset; if (m_PointSet.IsNotNull()) { internalPointset = m_PointSet; } else { internalPointset = m_CrosshairPointSet; } if (internalPointset.IsNull()) { return; } if (!this->DataSanityCheck()) { m_Controls.labelWarning->setText("Data can not be plotted, internally inconsistent."); m_Controls.labelWarning->show(); return; } auto maxIndex = internalPointset->GetMaxId().Index(); for (std::size_t number = 0; number < maxIndex + 1; ++number) { mitk::PointSet::PointType point; if (!internalPointset->GetPointIfExists(number, &point)) { continue; } if (!this->m_ZImage->GetGeometry()->IsInside(point)) { continue; } itk::Index<3> itkIndex; this->m_ZImage->GetGeometry()->WorldToIndex(point, itkIndex); itk::Index itkIndexTime; itkIndexTime[0] = itkIndex[0]; itkIndexTime[1] = itkIndex[1]; itkIndexTime[2] = itkIndex[2]; QmitkPlotWidget::DataVector values(numberOfSpectra); for (std::size_t step = 0; step < numberOfSpectra; ++step) { if (VImageDimension == 4) { itkIndexTime[3] = step; } values[step] = image->GetPixel(itkIndexTime); } std::stringstream name; name << "Point " << number; // Qcolor enums go from 0 to 19, but 19 is transparent and 0,1 are for bitmaps // 3 is white and thus not visible QColor color(static_cast(number % 17 + 4)); QmitkPlotWidget::DataVector xValues = this->m_zSpectrum; RemoveMZeros(xValues, values); ::SortVectors(xValues, std::less(), xValues, values); unsigned int curveId = this->m_Controls.m_DataViewWidget->InsertCurve(name.str().c_str()); this->m_Controls.m_DataViewWidget->SetCurveData(curveId, xValues, values); this->m_Controls.m_DataViewWidget->SetCurvePen(curveId, QPen(color)); QwtSymbol *symbol = new QwtSymbol(QwtSymbol::Rect, color, color, QSize(8, 8)); this->m_Controls.m_DataViewWidget->SetCurveSymbol(curveId, symbol); this->m_Controls.m_DataViewWidget->SetLegendAttribute(curveId, QwtPlotCurve::LegendShowSymbol); } if (this->m_Controls.fixedRangeCheckBox->isChecked()) { this->m_Controls.m_DataViewWidget->GetPlot()->setAxisAutoScale(2, false); this->m_Controls.m_DataViewWidget->GetPlot()->setAxisScale(2, this->m_Controls.fixedRangeLowerDoubleSpinBox->value(), this->m_Controls.fixedRangeUpperDoubleSpinBox->value()); } else { this->m_Controls.m_DataViewWidget->GetPlot()->setAxisAutoScale(2, true); } QwtLegend *legend = new QwtLegend(); legend->setFrameShape(QFrame::Box); legend->setFrameShadow(QFrame::Sunken); legend->setLineWidth(1); this->m_Controls.m_DataViewWidget->SetLegend(legend, QwtPlot::BottomLegend); m_Controls.m_DataViewWidget->GetPlot() ->axisScaleEngine(QwtPlot::Axis::xBottom) ->setAttributes(QwtScaleEngine::Inverted); this->m_Controls.m_DataViewWidget->Replot(); m_Controls.labelWarning->setVisible(false); } void QmitkCESTStatisticsView::OnFixedRangeCheckBoxToggled(bool state) { this->m_Controls.fixedRangeLowerDoubleSpinBox->setEnabled(state); this->m_Controls.fixedRangeUpperDoubleSpinBox->setEnabled(state); } void QmitkCESTStatisticsView::RemoveMZeros(QmitkPlotWidget::DataVector &xValues, QmitkPlotWidget::DataVector &yValues) { QmitkPlotWidget::DataVector tempX; QmitkPlotWidget::DataVector tempY; for (std::size_t index = 0; index < xValues.size(); ++index) { if ((xValues.at(index) < -299) || (xValues.at(index)) > 299) { // do not include } else { tempX.push_back(xValues.at(index)); tempY.push_back(yValues.at(index)); } } xValues = tempX; yValues = tempY; } void QmitkCESTStatisticsView::RemoveMZeros(QmitkPlotWidget::DataVector &xValues, QmitkPlotWidget::DataVector &yValues, QmitkPlotWidget::DataVector &stdDevs) { QmitkPlotWidget::DataVector tempX; QmitkPlotWidget::DataVector tempY; QmitkPlotWidget::DataVector tempDevs; for (std::size_t index = 0; index < xValues.size(); ++index) { if ((xValues.at(index) < -299) || (xValues.at(index)) > 299) { // do not include } else { tempX.push_back(xValues.at(index)); tempY.push_back(yValues.at(index)); tempDevs.push_back(stdDevs.at(index)); } } xValues = tempX; yValues = tempY; stdDevs = tempDevs; } void QmitkCESTStatisticsView::OnThreeDimToFourDimPushButtonClicked() { QList nodes = this->GetDataManagerSelection(); if (nodes.empty()) return; mitk::DataNode *node = nodes.front(); if (!node) { // Nothing selected. Inform the user and return QMessageBox::information(nullptr, "CEST View", "Please load and select an image before starting image processing."); return; } // here we have a valid mitk::DataNode // a node itself is not very useful, we need its data item (the image) mitk::BaseData *data = node->GetData(); if (data) { // test if this data item is an image or not (could also be a surface or something totally different) mitk::Image *image = dynamic_cast(data); if (image) { if (image->GetDimension() == 4) { AccessFixedDimensionByItk(image, CopyTimesteps, 4); } this->Clear(); } } } template void QmitkCESTStatisticsView::CopyTimesteps(itk::Image *image) { typedef itk::Image ImageType; // typedef itk::PasteImageFilter PasteImageFilterType; unsigned int numberOfTimesteps = image->GetLargestPossibleRegion().GetSize(3); typename ImageType::RegionType sourceRegion = image->GetLargestPossibleRegion(); sourceRegion.SetSize(3, 1); typename ImageType::RegionType targetRegion = image->GetLargestPossibleRegion(); targetRegion.SetSize(3, 1); for (unsigned int timestep = 1; timestep < numberOfTimesteps; ++timestep) { targetRegion.SetIndex(3, timestep); itk::ImageRegionConstIterator sourceIterator(image, sourceRegion); itk::ImageRegionIterator targetIterator(image, targetRegion); while (!sourceIterator.IsAtEnd()) { targetIterator.Set(sourceIterator.Get()); ++sourceIterator; ++targetIterator; } } } bool QmitkCESTStatisticsView::SetZSpectrum(mitk::StringProperty *zSpectrumProperty) { if (zSpectrumProperty == nullptr) { return false; } mitk::LocaleSwitch localeSwitch("C"); std::string zSpectrumString = zSpectrumProperty->GetValueAsString(); std::istringstream iss(zSpectrumString); std::vector zSpectra; std::copy( std::istream_iterator(iss), std::istream_iterator(), std::back_inserter(zSpectra)); m_zSpectrum.clear(); m_zSpectrum.resize(0); for (auto const &spectrumString : zSpectra) { m_zSpectrum.push_back(std::stod(spectrumString)); } return (m_zSpectrum.size() > 0); } bool QmitkCESTStatisticsView::DataSanityCheck() { QmitkPlotWidget::DataVector::size_type numberOfSpectra = m_zSpectrum.size(); // if we do not have a spectrum, the data can not be processed if (numberOfSpectra == 0) { return false; } // if we do not have CEST image data, the data can not be processed if (m_ZImage.IsNull()) { return false; } // if the CEST image data and the meta information do not match, the data can not be processed if (numberOfSpectra != m_ZImage->GetTimeSteps()) { MITK_INFO << "CEST meta information and number of volumes does not match."; return false; } // if we have neither a mask image, a point set nor a mask planar figure, we can not do statistics // statistics on the whole image would not make sense if (m_MaskImage.IsNull() && m_MaskPlanarFigure.IsNull() && m_PointSet.IsNull() && m_CrosshairPointSet->IsEmpty()) { return false; } // if we have a mask image and a mask planar figure, we can not do statistics // we do not know which one to use if (m_MaskImage.IsNotNull() && m_MaskPlanarFigure.IsNotNull()) { return false; } return true; } void QmitkCESTStatisticsView::Clear() { this->m_zSpectrum.clear(); this->m_zSpectrum.resize(0); this->m_ZImage = nullptr; this->m_MaskImage = nullptr; this->m_MaskPlanarFigure = nullptr; this->m_PointSet = nullptr; this->m_Controls.m_DataViewWidget->Clear(); this->m_Controls.m_StatisticsGroupBox->setEnabled(false); this->m_Controls.widget_statistics->SetImageNodes({}); this->m_Controls.widget_statistics->SetMaskNodes({}); } void QmitkCESTStatisticsView::OnSliceChanged() { mitk::Point3D currentSelectedPosition = this->GetRenderWindowPart()->GetSelectedPosition(nullptr); mitk::TimePointType currentSelectedTimePoint = this->GetRenderWindowPart()->GetSelectedTimePoint(); if (m_currentSelectedPosition != currentSelectedPosition || currentSelectedTimePoint != currentSelectedTimePoint) //|| m_selectedNodeTime > m_currentPositionTime) { // the current position has been changed or the selected node has been changed since the last position validation -> // check position m_currentSelectedPosition = currentSelectedPosition; m_currentSelectedTimePoint = currentSelectedTimePoint; m_currentPositionTime.Modified(); m_CrosshairPointSet->Clear(); m_CrosshairPointSet->SetPoint(0, m_currentSelectedPosition); QList nodes = this->GetDataManagerSelection(); if (nodes.empty() || nodes.size() > 1) return; mitk::DataNode *node = nodes.front(); if (!node) { return; } if (dynamic_cast(node->GetData()) != nullptr) { m_Controls.labelWarning->setVisible(false); bool zSpectrumSet = SetZSpectrum(dynamic_cast( node->GetData()->GetProperty(mitk::CEST_PROPERTY_NAME_OFFSETS().c_str()).GetPointer())); if (zSpectrumSet) { m_ZImage = dynamic_cast(node->GetData()); } else { return; } } else { return; } this->m_Controls.m_DataViewWidget->Clear(); AccessFixedDimensionByItk(m_ZImage, PlotPointSet, 4); } } diff --git a/Plugins/org.mitk.gui.qt.cmdlinemodules/src/internal/CommandLineModulesViewConstants.cpp b/Plugins/org.mitk.gui.qt.cmdlinemodules/src/internal/CommandLineModulesViewConstants.cpp index 8b2532e75e..6b63d6c35e 100644 --- a/Plugins/org.mitk.gui.qt.cmdlinemodules/src/internal/CommandLineModulesViewConstants.cpp +++ b/Plugins/org.mitk.gui.qt.cmdlinemodules/src/internal/CommandLineModulesViewConstants.cpp @@ -1,31 +1,31 @@ /*============================================================================ 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 "CommandLineModulesViewConstants.h" -const QString CommandLineModulesViewConstants::VIEW_ID = "org.mitk.gui.qt.cmdlinemodules"; +const QString CommandLineModulesViewConstants::VIEW_ID = "org.mitk.views.cmdlinemodules"; const QString CommandLineModulesViewConstants::TEMPORARY_DIRECTORY_NODE_NAME = "temporary directory"; const QString CommandLineModulesViewConstants::OUTPUT_DIRECTORY_NODE_NAME = "output directory"; const QString CommandLineModulesViewConstants::MODULE_DIRECTORIES_NODE_NAME = "module directories"; const QString CommandLineModulesViewConstants::MODULE_FILES_NODE_NAME = "module files"; const QString CommandLineModulesViewConstants::DEBUG_OUTPUT_NODE_NAME = "debug output"; const QString CommandLineModulesViewConstants::LOAD_FROM_APPLICATION_DIR = "load from application dir"; const QString CommandLineModulesViewConstants::LOAD_FROM_HOME_DIR = "load from home dir"; const QString CommandLineModulesViewConstants::LOAD_FROM_CURRENT_DIR = "load from current dir"; const QString CommandLineModulesViewConstants::LOAD_FROM_AUTO_LOAD_DIR = "load from auto-load dir"; const QString CommandLineModulesViewConstants::LOAD_FROM_APPLICATION_DIR_CLI_MODULES = "load from application dir/cli-modules"; const QString CommandLineModulesViewConstants::LOAD_FROM_HOME_DIR_CLI_MODULES = "load from home dir/cli-modules"; const QString CommandLineModulesViewConstants::LOAD_FROM_CURRENT_DIR_CLI_MODULES = "load from current dir/cli-modules"; const QString CommandLineModulesViewConstants::XML_VALIDATION_MODE = "xml validation mode"; const QString CommandLineModulesViewConstants::XML_TIMEOUT_SECS = "xml time-out"; const QString CommandLineModulesViewConstants::MAX_CONCURRENT = "max concurrent processes"; const QString CommandLineModulesViewConstants::SHOW_ADVANCED_WIDGETS_NAME = "show advanced widgets"; diff --git a/Plugins/org.mitk.gui.qt.dicominspector/documentation/UserManual/Manual.dox b/Plugins/org.mitk.gui.qt.dicominspector/documentation/UserManual/Manual.dox index f45e70d5e1..e1305a43b8 100644 --- a/Plugins/org.mitk.gui.qt.dicominspector/documentation/UserManual/Manual.dox +++ b/Plugins/org.mitk.gui.qt.dicominspector/documentation/UserManual/Manual.dox @@ -1,12 +1,12 @@ /** -\page org_mitk_gui_qt_dicominspector The DICOM Inspector +\page org_mitk_views_dicominspector The DICOM Inspector \imageMacro{ "inspector.png", "Icon of DICOM Inspector", 2} This is a simple view that displays all DICOM properties of the data of the currently selected node. DICOM properties are all properties that have a property name starting with "DICOM". The plugin will show the dicom values corresponding to the currently selected time point and z slice. E.G. the value of "acquesition time" will change with changing the time step of 3d+t image or the value of "slice position" will change with changing the current z slice of the image. */ diff --git a/Plugins/org.mitk.gui.qt.dicominspector/plugin.xml b/Plugins/org.mitk.gui.qt.dicominspector/plugin.xml index dde8b4b9d1..8da249251b 100644 --- a/Plugins/org.mitk.gui.qt.dicominspector/plugin.xml +++ b/Plugins/org.mitk.gui.qt.dicominspector/plugin.xml @@ -1,10 +1,10 @@ - diff --git a/Plugins/org.mitk.gui.qt.dicominspector/src/internal/QmitkDicomInspectorView.cpp b/Plugins/org.mitk.gui.qt.dicominspector/src/internal/QmitkDicomInspectorView.cpp index 8400fd4978..531f020f2b 100644 --- a/Plugins/org.mitk.gui.qt.dicominspector/src/internal/QmitkDicomInspectorView.cpp +++ b/Plugins/org.mitk.gui.qt.dicominspector/src/internal/QmitkDicomInspectorView.cpp @@ -1,376 +1,376 @@ /*============================================================================ 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. ============================================================================*/ // Blueberry #include #include #include // mitk #include #include #include // Qt #include #include #include #include #include "QmitkDicomInspectorView.h" -const std::string QmitkDicomInspectorView::VIEW_ID = "org.mitk.gui.qt.dicominspector"; +const std::string QmitkDicomInspectorView::VIEW_ID = "org.mitk.views.dicominspector"; QmitkDicomInspectorView::ObserverInfo::ObserverInfo(mitk::SliceNavigationController* controller, int observerTag, const std::string& renderWindowName, mitk::IRenderWindowPart* part) : controller(controller), observerTag(observerTag), renderWindowName(renderWindowName), renderWindowPart(part) { } QmitkDicomInspectorView::QmitkDicomInspectorView() : m_RenderWindowPart(nullptr) , m_PendingSliceChangedEvent(false) , m_SelectedNode(nullptr) , m_SelectedTimePoint(0.) , m_CurrentSelectedZSlice(0) { m_SelectedPosition.Fill(0.0); } QmitkDicomInspectorView::~QmitkDicomInspectorView() { this->RemoveAllObservers(); } void QmitkDicomInspectorView::RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) { if (m_RenderWindowPart != renderWindowPart) { m_RenderWindowPart = renderWindowPart; if (!InitObservers()) { QMessageBox::information(nullptr, "Error", "Unable to set up the event observers. The " \ "plot will not be triggered on changing the crosshair, " \ "position or time step."); } } } void QmitkDicomInspectorView::RenderWindowPartDeactivated(mitk::IRenderWindowPart* renderWindowPart) { m_RenderWindowPart = nullptr; this->RemoveAllObservers(renderWindowPart); } void QmitkDicomInspectorView::CreateQtPartControl(QWidget* parent) { // create GUI widgets from the Qt Designer's .ui file m_Controls.setupUi(parent); m_Controls.singleSlot->SetDataStorage(GetDataStorage()); m_Controls.singleSlot->SetSelectionIsOptional(true); m_Controls.singleSlot->SetEmptyInfo(QString("Please select a data node")); m_Controls.singleSlot->SetPopUpTitel(QString("Select data node")); m_SelectionServiceConnector = std::make_unique(); SetAsSelectionListener(true); m_Controls.timePointValueLabel->setText(QString("")); m_Controls.sliceNumberValueLabel->setText(QString("")); connect(m_Controls.singleSlot, &QmitkSingleNodeSelectionWidget::CurrentSelectionChanged, this, &QmitkDicomInspectorView::OnCurrentSelectionChanged); mitk::IRenderWindowPart* renderWindowPart = GetRenderWindowPart(); RenderWindowPartActivated(renderWindowPart); } bool QmitkDicomInspectorView::InitObservers() { bool result = true; typedef QHash WindowMapType; WindowMapType windowMap = m_RenderWindowPart->GetQmitkRenderWindows(); auto i = windowMap.begin(); while (i != windowMap.end()) { mitk::SliceNavigationController* sliceNavController = i.value()->GetSliceNavigationController(); if (sliceNavController) { auto cmdSliceEvent = itk::SimpleMemberCommand::New(); cmdSliceEvent->SetCallbackFunction(this, &QmitkDicomInspectorView::OnSliceChanged); int tag = sliceNavController->AddObserver( mitk::SliceNavigationController::GeometrySliceEvent(nullptr, 0), cmdSliceEvent); m_ObserverMap.insert(std::make_pair(sliceNavController, ObserverInfo(sliceNavController, tag, i.key().toStdString(), m_RenderWindowPart))); auto cmdTimeEvent = itk::SimpleMemberCommand::New(); cmdTimeEvent->SetCallbackFunction(this, &QmitkDicomInspectorView::OnSliceChanged); tag = sliceNavController->AddObserver( mitk::SliceNavigationController::GeometryTimeEvent(nullptr, 0), cmdTimeEvent); m_ObserverMap.insert(std::make_pair(sliceNavController, ObserverInfo(sliceNavController, tag, i.key().toStdString(), m_RenderWindowPart))); auto cmdDelEvent = itk::MemberCommand::New(); cmdDelEvent->SetCallbackFunction(this, &QmitkDicomInspectorView::OnSliceNavigationControllerDeleted); tag = sliceNavController->AddObserver(itk::DeleteEvent(), cmdDelEvent); m_ObserverMap.insert(std::make_pair(sliceNavController, ObserverInfo(sliceNavController, tag, i.key().toStdString(), m_RenderWindowPart))); } ++i; result = result && sliceNavController; } return result; } void QmitkDicomInspectorView::RemoveObservers(const mitk::SliceNavigationController* deletedSlicer) { std::pair obsRange = m_ObserverMap.equal_range(deletedSlicer); for (ObserverMapType::const_iterator pos = obsRange.first; pos != obsRange.second; ++pos) { pos->second.controller->RemoveObserver(pos->second.observerTag); } m_ObserverMap.erase(deletedSlicer); } void QmitkDicomInspectorView::RemoveAllObservers(mitk::IRenderWindowPart* deletedPart) { for (ObserverMapType::const_iterator pos = m_ObserverMap.begin(); pos != m_ObserverMap.end();) { ObserverMapType::const_iterator delPos = pos++; if (nullptr == deletedPart || deletedPart == delPos->second.renderWindowPart) { delPos->second.controller->RemoveObserver(delPos->second.observerTag); m_ObserverMap.erase(delPos); } } } void QmitkDicomInspectorView::OnCurrentSelectionChanged(QList nodes) { if (nodes.empty() || nodes.front().IsNull()) { m_SelectedNode = nullptr; m_SelectedData = nullptr; UpdateData(); return; } if (nodes.front() != this->m_SelectedNode) { // node is selected, create DICOM tag table m_SelectedNode = nodes.front(); m_SelectedData = this->m_SelectedNode->GetData(); m_SelectedNodeTime.Modified(); UpdateData(); OnSliceChangedDelayed(); } } void QmitkDicomInspectorView::OnSliceChanged() { // Taken from QmitkStdMultiWidget::HandleCrosshairPositionEvent(). // Since there are always 3 events arriving (one for each render window) every time the slice // or time changes, the slot OnSliceChangedDelayed is triggered - and only if it hasn't been // triggered yet - so it is only executed once for every slice/time change. if (!m_PendingSliceChangedEvent) { m_PendingSliceChangedEvent = true; QTimer::singleShot(0, this, SLOT(OnSliceChangedDelayed())); } } void QmitkDicomInspectorView::OnSliceNavigationControllerDeleted(const itk::Object* sender, const itk::EventObject& /*e*/) { auto sendingSlicer = dynamic_cast(sender); this->RemoveObservers(sendingSlicer); } void QmitkDicomInspectorView::ValidateAndSetCurrentPosition() { mitk::Point3D currentSelectedPosition = GetRenderWindowPart()->GetSelectedPosition(nullptr); const auto currentSelectedTimePoint = GetRenderWindowPart()->GetSelectedTimePoint(); if (m_SelectedPosition != currentSelectedPosition || m_SelectedTimePoint != currentSelectedTimePoint || m_SelectedNodeTime > m_CurrentPositionTime) { // the current position has been changed, the selected node has been changed since // the last position validation or the current time position has been changed -> check position m_SelectedPosition = currentSelectedPosition; m_SelectedTimePoint = currentSelectedTimePoint; m_CurrentPositionTime.Modified(); m_ValidSelectedPosition = false; if (m_SelectedData.IsNull()) { return; } mitk::BaseGeometry::Pointer geometry = m_SelectedData->GetTimeGeometry()->GetGeometryForTimePoint(m_SelectedTimePoint); // check for invalid time step if (geometry.IsNull()) { geometry = m_SelectedData->GetTimeGeometry()->GetGeometryForTimeStep(0); } if (geometry.IsNull()) { return; } m_ValidSelectedPosition = geometry->IsInside(m_SelectedPosition); itk::Index<3> index; geometry->WorldToIndex(m_SelectedPosition, index); m_CurrentSelectedZSlice = index[2]; } } void QmitkDicomInspectorView::OnSliceChangedDelayed() { m_PendingSliceChangedEvent = false; ValidateAndSetCurrentPosition(); m_Controls.tableTags->setEnabled(m_ValidSelectedPosition); if (m_SelectedNode.IsNotNull()) { RenderTable(); } } void QmitkDicomInspectorView::RenderTable() { assert(nullptr != m_RenderWindowPart); const auto timeStep = (m_SelectedData.IsNull()) ? 0 : m_SelectedData->GetTimeGeometry()->TimePointToTimeStep(m_SelectedTimePoint); unsigned int rowIndex = 0; for (const auto& element : m_Tags) { QTableWidgetItem* newItem = new QTableWidgetItem(QString::fromStdString( element.second.prop->GetValue(timeStep, m_CurrentSelectedZSlice, true, true))); m_Controls.tableTags->setItem(rowIndex, 3, newItem); ++rowIndex; } UpdateLabels(); } void QmitkDicomInspectorView::UpdateData() { QStringList headers; m_Controls.tableTags->horizontalHeader()->resizeSections(QHeaderView::ResizeToContents); m_Tags.clear(); if (m_SelectedData.IsNotNull()) { for (const auto& element : *(m_SelectedData->GetPropertyList()->GetMap())) { if (element.first.find("DICOM") == 0) { std::istringstream stream(element.first); std::string token; std::getline(stream, token, '.'); //drop the DICOM suffix std::getline(stream, token, '.'); //group id unsigned long dcmgroup = std::stoul(token, nullptr, 16); std::getline(stream, token, '.'); //element id unsigned long dcmelement = std::stoul(token, nullptr, 16); TagInfo info(mitk::DICOMTag(dcmgroup, dcmelement), dynamic_cast(element.second.GetPointer())); m_Tags.insert(std::make_pair(element.first, info)); } } } m_Controls.tableTags->setRowCount(m_Tags.size()); unsigned int rowIndex = 0; for (const auto& element : m_Tags) { QTableWidgetItem* newItem = new QTableWidgetItem(QString::number(element.second.tag.GetGroup(), 16)); m_Controls.tableTags->setItem(rowIndex, 0, newItem); newItem = new QTableWidgetItem(QString::number(element.second.tag.GetElement(), 16)); m_Controls.tableTags->setItem(rowIndex, 1, newItem); newItem = new QTableWidgetItem(QString::fromStdString(element.second.tag.GetName())); m_Controls.tableTags->setItem(rowIndex, 2, newItem); newItem = new QTableWidgetItem(QString::fromStdString(element.second.prop->GetValue())); m_Controls.tableTags->setItem(rowIndex, 3, newItem); ++rowIndex; } UpdateLabels(); } void QmitkDicomInspectorView::UpdateLabels() { if (m_SelectedData.IsNull()) { m_Controls.timePointValueLabel->setText(QString("")); m_Controls.sliceNumberValueLabel->setText(QString("")); } else { const auto timeStep = m_SelectedData->GetTimeGeometry()->TimePointToTimeStep(m_SelectedTimePoint); if (m_ValidSelectedPosition) { m_Controls.timePointValueLabel->setText(QString::number(timeStep) + QStringLiteral("(")+ QString::number(m_SelectedTimePoint/1000.) + QStringLiteral(" [s])")); m_Controls.sliceNumberValueLabel->setText(QString::number(m_CurrentSelectedZSlice)); } else { m_Controls.timePointValueLabel->setText(QString("outside data geometry")); m_Controls.sliceNumberValueLabel->setText(QString("outside data geometry")); } } } void QmitkDicomInspectorView::SetAsSelectionListener(bool checked) { if (checked) { m_SelectionServiceConnector->AddPostSelectionListener(GetSite()->GetWorkbenchWindow()->GetSelectionService()); connect(m_SelectionServiceConnector.get(), &QmitkSelectionServiceConnector::ServiceSelectionChanged, m_Controls.singleSlot, &QmitkSingleNodeSelectionWidget::SetCurrentSelection); } else { m_SelectionServiceConnector->RemovePostSelectionListener(); disconnect(m_SelectionServiceConnector.get(), &QmitkSelectionServiceConnector::ServiceSelectionChanged, m_Controls.singleSlot, &QmitkSingleNodeSelectionWidget::SetCurrentSelection); } } diff --git a/Plugins/org.mitk.gui.qt.fit.demo/src/internal/FitGeneratorDemoView.cpp b/Plugins/org.mitk.gui.qt.fit.demo/src/internal/FitGeneratorDemoView.cpp index 899fbaee1a..321d361ff4 100644 --- a/Plugins/org.mitk.gui.qt.fit.demo/src/internal/FitGeneratorDemoView.cpp +++ b/Plugins/org.mitk.gui.qt.fit.demo/src/internal/FitGeneratorDemoView.cpp @@ -1,254 +1,254 @@ /*============================================================================ 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 "FitGeneratorDemoView.h" #include #include #include #include #include "mitkWorkbenchUtil.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include -const std::string FitGeneratorDemoView::VIEW_ID = "org.mitk.gui.qt.fit.demo"; +const std::string FitGeneratorDemoView::VIEW_ID = "org.mitk.views.fit.demo"; typedef itk::Image FrameITKImageType; typedef itk::Image DynamicITKImageType; void FitGeneratorDemoView::SetFocus() { m_Controls.btnModelling->setFocus(); } void FitGeneratorDemoView::CreateQtPartControl(QWidget* parent) { m_Controls.setupUi(parent); m_Controls.btnModelling->setEnabled(false); connect(m_Controls.btnModelling, SIGNAL(clicked()), this, SLOT(OnModellingButtonClicked())); connect(m_Controls.btnGenerateTestData, SIGNAL(clicked()), this, SLOT(OnGenerateTestDataButtonClicked())); m_Controls.leFitName->setText(tr("demo")); } void FitGeneratorDemoView::OnModellingButtonClicked() { Generate(); } void FitGeneratorDemoView::OnGenerateTestDataButtonClicked() { mitk::Image::Pointer testImage = mitk::GenerateDynamicTestImageMITK(); mitk::DataNode::Pointer testNode = mitk::DataNode::New(); testNode->SetData(testImage); testNode->SetName("LinearModel_4DTestImage"); this->GetDataStorage()->Add(testNode); } void FitGeneratorDemoView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*source*/, const QList& /*nodes*/) { QList dataNodes = this->GetDataManagerSelection(); m_selectedNode = nullptr; m_selectedImage = nullptr; m_selectedMaskNode = nullptr; m_selectedMask = nullptr; if (!dataNodes.empty()) { m_selectedNode = dataNodes[0]; mitk::Image* selectedImage = dynamic_cast(m_selectedNode->GetData()); if (selectedImage && selectedImage->GetDimension(3) > 1) { m_selectedImage = selectedImage; } if (dataNodes.size() > 1) { m_selectedMaskNode = dataNodes[1]; mitk::NodePredicateDataType::Pointer isLabelSet = mitk::NodePredicateDataType::New("LabelSetImage"); mitk::NodePredicateDataType::Pointer isImage = mitk::NodePredicateDataType::New("Image"); mitk::NodePredicateProperty::Pointer isBinary = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); mitk::NodePredicateAnd::Pointer isLegacyMask = mitk::NodePredicateAnd::New(isImage, isBinary); mitk::NodePredicateOr::Pointer maskPredicate = mitk::NodePredicateOr::New(isLegacyMask, isLabelSet); mitk::Image* selectedMask = dynamic_cast(this->m_selectedMaskNode->GetData()); if (selectedMask && maskPredicate->CheckNode(m_selectedMaskNode)) { m_selectedMask = selectedMask; if (this->m_selectedMask->GetTimeSteps() > 1) { MITK_INFO << "Selected mask has multiple timesteps. Only use first timestep to mask model fit. Mask name: " << m_selectedMaskNode->GetName() ; mitk::ImageTimeSelector::Pointer maskedImageTimeSelector = mitk::ImageTimeSelector::New(); maskedImageTimeSelector->SetInput(this->m_selectedMask); maskedImageTimeSelector->SetTimeNr(0); maskedImageTimeSelector->UpdateLargestPossibleRegion(); this->m_selectedMask = maskedImageTimeSelector->GetOutput(); } } } } if (m_selectedImage) { m_Controls.lTimeseries->setText((m_selectedNode->GetName()).c_str()); } else { if (m_selectedNode.IsNull()) { m_Controls.lTimeseries->setText("None"); } else { m_Controls.lTimeseries->setText("Error. Selected node #1 is no 4D image!"); } } if (m_selectedMask) { m_Controls.lMask->setText((m_selectedMaskNode->GetName()).c_str()); } else { if (m_selectedMaskNode.IsNull()) { m_Controls.lMask->setText("None"); } else { m_Controls.lMask->setText("Error. Selected node #2 is no mask!"); } } m_Controls.btnModelling->setEnabled(m_selectedImage.IsNotNull()); } void FitGeneratorDemoView::Generate() { mitk::PixelBasedParameterFitImageGenerator::Pointer fitGenerator = mitk::PixelBasedParameterFitImageGenerator::New(); //Model configuration (static parameters) can be done now //Specify fitting strategy and evaluation parameters mitk::LevenbergMarquardtModelFitFunctor::Pointer fitFunctor = mitk::LevenbergMarquardtModelFitFunctor::New(); mitk::SumOfSquaredDifferencesFitCostFunction::Pointer evaluation = mitk::SumOfSquaredDifferencesFitCostFunction::New(); fitFunctor->RegisterEvaluationParameter("sum_diff^2", evaluation); //Parametrize fit generator mitk::LinearModelParameterizer::Pointer parameterizer = mitk::LinearModelParameterizer::New(); fitGenerator->SetModelParameterizer(parameterizer); fitGenerator->SetDynamicImage(m_selectedImage); fitGenerator->SetFitFunctor(fitFunctor); if (m_selectedMask.IsNotNull()) { fitGenerator->SetMask(m_selectedMask); } mitk::modelFit::ModelFitInfo::Pointer fitSession = mitk::modelFit::CreateFitInfoFromModelParameterizer(parameterizer, m_selectedNode->GetData(), mitk::ModelFitConstants::FIT_TYPE_VALUE_PIXELBASED(), m_Controls.leFitName->text().toStdString()); ///////////////////////// //create job and put it into the thread pool ParameterFitBackgroundJob* pJob = new ParameterFitBackgroundJob(fitGenerator, fitSession, m_selectedNode); pJob->setAutoDelete(true); connect(pJob, SIGNAL(Error(QString)), this, SLOT(OnJobError(QString))); connect(pJob, SIGNAL(Finished()), this, SLOT(OnJobFinished())); connect(pJob, SIGNAL(ResultsAreAvailable(mitk::modelFit::ModelFitResultNodeVectorType, const ParameterFitBackgroundJob*)), this, SLOT(OnJobResultsAreAvailable(mitk::modelFit::ModelFitResultNodeVectorType, const ParameterFitBackgroundJob*)), Qt::BlockingQueuedConnection); connect(pJob, SIGNAL(JobProgress(double)), this, SLOT(OnJobProgress(double))); connect(pJob, SIGNAL(JobStatusChanged(QString)), this, SLOT(OnJobStatusChanged(QString))); QThreadPool* threadPool = QThreadPool::globalInstance(); threadPool->start(pJob); } FitGeneratorDemoView::FitGeneratorDemoView() { m_selectedImage = nullptr; m_selectedNode = nullptr; } void FitGeneratorDemoView::OnJobFinished() { this->m_Controls.textEdit->append(QString("Fitting finished")); }; void FitGeneratorDemoView::OnJobError(QString err) { MITK_ERROR << err.toStdString().c_str(); m_Controls.textEdit->append(QString("") + err + QString("")); }; void FitGeneratorDemoView::OnJobResultsAreAvailable( mitk::modelFit::ModelFitResultNodeVectorType results, const ParameterFitBackgroundJob* pJob) { //Store the resulting parameter fit image via convenience helper function in data storage //(handles the correct generation of the nodes and their properties) mitk::modelFit::StoreResultsInDataStorage(this->GetDataStorage(), results, pJob->GetParentNode()); }; void FitGeneratorDemoView::OnJobProgress(double progress) { QString report = QString("Progress. ") + QString::number(progress); this->m_Controls.textEdit->append(report); }; void FitGeneratorDemoView::OnJobStatusChanged(QString info) { this->m_Controls.textEdit->append(info); } diff --git a/Plugins/org.mitk.gui.qt.fit.genericfitting/documentation/UserManual/Manual.dox b/Plugins/org.mitk.gui.qt.fit.genericfitting/documentation/UserManual/Manual.dox index 063fdf0dd9..c90a30a4de 100644 --- a/Plugins/org.mitk.gui.qt.fit.genericfitting/documentation/UserManual/Manual.dox +++ b/Plugins/org.mitk.gui.qt.fit.genericfitting/documentation/UserManual/Manual.dox @@ -1,16 +1,16 @@ /** -\page org_mitk_gui_qt_fit_genericfitting The Model Fit Generic Fitting View +\page org_mitk_views_fit_genericfitting The Model Fit Generic Fitting View \imageMacro{fit_generic_doc.svg,"Icon of the Generic Fitting View",3.0} \tableofcontents \section FIT_GENERIC_Introduction Introduction This plug-in offers a generic fitting component for time resolved image data. \section FIT_GENERIC_Contact Contact information This plug-in is being developed by the SIDT group (Software development for Integrated Diagnostics and Therapy) at the German Cancer Research Center (DKFZ). If you have any questions, need support, find a bug or have a feature request, feel free to contact us at www.mitk.org. */ diff --git a/Plugins/org.mitk.gui.qt.fit.genericfitting/plugin.xml b/Plugins/org.mitk.gui.qt.fit.genericfitting/plugin.xml index c77936d932..258904cf04 100644 --- a/Plugins/org.mitk.gui.qt.fit.genericfitting/plugin.xml +++ b/Plugins/org.mitk.gui.qt.fit.genericfitting/plugin.xml @@ -1,12 +1,12 @@ - diff --git a/Plugins/org.mitk.gui.qt.fit.genericfitting/src/internal/GenericDataFittingView.cpp b/Plugins/org.mitk.gui.qt.fit.genericfitting/src/internal/GenericDataFittingView.cpp index 3a8dfb2d14..44a8d83a62 100644 --- a/Plugins/org.mitk.gui.qt.fit.genericfitting/src/internal/GenericDataFittingView.cpp +++ b/Plugins/org.mitk.gui.qt.fit.genericfitting/src/internal/GenericDataFittingView.cpp @@ -1,639 +1,639 @@ /*============================================================================ 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 "GenericDataFittingView.h" #include "mitkWorkbenchUtil.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Includes for image casting between ITK and MITK #include #include "mitkImageCast.h" #include "mitkITKImageImport.h" #include #include #include -const std::string GenericDataFittingView::VIEW_ID = "org.mitk.gui.qt.fit.genericfitting"; +const std::string GenericDataFittingView::VIEW_ID = "org.mitk.views.fit.genericfitting"; void GenericDataFittingView::SetFocus() { m_Controls.btnModelling->setFocus(); } void GenericDataFittingView::CreateQtPartControl(QWidget* parent) { m_Controls.setupUi(parent); m_Controls.btnModelling->setEnabled(false); this->InitModelComboBox(); connect(m_Controls.btnModelling, SIGNAL(clicked()), this, SLOT(OnModellingButtonClicked())); connect(m_Controls.comboModel, SIGNAL(currentIndexChanged(int)), this, SLOT(OnModellSet(int))); connect(m_Controls.radioPixelBased, SIGNAL(toggled(bool)), this, SLOT(UpdateGUIControls())); //Gerneric setting m_Controls.groupGeneric->hide(); m_Controls.labelFormulaInfo->hide(); connect(m_Controls.editFormula, SIGNAL(textChanged(const QString&)), this, SLOT(UpdateGUIControls())); connect(m_Controls.checkFormulaInfo, SIGNAL(toggled(bool)), m_Controls.labelFormulaInfo, SLOT(setVisible(bool))); connect(m_Controls.nrOfParams, SIGNAL(valueChanged(int)), this, SLOT(OnNrOfParamsChanged())); //Model fit configuration m_Controls.groupBox_FitConfiguration->hide(); m_Controls.checkBox_Constraints->setEnabled(false); m_Controls.constraintManager->setEnabled(false); m_Controls.initialValuesManager->setEnabled(false); connect(m_Controls.radioButton_StartParameters, SIGNAL(toggled(bool)), this, SLOT(UpdateGUIControls())); connect(m_Controls.checkBox_Constraints, SIGNAL(toggled(bool)), this, SLOT(UpdateGUIControls())); connect(m_Controls.radioButton_StartParameters, SIGNAL(toggled(bool)), m_Controls.initialValuesManager, SLOT(setEnabled(bool))); connect(m_Controls.checkBox_Constraints, SIGNAL(toggled(bool)), m_Controls.constraintManager, SLOT(setEnabled(bool))); connect(m_Controls.checkBox_Constraints, SIGNAL(toggled(bool)), m_Controls.constraintManager, SLOT(setVisible(bool))); UpdateGUIControls(); } void GenericDataFittingView::UpdateGUIControls() { m_Controls.lineFitName->setPlaceholderText(QString::fromStdString(this->GetDefaultFitName())); m_Controls.lineFitName->setEnabled(!m_FittingInProgress); m_Controls.checkBox_Constraints->setEnabled(m_modelConstraints.IsNotNull()); bool isGenericFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; m_Controls.groupGeneric->setVisible(isGenericFactory); m_Controls.groupBox_FitConfiguration->setVisible(m_selectedModelFactory); m_Controls.groupBox->setEnabled(!m_FittingInProgress); m_Controls.comboModel->setEnabled(!m_FittingInProgress); m_Controls.groupGeneric->setEnabled(!m_FittingInProgress); m_Controls.groupBox_FitConfiguration->setEnabled(!m_FittingInProgress); m_Controls.radioROIbased->setEnabled(m_selectedMask.IsNotNull()); m_Controls.btnModelling->setEnabled(m_selectedImage.IsNotNull() && m_selectedModelFactory.IsNotNull() && !m_FittingInProgress && CheckModelSettings()); } std::string GenericDataFittingView::GetFitName() const { std::string fitName = m_Controls.lineFitName->text().toStdString(); if (fitName.empty()) { fitName = m_Controls.lineFitName->placeholderText().toStdString(); } return fitName; } std::string GenericDataFittingView::GetDefaultFitName() const { std::string defaultName = "undefined model"; if (this->m_selectedModelFactory.IsNotNull()) { defaultName = this->m_selectedModelFactory->GetClassID(); } if (this->m_Controls.radioPixelBased->isChecked()) { defaultName += "_pixel"; } else { defaultName += "_roi"; } return defaultName; } void GenericDataFittingView::OnNrOfParamsChanged() { PrepareFitConfiguration(); UpdateGUIControls(); } void GenericDataFittingView::OnModellSet(int index) { m_selectedModelFactory = nullptr; if (index > 0) { if (static_cast(index) <= m_FactoryStack.size() ) { m_selectedModelFactory = m_FactoryStack[index - 1]; } else { MITK_WARN << "Invalid model index. Index outside of the factory stack. Factory stack size: "<< m_FactoryStack.size() << "; invalid index: "<< index; } } UpdateGUIControls(); } bool GenericDataFittingView::IsGenericParamFactorySelected() const { return dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; } void GenericDataFittingView::PrepareFitConfiguration() { if (m_selectedModelFactory) { mitk::ModelBase::ParameterNamesType paramNames = m_selectedModelFactory->GetParameterNames(); unsigned int nrOfPools = this->m_Controls.nrOfParams->value(); //init values if (this->IsGenericParamFactorySelected()) { mitk::modelFit::ModelFitInfo::Pointer fitInfo = mitk::modelFit::ModelFitInfo::New(); fitInfo->staticParamMap.Add(mitk::GenericParamModel::NAME_STATIC_PARAMETER_number, { static_cast(nrOfPools) }); auto parameterizer = m_selectedModelFactory->CreateParameterizer(fitInfo); paramNames = parameterizer->GetParameterNames(); m_Controls.initialValuesManager->setInitialValues(paramNames, parameterizer->GetDefaultInitialParameterization()); } else { m_Controls.initialValuesManager->setInitialValues(paramNames, this->m_selectedModelFactory->GetDefaultInitialParameterization()); } //constraints this->m_modelConstraints = dynamic_cast (m_selectedModelFactory->CreateDefaultConstraints().GetPointer()); if (this->m_modelConstraints.IsNull()) { this->m_modelConstraints = mitk::SimpleBarrierConstraintChecker::New(); } m_Controls.constraintManager->setChecker(this->m_modelConstraints, paramNames); } }; void GenericDataFittingView::OnModellingButtonClicked() { //check if all static parameters set if (m_selectedModelFactory.IsNotNull() && CheckModelSettings()) { mitk::ParameterFitImageGeneratorBase::Pointer generator = nullptr; mitk::modelFit::ModelFitInfo::Pointer fitSession = nullptr; bool isLinearFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool isGenericFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool isT2DecayFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; if (isLinearFactory) { if (this->m_Controls.radioPixelBased->isChecked()) { GenerateModelFit_PixelBased(fitSession, generator); } else { GenerateModelFit_ROIBased(fitSession, generator); } } else if (isGenericFactory) { if (this->m_Controls.radioPixelBased->isChecked()) { GenerateModelFit_PixelBased(fitSession, generator); } else { GenerateModelFit_ROIBased(fitSession, generator); } } else if (isT2DecayFactory) { if (this->m_Controls.radioPixelBased->isChecked()) { GenerateModelFit_PixelBased(fitSession, generator); } else { GenerateModelFit_ROIBased(fitSession, generator); } } //add other models with else if if (generator.IsNotNull() && fitSession.IsNotNull()) { m_FittingInProgress = true; UpdateGUIControls(); DoFit(fitSession, generator); } else { QMessageBox box; box.setText("Fitting error!"); box.setInformativeText("Could not establish fitting job. Error when setting ab generator, model parameterizer or session info."); box.setStandardButtons(QMessageBox::Ok); box.setDefaultButton(QMessageBox::Ok); box.setIcon(QMessageBox::Warning); box.exec(); } } else { QMessageBox box; box.setText("Static parameters for model are not set!"); box.setInformativeText("Some static parameters, that are needed for calculation are not set and equal to zero. Modeling not possible"); box.setStandardButtons(QMessageBox::Ok); box.setDefaultButton(QMessageBox::Ok); box.setIcon(QMessageBox::Warning); box.exec(); } } void GenericDataFittingView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*source*/, const QList& selectedNodes) { m_selectedNode = nullptr; m_selectedImage = nullptr; m_selectedMaskNode = nullptr; m_selectedMask = nullptr; m_Controls.masklabel->setText("No (valid) mask selected."); m_Controls.timeserieslabel->setText("No (valid) series selected."); QList nodes = selectedNodes; mitk::NodePredicateDataType::Pointer isLabelSet = mitk::NodePredicateDataType::New("LabelSetImage"); mitk::NodePredicateDataType::Pointer isImage = mitk::NodePredicateDataType::New("Image"); mitk::NodePredicateProperty::Pointer isBinary = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); mitk::NodePredicateAnd::Pointer isLegacyMask = mitk::NodePredicateAnd::New(isImage, isBinary); mitk::NodePredicateOr::Pointer maskPredicate = mitk::NodePredicateOr::New(isLegacyMask, isLabelSet); if (nodes.size() > 0 && isImage->CheckNode(nodes.front())) { this->m_selectedNode = nodes.front(); this->m_selectedImage = dynamic_cast(this->m_selectedNode->GetData()); m_Controls.timeserieslabel->setText((this->m_selectedNode->GetName()).c_str()); nodes.pop_front(); } if (nodes.size() > 0 && maskPredicate->CheckNode(nodes.front())) { this->m_selectedMaskNode = nodes.front(); this->m_selectedMask = dynamic_cast(this->m_selectedMaskNode->GetData()); if (this->m_selectedMask->GetTimeSteps() > 1) { MITK_INFO << "Selected mask has multiple timesteps. Only use first timestep to mask model fit. Mask name: " << m_selectedMaskNode->GetName(); mitk::ImageTimeSelector::Pointer maskedImageTimeSelector = mitk::ImageTimeSelector::New(); maskedImageTimeSelector->SetInput(this->m_selectedMask); maskedImageTimeSelector->SetTimeNr(0); maskedImageTimeSelector->UpdateLargestPossibleRegion(); this->m_selectedMask = maskedImageTimeSelector->GetOutput(); } m_Controls.masklabel->setText((this->m_selectedMaskNode->GetName()).c_str()); } if (m_selectedMask.IsNull()) { this->m_Controls.radioPixelBased->setChecked(true); } UpdateGUIControls(); } bool GenericDataFittingView::CheckModelSettings() const { bool ok = true; //check wether any model is set at all. Otherwise exit with false if (m_selectedModelFactory.IsNotNull()) { bool isGenericFactory = dynamic_cast(m_selectedModelFactory.GetPointer()) != nullptr; if (isGenericFactory) { ok = !m_Controls.editFormula->text().isEmpty(); } } else { ok = false; } return ok; } void GenericDataFittingView::ConfigureInitialParametersOfParameterizer(mitk::ModelParameterizerBase* parameterizer) const { if (m_Controls.radioButton_StartParameters->isChecked()) { //use user defined initial parameters mitk::ValueBasedParameterizationDelegate::Pointer paramDelegate = mitk::ValueBasedParameterizationDelegate::New(); paramDelegate->SetInitialParameterization(m_Controls.initialValuesManager->getInitialValues()); parameterizer->SetInitialParameterizationDelegate(paramDelegate); } mitk::GenericParamModelParameterizer* genericParameterizer = dynamic_cast(parameterizer); if (genericParameterizer) { genericParameterizer->SetFunctionString(m_Controls.editFormula->text().toStdString()); } } template void GenericDataFittingView::GenerateModelFit_PixelBased(mitk::modelFit::ModelFitInfo::Pointer& modelFitInfo, mitk::ParameterFitImageGeneratorBase::Pointer& generator) { mitk::PixelBasedParameterFitImageGenerator::Pointer fitGenerator = mitk::PixelBasedParameterFitImageGenerator::New(); typename TParameterizer::Pointer modelParameterizer = TParameterizer::New(); auto genericParameterizer = dynamic_cast(modelParameterizer.GetPointer()); if (genericParameterizer) { genericParameterizer->SetNumberOfParameters(this->m_Controls.nrOfParams->value()); } this->ConfigureInitialParametersOfParameterizer(modelParameterizer); //Specify fitting strategy and criterion parameters mitk::ModelFitFunctorBase::Pointer fitFunctor = CreateDefaultFitFunctor(modelParameterizer); //Parametrize fit generator fitGenerator->SetModelParameterizer(modelParameterizer); std::string roiUID = ""; if (m_selectedMask.IsNotNull()) { fitGenerator->SetMask(m_selectedMask); roiUID = m_selectedMask->GetUID(); } fitGenerator->SetDynamicImage(this->m_selectedImage); fitGenerator->SetFitFunctor(fitFunctor); generator = fitGenerator.GetPointer(); //Create model info modelFitInfo = mitk::modelFit::CreateFitInfoFromModelParameterizer(modelParameterizer, m_selectedNode->GetData(), mitk::ModelFitConstants::FIT_TYPE_VALUE_PIXELBASED(), this->GetFitName(), roiUID); } template void GenericDataFittingView::GenerateModelFit_ROIBased( mitk::modelFit::ModelFitInfo::Pointer& modelFitInfo, mitk::ParameterFitImageGeneratorBase::Pointer& generator) { mitk::ROIBasedParameterFitImageGenerator::Pointer fitGenerator = mitk::ROIBasedParameterFitImageGenerator::New(); typename TParameterizer::Pointer modelParameterizer = TParameterizer::New(); auto genericParameterizer = dynamic_cast(modelParameterizer.GetPointer()); if (genericParameterizer) { genericParameterizer->SetNumberOfParameters(this->m_Controls.nrOfParams->value()); } this->ConfigureInitialParametersOfParameterizer(modelParameterizer); //Compute ROI signal mitk::MaskedDynamicImageStatisticsGenerator::Pointer signalGenerator = mitk::MaskedDynamicImageStatisticsGenerator::New(); signalGenerator->SetMask(m_selectedMask); signalGenerator->SetDynamicImage(m_selectedImage); signalGenerator->Generate(); mitk::MaskedDynamicImageStatisticsGenerator::ResultType roiSignal = signalGenerator->GetMean(); //Specify fitting strategy and criterion parameters mitk::ModelFitFunctorBase::Pointer fitFunctor = CreateDefaultFitFunctor(modelParameterizer); //Parametrize fit generator fitGenerator->SetModelParameterizer(modelParameterizer); fitGenerator->SetMask(m_selectedMask); fitGenerator->SetFitFunctor(fitFunctor); fitGenerator->SetSignal(roiSignal); fitGenerator->SetTimeGrid(mitk::ExtractTimeGrid(m_selectedImage)); generator = fitGenerator.GetPointer(); std::string roiUID = this->m_selectedMask->GetUID(); //Create model info modelFitInfo = mitk::modelFit::CreateFitInfoFromModelParameterizer(modelParameterizer, m_selectedNode->GetData(), mitk::ModelFitConstants::FIT_TYPE_VALUE_ROIBASED(), this->GetFitName(), roiUID); mitk::ScalarListLookupTable::ValueType infoSignal; for (mitk::MaskedDynamicImageStatisticsGenerator::ResultType::const_iterator pos = roiSignal.begin(); pos != roiSignal.end(); ++pos) { infoSignal.push_back(*pos); } modelFitInfo->inputData.SetTableValue("ROI", infoSignal); } void GenericDataFittingView::DoFit(const mitk::modelFit::ModelFitInfo* fitSession, mitk::ParameterFitImageGeneratorBase* generator) { QString message = "Fitting Data Set . . ."; m_Controls.infoBox->append(message); ///////////////////////// //create job and put it into the thread pool ParameterFitBackgroundJob* pJob = new ParameterFitBackgroundJob(generator, fitSession, this->m_selectedNode); pJob->setAutoDelete(true); connect(pJob, SIGNAL(Error(QString)), this, SLOT(OnJobError(QString))); connect(pJob, SIGNAL(Finished()), this, SLOT(OnJobFinished())); connect(pJob, SIGNAL(ResultsAreAvailable(mitk::modelFit::ModelFitResultNodeVectorType, const ParameterFitBackgroundJob*)), this, SLOT(OnJobResultsAreAvailable(mitk::modelFit::ModelFitResultNodeVectorType, const ParameterFitBackgroundJob*)), Qt::BlockingQueuedConnection); connect(pJob, SIGNAL(JobProgress(double)), this, SLOT(OnJobProgress(double))); connect(pJob, SIGNAL(JobStatusChanged(QString)), this, SLOT(OnJobStatusChanged(QString))); QThreadPool* threadPool = QThreadPool::globalInstance(); threadPool->start(pJob); } GenericDataFittingView::GenericDataFittingView() : m_FittingInProgress(false) { m_selectedImage = nullptr; m_selectedMask = nullptr; mitk::ModelFactoryBase::Pointer factory = mitk::LinearModelFactory::New().GetPointer(); m_FactoryStack.push_back(factory); factory = mitk::GenericParamModelFactory::New().GetPointer(); m_FactoryStack.push_back(factory); factory = mitk::T2DecayModelFactory::New().GetPointer(); m_FactoryStack.push_back(factory); this->m_IsNotABinaryImagePredicate = mitk::NodePredicateAnd::New( mitk::TNodePredicateDataType::New(), mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true))), mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object"))).GetPointer(); this->m_IsBinaryImagePredicate = mitk::NodePredicateAnd::New( mitk::TNodePredicateDataType::New(), mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)), mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object"))).GetPointer(); } void GenericDataFittingView::OnJobFinished() { this->m_Controls.infoBox->append(QString("Fitting finished")); this->m_FittingInProgress = false; this->UpdateGUIControls(); }; void GenericDataFittingView::OnJobError(QString err) { MITK_ERROR << err.toStdString().c_str(); m_Controls.infoBox->append(QString("") + err + QString("")); }; void GenericDataFittingView::OnJobResultsAreAvailable(mitk::modelFit::ModelFitResultNodeVectorType results, const ParameterFitBackgroundJob* pJob) { //Store the resulting parameter fit image via convenience helper function in data storage //(handles the correct generation of the nodes and their properties) mitk::modelFit::StoreResultsInDataStorage(this->GetDataStorage(), results, pJob->GetParentNode()); }; void GenericDataFittingView::OnJobProgress(double progress) { QString report = QString("Progress. ") + QString::number(progress); this->m_Controls.infoBox->append(report); }; void GenericDataFittingView::OnJobStatusChanged(QString info) { this->m_Controls.infoBox->append(info); } void GenericDataFittingView::InitModelComboBox() const { this->m_Controls.comboModel->clear(); this->m_Controls.comboModel->addItem(tr("No model selected")); for (ModelFactoryStackType::const_iterator pos = m_FactoryStack.begin(); pos != m_FactoryStack.end(); ++pos) { this->m_Controls.comboModel->addItem(QString::fromStdString((*pos)->GetClassID())); } this->m_Controls.comboModel->setCurrentIndex(0); }; mitk::ModelFitFunctorBase::Pointer GenericDataFittingView::CreateDefaultFitFunctor( const mitk::ModelParameterizerBase* parameterizer) const { mitk::LevenbergMarquardtModelFitFunctor::Pointer fitFunctor = mitk::LevenbergMarquardtModelFitFunctor::New(); mitk::NormalizedSumOfSquaredDifferencesFitCostFunction::Pointer chi2 = mitk::NormalizedSumOfSquaredDifferencesFitCostFunction::New(); fitFunctor->RegisterEvaluationParameter("Chi^2", chi2); if (m_Controls.checkBox_Constraints->isChecked()) { fitFunctor->SetConstraintChecker(m_modelConstraints); } mitk::ModelBase::Pointer refModel = parameterizer->GenerateParameterizedModel(); ::itk::LevenbergMarquardtOptimizer::ScalesType scales; scales.SetSize(refModel->GetNumberOfParameters()); scales.Fill(1.0); fitFunctor->SetScales(scales); fitFunctor->SetDebugParameterMaps(m_Controls.checkDebug->isChecked()); return fitFunctor.GetPointer(); } diff --git a/Plugins/org.mitk.gui.qt.fit.inspector/src/internal/ModelFitInspectorView.cpp b/Plugins/org.mitk.gui.qt.fit.inspector/src/internal/ModelFitInspectorView.cpp index dcf1116823..89d950ed79 100644 --- a/Plugins/org.mitk.gui.qt.fit.inspector/src/internal/ModelFitInspectorView.cpp +++ b/Plugins/org.mitk.gui.qt.fit.inspector/src/internal/ModelFitInspectorView.cpp @@ -1,920 +1,920 @@ /*============================================================================ 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. ============================================================================*/ // Blueberry #include #include #include // mitk #include // Qt #include #include #include #include #include "QmitkPlotWidget.h" #include "mitkNodePredicateFunction.h" #include "mitkScalarListLookupTableProperty.h" #include "mitkModelFitConstants.h" #include "mitkExtractTimeGrid.h" #include "mitkModelGenerator.h" #include "mitkModelFitException.h" #include "mitkModelFitParameterValueExtraction.h" #include "mitkTimeGridHelper.h" #include "mitkModelFitResultRelationRule.h" #include "mitkModelFitPlotDataHelper.h" #include "ModelFitInspectorView.h" -const std::string ModelFitInspectorView::VIEW_ID = "org.mitk.gui.gt.fit.inspector"; +const std::string ModelFitInspectorView::VIEW_ID = "org.mitk.views.fit.inspector"; const unsigned int ModelFitInspectorView::INTERPOLATION_STEPS = 10; const std::string DEFAULT_X_AXIS = "Time [s]"; ModelFitInspectorView::ModelFitInspectorView() : m_renderWindowPart(nullptr), m_internalUpdateFlag(false), m_currentFit(nullptr), m_currentModelParameterizer(nullptr), m_currentModelProviderService(nullptr), m_currentSelectedTimeStep(0), m_currentSelectedNode(nullptr) { m_currentSelectedPosition.Fill(0.0); m_modelfitList.clear(); } ModelFitInspectorView::~ModelFitInspectorView() { } void ModelFitInspectorView::RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) { if (m_renderWindowPart != renderWindowPart) { m_renderWindowPart = renderWindowPart; } this->m_SliceChangeListener.RenderWindowPartActivated(renderWindowPart); } void ModelFitInspectorView::RenderWindowPartDeactivated( mitk::IRenderWindowPart* renderWindowPart) { m_renderWindowPart = nullptr; this->m_SliceChangeListener.RenderWindowPartDeactivated(renderWindowPart); } void ModelFitInspectorView::CreateQtPartControl(QWidget* parent) { m_Controls.setupUi(parent); m_SelectionServiceConnector = std::make_unique(); m_SelectionServiceConnector->AddPostSelectionListener(this->GetSite()->GetWorkbenchWindow()->GetSelectionService()); m_Controls.inputNodeSelector->SetDataStorage(GetDataStorage()); m_Controls.inputNodeSelector->SetEmptyInfo(QString("Please select input data to be viewed.")); m_Controls.inputNodeSelector->SetInvalidInfo(QString("No input data is selected")); m_Controls.inputNodeSelector->SetPopUpTitel(QString("Choose 3D+t input data that should be viewed!")); m_Controls.inputNodeSelector->SetSelectionIsOptional(false); m_Controls.inputNodeSelector->SetSelectOnlyVisibleNodes(true); auto predicate = mitk::NodePredicateFunction::New([](const mitk::DataNode *node) { bool isModelFitNode = node->GetData() && node->GetData()->GetProperty(mitk::ModelFitConstants::FIT_UID_PROPERTY_NAME().c_str()).IsNotNull(); return isModelFitNode || (node && node->GetData() && node->GetData()->GetTimeSteps() > 1); }); m_Controls.inputNodeSelector->SetNodePredicate(predicate); connect(m_SelectionServiceConnector.get(), &QmitkSelectionServiceConnector::ServiceSelectionChanged, m_Controls.inputNodeSelector, &QmitkSingleNodeSelectionWidget::SetCurrentSelection); connect(m_Controls.inputNodeSelector, &QmitkAbstractNodeSelectionWidget::CurrentSelectionChanged, this, &ModelFitInspectorView::OnInputChanged); this->m_SliceChangeListener.RenderWindowPartActivated(this->GetRenderWindowPart()); connect(&m_SliceChangeListener, SIGNAL(SliceChanged()), this, SLOT(OnSliceChanged())); connect(m_Controls.cmbFit, SIGNAL(currentIndexChanged(int)), this, SLOT(OnFitSelectionChanged(int))); connect(m_Controls.radioScaleFixed, SIGNAL(toggled(bool)), m_Controls.sbFixMin, SLOT(setEnabled(bool))); connect(m_Controls.radioScaleFixed, SIGNAL(toggled(bool)), m_Controls.sbFixMax, SLOT(setEnabled(bool))); connect(m_Controls.radioScaleFixed, SIGNAL(toggled(bool)), m_Controls.labelFixMin, SLOT(setEnabled(bool))); connect(m_Controls.radioScaleFixed, SIGNAL(toggled(bool)), m_Controls.labelFixMax, SLOT(setEnabled(bool))); connect(m_Controls.radioScaleFixed, SIGNAL(toggled(bool)), m_Controls.btnScaleToData, SLOT(setEnabled(bool))); connect(m_Controls.radioScaleFixed, SIGNAL(toggled(bool)), this, SLOT(OnScaleFixedYChecked(bool))); connect(m_Controls.btnScaleToData, SIGNAL(clicked()), this, SLOT(OnScaleToDataYClicked())); connect(m_Controls.sbFixMax, SIGNAL(valueChanged(double)), this, SLOT(OnFixedScalingYChanged(double))); connect(m_Controls.sbFixMin, SIGNAL(valueChanged(double)), this, SLOT(OnFixedScalingYChanged(double))); connect(m_Controls.radioScaleFixed_x, SIGNAL(toggled(bool)), m_Controls.sbFixMin_x, SLOT(setEnabled(bool))); connect(m_Controls.radioScaleFixed_x, SIGNAL(toggled(bool)), m_Controls.sbFixMax_x, SLOT(setEnabled(bool))); connect(m_Controls.radioScaleFixed_x, SIGNAL(toggled(bool)), m_Controls.labelFixMin_x, SLOT(setEnabled(bool))); connect(m_Controls.radioScaleFixed_x, SIGNAL(toggled(bool)), m_Controls.labelFixMax_x, SLOT(setEnabled(bool))); connect(m_Controls.radioScaleFixed_x, SIGNAL(toggled(bool)), m_Controls.btnScaleToData_x, SLOT(setEnabled(bool))); connect(m_Controls.radioScaleFixed_x, SIGNAL(toggled(bool)), this, SLOT(OnScaleFixedXChecked(bool))); connect(m_Controls.btnScaleToData_x, SIGNAL(clicked()), this, SLOT(OnScaleToDataXClicked())); connect(m_Controls.sbFixMax_x, SIGNAL(valueChanged(double)), this, SLOT(OnFixedScalingXChanged(double))); connect(m_Controls.sbFixMin_x, SIGNAL(valueChanged(double)), this, SLOT(OnFixedScalingXChanged(double))); connect(m_Controls.btnFullPlot, SIGNAL(clicked(bool)), this, SLOT(OnFullPlotClicked(bool))); this->EnsureBookmarkPointSet(); m_Controls.inspectionPositionWidget->SetPositionBookmarkNode(m_PositionBookmarksNode.Lock()); connect(m_Controls.inspectionPositionWidget, SIGNAL(PositionBookmarksChanged()), this, SLOT(OnPositionBookmarksChanged())); // For some reason this needs to be called to set the plot widget's minimum width to an // acceptable level (since Qwt 6). // Otherwise it tries to keep both axes equal in length, resulting in a minimum width of // 400-500px which is way too much. m_Controls.widgetPlot->GetPlot()->updateAxes(); m_Controls.cmbFit->clear(); mitk::IRenderWindowPart* renderWindowPart = GetRenderWindowPart(); RenderWindowPartActivated(renderWindowPart); } void ModelFitInspectorView::SetFocus() { } void ModelFitInspectorView::NodeRemoved(const mitk::DataNode* node) { if (node == this->m_currentSelectedNode) { QmitkSingleNodeSelectionWidget::NodeList emptylist; this->m_Controls.inputNodeSelector->SetCurrentSelection(emptylist); } } void ModelFitInspectorView::OnScaleFixedYChecked(bool checked) { m_Controls.widgetPlot->GetPlot()->setAxisAutoScale(QwtPlot::yLeft, !checked); if (checked) { OnScaleToDataYClicked(); } m_Controls.widgetPlot->GetPlot()->replot(); }; void ModelFitInspectorView::OnScaleFixedXChecked(bool checked) { m_Controls.widgetPlot->GetPlot()->setAxisAutoScale(QwtPlot::xBottom, !checked); if (checked) { OnScaleToDataXClicked(); } m_Controls.widgetPlot->GetPlot()->replot(); }; void ModelFitInspectorView::OnScaleToDataYClicked() { auto minmax = this->m_PlotCurves.GetYMinMax(); auto min = minmax.first - std::abs(minmax.first) * 0.01; auto max = minmax.second + std::abs(minmax.second) * 0.01; m_Controls.sbFixMin->setValue(min); m_Controls.sbFixMax->setValue(max); }; void ModelFitInspectorView::OnScaleToDataXClicked() { auto minmax = this->m_PlotCurves.GetXMinMax(); auto min = minmax.first - std::abs(minmax.first) * 0.01; auto max = minmax.second + std::abs(minmax.second) * 0.01; m_Controls.sbFixMin_x->setValue(min); m_Controls.sbFixMax_x->setValue(max); }; void ModelFitInspectorView::OnFixedScalingYChanged(double /*value*/) { m_Controls.widgetPlot->GetPlot()->setAxisScale(QwtPlot::yLeft, m_Controls.sbFixMin->value(), m_Controls.sbFixMax->value()); m_Controls.widgetPlot->GetPlot()->replot(); }; void ModelFitInspectorView::OnFixedScalingXChanged(double /*value*/) { m_Controls.widgetPlot->GetPlot()->setAxisScale(QwtPlot::xBottom, m_Controls.sbFixMin_x->value(), m_Controls.sbFixMax_x->value()); m_Controls.widgetPlot->GetPlot()->replot(); }; void ModelFitInspectorView::OnFullPlotClicked(bool checked) { m_Controls.tabWidget->setVisible(!checked); }; int ModelFitInspectorView::ActualizeFitSelectionWidget() { mitk::modelFit::ModelFitInfo::UIDType selectedFitUD = ""; bool isModelFitNode = false; if (this->m_Controls.inputNodeSelector->GetSelectedNode().IsNotNull()) { isModelFitNode = this->m_Controls.inputNodeSelector->GetSelectedNode()->GetData()->GetPropertyList()->GetStringProperty( mitk::ModelFitConstants::FIT_UID_PROPERTY_NAME().c_str(), selectedFitUD); } mitk::DataStorage::Pointer storage = this->GetDataStorage(); mitk::modelFit::NodeUIDSetType fitUIDs = mitk::modelFit::GetFitUIDsOfNode( this->m_currentSelectedNode, storage); this->m_modelfitList.clear(); this->m_Controls.cmbFit->clear(); for (const auto & fitUID : fitUIDs) { mitk::modelFit::ModelFitInfo::ConstPointer info = mitk::modelFit::CreateFitInfoFromNode(fitUID, storage).GetPointer(); if (info.IsNotNull()) { this->m_modelfitList.insert(std::make_pair(info->uid, info)); std::ostringstream nameStrm; if (info->fitName.empty()) { nameStrm << info->uid; } else { nameStrm << info->fitName; } nameStrm << " (" << info->modelName << ")"; QVariant data(info->uid.c_str()); m_Controls.cmbFit->addItem(QString::fromStdString(nameStrm.str()), data); } else { MITK_ERROR << "Was not able to extract model fit information from storage. Node properties in storage may be invalid. Failed fit UID:" << fitUID; } } int cmbIndex = 0; if (m_modelfitList.empty()) { cmbIndex = -1; }; if (isModelFitNode) { //model was selected, thus select this one in combobox QVariant data(selectedFitUD.c_str()); cmbIndex = m_Controls.cmbFit->findData(data); if (cmbIndex == -1) { MITK_WARN << "Model fit Inspector in invalid state. Selected fit seems to be not avaible in plugin selection. Failed fit UID:" << selectedFitUD; } }; m_Controls.cmbFit->setCurrentIndex(cmbIndex); return cmbIndex; } void ModelFitInspectorView::OnInputChanged(const QList& nodes) { if (nodes.size() > 0) { if (nodes.front() != this->m_currentSelectedNode) { m_internalUpdateFlag = true; this->m_currentSelectedNode = nodes.front(); mitk::modelFit::ModelFitInfo::UIDType selectedFitUD = ""; bool isModelFitNode = this->m_currentSelectedNode->GetData()->GetPropertyList()->GetStringProperty( mitk::ModelFitConstants::FIT_UID_PROPERTY_NAME().c_str(), selectedFitUD); if (isModelFitNode) { this->m_currentSelectedNode = this->GetInputNode(this->m_currentSelectedNode); if (this->m_currentSelectedNode.IsNull()) { MITK_WARN << "Model fit Inspector in invalid state. Input image for selected fit cannot be found in data storage. Failed fit UID:" << selectedFitUD; } } auto cmbIndex = ActualizeFitSelectionWidget(); m_internalUpdateFlag = false; m_selectedNodeTime.Modified(); if (cmbIndex == -1) { //only raw 4D data selected. Just update plots for current position m_currentFit = nullptr; m_currentFitTime.Modified(); OnSliceChanged(); m_Controls.plotDataWidget->SetXName(DEFAULT_X_AXIS); } else { //refresh fit selection (and implicitly update plots) OnFitSelectionChanged(cmbIndex); } } } else { if (this->m_currentSelectedNode.IsNotNull()) { m_internalUpdateFlag = true; this->m_currentSelectedNode = nullptr; this->m_currentFit = nullptr; this->m_modelfitList.clear(); this->m_Controls.cmbFit->clear(); m_internalUpdateFlag = false; m_selectedNodeTime.Modified(); OnFitSelectionChanged(0); RefreshPlotData(); m_Controls.plotDataWidget->SetPlotData(&(this->m_PlotCurves)); m_Controls.fitParametersWidget->setFits(QmitkFitParameterModel::FitVectorType()); RenderPlot(); } } } mitk::DataNode::ConstPointer ModelFitInspectorView::GetInputNode(mitk::DataNode::ConstPointer node) { if (node.IsNotNull()) { std::string selectedFitUD = ""; auto rule = mitk::ModelFitResultRelationRule::New(); auto predicate = rule->GetDestinationsDetector(node); mitk::DataStorage::SetOfObjects::ConstPointer parentNodeList = GetDataStorage()->GetSubset(predicate); if (parentNodeList->size() > 0) { return parentNodeList->front().GetPointer(); } } return mitk::DataNode::ConstPointer(); } void ModelFitInspectorView::ValidateAndSetCurrentPosition() { mitk::Point3D currentSelectedPosition = GetRenderWindowPart()->GetSelectedPosition(nullptr); unsigned int currentSelectedTimestep = m_renderWindowPart->GetTimeNavigationController()->GetTime()-> GetPos(); if (m_currentSelectedPosition != currentSelectedPosition || m_currentSelectedTimeStep != currentSelectedTimestep || m_selectedNodeTime > m_currentPositionTime) { //the current position has been changed or the selected node has been changed since the last position validation -> check position m_currentSelectedPosition = currentSelectedPosition; m_currentSelectedTimeStep = currentSelectedTimestep; m_currentPositionTime.Modified(); m_validSelectedPosition = false; auto inputImage = this->GetCurrentInputImage(); if (inputImage.IsNull()) { return; } mitk::BaseGeometry::ConstPointer geometry = inputImage->GetTimeGeometry()->GetGeometryForTimeStep( m_currentSelectedTimeStep).GetPointer(); // check for invalid time step if (geometry.IsNull()) { geometry = inputImage->GetTimeGeometry()->GetGeometryForTimeStep(0); } if (geometry.IsNull()) { return; } m_validSelectedPosition = geometry->IsInside(m_currentSelectedPosition); } } mitk::Image::ConstPointer ModelFitInspectorView::GetCurrentInputImage() const { mitk::Image::ConstPointer result = nullptr; if (this->m_currentFit.IsNotNull()) { result = m_currentFit->inputImage; } else if (this->m_currentSelectedNode.IsNotNull()) { result = dynamic_cast(this->m_currentSelectedNode->GetData()); if (result.IsNotNull() && result->GetTimeSteps() <= 1) { //if the image is not dynamic, we can't use it. result = nullptr; } } return result; }; const mitk::ModelBase::TimeGridType ModelFitInspectorView::GetCurrentTimeGrid() const { if (m_currentModelProviderService && m_currentFit.IsNotNull()) { return m_currentModelProviderService->GetVariableGrid(m_currentFit); } else { //fall back if there is no model provider we assume to use the normal time grid. return ExtractTimeGrid(GetCurrentInputImage()); } }; void ModelFitInspectorView::OnSliceChanged() { ValidateAndSetCurrentPosition(); m_Controls.widgetPlot->setEnabled(m_validSelectedPosition); if (m_currentSelectedNode.IsNotNull()) { m_Controls.inspectionPositionWidget->SetCurrentPosition(m_currentSelectedPosition); if (RefreshPlotData()) { RenderPlot(); m_Controls.plotDataWidget->SetPlotData(&m_PlotCurves); RenderFitInfo(); } } } void ModelFitInspectorView::OnPositionBookmarksChanged() { if (RefreshPlotData()) { RenderPlot(); m_Controls.plotDataWidget->SetPlotData(&m_PlotCurves); RenderFitInfo(); } } void ModelFitInspectorView::OnFitSelectionChanged(int index) { if (!m_internalUpdateFlag) { MITK_DEBUG << "selected fit index: " << index; std::string uid = ""; if (m_Controls.cmbFit->count() > index) { uid = m_Controls.cmbFit->itemData(index).toString().toStdString(); } mitk::modelFit::ModelFitInfo::ConstPointer newFit = nullptr; ModelFitInfoListType::iterator finding = m_modelfitList.find(uid); if (finding != m_modelfitList.end()) { newFit = finding->second; } if (m_currentFit != newFit) { m_currentModelParameterizer = nullptr; m_currentModelProviderService = nullptr; if (newFit.IsNotNull()) { m_currentModelParameterizer = mitk::ModelGenerator::GenerateModelParameterizer(*newFit); m_currentModelProviderService = mitk::ModelGenerator::GetProviderService(newFit->functionClassID); } m_currentFit = newFit; m_currentFitTime.Modified(); auto name = m_currentFit->xAxisName; if (!m_currentFit->xAxisUnit.empty()) { name += " [" + m_currentFit->xAxisUnit + "]"; } m_Controls.plotDataWidget->SetXName(name); OnSliceChanged(); } } } mitk::PlotDataCurveCollection::Pointer ModelFitInspectorView::RefreshPlotDataCurveCollection(const mitk::Point3D& position, const mitk::Image* input, const mitk::modelFit::ModelFitInfo* fitInfo, const mitk::ModelBase::TimeGridType& timeGrid, mitk::ModelParameterizerBase* parameterizer) { mitk::PlotDataCurveCollection::Pointer result = mitk::PlotDataCurveCollection::New(); //sample curve if (input) { result->InsertElement(mitk::MODEL_FIT_PLOT_SAMPLE_NAME(), GenerateImageSamplePlotData(position, input, timeGrid)); } //model signal curve if (fitInfo) { // Interpolate time grid (x values) so the curve looks smooth const mitk::ModelBase::TimeGridType interpolatedTimeGrid = mitk::GenerateSupersampledTimeGrid(timeGrid, INTERPOLATION_STEPS); auto hires_curve = mitk::GenerateModelSignalPlotData(position, fitInfo, interpolatedTimeGrid, parameterizer); result->InsertElement(mitk::MODEL_FIT_PLOT_INTERPOLATED_SIGNAL_NAME(), hires_curve); auto curve = mitk::GenerateModelSignalPlotData(position, fitInfo, timeGrid, parameterizer); result->InsertElement(mitk::MODEL_FIT_PLOT_SIGNAL_NAME(), curve); } return result; }; bool ModelFitInspectorView::RefreshPlotData() { bool changed = false; if (m_currentSelectedNode.IsNull()) { this->m_PlotCurves = mitk::ModelFitPlotData(); changed = m_selectedNodeTime > m_lastRefreshTime; m_lastRefreshTime.Modified(); } else { assert(GetRenderWindowPart() != NULL); const mitk::Image* input = GetCurrentInputImage(); const mitk::ModelBase::TimeGridType timeGrid = GetCurrentTimeGrid(); if (m_currentFitTime > m_lastRefreshTime || m_currentPositionTime > m_lastRefreshTime) { if (m_validSelectedPosition) { m_PlotCurves.currentPositionPlots = RefreshPlotDataCurveCollection(m_currentSelectedPosition,input,m_currentFit, timeGrid, m_currentModelParameterizer); } else { m_PlotCurves.currentPositionPlots = mitk::PlotDataCurveCollection::New(); } changed = true; } auto bookmarks = m_PositionBookmarks.Lock(); if (bookmarks.IsNotNull()) { if (m_currentFitTime > m_lastRefreshTime || bookmarks->GetMTime() > m_lastRefreshTime) { m_PlotCurves.positionalPlots.clear(); auto endIter = bookmarks->End(); for (auto iter = bookmarks->Begin(); iter != endIter; iter++) { auto collection = RefreshPlotDataCurveCollection(iter.Value(), input, m_currentFit, timeGrid, m_currentModelParameterizer); m_PlotCurves.positionalPlots.emplace(iter.Index(), std::make_pair(iter.Value(), collection)); } changed = true; } } else { m_PlotCurves.positionalPlots.clear(); } // input data curve if (m_currentFitTime > m_lastRefreshTime) { m_PlotCurves.staticPlots->clear(); if (m_currentFit.IsNotNull()) { m_PlotCurves.staticPlots = GenerateAdditionalModelFitPlotData(m_currentSelectedPosition, m_currentFit, timeGrid); } changed = true; } m_lastRefreshTime.Modified(); } return changed; } void ModelFitInspectorView::RenderFitInfo() { assert(m_renderWindowPart != nullptr); // configure fit information if (m_currentFit.IsNull()) { m_Controls.lFitType->setText(""); m_Controls.lFitUID->setText(""); m_Controls.lModelName->setText(""); m_Controls.lModelType->setText(""); } else { m_Controls.lFitType->setText(QString::fromStdString(m_currentFit->fitType)); m_Controls.lFitUID->setText(QString::fromStdString(m_currentFit->uid)); m_Controls.lModelName->setText(QString::fromStdString(m_currentFit->modelName)); m_Controls.lModelType->setText(QString::fromStdString(m_currentFit->modelType)); } // print results std::stringstream infoOutput; m_Controls.fitParametersWidget->setVisible(false); m_Controls.groupSettings->setVisible(false); if (m_currentFit.IsNull()) { infoOutput << "No fit selected. Only raw image data is plotted."; } else if (!m_validSelectedPosition) { infoOutput << "Current position is outside of the input image of the selected fit.\nInspector is deactivated."; } else { m_Controls.fitParametersWidget->setVisible(true); m_Controls.fitParametersWidget->setFits({ m_currentFit }); m_Controls.fitParametersWidget->setPositionBookmarks(m_PositionBookmarks.Lock()); m_Controls.fitParametersWidget->setCurrentPosition(m_currentSelectedPosition); } // configure data table m_Controls.tableInputData->clearContents(); if (m_currentFit.IsNull()) { infoOutput << "No fit selected. Only raw image data is plotted."; } else { m_Controls.groupSettings->setVisible(true); m_Controls.tableInputData->setRowCount(m_PlotCurves.staticPlots->size()); unsigned int rowIndex = 0; for (mitk::PlotDataCurveCollection::const_iterator pos = m_PlotCurves.staticPlots->begin(); pos != m_PlotCurves.staticPlots->end(); ++pos, ++rowIndex) { QColor dataColor; if (pos->first == "ROI") { dataColor = QColor(0, 190, 0); } else { //Use HSV schema of QColor to calculate a different color depending on the //number of already existing free iso lines. dataColor.setHsv(((rowIndex + 1) * 85) % 360, 255, 255); } QTableWidgetItem* newItem = new QTableWidgetItem(QString::fromStdString(pos->first)); m_Controls.tableInputData->setItem(rowIndex, 0, newItem); newItem = new QTableWidgetItem(); newItem->setBackgroundColor(dataColor); m_Controls.tableInputData->setItem(rowIndex, 1, newItem); } } m_Controls.lInfo->setText(QString::fromStdString(infoOutput.str())); } void ModelFitInspectorView::RenderPlotCurve(const mitk::PlotDataCurveCollection* curveCollection, const QColor& sampleColor, const QColor& signalColor, const std::string& posString) { auto sampleCurve = mitk::ModelFitPlotData::GetSamplePlot(curveCollection); if (sampleCurve) { std::string name = mitk::MODEL_FIT_PLOT_SAMPLE_NAME() + posString; unsigned int curveId = m_Controls.widgetPlot->InsertCurve(name.c_str()); m_Controls.widgetPlot->SetCurveData(curveId, sampleCurve->GetValues()); m_Controls.widgetPlot->SetCurvePen(curveId, QPen(Qt::NoPen)); // QwtSymbol needs to passed as a real pointer from MITK v2013.09.0 on // (QwtPlotCurve deletes it on destruction and assignment). QwtSymbol* dataSymbol = new QwtSymbol(QwtSymbol::Diamond, sampleColor, sampleColor, QSize(8, 8)); m_Controls.widgetPlot->SetCurveSymbol(curveId, dataSymbol); // Again, there is no way to set a curve's legend attributes via QmitkPlotWidget so this // gets unnecessarily complicated. QwtPlotCurve* measurementCurve = dynamic_cast(m_Controls.widgetPlot-> GetPlot()->itemList(QwtPlotItem::Rtti_PlotCurve).back()); measurementCurve->setLegendAttribute(QwtPlotCurve::LegendShowSymbol); measurementCurve->setLegendIconSize(QSize(8, 8)); } //draw model curve auto signalCurve = mitk::ModelFitPlotData::GetInterpolatedSignalPlot(curveCollection); if (signalCurve) { std::string name = mitk::MODEL_FIT_PLOT_SIGNAL_NAME() + posString; QPen pen; pen.setColor(signalColor); pen.setWidth(2); unsigned int curveId = m_Controls.widgetPlot->InsertCurve(name.c_str()); m_Controls.widgetPlot->SetCurveData(curveId, signalCurve->GetValues()); m_Controls.widgetPlot->SetCurvePen(curveId, pen); // Manually set the legend attribute to use the symbol as the legend icon and alter its // size. Otherwise it would revert to default which is drawing a square which is the color // of the curve's pen, so in this case none which defaults to black. // Unfortunately, QmitkPlotWidget offers no way to set the legend attribute and icon size so // this looks a bit hacky. QwtPlotCurve* fitCurve = dynamic_cast(m_Controls.widgetPlot->GetPlot()-> itemList(QwtPlotItem::Rtti_PlotCurve).back()); fitCurve->setLegendAttribute(QwtPlotCurve::LegendShowLine); } } void ModelFitInspectorView::RenderPlot() { m_Controls.widgetPlot->Clear(); std::string xAxis = DEFAULT_X_AXIS; std::string yAxis = "Intensity"; std::string plotTitle = "Raw data plot: no data"; if (m_currentSelectedNode.IsNotNull()) { plotTitle = "Raw data plot: " + m_currentSelectedNode->GetName(); } if (m_currentFit.IsNotNull()) { plotTitle = m_currentFit->modelName.c_str(); xAxis = m_currentFit->xAxisName; if (!m_currentFit->xAxisUnit.empty()) { xAxis += " [" + m_currentFit->xAxisUnit + "]"; } yAxis = m_currentFit->yAxisName; if (!m_currentFit->yAxisUnit.empty()) { yAxis += " [" + m_currentFit->yAxisUnit + "]"; } } m_Controls.widgetPlot->SetAxisTitle(QwtPlot::xBottom, xAxis.c_str()); m_Controls.widgetPlot->SetAxisTitle(QwtPlot::yLeft, yAxis.c_str()); m_Controls.widgetPlot->SetPlotTitle(plotTitle.c_str()); // Draw static curves unsigned int colorIndex = 0; for (mitk::PlotDataCurveCollection::const_iterator pos = m_PlotCurves.staticPlots->begin(); pos != m_PlotCurves.staticPlots->end(); ++pos) { QColor dataColor; unsigned int curveId = m_Controls.widgetPlot->InsertCurve(pos->first.c_str()); m_Controls.widgetPlot->SetCurveData(curveId, pos->second->GetValues()); if (pos->first == "ROI") { dataColor = QColor(0, 190, 0); QPen pen; pen.setColor(dataColor); pen.setStyle(Qt::SolidLine); m_Controls.widgetPlot->SetCurvePen(curveId, pen); } else { //Use HSV schema of QColor to calculate a different color depending on the //number of already existing curves. dataColor.setHsv((++colorIndex * 85) % 360, 255, 150); m_Controls.widgetPlot->SetCurvePen(curveId, QPen(Qt::NoPen)); } // QwtSymbol needs to passed as a real pointer from MITK v2013.09.0 on // (QwtPlotCurve deletes it on destruction and assignment). QwtSymbol* dataSymbol = new QwtSymbol(QwtSymbol::Triangle, dataColor, dataColor, QSize(8, 8)); m_Controls.widgetPlot->SetCurveSymbol(curveId, dataSymbol); // Again, there is no way to set a curve's legend attributes via QmitkPlotWidget so this // gets unnecessarily complicated. QwtPlotCurve* measurementCurve = dynamic_cast(m_Controls.widgetPlot-> GetPlot()->itemList(QwtPlotItem::Rtti_PlotCurve).back()); measurementCurve->setLegendAttribute(QwtPlotCurve::LegendShowSymbol); measurementCurve->setLegendIconSize(QSize(8, 8)); } // Draw positional curves for (const auto& posIter : this->m_PlotCurves.positionalPlots) { QColor dataColor; dataColor.setHsv((++colorIndex * 85) % 360, 255, 150); this->RenderPlotCurve(posIter.second.second, dataColor, dataColor, " @ "+mitk::ModelFitPlotData::GetPositionalCollectionName(posIter)); } // Draw current pos curve this->RenderPlotCurve(m_PlotCurves.currentPositionPlots, QColor(Qt::red), QColor(Qt::black), ""); QwtLegend* legend = new QwtLegend(); legend->setFrameShape(QFrame::Box); legend->setFrameShadow(QFrame::Sunken); legend->setLineWidth(1); m_Controls.widgetPlot->SetLegend(legend, QwtPlot::BottomLegend); m_Controls.widgetPlot->Replot(); } void ModelFitInspectorView::EnsureBookmarkPointSet() { if (m_PositionBookmarks.IsExpired() || m_PositionBookmarksNode.IsExpired()) { const char* nodeName = "org.mitk.gui.qt.fit.inspector.positions"; mitk::DataNode::Pointer node = this->GetDataStorage()->GetNamedNode(nodeName); if (!node) { node = mitk::DataNode::New(); node->SetName(nodeName); node->SetBoolProperty("helper object", true); this->GetDataStorage()->Add(node); } m_PositionBookmarksNode = node; mitk::PointSet::Pointer pointSet = dynamic_cast(node->GetData()); if (pointSet.IsNull()) { pointSet = mitk::PointSet::New(); node->SetData(pointSet); } m_PositionBookmarks = pointSet; } } diff --git a/Plugins/org.mitk.gui.qt.pharmacokinetics.concentration.mri/src/internal/ConcentrationCurveConverterView.cpp b/Plugins/org.mitk.gui.qt.pharmacokinetics.concentration.mri/src/internal/ConcentrationCurveConverterView.cpp index 72750ec552..1ec7c9c470 100644 --- a/Plugins/org.mitk.gui.qt.pharmacokinetics.concentration.mri/src/internal/ConcentrationCurveConverterView.cpp +++ b/Plugins/org.mitk.gui.qt.pharmacokinetics.concentration.mri/src/internal/ConcentrationCurveConverterView.cpp @@ -1,551 +1,551 @@ /*============================================================================ 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 #include "mitkWorkbenchUtil.h" #include "ConcentrationCurveConverterView.h" #include "mitkConcentrationCurveGenerator.h" #include "mitkNodePredicateDataType.h" #include "mitkConvertToConcentrationTurboFlashFunctor.h" #include "mitkConvertToConcentrationAbsoluteFunctor.h" #include "mitkConvertToConcentrationRelativeFunctor.h" #include "itkBinaryFunctorImageFilter.h" #include "boost/math/constants/constants.hpp" #include #include #include #include #include #include #include "mitkNodePredicateFunction.h" #include #include // Includes for image casting between ITK and MITK #include "mitkImageTimeSelector.h" #include "mitkImageCast.h" #include "mitkITKImageImport.h" #include #include -const std::string ConcentrationCurveConverterView::VIEW_ID = "org.mitk.ConcentrationCurveConverterView"; +const std::string ConcentrationCurveConverterView::VIEW_ID = "org.mitk.views.pharmacokinetics.concentration.mri"; void ConcentrationCurveConverterView::SetFocus() { m_Controls.btnConvertToConcentration->setFocus(); } void ConcentrationCurveConverterView::CreateQtPartControl(QWidget* parent) { m_Controls.setupUi(parent); m_Controls.btnConvertToConcentration->setEnabled(false); connect(m_Controls.btnConvertToConcentration, SIGNAL(clicked()), this, SLOT(OnConvertToConcentrationButtonClicked())); m_Controls.timeSeriesNodeSelector->SetNodePredicate(this->m_isValidTimeSeriesImagePredicate); m_Controls.timeSeriesNodeSelector->SetDataStorage(this->GetDataStorage()); m_Controls.timeSeriesNodeSelector->SetSelectionIsOptional(false); m_Controls.timeSeriesNodeSelector->SetInvalidInfo("Please select time series."); m_Controls.image3DNodeSelector->SetNodePredicate(this->m_isValidPDWImagePredicate); m_Controls.image3DNodeSelector->SetDataStorage(this->GetDataStorage()); m_Controls.image3DNodeSelector->SetSelectionIsOptional(false); m_Controls.image3DNodeSelector->SetInvalidInfo("Please select 3D image."); m_Controls.baselineImageNodeSelector->SetNodePredicate(this->m_isValidPDWImagePredicate); m_Controls.baselineImageNodeSelector->SetDataStorage(this->GetDataStorage()); m_Controls.baselineImageNodeSelector->SetSelectionIsOptional(false); m_Controls.baselineImageNodeSelector->SetInvalidInfo("Please select baseline image."); m_Controls.t2TimeSeriesNodeSelector->SetNodePredicate(this->m_isValidTimeSeriesImagePredicate); m_Controls.t2TimeSeriesNodeSelector->SetDataStorage(this->GetDataStorage()); m_Controls.t2TimeSeriesNodeSelector->SetSelectionIsOptional(false); m_Controls.t2TimeSeriesNodeSelector->SetInvalidInfo("Please select time series."); m_Controls.PDWImageNodeSelector->SetNodePredicate(m_isValidPDWImagePredicate); m_Controls.PDWImageNodeSelector->SetDataStorage(this->GetDataStorage()); m_Controls.PDWImageNodeSelector->SetInvalidInfo("Please select PDW Image."); m_Controls.PDWImageNodeSelector->setEnabled(false); m_Controls.groupBox_T1->hide(); m_Controls.groupBox_T2->hide(); m_Controls.groupBox3D->hide(); m_Controls.groupBox4D->hide(); m_Controls.groupBoxTurboFlash->hide(); m_Controls.groupConcentration->hide(); connect(m_Controls.radioButton_T1, SIGNAL(toggled(bool)),this, SLOT(OnSettingChanged())); connect(m_Controls.radioButton_T2, SIGNAL(toggled(bool)),this, SLOT(OnSettingChanged())); connect(m_Controls.radioButton3D, SIGNAL(toggled(bool)),this, SLOT(OnSettingChanged())); connect(m_Controls.radioButton4D, SIGNAL(toggled(bool)),this, SLOT(OnSettingChanged())); //Concentration m_Controls.groupConcentration->hide(); m_Controls.groupBoxEnhancement->hide(); m_Controls.groupBoxTurboFlash->hide(); m_Controls.groupBox_T1MapviaVFA->hide(); m_Controls.spinBox_baselineStartTimeStep->setValue(0); m_Controls.spinBox_baselineEndTimeStep->setValue(0); m_Controls.spinBox_baselineEndTimeStep->setMinimum(0); m_Controls.spinBox_baselineStartTimeStep->setMinimum(0); m_Controls.spinBox_baselineStartTimeStepT2->setValue(0); m_Controls.spinBox_baselineEndTimeStepT2->setValue(0); m_Controls.spinBox_baselineEndTimeStepT2->setMinimum(0); m_Controls.spinBox_baselineStartTimeStepT2->setMinimum(0); connect(m_Controls.radioButtonTurboFlash, SIGNAL(toggled(bool)), m_Controls.groupBoxTurboFlash, SLOT(setVisible(bool))); connect(m_Controls.radioButtonTurboFlash, SIGNAL(toggled(bool)), this, SLOT(OnSettingChanged())); connect(m_Controls.relaxationtime, SIGNAL(valueChanged(double)), this, SLOT(OnSettingChanged())); connect(m_Controls.recoverytime, SIGNAL(valueChanged(double)), this, SLOT(OnSettingChanged())); connect(m_Controls.relaxivity, SIGNAL(valueChanged(double)), this, SLOT(OnSettingChanged())); connect(m_Controls.timeSeriesNodeSelector, &QmitkAbstractNodeSelectionWidget::CurrentSelectionChanged, this, &ConcentrationCurveConverterView::OnNodeSelectionChanged); connect(m_Controls.image3DNodeSelector, &QmitkAbstractNodeSelectionWidget::CurrentSelectionChanged, this, &ConcentrationCurveConverterView::OnNodeSelectionChanged); connect(m_Controls.baselineImageNodeSelector, &QmitkAbstractNodeSelectionWidget::CurrentSelectionChanged, this, &ConcentrationCurveConverterView::OnNodeSelectionChanged); connect(m_Controls.t2TimeSeriesNodeSelector, &QmitkAbstractNodeSelectionWidget::CurrentSelectionChanged, this, &ConcentrationCurveConverterView::OnNodeSelectionChanged); connect(m_Controls.PDWImageNodeSelector, &QmitkAbstractNodeSelectionWidget::CurrentSelectionChanged, this, &ConcentrationCurveConverterView::OnSettingChanged); connect(m_Controls.radioButton_absoluteEnhancement, SIGNAL(toggled(bool)), this, SLOT(OnSettingChanged())); connect(m_Controls.radioButton_relativeEnchancement, SIGNAL(toggled(bool)), this, SLOT(OnSettingChanged())); connect(m_Controls.radioButton_absoluteEnhancement, SIGNAL(toggled(bool)), m_Controls.groupBoxEnhancement, SLOT(setVisible(bool))); connect(m_Controls.radioButton_relativeEnchancement, SIGNAL(toggled(bool)), m_Controls.groupBoxEnhancement, SLOT(setVisible(bool))); connect(m_Controls.factorSpinBox, SIGNAL(valueChanged(double)), this, SLOT(OnSettingChanged())); connect(m_Controls.spinBox_baselineStartTimeStep, SIGNAL(valueChanged(int)), this, SLOT(OnSettingChanged())); connect(m_Controls.spinBox_baselineEndTimeStep, SIGNAL(valueChanged(int)), this, SLOT(OnSettingChanged())); connect(m_Controls.spinBox_baselineStartTimeStepT2, SIGNAL(valueChanged(int)), this, SLOT(OnSettingChanged())); connect(m_Controls.spinBox_baselineEndTimeStepT2, SIGNAL(valueChanged(int)), this, SLOT(OnSettingChanged())); connect(m_Controls.radioButtonUsingT1viaVFA, SIGNAL(toggled(bool)), m_Controls.groupBox_T1MapviaVFA, SLOT(setVisible(bool))); connect(m_Controls.radioButtonUsingT1viaVFA, SIGNAL(toggled(bool)), this, SLOT(OnSettingChanged())); connect(m_Controls.FlipangleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(OnSettingChanged())); connect(m_Controls.RelaxivitySpinBox, SIGNAL(valueChanged(double)), this, SLOT(OnSettingChanged())); connect(m_Controls.TRSpinBox, SIGNAL(valueChanged(double)), this, SLOT(OnSettingChanged())); connect(m_Controls.T2EchoTimeSpinBox, SIGNAL(valueChanged(double)), this, SLOT(OnSettingChanged())); connect(m_Controls.T2FactorSpinBox, SIGNAL(valueChanged(double)), this, SLOT(OnSettingChanged())); connect(m_Controls.radioButtonUsingT1viaVFA, SIGNAL(toggled(bool)), m_Controls.PDWImageNodeSelector, SLOT(setEnabled(bool))); } void ConcentrationCurveConverterView::OnSettingChanged() { bool ok = false; m_Controls.groupBox_T1->setVisible(m_Controls.radioButton_T1->isChecked()); m_Controls.groupBox_T2->setVisible(m_Controls.radioButton_T2->isChecked()); if(m_Controls.radioButton_T1->isChecked()) { m_Controls.groupBox3D->setVisible(m_Controls.radioButton3D->isChecked()); m_Controls.groupBox4D->setVisible(m_Controls.radioButton4D->isChecked()); if(m_Controls.radioButton4D->isChecked()) { m_Controls.groupConcentration->setVisible(true); ok = m_selectedImage.IsNotNull() && CheckSettings(); } else if(m_Controls.radioButton3D->isChecked()) { m_Controls.groupConcentration->setVisible(true); ok = m_selectedImage.IsNotNull() && m_selectedBaselineImage.IsNotNull() && CheckSettings(); } } else if (m_Controls.radioButton_T2->isChecked()) { m_Controls.groupConcentration->setVisible(false); ok = m_selectedImage.IsNotNull() && CheckSettings(); } m_Controls.btnConvertToConcentration->setEnabled(ok); } bool ConcentrationCurveConverterView::CheckSettings() const { bool ok = true; if (m_Controls.radioButton_T1->isChecked()) { if (this->m_Controls.radioButtonTurboFlash->isChecked()) { ok = ok && (m_Controls.recoverytime->value() > 0); ok = ok && (m_Controls.relaxationtime->value() > 0); ok = ok && (m_Controls.relaxivity->value() > 0); ok = ok && (m_Controls.AifRecoverytime->value() > 0); ok = ok && CheckBaselineSelectionSettings(); } else if (this->m_Controls.radioButton_absoluteEnhancement->isChecked() || this->m_Controls.radioButton_relativeEnchancement->isChecked()) { ok = ok && (m_Controls.factorSpinBox->value() > 0); ok = ok && CheckBaselineSelectionSettings(); } else if (this->m_Controls.radioButtonUsingT1viaVFA->isChecked()) { ok = ok && (m_Controls.FlipangleSpinBox->value() > 0); ok = ok && (m_Controls.TRSpinBox->value() > 0); ok = ok && (m_Controls.RelaxivitySpinBox->value() > 0); ok = ok && (m_Controls.PDWImageNodeSelector->GetSelectedNode().IsNotNull()); ok = ok && CheckBaselineSelectionSettings(); } else { ok = false; } } else if (this->m_Controls.radioButton_T2->isChecked()) { ok = ok && m_Controls.T2EchoTimeSpinBox->value() > 0; ok = ok && m_Controls.T2FactorSpinBox->value() > 0; ok = ok && CheckBaselineSelectionSettings(); } else { ok = false; } return ok; } bool ConcentrationCurveConverterView::CheckBaselineSelectionSettings() const { if (this->m_Controls.radioButton_T1->isChecked()) { return m_Controls.spinBox_baselineStartTimeStep->value() <= m_Controls.spinBox_baselineEndTimeStep->value(); } else if (this->m_Controls.radioButton_T2->isChecked()) { return m_Controls.spinBox_baselineStartTimeStepT2->value() <= m_Controls.spinBox_baselineEndTimeStepT2->value(); } else { return 0; } } void ConcentrationCurveConverterView::OnConvertToConcentrationButtonClicked() { mitk::Image::Pointer concentrationImage; mitk::DataNode::Pointer concentrationNode; if(m_Controls.radioButton_T1->isChecked()) { if(m_Controls.radioButton4D->isChecked()) { concentrationImage = this->Convert4DConcentrationImage(this->m_selectedImage); } else if(m_Controls.radioButton3D->isChecked()) { concentrationImage = Convert3DConcentrationImage(this->m_selectedImage, this->m_selectedBaselineImage); } } else if(m_Controls.radioButton_T2->isChecked()) { concentrationImage = this->ConvertT2ConcentrationImgage(this->m_selectedImage); } std::string nameOfResultImage = m_selectedNode->GetName(); nameOfResultImage.append("_Concentration"); concentrationNode = AddConcentrationImage(concentrationImage,nameOfResultImage); } mitk::Image::Pointer ConcentrationCurveConverterView::Convert3DConcentrationImage(mitk::Image::Pointer inputImage,mitk::Image::Pointer baselineImage) { typedef itk::Image InputImageType; InputImageType::Pointer itkInputImage = InputImageType::New(); InputImageType::Pointer itkBaselineImage = InputImageType::New(); mitk::CastToItkImage(inputImage, itkInputImage ); mitk::CastToItkImage(baselineImage, itkBaselineImage ); mitk::Image::Pointer outputImage; if(this->m_Controls.radioButtonTurboFlash->isChecked()) { typedef mitk::ConvertToConcentrationTurboFlashFunctor ConversionFunctorTurboFlashType; typedef itk::BinaryFunctorImageFilter FilterTurboFlashType; ConversionFunctorTurboFlashType ConversionTurboFlashFunctor; ConversionTurboFlashFunctor.initialize(m_Controls.relaxationtime->value(), m_Controls.relaxivity->value(), m_Controls.recoverytime->value()); FilterTurboFlashType::Pointer ConversionTurboFlashFilter = FilterTurboFlashType::New(); ConversionTurboFlashFilter->SetFunctor(ConversionTurboFlashFunctor); ConversionTurboFlashFilter->SetInput1(itkInputImage); ConversionTurboFlashFilter->SetInput2(itkBaselineImage); ConversionTurboFlashFilter->Update(); outputImage = mitk::ImportItkImage(ConversionTurboFlashFilter->GetOutput())->Clone(); } else if(this->m_Controls.radioButton_absoluteEnhancement->isChecked()) { typedef mitk::ConvertToConcentrationAbsoluteFunctor ConversionFunctorAbsoluteType; typedef itk::BinaryFunctorImageFilter FilterAbsoluteType; ConversionFunctorAbsoluteType ConversionAbsoluteFunctor; ConversionAbsoluteFunctor.initialize(m_Controls.factorSpinBox->value()); FilterAbsoluteType::Pointer ConversionAbsoluteFilter = FilterAbsoluteType::New(); ConversionAbsoluteFilter->SetFunctor(ConversionAbsoluteFunctor); ConversionAbsoluteFilter->SetInput1(itkInputImage); ConversionAbsoluteFilter->SetInput2(itkBaselineImage); ConversionAbsoluteFilter->Update(); outputImage = mitk::ImportItkImage(ConversionAbsoluteFilter->GetOutput())->Clone(); } else if(m_Controls.radioButton_relativeEnchancement->isChecked()) { typedef mitk::ConvertToConcentrationRelativeFunctor ConversionFunctorRelativeType; typedef itk::BinaryFunctorImageFilter FilterRelativeType; ConversionFunctorRelativeType ConversionRelativeFunctor; ConversionRelativeFunctor.initialize(m_Controls.factorSpinBox->value()); FilterRelativeType::Pointer ConversionRelativeFilter = FilterRelativeType::New(); ConversionRelativeFilter->SetFunctor(ConversionRelativeFunctor); ConversionRelativeFilter->SetInput1(itkInputImage); ConversionRelativeFilter->SetInput2(itkBaselineImage); ConversionRelativeFilter->Update(); outputImage = mitk::ImportItkImage(ConversionRelativeFilter->GetOutput())->Clone(); } return outputImage; } mitk::DataNode::Pointer ConcentrationCurveConverterView::AddConcentrationImage(mitk::Image* image, std::string nodeName) const { if (!image) { mitkThrow() << "Cannot generate concentration node. Passed image is null. parameter name: "; } mitk::DataNode::Pointer result = mitk::DataNode::New(); result->SetData(image); result->SetName(nodeName); result->SetVisibility(true); this->GetDataStorage()->Add(result, m_selectedNode); return result; }; mitk::Image::Pointer ConcentrationCurveConverterView::Convert4DConcentrationImage(mitk::Image::Pointer inputImage) { //Compute Concentration image mitk::ConcentrationCurveGenerator::Pointer concentrationGen = mitk::ConcentrationCurveGenerator::New(); concentrationGen->SetDynamicImage(inputImage); concentrationGen->SetisTurboFlashSequence(m_Controls.radioButtonTurboFlash->isChecked()); concentrationGen->SetAbsoluteSignalEnhancement(m_Controls.radioButton_absoluteEnhancement->isChecked()); concentrationGen->SetRelativeSignalEnhancement(m_Controls.radioButton_relativeEnchancement->isChecked()); concentrationGen->SetUsingT1Map(m_Controls.radioButtonUsingT1viaVFA->isChecked()); concentrationGen->SetBaselineStartTimeStep(m_Controls.spinBox_baselineStartTimeStepT2->value()); concentrationGen->SetBaselineEndTimeStep(m_Controls.spinBox_baselineEndTimeStepT2->value()); concentrationGen->SetisT2weightedImage(false); if (m_Controls.radioButtonTurboFlash->isChecked()) { concentrationGen->SetRecoveryTime(m_Controls.recoverytime->value()); concentrationGen->SetRelaxationTime(m_Controls.relaxationtime->value()); concentrationGen->SetRelaxivity(m_Controls.relaxivity->value()); concentrationGen->SetBaselineStartTimeStep(m_Controls.spinBox_baselineStartTimeStep->value()); concentrationGen->SetBaselineEndTimeStep(m_Controls.spinBox_baselineEndTimeStep->value()); } else if (this->m_Controls.radioButtonUsingT1viaVFA->isChecked()) { concentrationGen->SetRecoveryTime(m_Controls.TRSpinBox->value()); concentrationGen->SetRelaxivity(m_Controls.RelaxivitySpinBox->value()); concentrationGen->SetT10Image(dynamic_cast(m_Controls.PDWImageNodeSelector->GetSelectedNode()->GetData())); concentrationGen->SetBaselineStartTimeStep(m_Controls.spinBox_baselineStartTimeStep->value()); concentrationGen->SetBaselineEndTimeStep(m_Controls.spinBox_baselineEndTimeStep->value()); //Convert Flipangle from degree to radiant double alpha = m_Controls.FlipangleSpinBox->value()/360*2* boost::math::constants::pi(); concentrationGen->SetFlipAngle(alpha); } else { concentrationGen->SetFactor(m_Controls.factorSpinBox->value()); concentrationGen->SetBaselineStartTimeStep(m_Controls.spinBox_baselineStartTimeStep->value()); concentrationGen->SetBaselineEndTimeStep(m_Controls.spinBox_baselineEndTimeStep->value()); } mitk::Image::Pointer concentrationImage = concentrationGen->GetConvertedImage(); return concentrationImage; } mitk::Image::Pointer ConcentrationCurveConverterView::ConvertT2ConcentrationImgage(mitk::Image::Pointer inputImage) { //Compute Concentration image mitk::ConcentrationCurveGenerator::Pointer concentrationGen = mitk::ConcentrationCurveGenerator::New(); concentrationGen->SetDynamicImage(inputImage); concentrationGen->SetisTurboFlashSequence(false); concentrationGen->SetAbsoluteSignalEnhancement(false); concentrationGen->SetRelativeSignalEnhancement(false); concentrationGen->SetisT2weightedImage(true); concentrationGen->SetT2Factor(m_Controls.T2FactorSpinBox->value()); concentrationGen->SetT2EchoTime(m_Controls.T2EchoTimeSpinBox->value()); concentrationGen->SetBaselineStartTimeStep(m_Controls.spinBox_baselineStartTimeStep->value()); concentrationGen->SetBaselineEndTimeStep(m_Controls.spinBox_baselineEndTimeStep->value()); mitk::Image::Pointer concentrationImage = concentrationGen->GetConvertedImage(); return concentrationImage; } void ConcentrationCurveConverterView::OnNodeSelectionChanged(QList/*nodes*/) { m_selectedNode = nullptr; m_selectedImage = nullptr; m_selectedBaselineNode = nullptr; m_selectedBaselineImage = nullptr; if (m_Controls.radioButton_T1->isChecked()) { if (m_Controls.radioButton4D->isChecked()) { if (m_Controls.timeSeriesNodeSelector->GetSelectedNode().IsNotNull()) { this->m_selectedNode = m_Controls.timeSeriesNodeSelector->GetSelectedNode(); m_selectedImage = dynamic_cast(m_selectedNode->GetData()); } else { this->m_selectedNode = nullptr; this->m_selectedImage = nullptr; } } else if (m_Controls.radioButton3D->isChecked()) { if (m_Controls.image3DNodeSelector->GetSelectedNode().IsNotNull() && m_Controls.baselineImageNodeSelector->GetSelectedNode().IsNotNull()) { this->m_selectedNode = m_Controls.image3DNodeSelector->GetSelectedNode(); m_selectedImage = dynamic_cast(m_selectedNode->GetData()); this->m_selectedBaselineNode = m_Controls.baselineImageNodeSelector->GetSelectedNode(); m_selectedBaselineImage = dynamic_cast(m_selectedBaselineNode->GetData()); } else { this->m_selectedNode = nullptr; this->m_selectedImage = nullptr; m_selectedBaselineNode = nullptr; m_selectedBaselineImage = nullptr; } } if (this->m_selectedImage.IsNotNull()) { m_Controls.spinBox_baselineStartTimeStep->setMaximum((this->m_selectedImage->GetDimension(3)) - 1); m_Controls.spinBox_baselineEndTimeStep->setMaximum((this->m_selectedImage->GetDimension(3)) - 1); } } if (m_Controls.radioButton_T2->isChecked()) { if (m_Controls.t2TimeSeriesNodeSelector->GetSelectedNode().IsNotNull()) { this->m_selectedNode = m_Controls.t2TimeSeriesNodeSelector->GetSelectedNode(); m_selectedImage = dynamic_cast(m_selectedNode->GetData()); } else { this->m_selectedNode = nullptr; this->m_selectedImage = nullptr; } if (this->m_selectedImage.IsNotNull()) { m_Controls.spinBox_baselineStartTimeStepT2->setMaximum((this->m_selectedImage->GetDimension(3)) - 1); m_Controls.spinBox_baselineEndTimeStepT2->setMaximum((this->m_selectedImage->GetDimension(3)) - 1); } } m_Controls.btnConvertToConcentration->setEnabled(m_selectedImage.IsNotNull() && CheckSettings()); } ConcentrationCurveConverterView::ConcentrationCurveConverterView() { mitk::NodePredicateDataType::Pointer isLabelSet = mitk::NodePredicateDataType::New("LabelSetImage"); mitk::NodePredicateDataType::Pointer isImage = mitk::NodePredicateDataType::New("Image"); mitk::NodePredicateProperty::Pointer isBinary = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); mitk::NodePredicateAnd::Pointer isLegacyMask = mitk::NodePredicateAnd::New(isImage, isBinary); mitk::NodePredicateDimension::Pointer is3D = mitk::NodePredicateDimension::New(3); mitk::NodePredicateOr::Pointer isMask = mitk::NodePredicateOr::New(isLegacyMask, isLabelSet); mitk::NodePredicateAnd::Pointer isNoMask = mitk::NodePredicateAnd::New(isImage, mitk::NodePredicateNot::New(isMask)); mitk::NodePredicateAnd::Pointer is3DImage = mitk::NodePredicateAnd::New(isImage, is3D, isNoMask); this->m_IsMaskPredicate = mitk::NodePredicateAnd::New(isMask, mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object"))).GetPointer(); this->m_IsNoMaskImagePredicate = mitk::NodePredicateAnd::New(isNoMask, mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object"))).GetPointer(); auto isDynamicData = mitk::NodePredicateFunction::New([](const mitk::DataNode* node) { return (node && node->GetData() && node->GetData()->GetTimeSteps() > 1); }); auto modelFitResultRelationRule = mitk::ModelFitResultRelationRule::New(); auto isNoModelFitNodePredicate = mitk::NodePredicateNot::New(modelFitResultRelationRule->GetConnectedSourcesDetector()); this->m_isValidPDWImagePredicate = mitk::NodePredicateAnd::New(is3DImage, isNoModelFitNodePredicate); this->m_isValidTimeSeriesImagePredicate = mitk::NodePredicateAnd::New(isDynamicData, isImage, isNoMask); } diff --git a/Plugins/org.mitk.gui.qt.pharmacokinetics.curvedescriptor/src/internal/PerfusionCurveDescriptionParameterView.cpp b/Plugins/org.mitk.gui.qt.pharmacokinetics.curvedescriptor/src/internal/PerfusionCurveDescriptionParameterView.cpp index 58a2b09b74..8a3f465aff 100644 --- a/Plugins/org.mitk.gui.qt.pharmacokinetics.curvedescriptor/src/internal/PerfusionCurveDescriptionParameterView.cpp +++ b/Plugins/org.mitk.gui.qt.pharmacokinetics.curvedescriptor/src/internal/PerfusionCurveDescriptionParameterView.cpp @@ -1,216 +1,216 @@ /*============================================================================ 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 #include #include "mitkWorkbenchUtil.h" #include "PerfusionCurveDescriptionParameterView.h" #include "QmitkDescriptionParameterBackgroundJob.h" #include "mitkAreaUnderTheCurveDescriptionParameter.h" #include "mitkAreaUnderFirstMomentDescriptionParameter.h" #include "mitkMeanResidenceTimeDescriptionParameter.h" #include "mitkTimeToPeakCurveDescriptionParameter.h" #include "mitkMaximumCurveDescriptionParameter.h" #include "mitkPixelBasedDescriptionParameterImageGenerator.h" #include "mitkCurveParameterFunctor.h" #include "mitkExtractTimeGrid.h" #include const std::string PerfusionCurveDescriptionParameterView::VIEW_ID = - "org.mitk.gui.qt.pharmacokinetics.curvedescriptor"; + "org.mitk.views.pharmacokinetics.curvedescriptor"; void PerfusionCurveDescriptionParameterView::SetFocus() { m_Controls.btnCalculateParameters->setFocus(); } void PerfusionCurveDescriptionParameterView::CreateQtPartControl(QWidget* parent) { m_Controls.setupUi(parent); m_Controls.btnCalculateParameters->setEnabled(false); connect(m_Controls.btnCalculateParameters, SIGNAL(clicked()), this, SLOT(OnCalculateParametersButtonClicked())); InitParameterList(); } void PerfusionCurveDescriptionParameterView::OnSelectionChanged( berry::IWorkbenchPart::Pointer /*source*/, const QList& /*nodes*/) { m_Controls.btnCalculateParameters->setEnabled(false); QList dataNodes = this->GetDataManagerSelection(); if (dataNodes.empty()) { m_selectedNode = nullptr; m_selectedImage = nullptr; } else { m_selectedNode = dataNodes[0]; m_selectedImage = dynamic_cast(m_selectedNode->GetData()); } m_Controls.lableSelectedImage->setText("No series selected."); if (m_selectedImage.IsNotNull()) { if (m_selectedImage->GetTimeGeometry()->CountTimeSteps() > 1) { m_Controls.btnCalculateParameters->setEnabled(true); m_Controls.lableSelectedImage->setText((this->m_selectedNode->GetName()).c_str()); } else { this->OnJobStatusChanged("Cannot compute parameters. Selected image must have multiple time steps."); } } else if (m_selectedNode.IsNotNull()) { this->OnJobStatusChanged("Cannot compute parameters. Selected node is not an image."); } else { this->OnJobStatusChanged("Cannot compute parameters. No node selected."); } } PerfusionCurveDescriptionParameterView::PerfusionCurveDescriptionParameterView() { m_selectedNode = nullptr; m_selectedImage = nullptr; m_selectedMask = nullptr; } void PerfusionCurveDescriptionParameterView::InitParameterList() { m_ParameterMap.clear(); mitk::CurveDescriptionParameterBase::Pointer parameterFunction = mitk::AreaUnderTheCurveDescriptionParameter::New().GetPointer(); m_ParameterMap.insert(std::make_pair(ParameterNameType("AUC"), parameterFunction)); parameterFunction = mitk::AreaUnderFirstMomentDescriptionParameter::New().GetPointer(); m_ParameterMap.insert(std::make_pair(ParameterNameType("AUMC"), parameterFunction)); parameterFunction = mitk::MeanResidenceTimeDescriptionParameter::New().GetPointer(); m_ParameterMap.insert(std::make_pair(ParameterNameType("MRT"), parameterFunction)); parameterFunction = mitk::MaximumCurveDescriptionParameter::New().GetPointer(); m_ParameterMap.insert(std::make_pair(ParameterNameType("Maximum"), parameterFunction)); parameterFunction = mitk::TimeToPeakCurveDescriptionParameter::New().GetPointer(); m_ParameterMap.insert(std::make_pair(ParameterNameType("TimeToPeak"), parameterFunction)); for (ParameterMapType::const_iterator pos = m_ParameterMap.begin(); pos != m_ParameterMap.end(); ++pos) { QListWidgetItem* item = new QListWidgetItem(QString::fromStdString(pos->first), this->m_Controls.parameterlist); item->setFlags(item->flags() | Qt::ItemIsUserCheckable); item->setCheckState(Qt::Unchecked); } }; void PerfusionCurveDescriptionParameterView::ConfigureFunctor(mitk::CurveParameterFunctor* functor) const { functor->SetGrid(mitk::ExtractTimeGrid(m_selectedImage)); for (int pos = 0; pos < this->m_Controls.parameterlist->count(); ++pos) { QListWidgetItem* item = this->m_Controls.parameterlist->item(pos); mitk::CurveDescriptionParameterBase::Pointer parameterFunction = m_ParameterMap.at( item->text().toStdString()); if (item->checkState() == Qt::Checked) { functor->RegisterDescriptionParameter(item->text().toStdString(), parameterFunction); } } } void PerfusionCurveDescriptionParameterView::OnCalculateParametersButtonClicked() { mitk::PixelBasedDescriptionParameterImageGenerator::Pointer generator = mitk::PixelBasedDescriptionParameterImageGenerator::New(); mitk::CurveParameterFunctor::Pointer functor = mitk::CurveParameterFunctor::New(); this->ConfigureFunctor(functor); generator->SetFunctor(functor); generator->SetDynamicImage(m_selectedImage); generator->SetMask(m_selectedMask); ///////////////////////// //create job and put it into the thread pool DescriptionParameterBackgroundJob* pJob = new DescriptionParameterBackgroundJob(generator, this->m_selectedNode); pJob->setAutoDelete(true); connect(pJob, SIGNAL(Error(QString)), this, SLOT(OnJobError(QString))); connect(pJob, SIGNAL(Finished()), this, SLOT(OnJobFinished())); connect(pJob, SIGNAL(ResultsAreAvailable(mitk::modelFit::ModelFitResultNodeVectorType, const DescriptionParameterBackgroundJob*)), this, SLOT(OnJobResultsAreAvailable(mitk::modelFit::ModelFitResultNodeVectorType, const DescriptionParameterBackgroundJob*)), Qt::BlockingQueuedConnection); connect(pJob, SIGNAL(JobProgress(double)), this, SLOT(OnJobProgress(double))); connect(pJob, SIGNAL(JobStatusChanged(QString)), this, SLOT(OnJobStatusChanged(QString))); QThreadPool* threadPool = QThreadPool::globalInstance(); threadPool->start(pJob); } void PerfusionCurveDescriptionParameterView::OnJobFinished() { this->m_Controls.infoBox->append(QString("Fitting finished")); }; void PerfusionCurveDescriptionParameterView::OnJobError(QString err) { MITK_ERROR << err.toStdString().c_str(); m_Controls.infoBox->append(QString("") + err + QString("")); }; void PerfusionCurveDescriptionParameterView::OnJobResultsAreAvailable( mitk::modelFit::ModelFitResultNodeVectorType results, const DescriptionParameterBackgroundJob* pJob) { for (auto image : results) { this->GetDataStorage()->Add(image, pJob->GetParentNode()); } }; void PerfusionCurveDescriptionParameterView::OnJobProgress(double progress) { this->m_Controls.progressBar->setValue(100 * progress); QString report = QString("Progress. ") + QString::number(progress); this->m_Controls.infoBox->append(report); }; void PerfusionCurveDescriptionParameterView::OnJobStatusChanged(QString info) { this->m_Controls.infoBox->append(info); MITK_INFO << info.toStdString().c_str(); } diff --git a/Plugins/org.mitk.gui.qt.pharmacokinetics.mri/src/internal/MRPerfusionView.cpp b/Plugins/org.mitk.gui.qt.pharmacokinetics.mri/src/internal/MRPerfusionView.cpp index 9ee2b5e3f5..5158170817 100644 --- a/Plugins/org.mitk.gui.qt.pharmacokinetics.mri/src/internal/MRPerfusionView.cpp +++ b/Plugins/org.mitk.gui.qt.pharmacokinetics.mri/src/internal/MRPerfusionView.cpp @@ -1,1485 +1,1485 @@ /*============================================================================ 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 "MRPerfusionView.h" #include "boost/tokenizer.hpp" #include "boost/math/constants/constants.hpp" #include #include "mitkWorkbenchUtil.h" #include "mitkAterialInputFunctionGenerator.h" #include "mitkConcentrationCurveGenerator.h" #include #include #include #include "mitkThreeStepLinearModelFactory.h" #include "mitkThreeStepLinearModelParameterizer.h" #include "mitkTwoStepLinearModelFactory.h" #include "mitkTwoStepLinearModelParameterizer.h" #include #include #include #include #include "mitkTwoCompartmentExchangeModelFactory.h" #include "mitkTwoCompartmentExchangeModelParameterizer.h" #include "mitkNumericTwoCompartmentExchangeModelFactory.h" #include "mitkNumericTwoCompartmentExchangeModelParameterizer.h" #include #include #include #include #include #include #include #include "mitkNodePredicateFunction.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Includes for image casting between ITK and MITK #include #include "mitkImageCast.h" #include "mitkITKImageImport.h" #include #include -const std::string MRPerfusionView::VIEW_ID = "org.mitk.gui.qt.pharmacokinetics.mri"; +const std::string MRPerfusionView::VIEW_ID = "org.mitk.views.pharmacokinetics.mri"; inline double convertToDouble(const std::string& data) { std::istringstream stepStream(data); stepStream.imbue(std::locale("C")); double value = 0.0; if (!(stepStream >> value) || !(stepStream.eof())) { mitkThrow() << "Cannot convert string to double. String: " << data; } return value; } void MRPerfusionView::SetFocus() { m_Controls.btnModelling->setFocus(); } void MRPerfusionView::CreateQtPartControl(QWidget* parent) { m_Controls.setupUi(parent); m_Controls.btnModelling->setEnabled(false); this->InitModelComboBox(); m_Controls.timeSeriesNodeSelector->SetNodePredicate(this->m_isValidTimeSeriesImagePredicate); m_Controls.timeSeriesNodeSelector->SetDataStorage(this->GetDataStorage()); m_Controls.timeSeriesNodeSelector->SetSelectionIsOptional(false); m_Controls.timeSeriesNodeSelector->SetInvalidInfo("Please select time series."); m_Controls.timeSeriesNodeSelector->SetAutoSelectNewNodes(true); m_Controls.maskNodeSelector->SetNodePredicate(this->m_IsMaskPredicate); m_Controls.maskNodeSelector->SetDataStorage(this->GetDataStorage()); m_Controls.maskNodeSelector->SetSelectionIsOptional(true); m_Controls.maskNodeSelector->SetEmptyInfo("Please select (optional) mask."); connect(m_Controls.btnModelling, SIGNAL(clicked()), this, SLOT(OnModellingButtonClicked())); connect(m_Controls.comboModel, SIGNAL(currentIndexChanged(int)), this, SLOT(OnModellSet(int))); connect(m_Controls.radioPixelBased, SIGNAL(toggled(bool)), this, SLOT(UpdateGUIControls())); connect(m_Controls.timeSeriesNodeSelector, &QmitkAbstractNodeSelectionWidget::CurrentSelectionChanged, this, &MRPerfusionView::OnNodeSelectionChanged); connect(m_Controls.maskNodeSelector, &QmitkAbstractNodeSelectionWidget::CurrentSelectionChanged, this, &MRPerfusionView::OnNodeSelectionChanged); connect(m_Controls.AIFMaskNodeSelector, &QmitkAbstractNodeSelectionWidget::CurrentSelectionChanged, this, &MRPerfusionView::UpdateGUIControls); connect(m_Controls.AIFImageNodeSelector, &QmitkAbstractNodeSelectionWidget::CurrentSelectionChanged, this, &MRPerfusionView::UpdateGUIControls); //AIF setting m_Controls.groupAIF->hide(); m_Controls.btnAIFFile->setEnabled(false); m_Controls.btnAIFFile->setEnabled(false); m_Controls.radioAIFImage->setChecked(true); m_Controls.AIFMaskNodeSelector->SetDataStorage(this->GetDataStorage()); m_Controls.AIFMaskNodeSelector->SetNodePredicate(m_IsMaskPredicate); m_Controls.AIFMaskNodeSelector->setVisible(true); m_Controls.AIFMaskNodeSelector->setEnabled(true); m_Controls.AIFMaskNodeSelector->SetAutoSelectNewNodes(true); m_Controls.AIFImageNodeSelector->SetDataStorage(this->GetDataStorage()); m_Controls.AIFImageNodeSelector->SetNodePredicate(this->m_isValidTimeSeriesImagePredicate); m_Controls.AIFImageNodeSelector->setEnabled(false); m_Controls.checkDedicatedAIFImage->setEnabled(true); m_Controls.HCLSpinBox->setValue(mitk::AterialInputFunctionGenerator::DEFAULT_HEMATOCRIT_LEVEL); m_Controls.spinBox_baselineEndTimeStep->setMinimum(0); m_Controls.spinBox_baselineStartTimeStep->setMinimum(0); connect(m_Controls.radioAIFImage, SIGNAL(toggled(bool)), m_Controls.AIFMaskNodeSelector, SLOT(setVisible(bool))); connect(m_Controls.radioAIFImage, SIGNAL(toggled(bool)), m_Controls.labelAIFMask, SLOT(setVisible(bool))); connect(m_Controls.radioAIFImage, SIGNAL(toggled(bool)), m_Controls.checkDedicatedAIFImage, SLOT(setVisible(bool))); connect(m_Controls.radioAIFImage, SIGNAL(toggled(bool)), m_Controls.AIFMaskNodeSelector, SLOT(setEnabled(bool))); connect(m_Controls.radioAIFImage, SIGNAL(toggled(bool)), m_Controls.checkDedicatedAIFImage, SLOT(setEnabled(bool))); connect(m_Controls.radioAIFImage, SIGNAL(toggled(bool)), m_Controls.checkDedicatedAIFImage, SLOT(setVisible(bool))); connect(m_Controls.radioAIFImage, SIGNAL(toggled(bool)), m_Controls.AIFImageNodeSelector, SLOT(setVisible(bool))); connect(m_Controls.checkDedicatedAIFImage, SIGNAL(toggled(bool)), m_Controls.AIFImageNodeSelector, SLOT(setEnabled(bool))); connect(m_Controls.radioAIFImage, SIGNAL(toggled(bool)), this, SLOT(UpdateGUIControls())); connect(m_Controls.radioAIFFile, SIGNAL(toggled(bool)), m_Controls.btnAIFFile, SLOT(setEnabled(bool))); connect(m_Controls.radioAIFFile, SIGNAL(toggled(bool)), m_Controls.aifFilePath, SLOT(setEnabled(bool))); connect(m_Controls.radioAIFFile, SIGNAL(toggled(bool)), this, SLOT(UpdateGUIControls())); connect(m_Controls.btnAIFFile, SIGNAL(clicked()), this, SLOT(LoadAIFfromFile())); //Brix setting m_Controls.groupDescBrix->hide(); connect(m_Controls.injectiontime, SIGNAL(valueChanged(double)), this, SLOT(UpdateGUIControls())); //Num2CX setting m_Controls.groupNum2CXM->hide(); connect(m_Controls.odeStepSize, SIGNAL(valueChanged(double)), this, SLOT(UpdateGUIControls())); //Model fit configuration m_Controls.groupBox_FitConfiguration->hide(); m_Controls.checkBox_Constraints->setEnabled(false); m_Controls.constraintManager->setEnabled(false); m_Controls.initialValuesManager->setEnabled(false); m_Controls.initialValuesManager->setDataStorage(this->GetDataStorage()); connect(m_Controls.radioButton_StartParameters, SIGNAL(toggled(bool)), this, SLOT(UpdateGUIControls())); connect(m_Controls.checkBox_Constraints, SIGNAL(toggled(bool)), this, SLOT(UpdateGUIControls())); connect(m_Controls.initialValuesManager, SIGNAL(initialValuesChanged(void)), this, SLOT(UpdateGUIControls())); connect(m_Controls.radioButton_StartParameters, SIGNAL(toggled(bool)), m_Controls.initialValuesManager, SLOT(setEnabled(bool))); connect(m_Controls.checkBox_Constraints, SIGNAL(toggled(bool)), m_Controls.constraintManager, SLOT(setEnabled(bool))); connect(m_Controls.checkBox_Constraints, SIGNAL(toggled(bool)), m_Controls.constraintManager, SLOT(setVisible(bool))); //Concentration m_Controls.groupConcentration->hide(); m_Controls.groupBoxEnhancement->hide(); m_Controls.groupBoxTurboFlash->hide(); m_Controls.radioButtonNoConversion->setChecked(true); m_Controls.groupBox_T1MapviaVFA->hide(); m_Controls.spinBox_baselineStartTimeStep->setValue(0); m_Controls.spinBox_baselineEndTimeStep->setValue(0); connect(m_Controls.radioButtonTurboFlash, SIGNAL(toggled(bool)), m_Controls.groupBoxTurboFlash, SLOT(setVisible(bool))); connect(m_Controls.radioButtonTurboFlash, SIGNAL(toggled(bool)), this, SLOT(UpdateGUIControls())); connect(m_Controls.relaxationtime, SIGNAL(valueChanged(double)), this, SLOT(UpdateGUIControls())); connect(m_Controls.recoverytime, SIGNAL(valueChanged(double)), this, SLOT(UpdateGUIControls())); connect(m_Controls.relaxivity, SIGNAL(valueChanged(double)), this, SLOT(UpdateGUIControls())); connect(m_Controls.radioButton_absoluteEnhancement, SIGNAL(toggled(bool)), this, SLOT(UpdateGUIControls())); connect(m_Controls.radioButton_relativeEnchancement, SIGNAL(toggled(bool)), this, SLOT(UpdateGUIControls())); connect(m_Controls.radioButton_absoluteEnhancement, SIGNAL(toggled(bool)), m_Controls.groupBoxEnhancement, SLOT(setVisible(bool))); connect(m_Controls.radioButton_relativeEnchancement, SIGNAL(toggled(bool)), m_Controls.groupBoxEnhancement, SLOT(setVisible(bool))); connect(m_Controls.factorSpinBox, SIGNAL(valueChanged(double)), this, SLOT(UpdateGUIControls())); connect(m_Controls.spinBox_baselineStartTimeStep, SIGNAL(valueChanged(int)), this, SLOT(UpdateGUIControls())); connect(m_Controls.spinBox_baselineEndTimeStep, SIGNAL(valueChanged(int)), this, SLOT(UpdateGUIControls())); connect(m_Controls.radioButtonUsingT1viaVFA, SIGNAL(toggled(bool)), m_Controls.groupBox_T1MapviaVFA, SLOT(setVisible(bool))); connect(m_Controls.radioButtonUsingT1viaVFA, SIGNAL(toggled(bool)), this, SLOT(UpdateGUIControls())); connect(m_Controls.FlipangleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(UpdateGUIControls())); connect(m_Controls.RelaxivitySpinBox, SIGNAL(valueChanged(double)), this, SLOT(UpdateGUIControls())); connect(m_Controls.TRSpinBox, SIGNAL(valueChanged(double)), this, SLOT(UpdateGUIControls())); m_Controls.PDWImageNodeSelector->SetNodePredicate(m_isValidPDWImagePredicate); m_Controls.PDWImageNodeSelector->SetDataStorage(this->GetDataStorage()); m_Controls.PDWImageNodeSelector->SetInvalidInfo("Please select PDW Image."); m_Controls.PDWImageNodeSelector->setEnabled(false); connect(m_Controls.radioButtonUsingT1viaVFA, SIGNAL(toggled(bool)), m_Controls.PDWImageNodeSelector, SLOT(setEnabled(bool))); UpdateGUIControls(); } bool MRPerfusionView::IsTurboFlashSequenceFlag() const { return this->m_Controls.radioButtonTurboFlash->isChecked(); }; void MRPerfusionView::UpdateGUIControls() { m_Controls.lineFitName->setPlaceholderText(QString::fromStdString(this->GetDefaultFitName())); m_Controls.lineFitName->setEnabled(!m_FittingInProgress); m_Controls.checkBox_Constraints->setEnabled(m_modelConstraints.IsNotNull()); bool isDescBrixFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool isToftsFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr || dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool is2CXMFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr || dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool isNum2CXMFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool isSLFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr || dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; m_Controls.groupAIF->setVisible(isToftsFactory || is2CXMFactory); m_Controls.groupDescBrix->setVisible(isDescBrixFactory); m_Controls.groupNum2CXM->setVisible(isNum2CXMFactory); m_Controls.groupConcentration->setVisible(isToftsFactory || is2CXMFactory || isSLFactory); m_Controls.groupBox_FitConfiguration->setVisible(m_selectedModelFactory); m_Controls.groupBox->setEnabled(!m_FittingInProgress); m_Controls.comboModel->setEnabled(!m_FittingInProgress); m_Controls.groupAIF->setEnabled(!m_FittingInProgress); m_Controls.groupDescBrix->setEnabled(!m_FittingInProgress); m_Controls.groupNum2CXM->setEnabled(!m_FittingInProgress); m_Controls.groupConcentration->setEnabled(!m_FittingInProgress); m_Controls.groupBox_FitConfiguration->setEnabled(!m_FittingInProgress); m_Controls.radioROIbased->setEnabled(m_selectedMask.IsNotNull()); m_Controls.btnModelling->setEnabled(m_selectedImage.IsNotNull() && m_selectedModelFactory.IsNotNull() && !m_FittingInProgress && CheckModelSettings()); m_Controls.spinBox_baselineStartTimeStep->setEnabled(m_Controls.radioButtonTurboFlash->isChecked() || m_Controls.radioButton_absoluteEnhancement->isChecked() || m_Controls.radioButton_relativeEnchancement->isChecked() || m_Controls.radioButtonUsingT1viaVFA->isChecked()); m_Controls.spinBox_baselineEndTimeStep->setEnabled(m_Controls.radioButton_absoluteEnhancement->isChecked() || m_Controls.radioButton_relativeEnchancement->isChecked() || m_Controls.radioButtonUsingT1viaVFA->isChecked() || m_Controls.radioButtonTurboFlash->isChecked()); } void MRPerfusionView::OnModellSet(int index) { m_selectedModelFactory = nullptr; if (index > 0) { if (static_cast(index) <= m_FactoryStack.size() ) { m_selectedModelFactory = m_FactoryStack[index - 1]; } else { MITK_WARN << "Invalid model index. Index outside of the factory stack. Factory stack size: "<< m_FactoryStack.size() << "; invalid index: "<< index; } } if (m_selectedModelFactory) { this->m_modelConstraints = dynamic_cast (m_selectedModelFactory->CreateDefaultConstraints().GetPointer()); m_Controls.initialValuesManager->setInitialValues(m_selectedModelFactory->GetParameterNames(), m_selectedModelFactory->GetDefaultInitialParameterization()); if (this->m_modelConstraints.IsNull()) { this->m_modelConstraints = mitk::SimpleBarrierConstraintChecker::New(); } m_Controls.constraintManager->setChecker(this->m_modelConstraints, this->m_selectedModelFactory->GetParameterNames()); } UpdateGUIControls(); } std::string MRPerfusionView::GetFitName() const { std::string fitName = m_Controls.lineFitName->text().toStdString(); if (fitName.empty()) { fitName = m_Controls.lineFitName->placeholderText().toStdString(); } return fitName; } std::string MRPerfusionView::GetDefaultFitName() const { std::string defaultName = "undefined model"; if (this->m_selectedModelFactory.IsNotNull()) { defaultName = this->m_selectedModelFactory->GetClassID(); } if (this->m_Controls.radioPixelBased->isChecked()) { defaultName += "_pixel"; } else { defaultName += "_roi"; } return defaultName; } void MRPerfusionView::OnModellingButtonClicked() { //check if all static parameters set if (m_selectedModelFactory.IsNotNull() && CheckModelSettings()) { m_HasGeneratedNewInput = false; m_HasGeneratedNewInputAIF = false; mitk::ParameterFitImageGeneratorBase::Pointer generator = nullptr; mitk::modelFit::ModelFitInfo::Pointer fitSession = nullptr; bool isDescBrixFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool is3LinearFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool is2LinearFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool isExtToftsFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool isStanToftsFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool is2CXMFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool isNum2CXMFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; if (isDescBrixFactory) { if (this->m_Controls.radioPixelBased->isChecked()) { GenerateDescriptiveBrixModel_PixelBased(fitSession, generator); } else { GenerateDescriptiveBrixModel_ROIBased(fitSession, generator); } } else if (is2LinearFactory) { if (this->m_Controls.radioPixelBased->isChecked()) { GenerateLinearModelFit_PixelBased(fitSession, generator); } else { GenerateLinearModelFit_ROIBased(fitSession, generator); } } else if (is3LinearFactory) { if (this->m_Controls.radioPixelBased->isChecked()) { GenerateLinearModelFit_PixelBased(fitSession, generator); } else { GenerateLinearModelFit_ROIBased(fitSession, generator); } } else if (isStanToftsFactory) { if (this->m_Controls.radioPixelBased->isChecked()) { GenerateAIFbasedModelFit_PixelBased(fitSession, generator); } else { GenerateAIFbasedModelFit_ROIBased(fitSession, generator); } } else if (isExtToftsFactory) { if (this->m_Controls.radioPixelBased->isChecked()) { GenerateAIFbasedModelFit_PixelBased(fitSession, generator); } else { GenerateAIFbasedModelFit_ROIBased(fitSession, generator); } } else if (is2CXMFactory) { if (this->m_Controls.radioPixelBased->isChecked()) { GenerateAIFbasedModelFit_PixelBased(fitSession, generator); } else { GenerateAIFbasedModelFit_ROIBased(fitSession, generator); } } else if (isNum2CXMFactory) { if (this->m_Controls.radioPixelBased->isChecked()) { GenerateAIFbasedModelFit_PixelBased(fitSession, generator); } else { GenerateAIFbasedModelFit_ROIBased(fitSession, generator); } } //add other models with else if if (generator.IsNotNull() && fitSession.IsNotNull()) { m_FittingInProgress = true; UpdateGUIControls(); DoFit(fitSession, generator); } else { QMessageBox box; box.setText("Fitting error!"); box.setInformativeText("Could not establish fitting job. Error when setting ab generator, model parameterizer or session info."); box.setStandardButtons(QMessageBox::Ok); box.setDefaultButton(QMessageBox::Ok); box.setIcon(QMessageBox::Warning); box.exec(); } } else { QMessageBox box; box.setText("Static parameters for model are not set!"); box.setInformativeText("Some static parameters, that are needed for calculation are not set and equal to zero. Modeling not possible"); box.setStandardButtons(QMessageBox::Ok); box.setDefaultButton(QMessageBox::Ok); box.setIcon(QMessageBox::Warning); box.exec(); } } void MRPerfusionView::OnNodeSelectionChanged(QList/*nodes*/) { m_selectedMaskNode = nullptr; m_selectedMask = nullptr; if (m_Controls.timeSeriesNodeSelector->GetSelectedNode().IsNotNull()) { this->m_selectedNode = m_Controls.timeSeriesNodeSelector->GetSelectedNode(); m_selectedImage = dynamic_cast(m_selectedNode->GetData()); if (m_selectedImage) { this->m_Controls.initialValuesManager->setReferenceImageGeometry(m_selectedImage->GetGeometry()); } else { this->m_Controls.initialValuesManager->setReferenceImageGeometry(nullptr); } } else { this->m_selectedNode = nullptr; this->m_selectedImage = nullptr; this->m_Controls.initialValuesManager->setReferenceImageGeometry(nullptr); } if (m_Controls.maskNodeSelector->GetSelectedNode().IsNotNull()) { this->m_selectedMaskNode = m_Controls.maskNodeSelector->GetSelectedNode(); this->m_selectedMask = dynamic_cast(m_selectedMaskNode->GetData()); if (this->m_selectedMask.IsNotNull() && this->m_selectedMask->GetTimeSteps() > 1) { MITK_INFO << "Selected mask has multiple timesteps. Only use first timestep to mask model fit. Mask name: " << m_Controls.maskNodeSelector->GetSelectedNode()->GetName(); mitk::ImageTimeSelector::Pointer maskedImageTimeSelector = mitk::ImageTimeSelector::New(); maskedImageTimeSelector->SetInput(this->m_selectedMask); maskedImageTimeSelector->SetTimeNr(0); maskedImageTimeSelector->UpdateLargestPossibleRegion(); this->m_selectedMask = maskedImageTimeSelector->GetOutput(); } } if (m_selectedMask.IsNull()) { this->m_Controls.radioPixelBased->setChecked(true); } if (this->m_selectedImage.IsNotNull()) { m_Controls.spinBox_baselineStartTimeStep->setMaximum((this->m_selectedImage->GetDimension(3))-1); m_Controls.spinBox_baselineEndTimeStep->setMaximum((this->m_selectedImage->GetDimension(3)) - 1); } UpdateGUIControls(); } bool MRPerfusionView::CheckModelSettings() const { bool ok = true; //check wether any model is set at all. Otherwise exit with false if (m_selectedModelFactory.IsNotNull()) { bool isDescBrixFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool is3LinearFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool is2LinearFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool isToftsFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr|| dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool is2CXMFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool isNum2CXMFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; if (isDescBrixFactory) { //if all static parameters for this model are set, exit with true, Otherwise exit with false ok = m_Controls.injectiontime->value() > 0; } else if (is3LinearFactory || is2LinearFactory) { if (this->m_Controls.radioButtonTurboFlash->isChecked() ) { ok = ok && (m_Controls.recoverytime->value() > 0); ok = ok && (m_Controls.relaxationtime->value() > 0); ok = ok && (m_Controls.relaxivity->value() > 0); ok = ok && (m_Controls.AifRecoverytime->value() > 0); ok = ok && CheckBaselineSelectionSettings(); } else if (this->m_Controls.radioButton_absoluteEnhancement->isChecked() || this->m_Controls.radioButton_relativeEnchancement->isChecked() ) { ok = ok && (m_Controls.factorSpinBox->value() > 0); ok = ok && CheckBaselineSelectionSettings(); } else if (this->m_Controls.radioButtonUsingT1viaVFA->isChecked() ) { ok = ok && (m_Controls.FlipangleSpinBox->value() > 0); ok = ok && (m_Controls.TRSpinBox->value() > 0); ok = ok && (m_Controls.RelaxivitySpinBox->value() > 0); ok = ok && (m_Controls.PDWImageNodeSelector->GetSelectedNode().IsNotNull()); ok = ok && CheckBaselineSelectionSettings(); } else if (this->m_Controls.radioButtonNoConversion->isChecked()) { ok = true; } else { ok = false; } } else if (isToftsFactory || is2CXMFactory || isNum2CXMFactory) { if (this->m_Controls.radioAIFImage->isChecked()) { ok = ok && m_Controls.AIFMaskNodeSelector->GetSelectedNode().IsNotNull(); if (this->m_Controls.checkDedicatedAIFImage->isChecked()) { ok = ok && m_Controls.AIFImageNodeSelector->GetSelectedNode().IsNotNull(); } } else if (this->m_Controls.radioAIFFile->isChecked()) { ok = ok && (this->AIFinputGrid.size() != 0) && (this->AIFinputFunction.size() != 0); } else { ok = false; } if (this->m_Controls.radioButtonTurboFlash->isChecked() ) { ok = ok && (m_Controls.recoverytime->value() > 0); ok = ok && (m_Controls.relaxationtime->value() > 0); ok = ok && (m_Controls.relaxivity->value() > 0); ok = ok && (m_Controls.AifRecoverytime->value() > 0); ok = ok && CheckBaselineSelectionSettings(); } else if (this->m_Controls.radioButton_absoluteEnhancement->isChecked() || this->m_Controls.radioButton_relativeEnchancement->isChecked() ) { ok = ok && (m_Controls.factorSpinBox->value() > 0); ok = ok && CheckBaselineSelectionSettings(); } else if (this->m_Controls.radioButtonUsingT1viaVFA->isChecked() ) { ok = ok && (m_Controls.FlipangleSpinBox->value() > 0); ok = ok && (m_Controls.TRSpinBox->value() > 0); ok = ok && (m_Controls.RelaxivitySpinBox->value() > 0); ok = ok && (m_Controls.PDWImageNodeSelector->GetSelectedNode().IsNotNull()); ok = ok && CheckBaselineSelectionSettings(); } else if (this->m_Controls.radioButtonNoConversion->isChecked()) { ok = ok && true; } else { ok = false; } if (isNum2CXMFactory) { ok = ok && (this->m_Controls.odeStepSize->value() > 0); } } //add other models as else if and check wether all needed static parameters are set else { ok = false; } if (this->m_Controls.radioButton_StartParameters->isChecked() && !this->m_Controls.initialValuesManager->hasValidInitialValues()) { std::string warning = "Warning. Invalid start parameters. At least one parameter as an invalid image setting as source."; MITK_ERROR << warning; m_Controls.infoBox->append(QString("") + QString::fromStdString(warning) + QString("")); ok = false; }; } else { ok = false; } return ok; } bool MRPerfusionView::CheckBaselineSelectionSettings() const { return m_Controls.spinBox_baselineStartTimeStep->value() <= m_Controls.spinBox_baselineEndTimeStep->value(); } void MRPerfusionView::ConfigureInitialParametersOfParameterizer(mitk::ModelParameterizerBase* parameterizer) const { if (m_Controls.radioButton_StartParameters->isChecked()) { //use user defined initial parameters mitk::InitialParameterizationDelegateBase::Pointer paramDelegate = m_Controls.initialValuesManager->getInitialParametrizationDelegate(); parameterizer->SetInitialParameterizationDelegate(paramDelegate); } } void MRPerfusionView::GenerateDescriptiveBrixModel_PixelBased(mitk::modelFit::ModelFitInfo::Pointer& modelFitInfo, mitk::ParameterFitImageGeneratorBase::Pointer& generator) { mitk::PixelBasedParameterFitImageGenerator::Pointer fitGenerator = mitk::PixelBasedParameterFitImageGenerator::New(); mitk::DescriptivePharmacokineticBrixModelParameterizer::Pointer modelParameterizer = mitk::DescriptivePharmacokineticBrixModelParameterizer::New(); //Model configuration (static parameters) can be done now modelParameterizer->SetTau(m_Controls.injectiontime->value()); mitk::ImageTimeSelector::Pointer imageTimeSelector = mitk::ImageTimeSelector::New(); imageTimeSelector->SetInput(this->m_selectedImage); imageTimeSelector->SetTimeNr(0); imageTimeSelector->UpdateLargestPossibleRegion(); mitk::DescriptivePharmacokineticBrixModelParameterizer::BaseImageType::Pointer baseImage; mitk::CastToItkImage(imageTimeSelector->GetOutput(), baseImage); modelParameterizer->SetBaseImage(baseImage); this->ConfigureInitialParametersOfParameterizer(modelParameterizer); //Specify fitting strategy and criterion parameters mitk::ModelFitFunctorBase::Pointer fitFunctor = CreateDefaultFitFunctor(modelParameterizer); //Parametrize fit generator fitGenerator->SetModelParameterizer(modelParameterizer); std::string roiUID = ""; if (m_selectedMask.IsNotNull()) { fitGenerator->SetMask(m_selectedMask); roiUID = m_selectedMask->GetUID(); } fitGenerator->SetDynamicImage(m_selectedImage); fitGenerator->SetFitFunctor(fitFunctor); generator = fitGenerator.GetPointer(); //Create model info modelFitInfo = mitk::modelFit::CreateFitInfoFromModelParameterizer(modelParameterizer, m_selectedNode->GetData(), mitk::ModelFitConstants::FIT_TYPE_VALUE_PIXELBASED(), this->GetFitName(), roiUID); } void MRPerfusionView::GenerateDescriptiveBrixModel_ROIBased(mitk::modelFit::ModelFitInfo::Pointer& modelFitInfo, mitk::ParameterFitImageGeneratorBase::Pointer& generator) { if (m_selectedMask.IsNull()) { return; } mitk::ROIBasedParameterFitImageGenerator::Pointer fitGenerator = mitk::ROIBasedParameterFitImageGenerator::New(); mitk::DescriptivePharmacokineticBrixModelValueBasedParameterizer::Pointer modelParameterizer = mitk::DescriptivePharmacokineticBrixModelValueBasedParameterizer::New(); //Compute ROI signal mitk::MaskedDynamicImageStatisticsGenerator::Pointer signalGenerator = mitk::MaskedDynamicImageStatisticsGenerator::New(); signalGenerator->SetMask(m_selectedMask); signalGenerator->SetDynamicImage(m_selectedImage); signalGenerator->Generate(); mitk::MaskedDynamicImageStatisticsGenerator::ResultType roiSignal = signalGenerator->GetMean(); //Model configuration (static parameters) can be done now modelParameterizer->SetTau(m_Controls.injectiontime->value()); modelParameterizer->SetBaseValue(roiSignal[0]); this->ConfigureInitialParametersOfParameterizer(modelParameterizer); //Specify fitting strategy and criterion parameters mitk::ModelFitFunctorBase::Pointer fitFunctor = CreateDefaultFitFunctor(modelParameterizer); //Parametrize fit generator fitGenerator->SetModelParameterizer(modelParameterizer); fitGenerator->SetMask(m_selectedMask); fitGenerator->SetFitFunctor(fitFunctor); fitGenerator->SetSignal(roiSignal); fitGenerator->SetTimeGrid(mitk::ExtractTimeGrid(m_selectedImage)); generator = fitGenerator.GetPointer(); std::string roiUID = this->m_selectedMask->GetUID(); //Create model info modelFitInfo = mitk::modelFit::CreateFitInfoFromModelParameterizer(modelParameterizer, m_selectedNode->GetData(), mitk::ModelFitConstants::FIT_TYPE_VALUE_ROIBASED(), this->GetFitName(), roiUID); mitk::ScalarListLookupTable::ValueType infoSignal; for (mitk::MaskedDynamicImageStatisticsGenerator::ResultType::const_iterator pos = roiSignal.begin(); pos != roiSignal.end(); ++pos) { infoSignal.push_back(*pos); } modelFitInfo->inputData.SetTableValue("ROI", infoSignal); } template void MRPerfusionView::GenerateLinearModelFit_PixelBased(mitk::modelFit::ModelFitInfo::Pointer& modelFitInfo, mitk::ParameterFitImageGeneratorBase::Pointer& generator) { mitk::PixelBasedParameterFitImageGenerator::Pointer fitGenerator = mitk::PixelBasedParameterFitImageGenerator::New(); typename TParameterizer::Pointer modelParameterizer = TParameterizer::New(); this->ConfigureInitialParametersOfParameterizer(modelParameterizer); //Specify fitting strategy and criterion parameters mitk::ModelFitFunctorBase::Pointer fitFunctor = CreateDefaultFitFunctor(modelParameterizer); //Parametrize fit generator fitGenerator->SetModelParameterizer(modelParameterizer); std::string roiUID = ""; if (m_selectedMask.IsNotNull()) { fitGenerator->SetMask(m_selectedMask); roiUID = this->m_selectedMask->GetUID(); } fitGenerator->SetDynamicImage(m_selectedImage); fitGenerator->SetFitFunctor(fitFunctor); generator = fitGenerator.GetPointer(); //Create model info modelFitInfo = mitk::modelFit::CreateFitInfoFromModelParameterizer(modelParameterizer, m_selectedNode->GetData(), mitk::ModelFitConstants::FIT_TYPE_VALUE_PIXELBASED(), this->GetFitName(), roiUID); } template void MRPerfusionView::GenerateLinearModelFit_ROIBased(mitk::modelFit::ModelFitInfo::Pointer& modelFitInfo, mitk::ParameterFitImageGeneratorBase::Pointer& generator) { if (m_selectedMask.IsNull()) { return; } mitk::ROIBasedParameterFitImageGenerator::Pointer fitGenerator = mitk::ROIBasedParameterFitImageGenerator::New(); typename TParameterizer::Pointer modelParameterizer = TParameterizer::New(); //Compute ROI signal mitk::MaskedDynamicImageStatisticsGenerator::Pointer signalGenerator = mitk::MaskedDynamicImageStatisticsGenerator::New(); signalGenerator->SetMask(m_selectedMask); signalGenerator->SetDynamicImage(m_selectedImage); signalGenerator->Generate(); mitk::MaskedDynamicImageStatisticsGenerator::ResultType roiSignal = signalGenerator->GetMean(); //Model configuration (static parameters) can be done now this->ConfigureInitialParametersOfParameterizer(modelParameterizer); //Specify fitting strategy and criterion parameters mitk::ModelFitFunctorBase::Pointer fitFunctor = CreateDefaultFitFunctor(modelParameterizer); //Parametrize fit generator fitGenerator->SetModelParameterizer(modelParameterizer); fitGenerator->SetMask(m_selectedMask); fitGenerator->SetFitFunctor(fitFunctor); fitGenerator->SetSignal(roiSignal); fitGenerator->SetTimeGrid(mitk::ExtractTimeGrid(m_selectedImage)); generator = fitGenerator.GetPointer(); std::string roiUID = this->m_selectedMask->GetUID(); //Create model info modelFitInfo = mitk::modelFit::CreateFitInfoFromModelParameterizer(modelParameterizer, m_selectedNode->GetData(), mitk::ModelFitConstants::FIT_TYPE_VALUE_ROIBASED(), this->GetFitName(), roiUID); mitk::ScalarListLookupTable::ValueType infoSignal; for (mitk::MaskedDynamicImageStatisticsGenerator::ResultType::const_iterator pos = roiSignal.begin(); pos != roiSignal.end(); ++pos) { infoSignal.push_back(*pos); } modelFitInfo->inputData.SetTableValue("ROI", infoSignal); } template void MRPerfusionView::GenerateAIFbasedModelFit_PixelBased(mitk::modelFit::ModelFitInfo::Pointer& modelFitInfo, mitk::ParameterFitImageGeneratorBase::Pointer& generator) { mitk::PixelBasedParameterFitImageGenerator::Pointer fitGenerator = mitk::PixelBasedParameterFitImageGenerator::New(); typename TParameterizer::Pointer modelParameterizer = TParameterizer::New(); PrepareConcentrationImage(); mitk::AIFBasedModelBase::AterialInputFunctionType aif; mitk::AIFBasedModelBase::AterialInputFunctionType aifTimeGrid; GetAIF(aif, aifTimeGrid); modelParameterizer->SetAIF(aif); modelParameterizer->SetAIFTimeGrid(aifTimeGrid); this->ConfigureInitialParametersOfParameterizer(modelParameterizer); mitk::NumericTwoCompartmentExchangeModelParameterizer* numTCXParametrizer = dynamic_cast (modelParameterizer.GetPointer()); if (numTCXParametrizer) { numTCXParametrizer->SetODEINTStepSize(this->m_Controls.odeStepSize->value()); } //Specify fitting strategy and criterion parameters mitk::ModelFitFunctorBase::Pointer fitFunctor = CreateDefaultFitFunctor(modelParameterizer); //Parametrize fit generator fitGenerator->SetModelParameterizer(modelParameterizer); std::string roiUID = ""; if (m_selectedMask.IsNotNull()) { fitGenerator->SetMask(m_selectedMask); roiUID = this->m_selectedMask->GetUID(); } fitGenerator->SetDynamicImage(this->m_inputImage); fitGenerator->SetFitFunctor(fitFunctor); generator = fitGenerator.GetPointer(); //Create model info modelFitInfo = mitk::modelFit::CreateFitInfoFromModelParameterizer(modelParameterizer, this->m_inputImage, mitk::ModelFitConstants::FIT_TYPE_VALUE_PIXELBASED(), this->GetFitName(), roiUID); mitk::ScalarListLookupTable::ValueType infoSignal; for (mitk::AIFBasedModelBase::AterialInputFunctionType::const_iterator pos = aif.begin(); pos != aif.end(); ++pos) { infoSignal.push_back(*pos); } modelFitInfo->inputData.SetTableValue("AIF", infoSignal); } template void MRPerfusionView::GenerateAIFbasedModelFit_ROIBased( mitk::modelFit::ModelFitInfo::Pointer& modelFitInfo, mitk::ParameterFitImageGeneratorBase::Pointer& generator) { if (m_selectedMask.IsNull()) { return; } mitk::ROIBasedParameterFitImageGenerator::Pointer fitGenerator = mitk::ROIBasedParameterFitImageGenerator::New(); typename TParameterizer::Pointer modelParameterizer = TParameterizer::New(); PrepareConcentrationImage(); mitk::AIFBasedModelBase::AterialInputFunctionType aif; mitk::AIFBasedModelBase::AterialInputFunctionType aifTimeGrid; GetAIF(aif, aifTimeGrid); modelParameterizer->SetAIF(aif); modelParameterizer->SetAIFTimeGrid(aifTimeGrid); this->ConfigureInitialParametersOfParameterizer(modelParameterizer); mitk::NumericTwoCompartmentExchangeModelParameterizer* numTCXParametrizer = dynamic_cast (modelParameterizer.GetPointer()); if (numTCXParametrizer) { numTCXParametrizer->SetODEINTStepSize(this->m_Controls.odeStepSize->value()); } //Compute ROI signal mitk::MaskedDynamicImageStatisticsGenerator::Pointer signalGenerator = mitk::MaskedDynamicImageStatisticsGenerator::New(); signalGenerator->SetMask(m_selectedMask); signalGenerator->SetDynamicImage(this->m_inputImage); signalGenerator->Generate(); mitk::MaskedDynamicImageStatisticsGenerator::ResultType roiSignal = signalGenerator->GetMean(); //Specify fitting strategy and criterion parameters mitk::ModelFitFunctorBase::Pointer fitFunctor = CreateDefaultFitFunctor(modelParameterizer); //Parametrize fit generator fitGenerator->SetModelParameterizer(modelParameterizer); fitGenerator->SetMask(m_selectedMask); fitGenerator->SetFitFunctor(fitFunctor); fitGenerator->SetSignal(roiSignal); fitGenerator->SetTimeGrid(mitk::ExtractTimeGrid(this->m_inputImage)); generator = fitGenerator.GetPointer(); std::string roiUID = this->m_selectedMask->GetUID(); //Create model info modelFitInfo = mitk::modelFit::CreateFitInfoFromModelParameterizer(modelParameterizer, this->m_inputImage, mitk::ModelFitConstants::FIT_TYPE_VALUE_ROIBASED(), this->GetFitName(), roiUID); mitk::ScalarListLookupTable::ValueType infoSignal; for (mitk::MaskedDynamicImageStatisticsGenerator::ResultType::const_iterator pos = roiSignal.begin(); pos != roiSignal.end(); ++pos) { infoSignal.push_back(*pos); } modelFitInfo->inputData.SetTableValue("ROI", infoSignal); infoSignal.clear(); for (mitk::AIFBasedModelBase::AterialInputFunctionType::const_iterator pos = aif.begin(); pos != aif.end(); ++pos) { infoSignal.push_back(*pos); } modelFitInfo->inputData.SetTableValue("AIF", infoSignal); } void MRPerfusionView::DoFit(const mitk::modelFit::ModelFitInfo* fitSession, mitk::ParameterFitImageGeneratorBase* generator) { this->m_Controls.infoBox->append(QString("" + QString("Fitting Data Set . . .") + QString (""))); ///////////////////////// //create job and put it into the thread pool mitk::modelFit::ModelFitResultNodeVectorType additionalNodes; if (m_HasGeneratedNewInput) { additionalNodes.push_back(m_inputNode); } if (m_HasGeneratedNewInputAIF) { additionalNodes.push_back(m_inputAIFNode); } ParameterFitBackgroundJob* pJob = new ParameterFitBackgroundJob(generator, fitSession, this->m_selectedNode, additionalNodes); pJob->setAutoDelete(true); connect(pJob, SIGNAL(Error(QString)), this, SLOT(OnJobError(QString))); connect(pJob, SIGNAL(Finished()), this, SLOT(OnJobFinished())); connect(pJob, SIGNAL(ResultsAreAvailable(mitk::modelFit::ModelFitResultNodeVectorType, const ParameterFitBackgroundJob*)), this, SLOT(OnJobResultsAreAvailable(mitk::modelFit::ModelFitResultNodeVectorType, const ParameterFitBackgroundJob*)), Qt::BlockingQueuedConnection); connect(pJob, SIGNAL(JobProgress(double)), this, SLOT(OnJobProgress(double))); connect(pJob, SIGNAL(JobStatusChanged(QString)), this, SLOT(OnJobStatusChanged(QString))); QThreadPool* threadPool = QThreadPool::globalInstance(); threadPool->start(pJob); } MRPerfusionView::MRPerfusionView() : m_FittingInProgress(false), m_HasGeneratedNewInput(false), m_HasGeneratedNewInputAIF(false) { m_selectedImage = nullptr; m_selectedMask = nullptr; mitk::ModelFactoryBase::Pointer factory = mitk::DescriptivePharmacokineticBrixModelFactory::New().GetPointer(); m_FactoryStack.push_back(factory); factory = mitk::TwoStepLinearModelFactory::New().GetPointer(); m_FactoryStack.push_back(factory); factory = mitk::ThreeStepLinearModelFactory::New().GetPointer(); m_FactoryStack.push_back(factory); factory = mitk::StandardToftsModelFactory::New().GetPointer(); m_FactoryStack.push_back(factory); factory = mitk::ExtendedToftsModelFactory::New().GetPointer(); m_FactoryStack.push_back(factory); factory = mitk::TwoCompartmentExchangeModelFactory::New().GetPointer(); m_FactoryStack.push_back(factory); factory = mitk::NumericTwoCompartmentExchangeModelFactory::New().GetPointer(); m_FactoryStack.push_back(factory); mitk::NodePredicateDataType::Pointer isLabelSet = mitk::NodePredicateDataType::New("LabelSetImage"); mitk::NodePredicateDataType::Pointer isImage = mitk::NodePredicateDataType::New("Image"); mitk::NodePredicateProperty::Pointer isBinary = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); mitk::NodePredicateAnd::Pointer isLegacyMask = mitk::NodePredicateAnd::New(isImage, isBinary); mitk::NodePredicateDimension::Pointer is3D = mitk::NodePredicateDimension::New(3); mitk::NodePredicateOr::Pointer isMask = mitk::NodePredicateOr::New(isLegacyMask, isLabelSet); mitk::NodePredicateAnd::Pointer isNoMask = mitk::NodePredicateAnd::New(isImage, mitk::NodePredicateNot::New(isMask)); mitk::NodePredicateAnd::Pointer is3DImage = mitk::NodePredicateAnd::New(isImage, is3D, isNoMask); this->m_IsMaskPredicate = mitk::NodePredicateAnd::New(isMask, mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object"))).GetPointer(); this->m_IsNoMaskImagePredicate = mitk::NodePredicateAnd::New(isNoMask, mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object"))).GetPointer(); auto isDynamicData = mitk::NodePredicateFunction::New([](const mitk::DataNode* node) { return (node && node->GetData() && node->GetData()->GetTimeSteps() > 1); }); auto modelFitResultRelationRule = mitk::ModelFitResultRelationRule::New(); auto isNoModelFitNodePredicate = mitk::NodePredicateNot::New(modelFitResultRelationRule->GetConnectedSourcesDetector()); this->m_isValidPDWImagePredicate = mitk::NodePredicateAnd::New(is3DImage, isNoModelFitNodePredicate); this->m_isValidTimeSeriesImagePredicate = mitk::NodePredicateAnd::New(isDynamicData, isImage, isNoMask); } void MRPerfusionView::OnJobFinished() { this->m_Controls.infoBox->append(QString("Fitting finished.")); this->m_FittingInProgress = false; this->UpdateGUIControls(); }; void MRPerfusionView::OnJobError(QString err) { MITK_ERROR << err.toStdString().c_str(); m_Controls.infoBox->append(QString("") + err + QString("")); }; void MRPerfusionView::OnJobResultsAreAvailable(mitk::modelFit::ModelFitResultNodeVectorType results, const ParameterFitBackgroundJob* pJob) { //Store the resulting parameter fit image via convenience helper function in data storage //(handles the correct generation of the nodes and their properties) mitk::modelFit::StoreResultsInDataStorage(this->GetDataStorage(), results, pJob->GetParentNode()); //this stores the concentration image and AIF concentration image, if generated for this fit in the storage. //if not generated for this fit, relevant nodes are empty. mitk::modelFit::StoreResultsInDataStorage(this->GetDataStorage(), pJob->GetAdditionalRelevantNodes(), pJob->GetParentNode()); }; void MRPerfusionView::OnJobProgress(double progress) { QString report = QString("Progress. ") + QString::number(progress); this->m_Controls.infoBox->append(report); }; void MRPerfusionView::OnJobStatusChanged(QString info) { this->m_Controls.infoBox->append(info); } void MRPerfusionView::InitModelComboBox() const { this->m_Controls.comboModel->clear(); this->m_Controls.comboModel->addItem(tr("No model selected")); for (ModelFactoryStackType::const_iterator pos = m_FactoryStack.begin(); pos != m_FactoryStack.end(); ++pos) { this->m_Controls.comboModel->addItem(QString::fromStdString((*pos)->GetClassID())); } this->m_Controls.comboModel->setCurrentIndex(0); }; mitk::DataNode::Pointer MRPerfusionView::GenerateConcentrationNode(mitk::Image* image, const std::string& nodeName) const { if (!image) { mitkThrow() << "Cannot generate concentration node. Passed image is null. parameter name: "; } mitk::DataNode::Pointer result = mitk::DataNode::New(); result->SetData(image); result->SetName(nodeName); result->SetVisibility(true); return result; }; mitk::Image::Pointer MRPerfusionView::ConvertConcentrationImage(bool AIFMode) { //Compute Concentration image mitk::ConcentrationCurveGenerator::Pointer concentrationGen = mitk::ConcentrationCurveGenerator::New(); if (m_Controls.checkDedicatedAIFImage->isChecked() && AIFMode) { concentrationGen->SetDynamicImage(this->m_selectedAIFImage); } else { concentrationGen->SetDynamicImage(this->m_selectedImage); } concentrationGen->SetisTurboFlashSequence(IsTurboFlashSequenceFlag()); concentrationGen->SetAbsoluteSignalEnhancement(m_Controls.radioButton_absoluteEnhancement->isChecked()); concentrationGen->SetRelativeSignalEnhancement(m_Controls.radioButton_relativeEnchancement->isChecked()); concentrationGen->SetUsingT1Map(m_Controls.radioButtonUsingT1viaVFA->isChecked()); if (IsTurboFlashSequenceFlag()) { if (AIFMode) { concentrationGen->SetRecoveryTime(m_Controls.AifRecoverytime->value()); } else { concentrationGen->SetRecoveryTime(m_Controls.recoverytime->value()); } concentrationGen->SetRelaxationTime(m_Controls.relaxationtime->value()); concentrationGen->SetRelaxivity(m_Controls.relaxivity->value()); concentrationGen->SetBaselineStartTimeStep(m_Controls.spinBox_baselineStartTimeStep->value()); concentrationGen->SetBaselineEndTimeStep(m_Controls.spinBox_baselineEndTimeStep->value()); } else if (this->m_Controls.radioButtonUsingT1viaVFA->isChecked()) { concentrationGen->SetRecoveryTime(m_Controls.TRSpinBox->value()); concentrationGen->SetRelaxivity(m_Controls.RelaxivitySpinBox->value()); concentrationGen->SetT10Image(dynamic_cast(m_Controls.PDWImageNodeSelector->GetSelectedNode()->GetData())); concentrationGen->SetBaselineStartTimeStep(m_Controls.spinBox_baselineStartTimeStep->value()); concentrationGen->SetBaselineEndTimeStep(m_Controls.spinBox_baselineEndTimeStep->value()); //Convert Flipangle from degree to radiant double alpha = m_Controls.FlipangleSpinBox->value()/360*2* boost::math::constants::pi(); concentrationGen->SetFlipAngle(alpha); } else { concentrationGen->SetFactor(m_Controls.factorSpinBox->value()); concentrationGen->SetBaselineStartTimeStep(m_Controls.spinBox_baselineStartTimeStep->value()); concentrationGen->SetBaselineEndTimeStep(m_Controls.spinBox_baselineEndTimeStep->value()); } mitk::Image::Pointer concentrationImage = concentrationGen->GetConvertedImage(); return concentrationImage; } void MRPerfusionView::GetAIF(mitk::AIFBasedModelBase::AterialInputFunctionType& aif, mitk::AIFBasedModelBase::AterialInputFunctionType& aifTimeGrid) { if (this->m_Controls.radioAIFFile->isChecked()) { aif.clear(); aifTimeGrid.clear(); aif.SetSize(AIFinputFunction.size()); aifTimeGrid.SetSize(AIFinputGrid.size()); aif.fill(0.0); aifTimeGrid.fill(0.0); itk::Array::iterator aifPos = aif.begin(); for (std::vector::const_iterator pos = AIFinputFunction.begin(); pos != AIFinputFunction.end(); ++pos, ++aifPos) { *aifPos = *pos; } itk::Array::iterator gridPos = aifTimeGrid.begin(); for (std::vector::const_iterator pos = AIFinputGrid.begin(); pos != AIFinputGrid.end(); ++pos, ++gridPos) { *gridPos = *pos; } } else if (this->m_Controls.radioAIFImage->isChecked()) { aif.clear(); aifTimeGrid.clear(); mitk::AterialInputFunctionGenerator::Pointer aifGenerator = mitk::AterialInputFunctionGenerator::New(); //Hematocrit level aifGenerator->SetHCL(this->m_Controls.HCLSpinBox->value()); //mask settings this->m_selectedAIFMaskNode = m_Controls.AIFMaskNodeSelector->GetSelectedNode(); this->m_selectedAIFMask = dynamic_cast(this->m_selectedAIFMaskNode->GetData()); if (this->m_selectedAIFMask->GetTimeSteps() > 1) { MITK_INFO << "Selected AIF mask has multiple timesteps. Only use first timestep to mask model fit. AIF Mask name: " << m_selectedAIFMaskNode->GetName() ; mitk::ImageTimeSelector::Pointer maskedImageTimeSelector = mitk::ImageTimeSelector::New(); maskedImageTimeSelector->SetInput(this->m_selectedAIFMask); maskedImageTimeSelector->SetTimeNr(0); maskedImageTimeSelector->UpdateLargestPossibleRegion(); this->m_selectedAIFMask = maskedImageTimeSelector->GetOutput(); } if (this->m_selectedAIFMask.IsNotNull()) { aifGenerator->SetMask(this->m_selectedAIFMask); } //image settings if (this->m_Controls.checkDedicatedAIFImage->isChecked()) { this->m_selectedAIFImageNode = m_Controls.AIFImageNodeSelector->GetSelectedNode(); this->m_selectedAIFImage = dynamic_cast(this->m_selectedAIFImageNode->GetData()); } else { this->m_selectedAIFImageNode = m_selectedNode; this->m_selectedAIFImage = m_selectedImage; } this->PrepareAIFConcentrationImage(); aifGenerator->SetDynamicImage(this->m_inputAIFImage); aif = aifGenerator->GetAterialInputFunction(); aifTimeGrid = aifGenerator->GetAterialInputFunctionTimeGrid(); } else { mitkThrow() << "Cannot generate AIF. View is in a invalide state. No AIF mode selected."; } } void MRPerfusionView::LoadAIFfromFile() { QFileDialog dialog; dialog.setNameFilter(tr("Images (*.csv")); QString fileName = dialog.getOpenFileName(); m_Controls.aifFilePath->setText(fileName); std::string m_aifFilePath = fileName.toStdString(); //Read Input typedef boost::tokenizer< boost::escaped_list_separator > Tokenizer; ///////////////////////////////////////////////////////////////////////////////////////////////// //AIF Data std::ifstream in1(m_aifFilePath.c_str()); if (!in1.is_open()) { this->m_Controls.infoBox->append(QString("Could not open AIF File!")); } std::vector< std::string > vec1; std::string line1; while (getline(in1, line1)) { Tokenizer tok(line1); vec1.assign(tok.begin(), tok.end()); this->AIFinputGrid.push_back(convertToDouble(vec1[0])); this->AIFinputFunction.push_back(convertToDouble(vec1[1])); } } void MRPerfusionView::PrepareConcentrationImage() { mitk::Image::Pointer concentrationImage = this->m_selectedImage; mitk::DataNode::Pointer concentrationNode = this->m_selectedNode; m_HasGeneratedNewInput = false; if (!this->m_Controls.radioButtonNoConversion->isChecked()) { concentrationImage = this->ConvertConcentrationImage(false); concentrationNode = GenerateConcentrationNode(concentrationImage, "Concentration"); m_HasGeneratedNewInput = true; } m_inputImage = concentrationImage; m_inputNode = concentrationNode; } void MRPerfusionView::PrepareAIFConcentrationImage() { mitk::Image::Pointer concentrationImage = this->m_selectedImage; mitk::DataNode::Pointer concentrationNode = this->m_selectedNode; m_HasGeneratedNewInputAIF = false; if (this->m_Controls.checkDedicatedAIFImage->isChecked()) { concentrationImage = this->m_selectedAIFImage; concentrationNode = this->m_selectedAIFImageNode; } if (!this->m_Controls.radioButtonNoConversion->isChecked()) { if (!IsTurboFlashSequenceFlag() && !this->m_Controls.checkDedicatedAIFImage->isChecked()) { if (m_inputImage.IsNull()) { mitkThrow() << "Cannot get AIF concentration image. Invalid view state. Input image is not defined yet, but should be."; } //we can directly use the concentration input image/node (generated by GetConcentrationImage) also for the AIF concentrationImage = this->m_inputImage; concentrationNode = this->m_inputNode; } else { concentrationImage = this->ConvertConcentrationImage(true); concentrationNode = GenerateConcentrationNode(concentrationImage, "AIF Concentration"); m_HasGeneratedNewInputAIF = true; } } m_inputAIFImage = concentrationImage; m_inputAIFNode = concentrationNode; } mitk::ModelFitFunctorBase::Pointer MRPerfusionView::CreateDefaultFitFunctor( const mitk::ModelParameterizerBase* parameterizer) const { mitk::LevenbergMarquardtModelFitFunctor::Pointer fitFunctor = mitk::LevenbergMarquardtModelFitFunctor::New(); mitk::NormalizedSumOfSquaredDifferencesFitCostFunction::Pointer chi2 = mitk::NormalizedSumOfSquaredDifferencesFitCostFunction::New(); fitFunctor->RegisterEvaluationParameter("Chi^2", chi2); if (m_Controls.checkBox_Constraints->isChecked()) { fitFunctor->SetConstraintChecker(m_modelConstraints); } mitk::ModelBase::Pointer refModel = parameterizer->GenerateParameterizedModel(); ::itk::LevenbergMarquardtOptimizer::ScalesType scales; scales.SetSize(refModel->GetNumberOfParameters()); scales.Fill(1.0); fitFunctor->SetScales(scales); fitFunctor->SetDebugParameterMaps(m_Controls.checkDebug->isChecked()); return fitFunctor.GetPointer(); } diff --git a/Plugins/org.mitk.gui.qt.pharmacokinetics.pet/src/internal/PETDynamicView.cpp b/Plugins/org.mitk.gui.qt.pharmacokinetics.pet/src/internal/PETDynamicView.cpp index dc4a82d910..9e4a74c8c1 100644 --- a/Plugins/org.mitk.gui.qt.pharmacokinetics.pet/src/internal/PETDynamicView.cpp +++ b/Plugins/org.mitk.gui.qt.pharmacokinetics.pet/src/internal/PETDynamicView.cpp @@ -1,946 +1,946 @@ /*============================================================================ 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 "PETDynamicView.h" #include "mitkWorkbenchUtil.h" #include "mitkAterialInputFunctionGenerator.h" #include "mitkOneTissueCompartmentModelFactory.h" #include "mitkOneTissueCompartmentModelParameterizer.h" #include "mitkExtendedOneTissueCompartmentModelFactory.h" #include "mitkExtendedOneTissueCompartmentModelParameterizer.h" #include "mitkTwoTissueCompartmentFDGModelFactory.h" #include "mitkTwoTissueCompartmentFDGModelParameterizer.h" #include "mitkTwoTissueCompartmentModelFactory.h" #include "mitkTwoTissueCompartmentModelParameterizer.h" #include "mitkNumericTwoTissueCompartmentModelFactory.h" #include "mitkNumericTwoTissueCompartmentModelParameterizer.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Includes for image casting between ITK and MITK #include #include "mitkImageCast.h" #include "mitkITKImageImport.h" #include #include #include -const std::string PETDynamicView::VIEW_ID = "org.mitk.gui.qt.pharmacokinetics.pet"; +const std::string PETDynamicView::VIEW_ID = "org.mitk.views.pharmacokinetics.pet"; inline double convertToDouble(const std::string& data) { std::istringstream stepStream(data); double value = 0.0; stepStream >> value; return value; } void PETDynamicView::SetFocus() { m_Controls.btnModelling->setFocus(); } void PETDynamicView::CreateQtPartControl(QWidget* parent) { m_Controls.setupUi(parent); m_Controls.btnModelling->setEnabled(false); m_Controls.errorMessageLabel->hide(); this->InitModelComboBox(); connect(m_Controls.btnModelling, SIGNAL(clicked()), this, SLOT(OnModellingButtonClicked())); connect(m_Controls.comboModel, SIGNAL(currentIndexChanged(int)), this, SLOT(OnModellSet(int))); connect(m_Controls.radioPixelBased, SIGNAL(toggled(bool)), this, SLOT(UpdateGUIControls())); //AIF setting m_Controls.groupAIF->hide(); m_Controls.btnAIFFile->setEnabled(false); m_Controls.btnAIFFile->setEnabled(false); m_Controls.radioAIFImage->setChecked(true); m_Controls.comboAIFMask->SetDataStorage(this->GetDataStorage()); m_Controls.comboAIFMask->SetPredicate(m_IsMaskPredicate); m_Controls.comboAIFMask->setVisible(true); m_Controls.comboAIFMask->setEnabled(true); m_Controls.comboAIFImage->SetDataStorage(this->GetDataStorage()); m_Controls.comboAIFImage->SetPredicate(m_IsNoMaskImagePredicate); m_Controls.comboAIFImage->setEnabled(false); m_Controls.checkDedicatedAIFImage->setEnabled(true); m_Controls.HCLSpinBox->setValue(0.0); connect(m_Controls.radioAIFImage, SIGNAL(toggled(bool)), m_Controls.comboAIFMask, SLOT(setVisible(bool))); connect(m_Controls.radioAIFImage, SIGNAL(toggled(bool)), m_Controls.labelAIFMask, SLOT(setVisible(bool))); connect(m_Controls.radioAIFImage, SIGNAL(toggled(bool)), m_Controls.checkDedicatedAIFImage, SLOT(setVisible(bool))); connect(m_Controls.radioAIFImage, SIGNAL(toggled(bool)), m_Controls.comboAIFMask, SLOT(setEnabled(bool))); connect(m_Controls.radioAIFImage, SIGNAL(toggled(bool)), m_Controls.checkDedicatedAIFImage, SLOT(setEnabled(bool))); connect(m_Controls.radioAIFImage, SIGNAL(toggled(bool)), m_Controls.checkDedicatedAIFImage, SLOT(setVisible(bool))); connect(m_Controls.radioAIFImage, SIGNAL(toggled(bool)), m_Controls.comboAIFImage, SLOT(setVisible(bool))); connect(m_Controls.checkDedicatedAIFImage, SIGNAL(toggled(bool)), m_Controls.comboAIFImage, SLOT(setEnabled(bool))); connect(m_Controls.radioAIFImage, SIGNAL(toggled(bool)), this, SLOT(UpdateGUIControls())); connect(m_Controls.radioAIFFile, SIGNAL(toggled(bool)), m_Controls.btnAIFFile, SLOT(setEnabled(bool))); connect(m_Controls.radioAIFFile, SIGNAL(toggled(bool)), m_Controls.aifFilePath, SLOT(setEnabled(bool))); connect(m_Controls.radioAIFFile, SIGNAL(toggled(bool)), this, SLOT(UpdateGUIControls())); connect(m_Controls.btnAIFFile, SIGNAL(clicked()), this, SLOT(LoadAIFfromFile())); //Model fit configuration m_Controls.groupBox_FitConfiguration->hide(); m_Controls.checkBox_Constraints->setEnabled(false); m_Controls.constraintManager->setEnabled(false); m_Controls.initialValuesManager->setEnabled(false); m_Controls.initialValuesManager->setDataStorage(this->GetDataStorage()); connect(m_Controls.radioButton_StartParameters, SIGNAL(toggled(bool)), this, SLOT(UpdateGUIControls())); connect(m_Controls.checkBox_Constraints, SIGNAL(toggled(bool)), this, SLOT(UpdateGUIControls())); connect(m_Controls.initialValuesManager, SIGNAL(initialValuesChanged(void)), this, SLOT(UpdateGUIControls())); connect(m_Controls.radioButton_StartParameters, SIGNAL(toggled(bool)), m_Controls.initialValuesManager, SLOT(setEnabled(bool))); connect(m_Controls.checkBox_Constraints, SIGNAL(toggled(bool)), m_Controls.constraintManager, SLOT(setEnabled(bool))); connect(m_Controls.checkBox_Constraints, SIGNAL(toggled(bool)), m_Controls.constraintManager, SLOT(setVisible(bool))); UpdateGUIControls(); } void PETDynamicView::UpdateGUIControls() { m_Controls.lineFitName->setPlaceholderText(QString::fromStdString(this->GetDefaultFitName())); m_Controls.lineFitName->setEnabled(!m_FittingInProgress); m_Controls.checkBox_Constraints->setEnabled(m_modelConstraints.IsNotNull()); bool is1TCMFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool isExt1TCMFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool isFDGCMFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool is2TCMFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr || dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; m_Controls.groupAIF->setVisible(is1TCMFactory || isExt1TCMFactory || isFDGCMFactory || is2TCMFactory); m_Controls.groupBox_FitConfiguration->setVisible(m_selectedModelFactory); m_Controls.groupBox->setEnabled(!m_FittingInProgress); m_Controls.comboModel->setEnabled(!m_FittingInProgress); m_Controls.groupAIF->setEnabled(!m_FittingInProgress); m_Controls.groupBox_FitConfiguration->setEnabled(!m_FittingInProgress); m_Controls.radioROIbased->setEnabled(m_selectedMask.IsNotNull()); m_Controls.btnModelling->setEnabled(m_selectedImage.IsNotNull() && m_selectedModelFactory.IsNotNull() && !m_FittingInProgress && CheckModelSettings()); } //void PETDynamicView::OnModelSettingChanged() //{ // bool ok = m_selectedImage.IsNotNull() && m_selectedModelFactory.IsNotNull() && !m_FittingInProgress && CheckModelSettings(); // m_Controls.btnModelling->setEnabled(ok); //} void PETDynamicView::OnModellSet(int index) { m_selectedModelFactory = nullptr; if (index > 0) { if (static_cast(index) <= m_FactoryStack.size() ) { m_selectedModelFactory = m_FactoryStack[index - 1]; } else { MITK_WARN << "Invalid model index. Index outside of the factory stack. Factory stack size: "<< m_FactoryStack.size() << "; invalid index: "<< index; } } if (m_selectedModelFactory) { this->m_modelConstraints = dynamic_cast (m_selectedModelFactory->CreateDefaultConstraints().GetPointer()); m_Controls.initialValuesManager->setInitialValues(m_selectedModelFactory->GetParameterNames(), m_selectedModelFactory->GetDefaultInitialParameterization()); if (this->m_modelConstraints.IsNull()) { this->m_modelConstraints = mitk::SimpleBarrierConstraintChecker::New(); } m_Controls.constraintManager->setChecker(this->m_modelConstraints, this->m_selectedModelFactory->GetParameterNames()); } m_Controls.checkBox_Constraints->setEnabled(m_modelConstraints.IsNotNull()); UpdateGUIControls(); } std::string PETDynamicView::GetFitName() const { std::string fitName = m_Controls.lineFitName->text().toStdString(); if (fitName.empty()) { fitName = m_Controls.lineFitName->placeholderText().toStdString(); } return fitName; } std::string PETDynamicView::GetDefaultFitName() const { std::string defaultName = "undefined model"; if (this->m_selectedModelFactory.IsNotNull()) { defaultName = this->m_selectedModelFactory->GetClassID(); } if (this->m_Controls.radioPixelBased->isChecked()) { defaultName += "_pixel"; } else { defaultName += "_roi"; } return defaultName; } void PETDynamicView::OnModellingButtonClicked() { //check if all static parameters set if (m_selectedModelFactory.IsNotNull() && CheckModelSettings()) { mitk::ParameterFitImageGeneratorBase::Pointer generator = nullptr; mitk::modelFit::ModelFitInfo::Pointer fitSession = nullptr; bool isOTCFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool isextOTCFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool isFDGFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool isTTCFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool isNumTTCFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; if (isOTCFactory) { if (this->m_Controls.radioPixelBased->isChecked()) { GenerateModelFit_PixelBased(fitSession, generator); } else { GenerateModelFit_ROIBased(fitSession, generator); } } else if (isextOTCFactory) { if (this->m_Controls.radioPixelBased->isChecked()) { GenerateModelFit_PixelBased(fitSession, generator); } else { GenerateModelFit_ROIBased(fitSession, generator); } } else if (isFDGFactory) { if (this->m_Controls.radioPixelBased->isChecked()) { GenerateModelFit_PixelBased(fitSession, generator); } else { GenerateModelFit_ROIBased(fitSession, generator); } } else if (isTTCFactory) { if (this->m_Controls.radioPixelBased->isChecked()) { GenerateModelFit_PixelBased(fitSession, generator); } else { GenerateModelFit_ROIBased(fitSession, generator); } } else if (isNumTTCFactory) { if (this->m_Controls.radioPixelBased->isChecked()) { GenerateModelFit_PixelBased(fitSession, generator); } else { GenerateModelFit_ROIBased(fitSession, generator); } } //add other models with else if if (generator.IsNotNull() && fitSession.IsNotNull()) { m_FittingInProgress = true; DoFit(fitSession, generator); } else { QMessageBox box; box.setText("Fitting error!"); box.setInformativeText("Could not establish fitting job. Error when setting ab generator, model parameterizer or session info."); box.setStandardButtons(QMessageBox::Ok); box.setDefaultButton(QMessageBox::Ok); box.setIcon(QMessageBox::Warning); box.exec(); } } else { QMessageBox box; box.setText("Static parameters for model are not set!"); box.setInformativeText("Some static parameters, that are needed for calculation are not set and equal to zero. Modeling not possible"); box.setStandardButtons(QMessageBox::Ok); box.setDefaultButton(QMessageBox::Ok); box.setIcon(QMessageBox::Warning); box.exec(); } } void PETDynamicView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*source*/, const QList& selectedNodes) { m_selectedMaskNode = nullptr; m_selectedMask = nullptr; m_Controls.errorMessageLabel->setText(""); m_Controls.masklabel->setText("No (valid) mask selected."); m_Controls.timeserieslabel->setText("No (valid) series selected."); QList nodes = selectedNodes; if (nodes.size() > 0 && this->m_IsNoMaskImagePredicate->CheckNode(nodes.front())) { this->m_selectedNode = nodes.front(); auto selectedImage = dynamic_cast(this->m_selectedNode->GetData()); m_Controls.timeserieslabel->setText((this->m_selectedNode->GetName()).c_str()); if (selectedImage != this->m_selectedImage) { if (selectedImage) { this->m_Controls.initialValuesManager->setReferenceImageGeometry(selectedImage->GetGeometry()); } else { this->m_Controls.initialValuesManager->setReferenceImageGeometry(nullptr); } } this->m_selectedImage = selectedImage; nodes.pop_front(); } else { this->m_selectedNode = nullptr; this->m_selectedImage = nullptr; this->m_Controls.initialValuesManager->setReferenceImageGeometry(nullptr); } if (nodes.size() > 0 && this->m_IsMaskPredicate->CheckNode(nodes.front())) { this->m_selectedMaskNode = nodes.front(); this->m_selectedMask = dynamic_cast(this->m_selectedMaskNode->GetData()); if (this->m_selectedMask->GetTimeSteps() > 1) { MITK_INFO << "Selected mask has multiple timesteps. Only use first timestep to mask model fit. Mask name: " << m_selectedMaskNode->GetName(); mitk::ImageTimeSelector::Pointer maskedImageTimeSelector = mitk::ImageTimeSelector::New(); maskedImageTimeSelector->SetInput(this->m_selectedMask); maskedImageTimeSelector->SetTimeNr(0); maskedImageTimeSelector->UpdateLargestPossibleRegion(); this->m_selectedMask = maskedImageTimeSelector->GetOutput(); } m_Controls.masklabel->setText((this->m_selectedMaskNode->GetName()).c_str()); } if (m_selectedMask.IsNull()) { this->m_Controls.radioPixelBased->setChecked(true); } m_Controls.errorMessageLabel->show(); UpdateGUIControls(); } bool PETDynamicView::CheckModelSettings() const { bool ok = true; //check wether any model is set at all. Otherwise exit with false if (m_selectedModelFactory.IsNotNull()) { bool isOTCFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool isextOTCFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool isFDGFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool isTTCFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool isNumTTCFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; if (isOTCFactory || isextOTCFactory || isFDGFactory || isTTCFactory || isNumTTCFactory) { if (this->m_Controls.radioAIFImage->isChecked()) { ok = ok && m_Controls.comboAIFMask->GetSelectedNode().IsNotNull(); if (this->m_Controls.checkDedicatedAIFImage->isChecked()) { ok = ok && m_Controls.comboAIFImage->GetSelectedNode().IsNotNull(); } } else if (this->m_Controls.radioAIFFile->isChecked()) { ok = ok && (this->AIFinputGrid.size() != 0) && (this->AIFinputFunction.size() != 0); } else { ok = false; } } //add other models as else if and check wether all needed static parameters are set else { ok = false; } if (this->m_Controls.radioButton_StartParameters->isChecked() && !this->m_Controls.initialValuesManager->hasValidInitialValues()) { std::string warning = "Warning. Invalid start parameters. At least one parameter as an invalid image setting as source."; MITK_ERROR << warning; m_Controls.infoBox->append(QString("") + QString::fromStdString(warning) + QString("")); ok = false; }; } else { ok = false; } return ok; } void PETDynamicView::ConfigureInitialParametersOfParameterizer(mitk::ModelParameterizerBase* parameterizer) const { if (m_Controls.radioButton_StartParameters->isChecked()) { //use user defined initial parameters mitk::InitialParameterizationDelegateBase::Pointer paramDelegate = m_Controls.initialValuesManager->getInitialParametrizationDelegate(); parameterizer->SetInitialParameterizationDelegate(paramDelegate); } } template void PETDynamicView::GenerateModelFit_PixelBased( mitk::modelFit::ModelFitInfo::Pointer& modelFitInfo, mitk::ParameterFitImageGeneratorBase::Pointer& generator) { mitk::PixelBasedParameterFitImageGenerator::Pointer fitGenerator = mitk::PixelBasedParameterFitImageGenerator::New(); typename TParameterizer::Pointer modelParameterizer = TParameterizer::New(); mitk::AIFBasedModelBase::AterialInputFunctionType aif; mitk::AIFBasedModelBase::TimeGridType aifTimeGrid; GetAIF(aif, aifTimeGrid); //Model configuration (static parameters) can be done now modelParameterizer->SetAIF(aif); modelParameterizer->SetAIFTimeGrid(aifTimeGrid); this->ConfigureInitialParametersOfParameterizer(modelParameterizer); //Specify fitting strategy and criterion parameters mitk::ModelFitFunctorBase::Pointer fitFunctor = CreateDefaultFitFunctor(modelParameterizer); //Parametrize fit generator fitGenerator->SetModelParameterizer(modelParameterizer); std::string roiUID = ""; if (m_selectedMask.IsNotNull()) { fitGenerator->SetMask(m_selectedMask); roiUID = m_selectedMask->GetUID(); } fitGenerator->SetDynamicImage(this->m_selectedImage); fitGenerator->SetFitFunctor(fitFunctor); generator = fitGenerator.GetPointer(); //Create model info modelFitInfo = mitk::modelFit::CreateFitInfoFromModelParameterizer(modelParameterizer, m_selectedNode->GetData(), mitk::ModelFitConstants::FIT_TYPE_VALUE_PIXELBASED(), this->GetFitName(), roiUID); mitk::ScalarListLookupTable::ValueType infoSignal; for (mitk::AIFBasedModelBase::AterialInputFunctionType::const_iterator pos = aif.begin(); pos != aif.end(); ++pos) { infoSignal.push_back(*pos); } modelFitInfo->inputData.SetTableValue("AIF", infoSignal); } template void PETDynamicView::GenerateModelFit_ROIBased( mitk::modelFit::ModelFitInfo::Pointer& modelFitInfo, mitk::ParameterFitImageGeneratorBase::Pointer& generator) { mitk::ROIBasedParameterFitImageGenerator::Pointer fitGenerator = mitk::ROIBasedParameterFitImageGenerator::New(); typename TParameterizer::Pointer modelParameterizer = TParameterizer::New(); //Compute AIF mitk::AterialInputFunctionGenerator::Pointer aifGenerator = mitk::AterialInputFunctionGenerator::New(); aifGenerator->SetDynamicImage(this->m_selectedImage); aifGenerator->SetMask(this->m_selectedAIFMask); mitk::AIFBasedModelBase::AterialInputFunctionType aif = aifGenerator->GetAterialInputFunction(); mitk::AIFBasedModelBase::TimeGridType aifTimeGrid = aifGenerator->GetAterialInputFunctionTimeGrid(); //Model configuration (static parameters) can be done now modelParameterizer->SetAIF(aif); modelParameterizer->SetAIFTimeGrid(aifTimeGrid); this->ConfigureInitialParametersOfParameterizer(modelParameterizer); //Compute ROI signal mitk::MaskedDynamicImageStatisticsGenerator::Pointer signalGenerator = mitk::MaskedDynamicImageStatisticsGenerator::New(); signalGenerator->SetMask(m_selectedMask); signalGenerator->SetDynamicImage(m_selectedImage); signalGenerator->Generate(); mitk::MaskedDynamicImageStatisticsGenerator::ResultType roiSignal = signalGenerator->GetMean(); //Specify fitting strategy and criterion parameters mitk::ModelFitFunctorBase::Pointer fitFunctor = CreateDefaultFitFunctor(modelParameterizer); //Parametrize fit generator fitGenerator->SetModelParameterizer(modelParameterizer); fitGenerator->SetMask(m_selectedMask); fitGenerator->SetFitFunctor(fitFunctor); fitGenerator->SetSignal(roiSignal); fitGenerator->SetTimeGrid(mitk::ExtractTimeGrid(m_selectedImage)); generator = fitGenerator.GetPointer(); std::string roiUID = ""; if (m_selectedMask.IsNotNull()) { roiUID = m_selectedMask->GetUID(); } //Create model info modelFitInfo = mitk::modelFit::CreateFitInfoFromModelParameterizer(modelParameterizer, m_selectedNode->GetData(), mitk::ModelFitConstants::FIT_TYPE_VALUE_ROIBASED(), this->GetFitName(), roiUID); mitk::ScalarListLookupTable::ValueType infoSignal; for (mitk::MaskedDynamicImageStatisticsGenerator::ResultType::const_iterator pos = roiSignal.begin(); pos != roiSignal.end(); ++pos) { infoSignal.push_back(*pos); } modelFitInfo->inputData.SetTableValue("ROI", infoSignal); infoSignal.clear(); for (mitk::AIFBasedModelBase::AterialInputFunctionType::const_iterator pos = aif.begin(); pos != aif.end(); ++pos) { infoSignal.push_back(*pos); } modelFitInfo->inputData.SetTableValue("AIF", infoSignal); } void PETDynamicView::DoFit(const mitk::modelFit::ModelFitInfo* fitSession, mitk::ParameterFitImageGeneratorBase* generator) { std::stringstream message; message << "" << "Fitting Data Set . . ." << ""; m_Controls.errorMessageLabel->setText(message.str().c_str()); m_Controls.errorMessageLabel->show(); ///////////////////////// //create job and put it into the thread pool ParameterFitBackgroundJob* pJob = new ParameterFitBackgroundJob(generator, fitSession, this->m_selectedNode); pJob->setAutoDelete(true); connect(pJob, SIGNAL(Error(QString)), this, SLOT(OnJobError(QString))); connect(pJob, SIGNAL(Finished()), this, SLOT(OnJobFinished())); connect(pJob, SIGNAL(ResultsAreAvailable(mitk::modelFit::ModelFitResultNodeVectorType, const ParameterFitBackgroundJob*)), this, SLOT(OnJobResultsAreAvailable(mitk::modelFit::ModelFitResultNodeVectorType, const ParameterFitBackgroundJob*)), Qt::BlockingQueuedConnection); connect(pJob, SIGNAL(JobProgress(double)), this, SLOT(OnJobProgress(double))); connect(pJob, SIGNAL(JobStatusChanged(QString)), this, SLOT(OnJobStatusChanged(QString))); QThreadPool* threadPool = QThreadPool::globalInstance(); threadPool->start(pJob); } PETDynamicView::PETDynamicView() : m_FittingInProgress(false) { m_selectedImage = nullptr; m_selectedMask = nullptr; mitk::ModelFactoryBase::Pointer factory = mitk::OneTissueCompartmentModelFactory::New().GetPointer(); m_FactoryStack.push_back(factory); factory = mitk::ExtendedOneTissueCompartmentModelFactory::New().GetPointer(); m_FactoryStack.push_back(factory); factory = mitk::TwoTissueCompartmentModelFactory::New().GetPointer(); m_FactoryStack.push_back(factory); factory = mitk::TwoTissueCompartmentFDGModelFactory::New().GetPointer(); m_FactoryStack.push_back(factory); factory = mitk::NumericTwoTissueCompartmentModelFactory::New().GetPointer(); m_FactoryStack.push_back(factory); mitk::NodePredicateDataType::Pointer isLabelSet = mitk::NodePredicateDataType::New("LabelSetImage"); mitk::NodePredicateDataType::Pointer isImage = mitk::NodePredicateDataType::New("Image"); mitk::NodePredicateProperty::Pointer isBinary = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); mitk::NodePredicateAnd::Pointer isLegacyMask = mitk::NodePredicateAnd::New(isImage, isBinary); mitk::NodePredicateOr::Pointer isMask = mitk::NodePredicateOr::New(isLegacyMask, isLabelSet); mitk::NodePredicateAnd::Pointer isNoMask = mitk::NodePredicateAnd::New(isImage, mitk::NodePredicateNot::New(isMask)); this->m_IsMaskPredicate = mitk::NodePredicateAnd::New(isMask, mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object"))).GetPointer(); this->m_IsNoMaskImagePredicate = mitk::NodePredicateAnd::New(isNoMask, mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object"))).GetPointer(); } void PETDynamicView::OnJobFinished() { this->m_Controls.infoBox->append(QString("Fitting finished")); this->m_FittingInProgress = false; }; void PETDynamicView::OnJobError(QString err) { MITK_ERROR << err.toStdString().c_str(); m_Controls.infoBox->append(QString("") + err + QString("")); }; void PETDynamicView::OnJobResultsAreAvailable(mitk::modelFit::ModelFitResultNodeVectorType results, const ParameterFitBackgroundJob* pJob) { //Store the resulting parameter fit image via convenience helper function in data storage //(handles the correct generation of the nodes and their properties) mitk::modelFit::StoreResultsInDataStorage(this->GetDataStorage(), results, pJob->GetParentNode()); m_Controls.errorMessageLabel->setText(""); m_Controls.errorMessageLabel->hide(); }; void PETDynamicView::OnJobProgress(double progress) { QString report = QString("Progress. ") + QString::number(progress); this->m_Controls.infoBox->append(report); }; void PETDynamicView::OnJobStatusChanged(QString info) { this->m_Controls.infoBox->append(info); } void PETDynamicView::InitModelComboBox() const { this->m_Controls.comboModel->clear(); this->m_Controls.comboModel->addItem(tr("No model selected")); for (ModelFactoryStackType::const_iterator pos = m_FactoryStack.begin(); pos != m_FactoryStack.end(); ++pos) { this->m_Controls.comboModel->addItem(QString::fromStdString((*pos)->GetClassID())); } this->m_Controls.comboModel->setCurrentIndex(0); }; mitk::ModelFitFunctorBase::Pointer PETDynamicView::CreateDefaultFitFunctor( const mitk::ModelParameterizerBase* parameterizer) const { mitk::LevenbergMarquardtModelFitFunctor::Pointer fitFunctor = mitk::LevenbergMarquardtModelFitFunctor::New(); mitk::SumOfSquaredDifferencesFitCostFunction::Pointer evaluation = mitk::SumOfSquaredDifferencesFitCostFunction::New(); fitFunctor->RegisterEvaluationParameter("sum_diff^2", evaluation); mitk::ChiSquareFitCostFunction::Pointer chi2 = mitk::ChiSquareFitCostFunction::New(); fitFunctor->RegisterEvaluationParameter("Chi^2", chi2); mitk::ReducedChiSquareFitCostFunction::Pointer redchi2 = mitk::ReducedChiSquareFitCostFunction::New(); fitFunctor->RegisterEvaluationParameter("redChi^2", redchi2); if (m_Controls.checkBox_Constraints->isChecked()) { fitFunctor->SetConstraintChecker(m_modelConstraints); } mitk::ModelBase::Pointer refModel = parameterizer->GenerateParameterizedModel(); ::itk::LevenbergMarquardtOptimizer::ScalesType scales; scales.SetSize(refModel->GetNumberOfParameters()); scales.Fill(1.0); fitFunctor->SetScales(scales); return fitFunctor.GetPointer(); } void PETDynamicView::GetAIF(mitk::AIFBasedModelBase::AterialInputFunctionType& aif, mitk::AIFBasedModelBase::AterialInputFunctionType& aifTimeGrid) { if (this->m_Controls.radioAIFFile->isChecked()) { aif.clear(); aifTimeGrid.clear(); aif.SetSize(AIFinputFunction.size()); aifTimeGrid.SetSize(AIFinputGrid.size()); aif.fill(0.0); aifTimeGrid.fill(0.0); itk::Array::iterator aifPos = aif.begin(); for (std::vector::const_iterator pos = AIFinputFunction.begin(); pos != AIFinputFunction.end(); ++pos, ++aifPos) { *aifPos = *pos; } itk::Array::iterator gridPos = aifTimeGrid.begin(); for (std::vector::const_iterator pos = AIFinputGrid.begin(); pos != AIFinputGrid.end(); ++pos, ++gridPos) { *gridPos = *pos; } } else if (this->m_Controls.radioAIFImage->isChecked()) { aif.clear(); aifTimeGrid.clear(); mitk::AterialInputFunctionGenerator::Pointer aifGenerator = mitk::AterialInputFunctionGenerator::New(); //Hematocrit level aifGenerator->SetHCL(this->m_Controls.HCLSpinBox->value()); //mask settings this->m_selectedAIFMaskNode = m_Controls.comboAIFMask->GetSelectedNode(); this->m_selectedAIFMask = dynamic_cast(this->m_selectedAIFMaskNode->GetData()); if (this->m_selectedAIFMask->GetTimeSteps() > 1) { MITK_INFO << "Selected AIF mask has multiple timesteps. Only use first timestep to mask model fit. AIF Mask name: " << m_selectedAIFMaskNode->GetName() ; mitk::ImageTimeSelector::Pointer maskedImageTimeSelector = mitk::ImageTimeSelector::New(); maskedImageTimeSelector->SetInput(this->m_selectedAIFMask); maskedImageTimeSelector->SetTimeNr(0); maskedImageTimeSelector->UpdateLargestPossibleRegion(); this->m_selectedAIFMask = maskedImageTimeSelector->GetOutput(); } if (this->m_selectedAIFMask.IsNotNull()) { aifGenerator->SetMask(this->m_selectedAIFMask); } //image settings if (this->m_Controls.checkDedicatedAIFImage->isChecked()) { this->m_selectedAIFImageNode = m_Controls.comboAIFImage->GetSelectedNode(); this->m_selectedAIFImage = dynamic_cast(this->m_selectedAIFImageNode->GetData()); } else { this->m_selectedAIFImageNode = m_selectedNode; this->m_selectedAIFImage = m_selectedImage; } aifGenerator->SetDynamicImage(this->m_selectedAIFImage); aif = aifGenerator->GetAterialInputFunction(); aifTimeGrid = aifGenerator->GetAterialInputFunctionTimeGrid(); } else { mitkThrow() << "Cannot generate AIF. View is in a invalide state. No AIF mode selected."; } } void PETDynamicView::LoadAIFfromFile() { QFileDialog dialog; dialog.setNameFilter(tr("Images (*.csv")); QString fileName = dialog.getOpenFileName(); m_Controls.aifFilePath->setText(fileName); std::string m_aifFilePath = fileName.toStdString(); //Read Input typedef boost::tokenizer< boost::escaped_list_separator > Tokenizer; ///////////////////////////////////////////////////////////////////////////////////////////////// //AIF Data std::ifstream in1(m_aifFilePath.c_str()); if (!in1.is_open()) { m_Controls.errorMessageLabel->setText("Could not open AIF File!"); } std::vector< std::string > vec1; std::string line1; while (getline(in1, line1)) { Tokenizer tok(line1); vec1.assign(tok.begin(), tok.end()); // if (vec1.size() < 3) continue; this->AIFinputGrid.push_back(convertToDouble(vec1[0])); this->AIFinputFunction.push_back(convertToDouble(vec1[1])); } } diff --git a/Plugins/org.mitk.gui.qt.pharmacokinetics.simulation/documentation/UserManual/Manual.dox b/Plugins/org.mitk.gui.qt.pharmacokinetics.simulation/documentation/UserManual/Manual.dox index 667143d2b5..90b183b1e3 100644 --- a/Plugins/org.mitk.gui.qt.pharmacokinetics.simulation/documentation/UserManual/Manual.dox +++ b/Plugins/org.mitk.gui.qt.pharmacokinetics.simulation/documentation/UserManual/Manual.dox @@ -1,5 +1,5 @@ /** -\page org_mitk_gui_qt_pharmacokinetics_simulation The Perfusion Data Simulation View +\page org_mitk_views_pharmacokinetics_simulation The Perfusion Data Simulation View */ diff --git a/Plugins/org.mitk.gui.qt.pharmacokinetics.simulation/plugin.xml b/Plugins/org.mitk.gui.qt.pharmacokinetics.simulation/plugin.xml index 8528041735..6a016c3091 100644 --- a/Plugins/org.mitk.gui.qt.pharmacokinetics.simulation/plugin.xml +++ b/Plugins/org.mitk.gui.qt.pharmacokinetics.simulation/plugin.xml @@ -1,12 +1,12 @@ - diff --git a/Plugins/org.mitk.gui.qt.pharmacokinetics.simulation/src/internal/PerfusionDataSimulationView.cpp b/Plugins/org.mitk.gui.qt.pharmacokinetics.simulation/src/internal/PerfusionDataSimulationView.cpp index b886c853a0..9a250cb94a 100644 --- a/Plugins/org.mitk.gui.qt.pharmacokinetics.simulation/src/internal/PerfusionDataSimulationView.cpp +++ b/Plugins/org.mitk.gui.qt.pharmacokinetics.simulation/src/internal/PerfusionDataSimulationView.cpp @@ -1,1000 +1,1000 @@ /*============================================================================ 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 #include "mitkWorkbenchUtil.h" #include "PerfusionDataSimulationView.h" #include "itkUnaryFunctorImageFilter.h" #include #include "mitkImageCast.h" #include "mitkImageTimeSelector.h" #include "mitkITKImageImport.h" #include "mitkGaussianNoiseFunctor.h" #include "mitkTwoCompartmentExchangeModel.h" #include "mitkTwoCompartmentExchangeModelParameterizer.h" #include "mitkTwoCompartmentExchangeModelFactory.h" #include "mitkNumericTwoCompartmentExchangeModel.h" #include "mitkNumericTwoCompartmentExchangeModelParameterizer.h" #include "mitkNumericTwoCompartmentExchangeModelFactory.h" #include "mitkExtendedToftsModel.h" #include "mitkExtendedToftsModelFactory.h" #include "mitkExtendedToftsModelParameterizer.h" #include "mitkTwoTissueCompartmentModel.h" #include "mitkTwoTissueCompartmentModelParameterizer.h" #include "mitkTwoTissueCompartmentModelFactory.h" #include "mitkOneTissueCompartmentModel.h" #include "mitkOneTissueCompartmentModelParameterizer.h" #include "mitkOneTissueCompartmentModelFactory.h" #include "mitkModelSignalImageGenerator.h" #include #include #include #include #include "mitkSimpleFunctorBase.h" #include "mitkArbitraryTimeGeometry.h" #include #include -const std::string PerfusionDataSimulationView::VIEW_ID = "org.mitk.gui.qt.pharmacokinetics.simulation"; +const std::string PerfusionDataSimulationView::VIEW_ID = "org.mitk.views.pharmacokinetics.simulation"; inline double convertToDouble(const std::string& data) { std::istringstream stepStream(data); stepStream.imbue(std::locale("C")); double value = 0.0; if (!(stepStream >> value) || !(stepStream.eof())) { mitkThrow() << "Cannot convert string to double. String: " << data; } return value; } inline double FindeMaxConcentration(std::vector Concentration) { double maximum = Concentration[0]; for (std::vector::size_type i =0; isetFocus(); } void PerfusionDataSimulationView::CreateQtPartControl(QWidget* parent) { m_Controls.setupUi(parent); m_Controls.GenerateBtn->setEnabled(false); m_Controls.groupBox_TM->hide(); m_Controls.groupBox_2CXM->hide(); m_Controls.groupBox_2TCM->hide(); m_Controls.groupBox_1TCM->hide(); m_Controls.groupBox_CNR->hide(); this->InitModelComboBox(); /** #2 @todo Reduce code ? */ m_Controls.comboBox_F->SetDataStorage(this->GetDataStorage()); m_Controls.comboBox_F->SetPredicate(m_IsNotABinaryImagePredicate); m_Controls.comboBox_PS->SetDataStorage(this->GetDataStorage()); m_Controls.comboBox_PS->SetPredicate(m_IsNotABinaryImagePredicate); m_Controls.comboBox_fp->SetDataStorage(this->GetDataStorage()); m_Controls.comboBox_fp->SetPredicate(m_IsNotABinaryImagePredicate); m_Controls.comboBox_fi->SetDataStorage(this->GetDataStorage()); m_Controls.comboBox_fi->SetPredicate(m_IsNotABinaryImagePredicate); m_Controls.comboBox_Ktrans->SetDataStorage(this->GetDataStorage()); m_Controls.comboBox_Ktrans->SetPredicate(m_IsNotABinaryImagePredicate); m_Controls.comboBox_vp->SetDataStorage(this->GetDataStorage()); m_Controls.comboBox_vp->SetPredicate(m_IsNotABinaryImagePredicate); m_Controls.comboBox_ve->SetDataStorage(this->GetDataStorage()); m_Controls.comboBox_ve->SetPredicate(m_IsNotABinaryImagePredicate); m_Controls.comboBox_K1->SetDataStorage(this->GetDataStorage()); m_Controls.comboBox_K1->SetPredicate(m_IsNotABinaryImagePredicate); m_Controls.comboBox_K2->SetDataStorage(this->GetDataStorage()); m_Controls.comboBox_K2->SetPredicate(m_IsNotABinaryImagePredicate); m_Controls.comboBox_K3->SetDataStorage(this->GetDataStorage()); m_Controls.comboBox_K3->SetPredicate(m_IsNotABinaryImagePredicate); m_Controls.comboBox_K4->SetDataStorage(this->GetDataStorage()); m_Controls.comboBox_K4->SetPredicate(m_IsNotABinaryImagePredicate); m_Controls.comboBox_VB->SetDataStorage(this->GetDataStorage()); m_Controls.comboBox_VB->SetPredicate(m_IsNotABinaryImagePredicate); m_Controls.comboBox_k1->SetDataStorage(this->GetDataStorage()); m_Controls.comboBox_k1->SetPredicate(m_IsNotABinaryImagePredicate); m_Controls.comboBox_k2->SetDataStorage(this->GetDataStorage()); m_Controls.comboBox_k2->SetPredicate(m_IsNotABinaryImagePredicate); connect(m_Controls.AifFileBtn, SIGNAL(clicked()), this, SLOT(LoadAIFFile())); connect(m_Controls.ModelSelection, SIGNAL(currentIndexChanged(int)), this, SLOT(OnModellSet(int))); connect(m_Controls.GenerateBtn, SIGNAL(clicked()), this, SLOT(OnGenerateDataButtonClicked())); connect(m_Controls.comboBox_F, SIGNAL(currentIndexChanged(int)), this, SLOT(OnSimulationConfigurationChanged())); connect(m_Controls.comboBox_PS, SIGNAL(currentIndexChanged(int)), this, SLOT(OnSimulationConfigurationChanged())); connect(m_Controls.comboBox_fp, SIGNAL(currentIndexChanged(int)), this, SLOT(OnSimulationConfigurationChanged())); connect(m_Controls.comboBox_fi, SIGNAL(currentIndexChanged(int)), this, SLOT(OnSimulationConfigurationChanged())); connect(m_Controls.comboBox_VB, SIGNAL(currentIndexChanged(int)), this, SLOT(OnSimulationConfigurationChanged())); connect(m_Controls.comboBox_K1, SIGNAL(currentIndexChanged(int)), this, SLOT(OnSimulationConfigurationChanged())); connect(m_Controls.comboBox_K2, SIGNAL(currentIndexChanged(int)), this, SLOT(OnSimulationConfigurationChanged())); connect(m_Controls.comboBox_K3, SIGNAL(currentIndexChanged(int)), this, SLOT(OnSimulationConfigurationChanged())); connect(m_Controls.comboBox_K4, SIGNAL(currentIndexChanged(int)), this, SLOT(OnSimulationConfigurationChanged())); connect(m_Controls.comboBox_k1, SIGNAL(currentIndexChanged(int)), this, SLOT(OnSimulationConfigurationChanged())); connect(m_Controls.comboBox_k2, SIGNAL(currentIndexChanged(int)), this, SLOT(OnSimulationConfigurationChanged())); connect(m_Controls.comboBox_Ktrans, SIGNAL(currentIndexChanged(int)), this, SLOT(OnSimulationConfigurationChanged())); connect(m_Controls.comboBox_vp, SIGNAL(currentIndexChanged(int)), this, SLOT(OnSimulationConfigurationChanged())); connect(m_Controls.comboBox_ve, SIGNAL(currentIndexChanged(int)), this, SLOT(OnSimulationConfigurationChanged())); connect(m_Controls.CNRSpinBox, SIGNAL(valueChanged(double)),this, SLOT(OnSimulationConfigurationChanged())); connect(m_Controls.NoiseCheckBox, SIGNAL(stateChanged(int)),this, SLOT(OnSimulationConfigurationChanged())); // UpdateDataSelection(); } void PerfusionDataSimulationView::UpdateDataSelection() { } //void PerfusionDataSimulationView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*source*/, // const QList& selectedNodes) //{ // UpdateDataSelection(); // m_Controls.GenerateBtn->setEnabled(CheckModelSettings()); //} void PerfusionDataSimulationView::OnSimulationConfigurationChanged() { // UpdateDataSelection(); m_Controls.groupBox_CNR->setVisible(m_Controls.NoiseCheckBox->isChecked()); this->m_CNR = m_Controls.CNRSpinBox->value(); m_Controls.GenerateBtn->setEnabled( CheckModelSettings() ); } void PerfusionDataSimulationView::OnModellSet(int index) { m_selectedModelFactory = nullptr; if (index > 0) { if (static_cast(index) <= m_FactoryStack.size() ) { m_selectedModelFactory = m_FactoryStack[index - 1]; } else { MITK_WARN << "Invalid model index. Index outside of the factory stack. Factory stack size: "<< m_FactoryStack.size() << "; invalid index: "<< index; } } bool isToftsFactory = dynamic_cast(m_selectedModelFactory.GetPointer()) != nullptr; bool is2CXMFactory = dynamic_cast(m_selectedModelFactory.GetPointer()) != nullptr || dynamic_cast(m_selectedModelFactory.GetPointer()) != nullptr; bool is2TCMFactory = dynamic_cast(m_selectedModelFactory.GetPointer()) != nullptr; bool is1TCMFactory = dynamic_cast(m_selectedModelFactory.GetPointer()) != nullptr; m_Controls.groupBox_TM->setVisible(isToftsFactory); m_Controls.groupBox_2CXM->setVisible(is2CXMFactory ); m_Controls.groupBox_2TCM->setVisible(is2TCMFactory ); m_Controls.groupBox_1TCM->setVisible(is1TCMFactory ); m_Controls.GenerateBtn->setEnabled( CheckModelSettings() ); // UpdateDataSelection(); } bool PerfusionDataSimulationView::CheckModelSettings() { bool ok = true; if(m_selectedModelFactory.IsNull()) { return false; } if(this->m_AterialInputFunction.GetSize() == 0 || this->m_TimeGrid.GetSize() == 0) { return false; } bool isToftsFactory = dynamic_cast(m_selectedModelFactory.GetPointer()) != nullptr; bool is2CXMFactory = dynamic_cast(m_selectedModelFactory.GetPointer()) != nullptr || dynamic_cast(m_selectedModelFactory.GetPointer()) != nullptr; bool is2TCMFactory = dynamic_cast(m_selectedModelFactory.GetPointer()) != nullptr; bool is1TCMFactory = dynamic_cast(m_selectedModelFactory.GetPointer()) != nullptr; if(isToftsFactory) { ok = ok && m_Controls.comboBox_Ktrans->GetSelectedNode().IsNotNull(); ok = ok && m_Controls.comboBox_vp->GetSelectedNode().IsNotNull(); ok = ok && m_Controls.comboBox_ve->GetSelectedNode().IsNotNull(); } else if(is2CXMFactory) { ok = ok && m_Controls.comboBox_F->GetSelectedNode().IsNotNull(); ok = ok && m_Controls.comboBox_PS->GetSelectedNode().IsNotNull(); ok = ok && m_Controls.comboBox_fp->GetSelectedNode().IsNotNull(); ok = ok && m_Controls.comboBox_fi->GetSelectedNode().IsNotNull(); } else if(is2TCMFactory) { ok = ok && m_Controls.comboBox_K1->GetSelectedNode().IsNotNull(); ok = ok && m_Controls.comboBox_K2->GetSelectedNode().IsNotNull(); ok = ok && m_Controls.comboBox_K3->GetSelectedNode().IsNotNull(); ok = ok && m_Controls.comboBox_K4->GetSelectedNode().IsNotNull(); ok = ok && m_Controls.comboBox_VB->GetSelectedNode().IsNotNull(); } else if(is1TCMFactory) { ok = ok && m_Controls.comboBox_k1->GetSelectedNode().IsNotNull(); ok = ok && m_Controls.comboBox_k2->GetSelectedNode().IsNotNull(); } else { return false; } if(m_Controls.NoiseCheckBox->isChecked()) { if(m_CNR !=0 && m_MaxConcentration !=0) { this->m_Sigma = m_MaxConcentration/m_CNR; } if(m_Sigma==0) { return false; } } return ok; } void PerfusionDataSimulationView::InitModelComboBox() const { this->m_Controls.ModelSelection->clear(); this->m_Controls.ModelSelection->addItem(tr("No model selected")); for (ModelFactoryStackType::const_iterator pos = m_FactoryStack.begin(); pos != m_FactoryStack.end(); ++pos) { this->m_Controls.ModelSelection->addItem(QString::fromStdString((*pos)->GetClassID())); } this->m_Controls.ModelSelection->setCurrentIndex(0); }; void PerfusionDataSimulationView::LoadAIFFile() { QFileDialog dialog; dialog.setNameFilter(tr("Images (*.csv")); QString fileName = dialog.getOpenFileName(); m_Controls.AifFilePath->setText( fileName ); std::string aifFilePath = fileName.toStdString(); //Read Input typedef boost::tokenizer< boost::escaped_list_separator > Tokenizer; ///////////////////////////////////////////////////////////////////////////////////////////////// //AIF Data std::vector inputFunction; std::vector inputGrid; std::ifstream in1(aifFilePath.c_str()); if(!in1.is_open()) { m_Controls.errorMessageLabel->setText("Could not open AIF File!"); } std::vector< std::string > vec1; std::string line1; while (getline(in1,line1)) { Tokenizer tok(line1); vec1.assign(tok.begin(),tok.end()); // if (vec1.size() < 3) continue; inputGrid.push_back(convertToDouble(vec1[0])); inputFunction.push_back(convertToDouble(vec1[1])); } this->m_MaxConcentration = FindeMaxConcentration(inputFunction); itk::Array aif; itk::Array grid; aif.SetSize(inputFunction.size()); grid.SetSize(inputGrid.size()); aif.fill(0.0); grid.fill(0.0); itk::Array::iterator aifPos = aif.begin(); for(std::vector::const_iterator pos = inputFunction.begin(); pos != inputFunction.end(); ++pos, ++aifPos) { *aifPos = *pos; } itk::Array::iterator gridPos = grid.begin(); for(std::vector::const_iterator pos = inputGrid.begin(); pos != inputGrid.end(); ++pos, ++gridPos) { *gridPos = *pos; } this->m_AterialInputFunction = aif; this->m_TimeGrid = grid; m_Controls.GenerateBtn->setEnabled( CheckModelSettings() ); // UpdateDataSelection(); } /** @todo #2 Same function for Numeric and analytic version of FillParameterMap2CXM */ void PerfusionDataSimulationView::FillParameterMap2CXM() { ParameterMapType stack; mitk::DataNode::Pointer m_selectedNode = m_Controls.comboBox_F->GetSelectedNode(); mitk::Image::Pointer m_selectedImage = dynamic_cast(m_selectedNode->GetData()); stack.insert(std::make_pair(mitk::TwoCompartmentExchangeModel::NAME_PARAMETER_F,m_selectedImage)); m_selectedNode = m_Controls.comboBox_PS->GetSelectedNode(); m_selectedImage = dynamic_cast(m_selectedNode->GetData()); stack.insert(std::make_pair(mitk::TwoCompartmentExchangeModel::NAME_PARAMETER_PS,m_selectedImage)); m_selectedNode = m_Controls.comboBox_fp->GetSelectedNode(); m_selectedImage = dynamic_cast(m_selectedNode->GetData()); stack.insert(std::make_pair(mitk::TwoCompartmentExchangeModel::NAME_PARAMETER_vp,m_selectedImage)); m_selectedNode = m_Controls.comboBox_fi->GetSelectedNode(); m_selectedImage = dynamic_cast(m_selectedNode->GetData()); stack.insert(std::make_pair(mitk::TwoCompartmentExchangeModel::NAME_PARAMETER_ve,m_selectedImage)); this->m_ParameterImageMap = stack; } void PerfusionDataSimulationView::FillParameterMapNumeric2CXM() { ParameterMapType stack; mitk::DataNode::Pointer m_selectedNode = m_Controls.comboBox_F->GetSelectedNode(); mitk::Image::Pointer m_selectedImage = dynamic_cast(m_selectedNode->GetData()); stack.insert(std::make_pair(mitk::NumericTwoCompartmentExchangeModel::NAME_PARAMETER_F,m_selectedImage)); m_selectedNode = m_Controls.comboBox_PS->GetSelectedNode(); m_selectedImage = dynamic_cast(m_selectedNode->GetData()); stack.insert(std::make_pair(mitk::NumericTwoCompartmentExchangeModel::NAME_PARAMETER_PS,m_selectedImage)); m_selectedNode = m_Controls.comboBox_fp->GetSelectedNode(); m_selectedImage = dynamic_cast(m_selectedNode->GetData()); stack.insert(std::make_pair(mitk::NumericTwoCompartmentExchangeModel::NAME_PARAMETER_vp,m_selectedImage)); m_selectedNode = m_Controls.comboBox_fi->GetSelectedNode(); m_selectedImage = dynamic_cast(m_selectedNode->GetData()); stack.insert(std::make_pair(mitk::NumericTwoCompartmentExchangeModel::NAME_PARAMETER_ve,m_selectedImage)); this->m_ParameterImageMap = stack; } void PerfusionDataSimulationView::FillParameterMapETM() { ParameterMapType stack; mitk::DataNode::Pointer m_selectedNode = m_Controls.comboBox_Ktrans->GetSelectedNode(); mitk::Image::Pointer m_selectedImage = dynamic_cast(m_selectedNode->GetData()); stack.insert(std::make_pair(mitk::ExtendedToftsModel::NAME_PARAMETER_Ktrans,m_selectedImage)); m_selectedNode = m_Controls.comboBox_vp->GetSelectedNode(); m_selectedImage = dynamic_cast(m_selectedNode->GetData()); stack.insert(std::make_pair(mitk::ExtendedToftsModel::NAME_PARAMETER_vp,m_selectedImage)); m_selectedNode = m_Controls.comboBox_ve->GetSelectedNode(); m_selectedImage = dynamic_cast(m_selectedNode->GetData()); stack.insert(std::make_pair(mitk::ExtendedToftsModel::NAME_PARAMETER_ve,m_selectedImage)); this->m_ParameterImageMap = stack; } void PerfusionDataSimulationView::FillParameterMap2TCM() { ParameterMapType stack; mitk::DataNode::Pointer m_selectedNode = m_Controls.comboBox_K1->GetSelectedNode(); mitk::Image::Pointer m_selectedImage = dynamic_cast(m_selectedNode->GetData()); stack.insert(std::make_pair(mitk::TwoTissueCompartmentModel::NAME_PARAMETER_K1,m_selectedImage)); m_selectedNode = m_Controls.comboBox_K2->GetSelectedNode(); m_selectedImage = dynamic_cast(m_selectedNode->GetData()); stack.insert(std::make_pair(mitk::TwoTissueCompartmentModel::NAME_PARAMETER_k2,m_selectedImage)); m_selectedNode = m_Controls.comboBox_K3->GetSelectedNode(); m_selectedImage = dynamic_cast(m_selectedNode->GetData()); stack.insert(std::make_pair(mitk::TwoTissueCompartmentModel::NAME_PARAMETER_k3,m_selectedImage)); m_selectedNode = m_Controls.comboBox_K4->GetSelectedNode(); m_selectedImage = dynamic_cast(m_selectedNode->GetData()); stack.insert(std::make_pair(mitk::TwoTissueCompartmentModel::NAME_PARAMETER_k4,m_selectedImage)); m_selectedNode = m_Controls.comboBox_VB->GetSelectedNode(); m_selectedImage = dynamic_cast(m_selectedNode->GetData()); stack.insert(std::make_pair(mitk::TwoTissueCompartmentModel::NAME_PARAMETER_VB,m_selectedImage)); this->m_ParameterImageMap = stack; } void PerfusionDataSimulationView::FillParameterMap1TCM() { ParameterMapType stack; mitk::DataNode::Pointer m_selectedNode = m_Controls.comboBox_k1->GetSelectedNode(); mitk::Image::Pointer m_selectedImage = dynamic_cast(m_selectedNode->GetData()); stack.insert(std::make_pair(mitk::OneTissueCompartmentModel::NAME_PARAMETER_k1,m_selectedImage)); m_selectedNode = m_Controls.comboBox_k2->GetSelectedNode(); m_selectedImage = dynamic_cast(m_selectedNode->GetData()); stack.insert(std::make_pair(mitk::OneTissueCompartmentModel::NAME_PARAMETER_k2,m_selectedImage)); this->m_ParameterImageMap = stack; } void PerfusionDataSimulationView::OnGenerateDataButtonClicked() { mitk::Image::Pointer m_DynamicImage = mitk::Image::New(); bool isToftsFactory = dynamic_cast(m_selectedModelFactory.GetPointer()) != nullptr; bool isPhysBrixFactory = dynamic_cast(m_selectedModelFactory.GetPointer()) != nullptr; bool isNumPhysBrixFactory = dynamic_cast(m_selectedModelFactory.GetPointer()) != nullptr; bool is2TCMFactory = dynamic_cast(m_selectedModelFactory.GetPointer()) != nullptr; bool is1TCMFactory = dynamic_cast(m_selectedModelFactory.GetPointer()) != nullptr; if(isToftsFactory) { this->FillParameterMapETM(); m_DynamicImage = this->GenerateETModelData(); } if (isPhysBrixFactory) { this->FillParameterMap2CXM(); m_DynamicImage = this->Generate2CXModelData(); } if (isNumPhysBrixFactory) { this->FillParameterMapNumeric2CXM(); m_DynamicImage = this->GenerateNumeric2CXModelData(); } if (is2TCMFactory) { this->FillParameterMap2TCM(); m_DynamicImage = this->Generate2TCModelData(); } if (is1TCMFactory) { this->FillParameterMap1TCM(); m_DynamicImage = this->Generate1TCModelData(); } mitk::DataNode::Pointer resultNode = mitk::DataNode::New(); std::string nameOfResultImage = "SimulationData_"; nameOfResultImage.append(m_selectedModelFactory->GetModelDisplayName()); resultNode->SetProperty("name", mitk::StringProperty::New(nameOfResultImage) ); resultNode->SetData(m_DynamicImage); // set data of new node this->GetDataStorage()->Add(resultNode); } mitk::Image::Pointer PerfusionDataSimulationView::Generate2CXModelData() { mitk::ModelSignalImageGenerator::Pointer generator = mitk::ModelSignalImageGenerator::New(); mitk::TwoCompartmentExchangeModelParameterizer::Pointer modelParameterizer = mitk::TwoCompartmentExchangeModelParameterizer::New(); /** @todo #2 necessary? Generator need to have a map with Parameters in order of Model in order to pass vector parameters correctly to Model. * I wanted to make it independend from the order the images are passed on */ for(ParameterMapType::const_iterator pos = this->m_ParameterImageMap.begin(); pos != this->m_ParameterImageMap.end(); ++pos) { if(pos->first == mitk::TwoCompartmentExchangeModel::NAME_PARAMETER_F) { generator->SetParameterInputImage(mitk::TwoCompartmentExchangeModel::POSITION_PARAMETER_F, pos->second); } if(pos->first == mitk::TwoCompartmentExchangeModel::NAME_PARAMETER_PS) { generator->SetParameterInputImage(mitk::TwoCompartmentExchangeModel::POSITION_PARAMETER_PS, pos->second); } if(pos->first == mitk::TwoCompartmentExchangeModel::NAME_PARAMETER_ve) { generator->SetParameterInputImage(mitk::TwoCompartmentExchangeModel::POSITION_PARAMETER_ve, pos->second); } if(pos->first == mitk::TwoCompartmentExchangeModel::NAME_PARAMETER_vp) { generator->SetParameterInputImage(mitk::TwoCompartmentExchangeModel::POSITION_PARAMETER_vp, pos->second); } } modelParameterizer->SetAIF(this->m_AterialInputFunction); modelParameterizer->SetAIFTimeGrid(this->m_TimeGrid); modelParameterizer->SetDefaultTimeGrid(this->m_TimeGrid); generator->SetParameterizer(modelParameterizer); mitk::Image::Pointer generatedImage = generator->GetGeneratedImage(); mitk::Image::Pointer resultImage = mitk::Image::New(); if(m_Controls.NoiseCheckBox->isChecked()) { typedef itk::Image ImageType; mitk::Image::Pointer tempImage = mitk::Image::New(); tempImage->Initialize(generatedImage); mitk::ArbitraryTimeGeometry* timeGeometry = dynamic_cast (generatedImage->GetTimeGeometry()); tempImage->SetTimeGeometry(timeGeometry); ImageType::Pointer itkImage = ImageType::New(); mitk::ImageTimeSelector::Pointer imageTimeSelector = mitk::ImageTimeSelector::New(); imageTimeSelector->SetInput(generatedImage); for(unsigned int i = 0; i< generatedImage->GetTimeSteps(); ++i) { imageTimeSelector->SetTimeNr(i); imageTimeSelector->UpdateLargestPossibleRegion(); mitk::Image::Pointer mitkInputImage = imageTimeSelector->GetOutput(); mitk::CastToItkImage(mitkInputImage, itkImage ); typedef mitk::GaussianNoiseFunctor NoiseFunctorType; typedef itk::UnaryFunctorImageFilter NoiseFilterType; NoiseFilterType::Pointer noiseFilter = NoiseFilterType::New(); NoiseFunctorType noiseFunctor; noiseFunctor.SetMean(0.0); noiseFunctor.SetSigma(this->m_Sigma); noiseFilter->SetFunctor(noiseFunctor); noiseFilter->SetInput(itkImage); mitk::Image::Pointer outputImage = mitk::ImportItkImage(noiseFilter->GetOutput())->Clone(); mitk::ImageReadAccessor accessor(outputImage); tempImage->SetVolume(accessor.GetData(), i); } resultImage = tempImage->Clone(); } else { resultImage = generatedImage; } return resultImage; } /** @todo #2 Synergie? Function implementation for every Model to complicated? */ mitk::Image::Pointer PerfusionDataSimulationView::GenerateNumeric2CXModelData() { mitk::ModelSignalImageGenerator::Pointer generator = mitk::ModelSignalImageGenerator::New(); mitk::NumericTwoCompartmentExchangeModelParameterizer::Pointer modelParameterizer = mitk::NumericTwoCompartmentExchangeModelParameterizer::New(); for(ParameterMapType::const_iterator pos = this->m_ParameterImageMap.begin(); pos != this->m_ParameterImageMap.end(); ++pos) { if(pos->first == mitk::NumericTwoCompartmentExchangeModel::NAME_PARAMETER_F) { generator->SetParameterInputImage(mitk::NumericTwoCompartmentExchangeModel::POSITION_PARAMETER_F, pos->second); } if(pos->first == mitk::NumericTwoCompartmentExchangeModel::NAME_PARAMETER_PS) { generator->SetParameterInputImage(mitk::NumericTwoCompartmentExchangeModel::POSITION_PARAMETER_PS, pos->second); } if(pos->first == mitk::NumericTwoCompartmentExchangeModel::NAME_PARAMETER_ve) { generator->SetParameterInputImage(mitk::NumericTwoCompartmentExchangeModel::POSITION_PARAMETER_ve, pos->second); } if(pos->first == mitk::NumericTwoCompartmentExchangeModel::NAME_PARAMETER_vp) { generator->SetParameterInputImage(mitk::NumericTwoCompartmentExchangeModel::POSITION_PARAMETER_vp, pos->second); } } modelParameterizer->SetAIF(this->m_AterialInputFunction); modelParameterizer->SetAIFTimeGrid(this->m_TimeGrid); modelParameterizer->SetDefaultTimeGrid(this->m_TimeGrid); modelParameterizer->SetODEINTStepSize(0.05); generator->SetParameterizer(modelParameterizer); mitk::Image::Pointer generatedImage = generator->GetGeneratedImage(); mitk::Image::Pointer resultImage = mitk::Image::New(); if(m_Controls.NoiseCheckBox->isChecked()) { typedef itk::Image ImageType; mitk::Image::Pointer tempImage = mitk::Image::New(); tempImage->Initialize(generatedImage); mitk::ArbitraryTimeGeometry* timeGeometry = dynamic_cast (generatedImage->GetTimeGeometry()); tempImage->SetTimeGeometry(timeGeometry); ImageType::Pointer itkImage = ImageType::New(); mitk::ImageTimeSelector::Pointer imageTimeSelector = mitk::ImageTimeSelector::New(); imageTimeSelector->SetInput(generatedImage); for(unsigned int i = 0; i< generatedImage->GetTimeSteps(); ++i) { imageTimeSelector->SetTimeNr(i); imageTimeSelector->UpdateLargestPossibleRegion(); mitk::Image::Pointer mitkInputImage = imageTimeSelector->GetOutput(); mitk::CastToItkImage(mitkInputImage, itkImage ); typedef mitk::GaussianNoiseFunctor NoiseFunctorType; typedef itk::UnaryFunctorImageFilter NoiseFilterType; NoiseFilterType::Pointer noiseFilter = NoiseFilterType::New(); NoiseFunctorType noiseFunctor; noiseFunctor.SetMean(0.0); noiseFunctor.SetSigma(this->m_Sigma); noiseFilter->SetFunctor(noiseFunctor); noiseFilter->SetInput(itkImage); mitk::Image::Pointer outputImage = mitk::ImportItkImage(noiseFilter->GetOutput())->Clone(); mitk::ImageReadAccessor accessor(outputImage); tempImage->SetVolume(accessor.GetData(), i); } resultImage = tempImage->Clone(); } else { resultImage = generatedImage; } return resultImage; } mitk::Image::Pointer PerfusionDataSimulationView::GenerateETModelData() { mitk::ModelSignalImageGenerator::Pointer generator = mitk::ModelSignalImageGenerator::New(); mitk::ExtendedToftsModelParameterizer::Pointer modelParameterizer = mitk::ExtendedToftsModelParameterizer::New(); for(ParameterMapType::const_iterator pos = this->m_ParameterImageMap.begin(); pos != this->m_ParameterImageMap.end(); ++pos) { if(pos->first == mitk::ExtendedToftsModel::NAME_PARAMETER_Ktrans) { generator->SetParameterInputImage(mitk::ExtendedToftsModel::POSITION_PARAMETER_Ktrans, pos->second); } if(pos->first == mitk::ExtendedToftsModel::NAME_PARAMETER_vp) { generator->SetParameterInputImage(mitk::ExtendedToftsModel::POSITION_PARAMETER_vp, pos->second); } if(pos->first == mitk::ExtendedToftsModel::NAME_PARAMETER_ve) { generator->SetParameterInputImage(mitk::ExtendedToftsModel::POSITION_PARAMETER_ve, pos->second); } } modelParameterizer->SetAIF(this->m_AterialInputFunction); modelParameterizer->SetAIFTimeGrid(this->m_TimeGrid); modelParameterizer->SetDefaultTimeGrid(this->m_TimeGrid); generator->SetParameterizer(modelParameterizer); mitk::Image::Pointer generatedImage = generator->GetGeneratedImage(); mitk::Image::Pointer resultImage = mitk::Image::New(); if(m_Controls.NoiseCheckBox->isChecked()) { typedef itk::Image ImageType; mitk::Image::Pointer tempImage = mitk::Image::New(); tempImage->Initialize(generatedImage); mitk::ArbitraryTimeGeometry* timeGeometry = dynamic_cast (generatedImage->GetTimeGeometry()); tempImage->SetTimeGeometry(timeGeometry); ImageType::Pointer itkImage = ImageType::New(); mitk::ImageTimeSelector::Pointer imageTimeSelector = mitk::ImageTimeSelector::New(); imageTimeSelector->SetInput(generatedImage); for(unsigned int i = 0; i< generatedImage->GetTimeSteps(); ++i) { imageTimeSelector->SetTimeNr(i); imageTimeSelector->UpdateLargestPossibleRegion(); mitk::Image::Pointer mitkInputImage = imageTimeSelector->GetOutput(); mitk::CastToItkImage(mitkInputImage, itkImage ); typedef mitk::GaussianNoiseFunctor NoiseFunctorType; typedef itk::UnaryFunctorImageFilter NoiseFilterType; NoiseFilterType::Pointer noiseFilter = NoiseFilterType::New(); NoiseFunctorType noiseFunctor; noiseFunctor.SetMean(0.0); noiseFunctor.SetSigma(this->m_Sigma); noiseFilter->SetFunctor(noiseFunctor); noiseFilter->SetInput(itkImage); mitk::Image::Pointer outputImage = mitk::ImportItkImage(noiseFilter->GetOutput())->Clone(); mitk::ImageReadAccessor accessor(outputImage); tempImage->SetVolume(accessor.GetData(), i); } resultImage = tempImage->Clone(); } else { resultImage = generatedImage; } return resultImage; } mitk::Image::Pointer PerfusionDataSimulationView::Generate2TCModelData() { mitk::ModelSignalImageGenerator::Pointer generator = mitk::ModelSignalImageGenerator::New(); mitk::TwoTissueCompartmentModelParameterizer::Pointer modelParameterizer = mitk::TwoTissueCompartmentModelParameterizer::New(); for(ParameterMapType::const_iterator pos = this->m_ParameterImageMap.begin(); pos != this->m_ParameterImageMap.end(); ++pos) { if(pos->first == mitk::TwoTissueCompartmentModel::NAME_PARAMETER_K1) { generator->SetParameterInputImage(mitk::TwoTissueCompartmentModel::POSITION_PARAMETER_K1, pos->second); } if(pos->first == mitk::TwoTissueCompartmentModel::NAME_PARAMETER_k2) { generator->SetParameterInputImage(mitk::TwoTissueCompartmentModel::POSITION_PARAMETER_k2, pos->second); } if(pos->first == mitk::TwoTissueCompartmentModel::NAME_PARAMETER_k3) { generator->SetParameterInputImage(mitk::TwoTissueCompartmentModel::POSITION_PARAMETER_k3, pos->second); } if(pos->first == mitk::TwoTissueCompartmentModel::NAME_PARAMETER_k4) { generator->SetParameterInputImage(mitk::TwoTissueCompartmentModel::POSITION_PARAMETER_k4, pos->second); } if(pos->first == mitk::TwoTissueCompartmentModel::NAME_PARAMETER_VB) { generator->SetParameterInputImage(mitk::TwoTissueCompartmentModel::POSITION_PARAMETER_VB, pos->second); } } modelParameterizer->SetAIF(this->m_AterialInputFunction); modelParameterizer->SetAIFTimeGrid(this->m_TimeGrid); modelParameterizer->SetDefaultTimeGrid(this->m_TimeGrid); generator->SetParameterizer(modelParameterizer); mitk::Image::Pointer generatedImage = generator->GetGeneratedImage(); mitk::Image::Pointer resultImage = mitk::Image::New(); if(m_Controls.NoiseCheckBox->isChecked()) { typedef itk::Image ImageType; mitk::Image::Pointer tempImage = mitk::Image::New(); tempImage->Initialize(generatedImage); mitk::ArbitraryTimeGeometry* timeGeometry = dynamic_cast (generatedImage->GetTimeGeometry()); tempImage->SetTimeGeometry(timeGeometry); ImageType::Pointer itkImage = ImageType::New(); mitk::ImageTimeSelector::Pointer imageTimeSelector = mitk::ImageTimeSelector::New(); imageTimeSelector->SetInput(generatedImage); for(unsigned int i = 0; i< generatedImage->GetTimeSteps(); ++i) { imageTimeSelector->SetTimeNr(i); imageTimeSelector->UpdateLargestPossibleRegion(); mitk::Image::Pointer mitkInputImage = imageTimeSelector->GetOutput(); mitk::CastToItkImage(mitkInputImage, itkImage ); typedef mitk::GaussianNoiseFunctor NoiseFunctorType; typedef itk::UnaryFunctorImageFilter NoiseFilterType; NoiseFilterType::Pointer noiseFilter = NoiseFilterType::New(); NoiseFunctorType noiseFunctor; noiseFunctor.SetMean(0.0); noiseFunctor.SetSigma(this->m_Sigma); noiseFilter->SetFunctor(noiseFunctor); noiseFilter->SetInput(itkImage); mitk::Image::Pointer outputImage = mitk::ImportItkImage(noiseFilter->GetOutput())->Clone(); mitk::ImageReadAccessor accessor(outputImage); tempImage->SetVolume(accessor.GetData(), i); } resultImage = tempImage->Clone(); } else { resultImage = generatedImage; } return resultImage; } mitk::Image::Pointer PerfusionDataSimulationView::Generate1TCModelData() { mitk::ModelSignalImageGenerator::Pointer generator = mitk::ModelSignalImageGenerator::New(); mitk::OneTissueCompartmentModelParameterizer::Pointer modelParameterizer = mitk::OneTissueCompartmentModelParameterizer::New(); for(ParameterMapType::const_iterator pos = this->m_ParameterImageMap.begin(); pos != this->m_ParameterImageMap.end(); ++pos) { if(pos->first == mitk::OneTissueCompartmentModel::NAME_PARAMETER_k1) { generator->SetParameterInputImage(mitk::OneTissueCompartmentModel::POSITION_PARAMETER_k1, pos->second); } if(pos->first == mitk::OneTissueCompartmentModel::NAME_PARAMETER_k2) { generator->SetParameterInputImage(mitk::OneTissueCompartmentModel::POSITION_PARAMETER_k2, pos->second); } } modelParameterizer->SetAIF(this->m_AterialInputFunction); modelParameterizer->SetAIFTimeGrid(this->m_TimeGrid); modelParameterizer->SetDefaultTimeGrid(this->m_TimeGrid); generator->SetParameterizer(modelParameterizer); mitk::Image::Pointer generatedImage = generator->GetGeneratedImage(); mitk::Image::Pointer resultImage = mitk::Image::New(); if(m_Controls.NoiseCheckBox->isChecked()) { typedef itk::Image ImageType; mitk::Image::Pointer tempImage = mitk::Image::New(); tempImage->Initialize(generatedImage); mitk::ArbitraryTimeGeometry* timeGeometry = dynamic_cast (generatedImage->GetTimeGeometry()); tempImage->SetTimeGeometry(timeGeometry); ImageType::Pointer itkImage = ImageType::New(); mitk::ImageTimeSelector::Pointer imageTimeSelector = mitk::ImageTimeSelector::New(); imageTimeSelector->SetInput(generatedImage); for(unsigned int i = 0; i< generatedImage->GetTimeSteps(); ++i) { imageTimeSelector->SetTimeNr(i); imageTimeSelector->UpdateLargestPossibleRegion(); mitk::Image::Pointer mitkInputImage = imageTimeSelector->GetOutput(); mitk::CastToItkImage(mitkInputImage, itkImage ); typedef mitk::GaussianNoiseFunctor NoiseFunctorType; typedef itk::UnaryFunctorImageFilter NoiseFilterType; NoiseFilterType::Pointer noiseFilter = NoiseFilterType::New(); NoiseFunctorType noiseFunctor; noiseFunctor.SetMean(0.0); noiseFunctor.SetSigma(this->m_Sigma); noiseFilter->SetFunctor(noiseFunctor); noiseFilter->SetInput(itkImage); mitk::Image::Pointer outputImage = mitk::ImportItkImage(noiseFilter->GetOutput())->Clone(); mitk::ImageReadAccessor accessor(outputImage); tempImage->SetVolume(accessor.GetData(), i); } resultImage = tempImage->Clone(); } else { resultImage = generatedImage; } return resultImage; } PerfusionDataSimulationView::PerfusionDataSimulationView() { m_Sigma = 0; m_CNR=0; m_MaxConcentration=0; m_selectedModelFactory = nullptr; mitk::ModelFactoryBase::Pointer factory = mitk::ExtendedToftsModelFactory::New().GetPointer(); m_FactoryStack.push_back(factory); factory = mitk::TwoCompartmentExchangeModelFactory::New().GetPointer(); m_FactoryStack.push_back(factory); factory = mitk::NumericTwoCompartmentExchangeModelFactory::New().GetPointer(); m_FactoryStack.push_back(factory); factory = mitk::TwoTissueCompartmentModelFactory::New().GetPointer(); m_FactoryStack.push_back(factory); factory = mitk::OneTissueCompartmentModelFactory::New().GetPointer(); m_FactoryStack.push_back(factory); m_IsNotABinaryImagePredicate = mitk::NodePredicateAnd::New( mitk::TNodePredicateDataType::New(), mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true))), mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object"))).GetPointer(); } diff --git a/Plugins/org.mitk.gui.qt.python/documentation/UserManual/QmitkPython.dox b/Plugins/org.mitk.gui.qt.python/documentation/UserManual/QmitkPython.dox index 114be980c4..73d1ecb6af 100644 --- a/Plugins/org.mitk.gui.qt.python/documentation/UserManual/QmitkPython.dox +++ b/Plugins/org.mitk.gui.qt.python/documentation/UserManual/QmitkPython.dox @@ -1,33 +1,33 @@ /** -\page org_mitk_gui_qt_python The Python Plugin +\page org_mitk_views_python The Python Plugin Available sections: - - \ref org_mitk_gui_qt_pythonOverview - - \ref org_mitk_gui_qt_pythonUsage - - \ref org_mitk_gui_qt_PythonConsole - - \ref org_mitk_gui_qt_PythonSnippets + - \ref org_mitk_views_pythonOverview + - \ref org_mitk_views_pythonUsage + - \ref org_mitk_views_pythonConsole + - \ref org_mitk_views_pythonSnippets -\section org_mitk_gui_qt_pythonOverview Overview +\section org_mitk_views_pythonOverview Overview The Python view provides the graphical front end to run Python code through the mitkPython module. Furthermore the SimpleITK/VTK/OpenCV Python wrapping can be used. Images and surfaces in the DataManager can be transferred via a drag & drop mechanism into the MITK Python Console. -\section org_mitk_gui_qt_pythonUsage Transfer data +\section org_mitk_views_pythonUsage Transfer data Images and surfaces can be tranferred from the data manger into the python console. To transfer an image or surface simply drag it from the data manager into the Variable Stack view, as shown in Figure. A new entry will appear in the Variable Stack, as soon as the data is transferred. As soon as the -entry is available the object can be accessed and modified in the python console. Three dimensional +entry is available the object can be accessed and modified in the python console. Three dimensional images will be copied in-memory to python via numpy and a SimpleITK image object is created with the same properties. When a two dimensional image is transferred the user can choose to transfer it as an OpenCV image object. Surfaces are fully memory mapped as a vtkPolyData object. To transfer an image or surface from the python runtime to the data manager just double click on the corresponding entry in the Variable Stack View. \imageMacro{MitkPythonPluginView.png,"Screenshot of the MITK Python Plugin",6} -\section org_mitk_gui_qt_PythonConsole Console +\section org_mitk_views_pythonConsole Console The Python console can be used for interactive programming. All items in the data storage can be accessed in the python console. The console can also be used to load python scripts and run them. -\section org_mitk_gui_qt_PythonSnippets Snippets +\section org_mitk_views_pythonSnippets Snippets The python plugin contains some code snippets of SimpleITK/VTK/OpenCV that can be run in the python console. Snippets can be modified and saved by the user. */ diff --git a/Plugins/org.mitk.gui.qt.radiomics/documentation/UserManual/QmitkPhenotypingPortalPage.dox b/Plugins/org.mitk.gui.qt.radiomics/documentation/UserManual/QmitkPhenotypingPortalPage.dox index aebb075d1b..550c6d9daf 100644 --- a/Plugins/org.mitk.gui.qt.radiomics/documentation/UserManual/QmitkPhenotypingPortalPage.dox +++ b/Plugins/org.mitk.gui.qt.radiomics/documentation/UserManual/QmitkPhenotypingPortalPage.dox @@ -1,41 +1,40 @@ /** \page org_mitk_gui_qt_mitkphenotyping The Phenotyping \tableofcontents -MITK Phenotyping is a selection of algorithms that can be used to extract image-based phenotypes, for example using a radiomics approach. The software is part of the research of the Division of Medical Image Computing of the German Cancer Research Center (DKFZ). MITK Phenotyping is not intended to be a single application, it is rather a collection of the necessary plugins within the offical MITK releases. +MITK Phenotyping is a selection of algorithms that can be used to extract image-based phenotypes, for example using a radiomics approach. The software is part of the research of the Division of Medical Image Computing of the German Cancer Research Center (DKFZ). MITK Phenotyping is not intended to be a single application, it is rather a collection of the necessary plugins within the offical MITK releases. -The functionality of MITK Phenotyping can be accessed in different ways: Using the graphical interface using the Plugins listed below, using command line applications, or using one of the programming interfaces. +The functionality of MITK Phenotyping can be accessed in different ways: Using the graphical interface using the Plugins listed below, using command line applications, or using one of the programming interfaces. -\section org_mitk_gui_qt_mitkphenotyping_Tutorials Tutorials -\li \subpage org_mitk_views_radiomicstutorial_gui_portal A tutorial on how to use the grapical interface of MITK Phenotying +\section org_mitk_gui_qt_mitkphenotyping_Tutorials Tutorials +\li \subpage org_mitk_views_radiomicstutorial_gui_portal A tutorial on how to use the grapical interface of MITK Phenotying \section org_mitk_gui_qt_mitkphenotyping_Views Views \subsection sub2 Specific Views: -Views that were developed with the main focus on Radiomics. They still might be used in other use-cases as well: +Views that were developed with the main focus on Radiomics. They still might be used in other use-cases as well: \li \subpage org_mitk_views_radiomicstransformationview : Image transformations like Resampling, Laplacian of Gaussian, and Wavelet Transformations \li \subpage org_mitk_views_radiomicsmaskprocessingview : Processing and Cleaning of Masks \li \subpage org_mitk_views_radiomicsarithmetricview : Processing images using mathematical operations \li \subpage org_mitk_views_radiomicsstatisticview : Calculate Radiomics Features \subsection sub1 Non-Specific Views: -This section contains views that are included within MITK Phenotyping, but were developed with a broader application in mind. +This section contains views that are included within MITK Phenotyping, but were developed with a broader application in mind. \li \ref org_mitk_views_basicimageprocessing : Deprecated plugin for performing different image-related tasks like subtraction, mutliplaction, filtering etc. \li \ref org_mitk_views_matchpoint_algorithm_browser : Selection of MatchPoint (Registration) Algorithm \li \ref org_mitk_views_matchpoint_algorithm_control : Configuring and Controlling MatchPoint (Registration) Algorithm \li \ref org_mitk_views_matchpoint_evaluator : Evaluate the Registration performance using MatchPoint \li \ref org_mitk_views_matchpoint_manipulator : Adapt a registration calculated using MatchPoint \li \ref org_mitk_views_matchpoint_mapper : Apply a MatchPoint Registration to a specific image \li \ref org_mitk_views_matchpoint_visualizer : Visualize a Registration obtained with MatchPoint -\li \ref org_mitk_views_matchpoint_algorithm_batch : Running MatchPoint over multiple images (BatchMode) \li \ref org_mitk_views_multilabelsegmentation : Create and editing of Multilabel-Segmentations. \li \ref org_mitk_views_segmentation : Create simple segmentations -\li \ref org_mitk_views_segmentationutilities : Utilities for the processing of simple segmentations. +\li \ref org_mitk_views_segmentationutilities : Utilities for the processing of simple segmentations. \section radiomics_miniapps MiniApps (Command line Tools) \li \subpage MiniAppExplainPage Explanation of the Command Line App concept in MITK \li \subpage mitkBasicImageProcessingMiniAppsPortalPage : List of common preprocessing MiniApps \li \subpage mitkClassificationMiniAppsPortalPage : (Incomplete) list of MITK Classification MiniApps */ diff --git a/Plugins/org.mitk.gui.qt.remeshing/documentation/UserManual/QmitkRemeshing.dox b/Plugins/org.mitk.gui.qt.remeshing/documentation/UserManual/QmitkRemeshing.dox index 4f609da6ec..884f46b296 100644 --- a/Plugins/org.mitk.gui.qt.remeshing/documentation/UserManual/QmitkRemeshing.dox +++ b/Plugins/org.mitk.gui.qt.remeshing/documentation/UserManual/QmitkRemeshing.dox @@ -1,19 +1,19 @@ /** -\page org_mitk_gui_qt_remeshing The Remeshing +\page org_mitk_views_remeshing The Remeshing \imageMacro{RemeshingIcon.png,"Icon of the Remeshing Plugin.",2.00} \tableofcontents -\section org_mitk_gui_qt_remeshingOverview Overview +\section org_mitk_views_remeshingOverview Overview The Remeshing View allows you to remesh surfaces. If done right, remeshing can dramatically increase the quality of your surface mesh. However, you might lose precision if you reduce the vertex density of your surface mesh too strong. Even when you preserve the detail of your mesh, there might be a tiny distance between your original surface and the remeshed surface. Hence, be careful when using remeshed surfaces for evaluation purposes and always keep the original versions. -\section org_mitk_gui_qt_remeshingUsage Usage +\section org_mitk_views_remeshingUsage Usage The Remeshing View provides details on its parameters in its user interface. When in doubt, start with the default parameters and iterate to your desired result by reducing the density parameter. */ diff --git a/Plugins/org.mitk.gui.qt.remeshing/src/internal/QmitkRemeshingView.cpp b/Plugins/org.mitk.gui.qt.remeshing/src/internal/QmitkRemeshingView.cpp index 8a1d0b8716..9e230b5dfc 100644 --- a/Plugins/org.mitk.gui.qt.remeshing/src/internal/QmitkRemeshingView.cpp +++ b/Plugins/org.mitk.gui.qt.remeshing/src/internal/QmitkRemeshingView.cpp @@ -1,161 +1,163 @@ /*============================================================================ 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 "QmitkRemeshingView.h" #include #include #include #include #include #include #include #include #include #include #include +const std::string QmitkRemeshingView::VIEW_ID = "org.mitk.views.remeshing"; + QmitkRemeshingView::QmitkRemeshingView() { } QmitkRemeshingView::~QmitkRemeshingView() { } void QmitkRemeshingView::CreateQtPartControl(QWidget* parent) { m_Controls.setupUi(parent); m_Controls.remeshPushButton->setIcon(berry::QtStyleManager::ThemeIcon(QStringLiteral(":/Remeshing/RemeshingIcon.svg"))); m_Controls.selectionWidget->SetDataStorage(this->GetDataStorage()); m_Controls.selectionWidget->SetSelectionIsOptional(true); m_Controls.selectionWidget->SetEmptyInfo(QStringLiteral("Select a surface")); m_Controls.selectionWidget->SetAutoSelectNewNodes(true); m_Controls.selectionWidget->SetNodePredicate(mitk::NodePredicateAnd::New( mitk::TNodePredicateDataType::New(), mitk::NodePredicateNot::New(mitk::NodePredicateOr::New( mitk::NodePredicateProperty::New("helper object"), mitk::NodePredicateProperty::New("hidden object"))))); connect(m_Controls.selectionWidget, &QmitkSingleNodeSelectionWidget::CurrentSelectionChanged, this, &QmitkRemeshingView::OnSelectedSurfaceChanged); connect(m_Controls.densitySlider, SIGNAL(valueChanged(int)), this, SLOT(OnDensityChanged(int))); connect(m_Controls.densitySpinBox, SIGNAL(valueChanged(int)), this, SLOT(OnDensityChanged(int))); connect(m_Controls.remeshPushButton, SIGNAL(clicked()), this, SLOT(OnRemeshButtonClicked())); this->OnSelectedSurfaceChanged(m_Controls.selectionWidget->GetSelectedNodes()); } void QmitkRemeshingView::OnSelectedSurfaceChanged(const QmitkSingleNodeSelectionWidget::NodeList& nodes) { if (!nodes.empty() && nodes.front().IsNotNull()) { m_MaxNumberOfVertices = static_cast(static_cast(nodes.front()->GetData())->GetVtkPolyData()->GetNumberOfPoints()); this->EnableWidgets(true); } else { m_MaxNumberOfVertices = 0; this->EnableWidgets(false); } } void QmitkRemeshingView::OnDensityChanged(int density) { if (density != m_Controls.densitySlider->value()) m_Controls.densitySlider->setValue(density); if (density != m_Controls.densitySpinBox->value()) m_Controls.densitySpinBox->setValue(density); } void QmitkRemeshingView::OnRemeshButtonClicked() { mitk::DataNode::Pointer selectedNode = m_Controls.selectionWidget->GetSelectedNode(); mitk::Surface::ConstPointer surface = static_cast(selectedNode->GetData()); int density = m_Controls.densitySpinBox->value(); int numVertices = std::max(100, static_cast(m_MaxNumberOfVertices * (density * 0.01))); double gradation = m_Controls.remeshingComboBox->currentText() == QStringLiteral("Adaptive") ? 1.0 : 0.0; const QString quality = m_Controls.qualityComboBox->currentText(); int subsampling; if (QStringLiteral("High (slow)") == quality) { subsampling = 50; } else if (QStringLiteral("Maximum (very slow)") == quality) { subsampling = 500; } else // The default is "Medium (fast)". { subsampling = 10; } bool boundaryFixing = m_Controls.preserveEdgesCheckBox->isChecked(); mitk::ACVD::RemeshFilter::Pointer remesher = mitk::ACVD::RemeshFilter::New(); remesher->SetInput(surface); remesher->SetTimeStep(0); remesher->SetNumVertices(numVertices); remesher->SetGradation(gradation); remesher->SetSubsampling(subsampling); remesher->SetEdgeSplitting(0.0); remesher->SetOptimizationLevel(1.0); remesher->SetForceManifold(false); remesher->SetBoundaryFixing(boundaryFixing); try { remesher->Update(); } catch(const mitk::Exception& exception) { MITK_ERROR << exception.GetDescription(); return; } mitk::Surface::Pointer remeshedSurface = remesher->GetOutput(); mitk::DataNode::Pointer newNode = mitk::DataNode::New(); newNode->SetName(QString("%1 (%2%)").arg(selectedNode->GetName().c_str()).arg(density).toStdString()); newNode->SetProperty("material.representation", mitk::VtkRepresentationProperty::New(VTK_WIREFRAME)); newNode->SetData(remeshedSurface); this->GetDataStorage()->Add(newNode, selectedNode); } void QmitkRemeshingView::EnableWidgets(bool enable) { m_Controls.densitySlider->setEnabled(enable); m_Controls.densitySpinBox->setEnabled(enable); m_Controls.remeshingComboBox->setEnabled(enable); m_Controls.qualityComboBox->setEnabled(enable); m_Controls.preserveEdgesCheckBox->setEnabled(enable); m_Controls.remeshPushButton->setEnabled(enable); m_Controls.explanationLabel->setVisible(enable); } void QmitkRemeshingView::SetFocus() { m_Controls.selectionWidget->setFocus(); } diff --git a/Plugins/org.mitk.gui.qt.remeshing/src/internal/QmitkRemeshingView.h b/Plugins/org.mitk.gui.qt.remeshing/src/internal/QmitkRemeshingView.h index 66d3728c8c..33b384f4d6 100644 --- a/Plugins/org.mitk.gui.qt.remeshing/src/internal/QmitkRemeshingView.h +++ b/Plugins/org.mitk.gui.qt.remeshing/src/internal/QmitkRemeshingView.h @@ -1,43 +1,45 @@ /*============================================================================ 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 QmitkRemeshingView_h #define QmitkRemeshingView_h #include #include #include class QmitkRemeshingView : public QmitkAbstractView { Q_OBJECT public: + static const std::string VIEW_ID; + QmitkRemeshingView(); ~QmitkRemeshingView() override; void CreateQtPartControl(QWidget* parent) override; void SetFocus() override; private slots: void OnSelectedSurfaceChanged(const QmitkSingleNodeSelectionWidget::NodeList& nodes); void OnDensityChanged(int numVertices); void OnRemeshButtonClicked(); private: void EnableWidgets(bool enable); Ui::QmitkRemeshingViewControls m_Controls; int m_MaxNumberOfVertices; }; #endif diff --git a/Plugins/org.mitk.gui.qt.viewnavigator/documentation/UserManual/QmitkViewNavigator.dox b/Plugins/org.mitk.gui.qt.viewnavigator/documentation/UserManual/QmitkViewNavigator.dox index e44be368d5..e3fc8577b8 100644 --- a/Plugins/org.mitk.gui.qt.viewnavigator/documentation/UserManual/QmitkViewNavigator.dox +++ b/Plugins/org.mitk.gui.qt.viewnavigator/documentation/UserManual/QmitkViewNavigator.dox @@ -1,43 +1,43 @@ /** -\page org_mitk_gui_qt_viewnavigator The View Navigator +\page org_mitk_views_viewnavigatorview The View Navigator \imageMacro{view-manager.png,"Icon of the view navigator",2.00} \tableofcontents -\section org_mitk_gui_qt_viewnavigatorOverview Overview +\section org_mitk_views_viewnavigatorviewOverview Overview This view allows for the easy navigation of the available views. You can select which view to open by double-clicking the name of the view in the view navigator. It provides a keyworded, grouped and searchable list of views. -\section org_mitk_gui_qt_viewnavigatorUsage Usage +\section org_mitk_views_viewnavigatorviewUsage Usage You can toggle the View Navigator on and off by clicking on its icon in the menu bar. Alternatively it is also available via the Window->Show Views dialog. \imageMacro{QmitkViewNavigatorGUI.png,"The View Navigator GUI",6.00} Once the View Navigator has been opened you will see a list divided in workflows/perspectives and views. Via this list you can access any view or perspective provided by the application. They are further organized based on their associated category. An entry on the list is opened by a double left-click. -\subsection org_mitk_gui_qt_viewnavigatorSearch Search +\subsection org_mitk_views_viewnavigatorviewSearch Search You can search the lists for view/workflow names, keywords or categories. \imageMacro{QmitkViewNavigatorSearch.png,"Search the View Navigator",4.00} -\subsection org_mitk_gui_qt_viewnavigatorCustomWorkflows Custom Workflows +\subsection org_mitk_views_viewnavigatorviewCustomWorkflows Custom Workflows \imageMacro{QmitkViewNavigatorContextMenuWorkflows.png,"The workflow context menu",4.00} A right click on a workflow opens a context menu that allows you to copy that workflow to create your own custom one. \note The duplicated workflow will look like the basic state of the original workflow. Any changes to the original workflow will not be copied. \imageMacro{QmitkViewNavigatorNewWorkflow.png,"Custom workflow creation dialog",4.00} Your new workflow will appear in the list and you can modify it independently of the original workflow. Any changes will be stored for future sessions unless the workflow is deleted. \note Resetting a custom perspective will return it to the original state after duplicating. \imageMacro{QmitkViewNavigatorContextMenuCustomWorkflow.png,"Custom workflow context menu",4.00} */ diff --git a/Plugins/org.mitk.matchpoint.core.helper/src/internal/MatchPointBrowserConstants.cpp b/Plugins/org.mitk.matchpoint.core.helper/src/internal/MatchPointBrowserConstants.cpp index 4341cdfe47..6acedb7c5e 100644 --- a/Plugins/org.mitk.matchpoint.core.helper/src/internal/MatchPointBrowserConstants.cpp +++ b/Plugins/org.mitk.matchpoint.core.helper/src/internal/MatchPointBrowserConstants.cpp @@ -1,22 +1,22 @@ /*============================================================================ 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 "MatchPointBrowserConstants.h" -const std::string MatchPointBrowserConstants::VIEW_ID = "org.mitk.gui.qt.algorithm.browser"; +const std::string MatchPointBrowserConstants::VIEW_ID = "org.mitk.views.matchpoint.algorithm.browser"; const std::string MatchPointBrowserConstants::MDAR_DIRECTORIES_NODE_NAME = "Deployed algorithm directories"; const std::string MatchPointBrowserConstants::MDAR_FILES_NODE_NAME = "Deployed algorithms"; const std::string MatchPointBrowserConstants::DEBUG_OUTPUT_NODE_NAME = "debug output"; const std::string MatchPointBrowserConstants::LOAD_FROM_APPLICATION_DIR = "load from application dir"; const std::string MatchPointBrowserConstants::LOAD_FROM_HOME_DIR = "load from home dir"; const std::string MatchPointBrowserConstants::LOAD_FROM_CURRENT_DIR = "load from current dir"; const std::string MatchPointBrowserConstants::LOAD_FROM_AUTO_LOAD_DIR = "load from auto-load dir";