diff --git a/Modules/MapperExt/src/mitkVolumeMapperVtkSmart3D.cpp b/Modules/MapperExt/src/mitkVolumeMapperVtkSmart3D.cpp index ee9a32ef57..03cd67e759 100644 --- a/Modules/MapperExt/src/mitkVolumeMapperVtkSmart3D.cpp +++ b/Modules/MapperExt/src/mitkVolumeMapperVtkSmart3D.cpp @@ -1,237 +1,236 @@ /*============================================================================ 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 "mitkVolumeMapperVtkSmart3D.h" #include "mitkTransferFunctionProperty.h" #include "mitkTransferFunctionInitializer.h" #include "mitkLevelWindowProperty.h" #include #include #include #include void mitk::VolumeMapperVtkSmart3D::GenerateDataForRenderer(mitk::BaseRenderer *renderer) { bool value; this->GetDataNode()->GetBoolProperty("volumerendering", value, renderer); if (!value) { m_Volume->VisibilityOff(); return; } else { + createMapper(GetInputImage()); m_Volume->VisibilityOn(); } UpdateTransferFunctions(renderer); UpdateRenderMode(renderer); this->Modified(); } vtkProp* mitk::VolumeMapperVtkSmart3D::GetVtkProp(mitk::BaseRenderer *) { if (!m_Volume->GetMapper()) { createMapper(GetInputImage()); createVolume(); createVolumeProperty(); } return m_Volume; } void mitk::VolumeMapperVtkSmart3D::ApplyProperties(vtkActor *, mitk::BaseRenderer *) { } void mitk::VolumeMapperVtkSmart3D::SetDefaultProperties(mitk::DataNode *node, mitk::BaseRenderer *renderer, bool overwrite) { // GPU_INFO << "SetDefaultProperties"; node->AddProperty("volumerendering", mitk::BoolProperty::New(false), renderer, overwrite); node->AddProperty("volumerendering.usemip", mitk::BoolProperty::New(false), renderer, overwrite); node->AddProperty("volumerendering.cpu.ambient", mitk::FloatProperty::New(0.10f), renderer, overwrite); node->AddProperty("volumerendering.cpu.diffuse", mitk::FloatProperty::New(0.50f), renderer, overwrite); node->AddProperty("volumerendering.cpu.specular", mitk::FloatProperty::New(0.40f), renderer, overwrite); node->AddProperty("volumerendering.cpu.specular.power", mitk::FloatProperty::New(16.0f), renderer, overwrite); node->AddProperty("volumerendering.usegpu", mitk::BoolProperty::New(false), renderer, overwrite); node->AddProperty("volumerendering.useray", mitk::BoolProperty::New(false), renderer, overwrite); node->AddProperty("volumerendering.gpu.ambient", mitk::FloatProperty::New(0.25f), renderer, overwrite); node->AddProperty("volumerendering.gpu.diffuse", mitk::FloatProperty::New(0.50f), renderer, overwrite); node->AddProperty("volumerendering.gpu.specular", mitk::FloatProperty::New(0.40f), renderer, overwrite); node->AddProperty("volumerendering.gpu.specular.power", mitk::FloatProperty::New(16.0f), renderer, overwrite); node->AddProperty("binary", mitk::BoolProperty::New(false), renderer, overwrite); mitk::Image::Pointer image = dynamic_cast(node->GetData()); if (image.IsNotNull() && image->IsInitialized()) { if ((overwrite) || (node->GetProperty("TransferFunction", renderer) == nullptr)) { // add a default transfer function mitk::TransferFunction::Pointer tf = mitk::TransferFunction::New(); mitk::TransferFunctionInitializer::Pointer tfInit = mitk::TransferFunctionInitializer::New(tf); tfInit->SetTransferFunctionMode(0); node->SetProperty("TransferFunction", mitk::TransferFunctionProperty::New(tf.GetPointer())); } } Superclass::SetDefaultProperties(node, renderer, overwrite); } vtkImageData* mitk::VolumeMapperVtkSmart3D::GetInputImage() { auto input = dynamic_cast(this->GetDataNode()->GetData()); return input->GetVtkImageData(this->GetTimestep()); } void mitk::VolumeMapperVtkSmart3D::createMapper(vtkImageData* imageData) { Vector3D spacing; FillVector3D(spacing, 1.0, 1.0, 1.0); m_ImageChangeInformation->SetInputData(imageData); m_ImageChangeInformation->SetOutputSpacing(spacing.GetDataPointer()); m_SmartVolumeMapper->SetBlendModeToComposite(); m_SmartVolumeMapper->SetInputConnection(m_ImageChangeInformation->GetOutputPort()); } void mitk::VolumeMapperVtkSmart3D::createVolume() { - m_Volume->VisibilityOff(); m_Volume->SetMapper(m_SmartVolumeMapper); m_Volume->SetProperty(m_VolumeProperty); } void mitk::VolumeMapperVtkSmart3D::createVolumeProperty() { m_VolumeProperty->ShadeOn(); m_VolumeProperty->SetInterpolationType(VTK_LINEAR_INTERPOLATION); } void mitk::VolumeMapperVtkSmart3D::UpdateTransferFunctions(mitk::BaseRenderer *renderer) { vtkSmartPointer opacityTransferFunction; vtkSmartPointer gradientTransferFunction; vtkSmartPointer colorTransferFunction; bool isBinary = false; this->GetDataNode()->GetBoolProperty("binary", isBinary, renderer); if (isBinary) { colorTransferFunction = vtkSmartPointer::New(); float rgb[3]; if (!GetDataNode()->GetColor(rgb, renderer)) rgb[0] = rgb[1] = rgb[2] = 1; colorTransferFunction->AddRGBPoint(0, rgb[0], rgb[1], rgb[2]); colorTransferFunction->Modified(); opacityTransferFunction = vtkSmartPointer::New(); gradientTransferFunction = vtkSmartPointer::New(); } else { auto *transferFunctionProp = dynamic_cast(this->GetDataNode()->GetProperty("TransferFunction", renderer)); if (transferFunctionProp) { opacityTransferFunction = transferFunctionProp->GetValue()->GetScalarOpacityFunction(); gradientTransferFunction = transferFunctionProp->GetValue()->GetGradientOpacityFunction(); colorTransferFunction = transferFunctionProp->GetValue()->GetColorTransferFunction(); } else { opacityTransferFunction = vtkSmartPointer::New(); gradientTransferFunction = vtkSmartPointer::New(); colorTransferFunction = vtkSmartPointer::New(); } } - m_VolumeProperty->SetColor(colorTransferFunction); m_VolumeProperty->SetScalarOpacity(opacityTransferFunction); m_VolumeProperty->SetGradientOpacity(gradientTransferFunction); } void mitk::VolumeMapperVtkSmart3D::UpdateRenderMode(mitk::BaseRenderer *renderer) { bool usegpu = false; bool useray = false; bool usemip = false; this->GetDataNode()->GetBoolProperty("volumerendering.usegpu", usegpu); this->GetDataNode()->GetBoolProperty("volumerendering.useray", useray); this->GetDataNode()->GetBoolProperty("volumerendering.usemip", usemip); if (usegpu) m_SmartVolumeMapper->SetRequestedRenderModeToGPU(); else if (useray) m_SmartVolumeMapper->SetRequestedRenderModeToRayCast(); else m_SmartVolumeMapper->SetRequestedRenderModeToDefault(); int blendMode; if (this->GetDataNode()->GetIntProperty("volumerendering.blendmode", blendMode)) m_SmartVolumeMapper->SetBlendMode(blendMode); else if (usemip) m_SmartVolumeMapper->SetBlendMode(vtkSmartVolumeMapper::MAXIMUM_INTENSITY_BLEND); // shading parameter if (m_SmartVolumeMapper->GetRequestedRenderMode() == vtkSmartVolumeMapper::GPURenderMode) { float value = 0; if (this->GetDataNode()->GetFloatProperty("volumerendering.gpu.ambient", value, renderer)) m_VolumeProperty->SetAmbient(value); if (this->GetDataNode()->GetFloatProperty("volumerendering.gpu.diffuse", value, renderer)) m_VolumeProperty->SetDiffuse(value); if (this->GetDataNode()->GetFloatProperty("volumerendering.gpu.specular", value, renderer)) m_VolumeProperty->SetSpecular(value); if (this->GetDataNode()->GetFloatProperty("volumerendering.gpu.specular.power", value, renderer)) m_VolumeProperty->SetSpecularPower(value); } else { float value = 0; if (this->GetDataNode()->GetFloatProperty("volumerendering.cpu.ambient", value, renderer)) m_VolumeProperty->SetAmbient(value); if (this->GetDataNode()->GetFloatProperty("volumerendering.cpu.diffuse", value, renderer)) m_VolumeProperty->SetDiffuse(value); if (this->GetDataNode()->GetFloatProperty("volumerendering.cpu.specular", value, renderer)) m_VolumeProperty->SetSpecular(value); if (this->GetDataNode()->GetFloatProperty("volumerendering.cpu.specular.power", value, renderer)) m_VolumeProperty->SetSpecularPower(value); } } mitk::VolumeMapperVtkSmart3D::VolumeMapperVtkSmart3D() { m_SmartVolumeMapper = vtkSmartPointer::New(); m_SmartVolumeMapper->SetBlendModeToComposite(); m_ImageChangeInformation = vtkSmartPointer::New(); m_VolumeProperty = vtkSmartPointer::New(); m_Volume = vtkSmartPointer::New(); } mitk::VolumeMapperVtkSmart3D::~VolumeMapperVtkSmart3D() { } diff --git a/Modules/QtWidgetsExt/include/QmitkTransferFunctionGeneratorWidget.h b/Modules/QtWidgetsExt/include/QmitkTransferFunctionGeneratorWidget.h index 5bf7ea8d64..443f1b7cac 100644 --- a/Modules/QtWidgetsExt/include/QmitkTransferFunctionGeneratorWidget.h +++ b/Modules/QtWidgetsExt/include/QmitkTransferFunctionGeneratorWidget.h @@ -1,80 +1,80 @@ /*============================================================================ 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 QMITKTRANSFERFUNCTIONGENERATORWIDGET_H #define QMITKTRANSFERFUNCTIONGENERATORWIDGET_H #include "MitkQtWidgetsExtExports.h" #include "ui_QmitkTransferFunctionGeneratorWidget.h" #include #include #include #include class MITKQTWIDGETSEXT_EXPORT QmitkTransferFunctionGeneratorWidget : public QWidget, public Ui::QmitkTransferFunctionGeneratorWidget { Q_OBJECT public: QmitkTransferFunctionGeneratorWidget(QWidget *parent = nullptr, Qt::WindowFlags f = nullptr); ~QmitkTransferFunctionGeneratorWidget() override; - void SetDataNode(mitk::DataNode *node); + void SetDataNode(mitk::DataNode *node, mitk::TimeStepType timestep = 0); int AddPreset(const QString &presetName); void SetPresetsTabEnabled(bool enable); void SetThresholdTabEnabled(bool enable); void SetBellTabEnabled(bool enable); public slots: void OnSavePreset(); void OnLoadPreset(); void OnDeltaLevelWindow(int dx, int dy); void OnDeltaThreshold(int dx, int dy); signals: void SignalTransferFunctionModeChanged(int); void SignalUpdateCanvas(); protected slots: void OnPreset(int mode); protected: mitk::TransferFunctionProperty::Pointer tfpToChange; double histoMinimum; double histoMaximum; double thPos; double thDelta; double deltaScale; double deltaMax; double deltaMin; const mitk::Image::HistogramType *histoGramm; QString presetFileName; double ScaleDelta(int d) const; }; #endif diff --git a/Modules/QtWidgetsExt/include/QmitkTransferFunctionWidget.h b/Modules/QtWidgetsExt/include/QmitkTransferFunctionWidget.h index d1d5a901d4..0ab5534657 100755 --- a/Modules/QtWidgetsExt/include/QmitkTransferFunctionWidget.h +++ b/Modules/QtWidgetsExt/include/QmitkTransferFunctionWidget.h @@ -1,79 +1,79 @@ /*============================================================================ 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 QMITKTRANSFERFUNCTIONWIDGET_H #define QMITKTRANSFERFUNCTIONWIDGET_H #include "MitkQtWidgetsExtExports.h" #include "ui_QmitkTransferFunctionWidget.h" #include #include #include #include #include #include #include namespace mitk { class BaseRenderer; } class MITKQTWIDGETSEXT_EXPORT QmitkTransferFunctionWidget : public QWidget, public Ui::QmitkTransferFunctionWidget { Q_OBJECT public: QmitkTransferFunctionWidget(QWidget *parent = nullptr, Qt::WindowFlags f = nullptr); ~QmitkTransferFunctionWidget() override; - void SetDataNode(mitk::DataNode *node, const mitk::BaseRenderer *renderer = nullptr); + void SetDataNode(mitk::DataNode *node, mitk::TimeStepType timestep = 0, const mitk::BaseRenderer *renderer = nullptr); void SetScalarLabel(const QString &scalarLabel); void ShowScalarOpacityFunction(bool show); void ShowColorFunction(bool show); void ShowGradientOpacityFunction(bool show); void SetScalarOpacityFunctionEnabled(bool enable); void SetColorFunctionEnabled(bool enable); void SetGradientOpacityFunctionEnabled(bool enable); public slots: void SetXValueScalar(const QString text); void SetYValueScalar(const QString text); void SetXValueGradient(const QString text); void SetYValueGradient(const QString text); void SetXValueColor(const QString text); void OnUpdateCanvas(); void UpdateRanges(); void OnResetSlider(); void OnSpanChanged(int lower, int upper); protected: mitk::TransferFunctionProperty::Pointer tfpToChange; int m_RangeSliderMin; int m_RangeSliderMax; mitk::SimpleHistogramCache histogramCache; }; #endif diff --git a/Modules/QtWidgetsExt/src/QmitkTransferFunctionGeneratorWidget.cpp b/Modules/QtWidgetsExt/src/QmitkTransferFunctionGeneratorWidget.cpp index e244bb77a1..861c103b23 100644 --- a/Modules/QtWidgetsExt/src/QmitkTransferFunctionGeneratorWidget.cpp +++ b/Modules/QtWidgetsExt/src/QmitkTransferFunctionGeneratorWidget.cpp @@ -1,353 +1,367 @@ /*============================================================================ 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 "QmitkTransferFunctionGeneratorWidget.h" #include #include #include #include #include #include #include #include #include QmitkTransferFunctionGeneratorWidget::QmitkTransferFunctionGeneratorWidget(QWidget *parent, Qt::WindowFlags f) : QWidget(parent, f), deltaScale(1.0), deltaMax(1024), deltaMin(1) { histoGramm = nullptr; this->setupUi(this); // LevelWindow Tab { connect(m_CrossLevelWindow, SIGNAL(SignalDeltaMove(int, int)), this, SLOT(OnDeltaLevelWindow(int, int))); } // Threshold Tab { connect(m_CrossThreshold, SIGNAL(SignalDeltaMove(int, int)), this, SLOT(OnDeltaThreshold(int, int))); thDelta = 100; } // Presets Tab { m_TransferFunctionComboBox->setVisible(false); connect(m_TransferFunctionComboBox, SIGNAL(activated(int)), this, SIGNAL(SignalTransferFunctionModeChanged(int))); connect(m_TransferFunctionComboBox, SIGNAL(activated(int)), this, SLOT(OnPreset(int))); connect(m_SavePreset, SIGNAL(clicked()), this, SLOT(OnSavePreset())); connect(m_LoadPreset, SIGNAL(clicked()), this, SLOT(OnLoadPreset())); } presetFileName = "."; } int QmitkTransferFunctionGeneratorWidget::AddPreset(const QString &presetName) { m_TransferFunctionComboBox->setVisible(true); m_TransferFunctionComboBox->addItem(presetName); return m_TransferFunctionComboBox->count() - 1; } void QmitkTransferFunctionGeneratorWidget::SetPresetsTabEnabled(bool enable) { m_PresetTab->setEnabled(enable); } void QmitkTransferFunctionGeneratorWidget::SetThresholdTabEnabled(bool enable) { m_ThresholdTab->setEnabled(enable); } void QmitkTransferFunctionGeneratorWidget::SetBellTabEnabled(bool enable) { m_BellTab->setEnabled(enable); } void QmitkTransferFunctionGeneratorWidget::OnSavePreset() { if (tfpToChange.IsNull()) return; mitk::TransferFunction::Pointer tf = tfpToChange->GetValue(); presetFileName = QFileDialog::getSaveFileName( this, "Choose a filename to save the transfer function", presetFileName, "Transferfunction (*.xml)"); if (!presetFileName.endsWith(".xml")) presetFileName.append(".xml"); MITK_INFO << "Saving Transferfunction under path: " << presetFileName.toStdString(); if (mitk::TransferFunctionPropertySerializer::SerializeTransferFunction(presetFileName.toLatin1(), tf)) { QFontMetrics metrics(m_InfoPreset->font()); QString text = metrics.elidedText(presetFileName, Qt::ElideMiddle, m_InfoPreset->width()); m_InfoPreset->setText(QString("saved ") + text); } else { m_InfoPreset->setText(QString("saving failed")); } } void QmitkTransferFunctionGeneratorWidget::OnLoadPreset() { if (tfpToChange.IsNull()) return; presetFileName = QFileDialog::getOpenFileName( this, "Choose a file to open the transfer function from", presetFileName, "Transferfunction (*.xml)"); MITK_INFO << "Loading Transferfunction from path: " << presetFileName.toStdString(); mitk::TransferFunction::Pointer tf = mitk::TransferFunctionPropertySerializer::DeserializeTransferFunction(presetFileName.toLatin1()); if (tf.IsNotNull()) { tfpToChange->SetValue(tf); QFontMetrics metrics(m_InfoPreset->font()); QString text = metrics.elidedText(presetFileName, Qt::ElideMiddle, m_InfoPreset->width()); m_InfoPreset->setText(QString("loaded ") + text); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); emit SignalUpdateCanvas(); } } void QmitkTransferFunctionGeneratorWidget::OnPreset(int mode) { // first item is only information if (--mode == -1) return; m_InfoPreset->setText(QString("selected ") + m_TransferFunctionComboBox->currentText()); // revert to first item m_TransferFunctionComboBox->setCurrentIndex(0); } static double transformationGlocke(double x) { double z = 0.1; double a = 2 - 2 * z; double b = 2 * z - 1; x = a * x + b; return x; } static double stepFunctionGlocke(double x) { x = 1 - (2 * x - 1.0); // map [0.5;1] to [0,1] x = x * (3 * x - 2 * x * x); // apply smoothing function x = x * x; return x; } double QmitkTransferFunctionGeneratorWidget::ScaleDelta(int d) const { return deltaScale * (double)d; } void QmitkTransferFunctionGeneratorWidget::OnDeltaLevelWindow(int dx, int dy) // bell { if (tfpToChange.IsNull()) return; thPos += ScaleDelta(dx); thDelta -= ScaleDelta(dy); if (thDelta < deltaMin) thDelta = deltaMin; if (thDelta > deltaMax) thDelta = deltaMax; if (thPos < histoMinimum) thPos = histoMinimum; if (thPos > histoMaximum) thPos = histoMaximum; std::stringstream ss; ss << "Click on the cross and move the mouse" << "\n" << "\n" << "center at " << thPos << "\n" << "width " << thDelta * 2; m_InfoLevelWindow->setText(QString(ss.str().c_str())); mitk::TransferFunction::Pointer tf = tfpToChange->GetValue(); // grayvalue->opacity { vtkPiecewiseFunction *f = tf->GetScalarOpacityFunction(); f->RemoveAllPoints(); for (int r = 0; r <= 6; r++) { double relPos = (r / 6.0) * 0.5 + 0.5; f->AddPoint(thPos + thDelta * (-transformationGlocke(relPos)), stepFunctionGlocke(relPos)); f->AddPoint(thPos + thDelta * (transformationGlocke(relPos)), stepFunctionGlocke(relPos)); } f->Modified(); } // gradient at grayvalue->opacity { vtkPiecewiseFunction *f = tf->GetGradientOpacityFunction(); f->RemoveAllPoints(); f->AddPoint(0, 1.0); f->Modified(); } tf->Modified(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); emit SignalUpdateCanvas(); } static double stepFunctionThreshold(double x) { x = 0.5 * x + 0.5; // map [-1;1] to [0,1] x = x * (3 * x - 2 * x * x); // apply smoothing function x = x * x; return x; } void QmitkTransferFunctionGeneratorWidget::OnDeltaThreshold(int dx, int dy) // LEVELWINDOW { if (tfpToChange.IsNull()) return; thPos += ScaleDelta(dx); thDelta += ScaleDelta(dy); if (thDelta < deltaMin) thDelta = deltaMin; if (thDelta > deltaMax) thDelta = deltaMax; if (thPos < histoMinimum) thPos = histoMinimum; if (thPos > histoMaximum) thPos = histoMaximum; std::stringstream ss; ss << "Click on the cross and move the mouse" << "\n" << "\n" << "threshold at " << thPos << "\n" << "width " << thDelta * 2; m_InfoThreshold->setText(QString(ss.str().c_str())); mitk::TransferFunction::Pointer tf = tfpToChange->GetValue(); // grayvalue->opacity { vtkPiecewiseFunction *f = tf->GetScalarOpacityFunction(); f->RemoveAllPoints(); for (int r = 1; r <= 4; r++) { double relPos = r / 4.0; f->AddPoint(thPos + thDelta * (-relPos), stepFunctionThreshold(-relPos)); f->AddPoint(thPos + thDelta * (relPos), stepFunctionThreshold(relPos)); } f->Modified(); } // gradient at grayvalue->opacity { vtkPiecewiseFunction *f = tf->GetGradientOpacityFunction(); f->RemoveAllPoints(); f->AddPoint(0, 1.0); f->Modified(); } tf->Modified(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); emit SignalUpdateCanvas(); } QmitkTransferFunctionGeneratorWidget::~QmitkTransferFunctionGeneratorWidget() { } -void QmitkTransferFunctionGeneratorWidget::SetDataNode(mitk::DataNode *node) +void QmitkTransferFunctionGeneratorWidget::SetDataNode(mitk::DataNode *node, mitk::TimeStepType timestep) { histoGramm = nullptr; if (node) { tfpToChange = dynamic_cast(node->GetProperty("TransferFunction")); if (!tfpToChange) node->SetProperty("TransferFunction", tfpToChange = mitk::TransferFunctionProperty::New()); mitk::TransferFunction::Pointer tf = tfpToChange->GetValue(); if (mitk::Image *image = dynamic_cast(node->GetData())) { - mitk::ImageStatisticsHolder *statistics = image->GetStatistics(); + mitk::Image::Pointer inputImage = image; + if (image->GetTimeSteps() > 1) + { + if (!image->GetTimeGeometry()->IsValidTimeStep(timestep)) + { + return; + } + mitk::ImageTimeSelector::Pointer timeselector = mitk::ImageTimeSelector::New(); + timeselector->SetInput(image); + timeselector->SetTimeNr(timestep); + timeselector->UpdateLargestPossibleRegion(); + inputImage = timeselector->GetOutput(); + } + + mitk::ImageStatisticsHolder *statistics = inputImage->GetStatistics(); histoMinimum = statistics->GetScalarValueMin(); histoMaximum = statistics->GetScalarValueMax(); } else if (mitk::UnstructuredGrid *grid = dynamic_cast(node->GetData())) { double *range = grid->GetVtkUnstructuredGrid()->GetScalarRange(); histoMinimum = range[0]; histoMaximum = range[1]; double histoRange = histoMaximum - histoMinimum; deltaMax = histoRange / 4.0; deltaMin = histoRange / 400.0; deltaScale = histoRange / 1024.0; } else { MITK_WARN << "QmitkTransferFunctonGeneratorWidget does not support " << node->GetData()->GetNameOfClass() << " instances"; } thPos = (histoMinimum + histoMaximum) / 2.0; } else { tfpToChange = nullptr; m_InfoPreset->setText(QString("")); } } diff --git a/Modules/QtWidgetsExt/src/QmitkTransferFunctionWidget.cpp b/Modules/QtWidgetsExt/src/QmitkTransferFunctionWidget.cpp index bde5c54854..2f5e727ba6 100755 --- a/Modules/QtWidgetsExt/src/QmitkTransferFunctionWidget.cpp +++ b/Modules/QtWidgetsExt/src/QmitkTransferFunctionWidget.cpp @@ -1,246 +1,263 @@ /*============================================================================ 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 "QmitkTransferFunctionWidget.h" +#include "mitkImageTimeSelector.h" #include QmitkTransferFunctionWidget::QmitkTransferFunctionWidget(QWidget *parent, Qt::WindowFlags f) : QWidget(parent, f) { this->setupUi(this); // signals and slots connections connect(m_XEditScalarOpacity, SIGNAL(textEdited(const QString &)), this, SLOT(SetXValueScalar(const QString &))); connect(m_YEditScalarOpacity, SIGNAL(textEdited(const QString &)), this, SLOT(SetYValueScalar(const QString &))); connect(m_XEditGradientOpacity, SIGNAL(textEdited(const QString &)), this, SLOT(SetXValueGradient(const QString &))); connect(m_YEditGradientOpacity, SIGNAL(textEdited(const QString &)), this, SLOT(SetYValueGradient(const QString &))); connect(m_XEditColor, SIGNAL(textEdited(const QString &)), this, SLOT(SetXValueColor(const QString &))); m_RangeSlider->setMinimum(-2048); m_RangeSlider->setMaximum(2048); connect(m_RangeSlider, SIGNAL(valuesChanged(int, int)), this, SLOT(OnSpanChanged(int, int))); // reset button connect(m_RangeSliderReset, SIGNAL(pressed()), this, SLOT(OnResetSlider())); m_ScalarOpacityFunctionCanvas->SetQLineEdits(m_XEditScalarOpacity, m_YEditScalarOpacity); m_GradientOpacityCanvas->SetQLineEdits(m_XEditGradientOpacity, m_YEditGradientOpacity); m_ColorTransferFunctionCanvas->SetQLineEdits(m_XEditColor, nullptr); m_ScalarOpacityFunctionCanvas->SetTitle("Grayvalue -> Opacity"); m_GradientOpacityCanvas->SetTitle("Grayvalue/Gradient -> Opacity"); m_ColorTransferFunctionCanvas->SetTitle("Grayvalue -> Color"); } QmitkTransferFunctionWidget::~QmitkTransferFunctionWidget() { } void QmitkTransferFunctionWidget::SetScalarLabel(const QString &scalarLabel) { m_textLabelX->setText(scalarLabel); m_textLabelX_2->setText(scalarLabel); m_textLabelX_3->setText(scalarLabel); m_ScalarOpacityFunctionCanvas->SetTitle(scalarLabel + " -> Opacity"); m_GradientOpacityCanvas->SetTitle(scalarLabel + "/Gradient -> Opacity"); m_ColorTransferFunctionCanvas->SetTitle(scalarLabel + " -> Color"); } void QmitkTransferFunctionWidget::ShowScalarOpacityFunction(bool show) { m_ScalarOpacityWidget->setVisible(show); } void QmitkTransferFunctionWidget::ShowColorFunction(bool show) { m_ColorWidget->setVisible(show); } void QmitkTransferFunctionWidget::ShowGradientOpacityFunction(bool show) { m_GradientOpacityWidget->setVisible(show); } void QmitkTransferFunctionWidget::SetScalarOpacityFunctionEnabled(bool enable) { m_ScalarOpacityWidget->setEnabled(enable); } void QmitkTransferFunctionWidget::SetColorFunctionEnabled(bool enable) { m_ColorWidget->setEnabled(enable); } void QmitkTransferFunctionWidget::SetGradientOpacityFunctionEnabled(bool enable) { m_GradientOpacityWidget->setEnabled(enable); } -void QmitkTransferFunctionWidget::SetDataNode(mitk::DataNode *node, const mitk::BaseRenderer *renderer) +void QmitkTransferFunctionWidget::SetDataNode(mitk::DataNode *node, mitk::TimeStepType timestep, const mitk::BaseRenderer *renderer) { if (node) { tfpToChange = dynamic_cast(node->GetProperty("TransferFunction", renderer)); - if (!tfpToChange) { if (!dynamic_cast(node->GetData())) { MITK_WARN << "QmitkTransferFunctionWidget::SetDataNode called with non-image node"; goto turnOff; } node->SetProperty("TransferFunction", tfpToChange = mitk::TransferFunctionProperty::New()); } mitk::TransferFunction::Pointer tf = tfpToChange->GetValue(); - if (mitk::BaseData *data = node->GetData()) + if (mitk::Image *data = dynamic_cast(node->GetData())) { - mitk::SimpleHistogram *h = histogramCache[data]; + mitk::SimpleHistogram *h = nullptr; + if (data->GetTimeSteps() > 1) + { + if (!data->GetTimeGeometry()->IsValidTimeStep(timestep)) + { + return; + } + mitk::ImageTimeSelector::Pointer timeselector = mitk::ImageTimeSelector::New(); + timeselector->SetInput(data); + timeselector->SetTimeNr(timestep); + timeselector->UpdateLargestPossibleRegion(); + auto inputImage = timeselector->GetOutput(); + h = histogramCache[inputImage]; + } + else + { + h = histogramCache[data]; + } m_RangeSliderMin = h->GetMin(); m_RangeSliderMax = h->GetMax(); m_RangeSlider->blockSignals(true); m_RangeSlider->setMinimum(m_RangeSliderMin); m_RangeSlider->setMaximum(m_RangeSliderMax); m_RangeSlider->setMinimumValue(m_RangeSliderMin); m_RangeSlider->setMaximumValue(m_RangeSliderMax); m_RangeSlider->blockSignals(false); m_ScalarOpacityFunctionCanvas->SetHistogram(h); m_GradientOpacityCanvas->SetHistogram(h); m_ColorTransferFunctionCanvas->SetHistogram(h); } OnUpdateCanvas(); return; } turnOff: m_ScalarOpacityFunctionCanvas->setEnabled(false); m_ScalarOpacityFunctionCanvas->SetHistogram(nullptr); m_GradientOpacityCanvas->setEnabled(false); m_GradientOpacityCanvas->SetHistogram(nullptr); m_ColorTransferFunctionCanvas->setEnabled(false); m_ColorTransferFunctionCanvas->SetHistogram(nullptr); tfpToChange = nullptr; } void QmitkTransferFunctionWidget::OnUpdateCanvas() { if (tfpToChange.IsNull()) return; mitk::TransferFunction::Pointer tf = tfpToChange->GetValue(); if (tf.IsNull()) return; m_ScalarOpacityFunctionCanvas->SetPiecewiseFunction(tf->GetScalarOpacityFunction()); m_GradientOpacityCanvas->SetPiecewiseFunction(tf->GetGradientOpacityFunction()); m_ColorTransferFunctionCanvas->SetColorTransferFunction(tf->GetColorTransferFunction()); UpdateRanges(); m_ScalarOpacityFunctionCanvas->update(); m_GradientOpacityCanvas->update(); m_ColorTransferFunctionCanvas->update(); } void QmitkTransferFunctionWidget::SetXValueScalar(const QString text) { if (!text.endsWith(".")) { m_ScalarOpacityFunctionCanvas->SetX(text.toFloat()); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkTransferFunctionWidget::SetYValueScalar(const QString text) { if (!text.endsWith(".")) { m_ScalarOpacityFunctionCanvas->SetY(text.toFloat()); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkTransferFunctionWidget::SetXValueGradient(const QString text) { if (!text.endsWith(".")) { m_GradientOpacityCanvas->SetX(text.toFloat()); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkTransferFunctionWidget::SetYValueGradient(const QString text) { if (!text.endsWith(".")) { m_GradientOpacityCanvas->SetY(text.toFloat()); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkTransferFunctionWidget::SetXValueColor(const QString text) { if (!text.endsWith(".")) { m_ColorTransferFunctionCanvas->SetX(text.toFloat()); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkTransferFunctionWidget::UpdateRanges() { int lower = m_RangeSlider->minimumValue(); int upper = m_RangeSlider->maximumValue(); m_ScalarOpacityFunctionCanvas->SetMin(lower); m_ScalarOpacityFunctionCanvas->SetMax(upper); m_GradientOpacityCanvas->SetMin(lower); m_GradientOpacityCanvas->SetMax(upper); m_ColorTransferFunctionCanvas->SetMin(lower); m_ColorTransferFunctionCanvas->SetMax(upper); } void QmitkTransferFunctionWidget::OnSpanChanged(int, int) { UpdateRanges(); m_GradientOpacityCanvas->update(); m_ColorTransferFunctionCanvas->update(); m_ScalarOpacityFunctionCanvas->update(); } void QmitkTransferFunctionWidget::OnResetSlider() { m_RangeSlider->blockSignals(true); m_RangeSlider->setMaximumValue(m_RangeSliderMax); m_RangeSlider->setMinimumValue(m_RangeSliderMin); m_RangeSlider->blockSignals(false); UpdateRanges(); m_GradientOpacityCanvas->update(); m_ColorTransferFunctionCanvas->update(); m_ScalarOpacityFunctionCanvas->update(); } diff --git a/Plugins/org.mitk.gui.qt.volumevisualization/src/internal/QmitkVolumeVisualizationView.cpp b/Plugins/org.mitk.gui.qt.volumevisualization/src/internal/QmitkVolumeVisualizationView.cpp index 2e931cec19..8cfa70dc4b 100755 --- a/Plugins/org.mitk.gui.qt.volumevisualization/src/internal/QmitkVolumeVisualizationView.cpp +++ b/Plugins/org.mitk.gui.qt.volumevisualization/src/internal/QmitkVolumeVisualizationView.cpp @@ -1,293 +1,314 @@ /*============================================================================ 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 "QmitkVolumeVisualizationView.h" #include #include #include #include #include #include #include #include #include #include #include #include const std::string QmitkVolumeVisualizationView::VIEW_ID = "org.mitk.views.volumevisualization"; enum { DEFAULT_RENDERMODE = 0, RAYCAST_RENDERMODE = 1, GPU_RENDERMODE = 2 }; QmitkVolumeVisualizationView::QmitkVolumeVisualizationView() : QmitkAbstractView() , m_Controls(nullptr) { } void QmitkVolumeVisualizationView::SetFocus() { UpdateInterface(); } void QmitkVolumeVisualizationView::CreateQtPartControl(QWidget* parent) { m_Controls = new Ui::QmitkVolumeVisualizationViewControls; m_Controls->setupUi(parent); m_Controls->volumeSelectionWidget->SetDataStorage(GetDataStorage()); m_Controls->volumeSelectionWidget->SetNodePredicate(mitk::NodePredicateAnd::New( mitk::TNodePredicateDataType::New(), mitk::NodePredicateOr::New(mitk::NodePredicateDimension::New(3), mitk::NodePredicateDimension::New(4)), mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object")))); m_Controls->volumeSelectionWidget->SetSelectionIsOptional(true); m_Controls->volumeSelectionWidget->SetEmptyInfo(QString("Please select a 3D / 4D image volume")); m_Controls->volumeSelectionWidget->SetPopUpTitel(QString("Select image volume")); // Fill the transfer function presets in the generator widget std::vector names; mitk::TransferFunctionInitializer::GetPresetNames(names); for (const auto& name : names) { m_Controls->transferFunctionGeneratorWidget->AddPreset(QString::fromStdString(name)); } // see enum in vtkSmartVolumeMapper m_Controls->renderMode->addItem("Default"); m_Controls->renderMode->addItem("RayCast"); m_Controls->renderMode->addItem("GPU"); // see vtkVolumeMapper::BlendModes m_Controls->blendMode->addItem("Comp"); m_Controls->blendMode->addItem("Max"); m_Controls->blendMode->addItem("Min"); m_Controls->blendMode->addItem("Avg"); m_Controls->blendMode->addItem("Add"); connect(m_Controls->volumeSelectionWidget, &QmitkSingleNodeSelectionWidget::CurrentSelectionChanged, this, &QmitkVolumeVisualizationView::OnCurrentSelectionChanged); connect(m_Controls->enableRenderingCB, SIGNAL(toggled(bool)), this, SLOT(OnEnableRendering(bool))); connect(m_Controls->renderMode, SIGNAL(activated(int)), this, SLOT(OnRenderMode(int))); connect(m_Controls->blendMode, SIGNAL(activated(int)), this, SLOT(OnBlendMode(int))); connect(m_Controls->transferFunctionGeneratorWidget, SIGNAL(SignalUpdateCanvas()), m_Controls->transferFunctionWidget, SLOT(OnUpdateCanvas())); connect(m_Controls->transferFunctionGeneratorWidget, SIGNAL(SignalTransferFunctionModeChanged(int)), SLOT(OnMitkInternalPreset(int))); m_Controls->enableRenderingCB->setEnabled(false); m_Controls->blendMode->setEnabled(false); m_Controls->renderMode->setEnabled(false); m_Controls->transferFunctionWidget->setEnabled(false); m_Controls->transferFunctionGeneratorWidget->setEnabled(false); m_Controls->volumeSelectionWidget->SetAutoSelectNewNodes(true); + + this->m_TimePointChangeListener.RenderWindowPartActivated(this->GetRenderWindowPart()); + connect(&m_TimePointChangeListener, + &QmitkSliceNavigationListener::SelectedTimePointChanged, + this, + &QmitkVolumeVisualizationView::OnSelectedTimePointChanged); +} + +void QmitkVolumeVisualizationView::RenderWindowPartActivated(mitk::IRenderWindowPart *renderWindowPart) +{ + this->m_TimePointChangeListener.RenderWindowPartActivated(renderWindowPart); +} + +void QmitkVolumeVisualizationView::RenderWindowPartDeactivated(mitk::IRenderWindowPart *renderWindowPart) +{ + this->m_TimePointChangeListener.RenderWindowPartDeactivated(renderWindowPart); } void QmitkVolumeVisualizationView::OnMitkInternalPreset(int mode) { if (m_SelectedNode.IsExpired()) { return; } auto node = m_SelectedNode.Lock(); mitk::TransferFunctionProperty::Pointer transferFuncProp; if (node->GetProperty(transferFuncProp, "TransferFunction")) { // first item is only information if (--mode == -1) return; // -- Creat new TransferFunction mitk::TransferFunctionInitializer::Pointer tfInit = mitk::TransferFunctionInitializer::New(transferFuncProp->GetValue()); tfInit->SetTransferFunctionMode(mode); RequestRenderWindowUpdate(); m_Controls->transferFunctionWidget->OnUpdateCanvas(); } } void QmitkVolumeVisualizationView::OnCurrentSelectionChanged(QList nodes) { m_SelectedNode = nullptr; if (nodes.empty() || nodes.front().IsNull()) { UpdateInterface(); return; } auto selectedNode = nodes.front(); auto image = dynamic_cast(selectedNode->GetData()); if (nullptr != image) { m_SelectedNode = selectedNode; } UpdateInterface(); } void QmitkVolumeVisualizationView::OnEnableRendering(bool state) { if (m_SelectedNode.IsExpired()) { return; } m_SelectedNode.Lock()->SetProperty("volumerendering", mitk::BoolProperty::New(state)); UpdateInterface(); RequestRenderWindowUpdate(); } void QmitkVolumeVisualizationView::OnRenderMode(int mode) { if (m_SelectedNode.IsExpired()) { return; } auto selectedNode = m_SelectedNode.Lock(); bool usegpu = false; bool useray = false; if (DEFAULT_RENDERMODE == mode) { useray = true; usegpu = true; } else if (GPU_RENDERMODE == mode) { usegpu = true; } else if (RAYCAST_RENDERMODE == mode) { useray = true; } selectedNode->SetProperty("volumerendering.usegpu", mitk::BoolProperty::New(usegpu)); selectedNode->SetProperty("volumerendering.useray", mitk::BoolProperty::New(useray)); RequestRenderWindowUpdate(); } void QmitkVolumeVisualizationView::OnBlendMode(int mode) { if (m_SelectedNode.IsExpired()) { return; } auto selectedNode = m_SelectedNode.Lock(); bool usemip = false; if (vtkVolumeMapper::MAXIMUM_INTENSITY_BLEND == mode) { usemip = true; } selectedNode->SetProperty("volumerendering.usemip", mitk::BoolProperty::New(usemip)); selectedNode->SetProperty("volumerendering.blendmode", mitk::IntProperty::New(mode)); RequestRenderWindowUpdate(); } +void QmitkVolumeVisualizationView::OnSelectedTimePointChanged(const mitk::TimePointType & /*newTimePoint*/) +{ + this->UpdateInterface(); +} + void QmitkVolumeVisualizationView::UpdateInterface() { if (m_SelectedNode.IsExpired()) { // turnoff all m_Controls->enableRenderingCB->setChecked(false); m_Controls->enableRenderingCB->setEnabled(false); m_Controls->blendMode->setCurrentIndex(0); m_Controls->blendMode->setEnabled(false); m_Controls->renderMode->setCurrentIndex(0); m_Controls->renderMode->setEnabled(false); m_Controls->transferFunctionWidget->SetDataNode(nullptr); m_Controls->transferFunctionWidget->setEnabled(false); m_Controls->transferFunctionGeneratorWidget->SetDataNode(nullptr); m_Controls->transferFunctionGeneratorWidget->setEnabled(false); return; } bool enabled = false; auto selectedNode = m_SelectedNode.Lock(); selectedNode->GetBoolProperty("volumerendering", enabled); m_Controls->enableRenderingCB->setEnabled(true); m_Controls->enableRenderingCB->setChecked(enabled); if (!enabled) { // turnoff all except volumerendering checkbox m_Controls->blendMode->setCurrentIndex(0); m_Controls->blendMode->setEnabled(false); m_Controls->renderMode->setCurrentIndex(0); m_Controls->renderMode->setEnabled(false); m_Controls->transferFunctionWidget->SetDataNode(nullptr); m_Controls->transferFunctionWidget->setEnabled(false); m_Controls->transferFunctionGeneratorWidget->SetDataNode(nullptr); m_Controls->transferFunctionGeneratorWidget->setEnabled(false); return; } // otherwise we can activate em all m_Controls->blendMode->setEnabled(true); m_Controls->renderMode->setEnabled(true); // Determine Combo Box mode { bool usegpu = false; bool useray = false; bool usemip = false; selectedNode->GetBoolProperty("volumerendering.usegpu", usegpu); selectedNode->GetBoolProperty("volumerendering.useray", useray); selectedNode->GetBoolProperty("volumerendering.usemip", usemip); int blendMode; if (selectedNode->GetIntProperty("volumerendering.blendmode", blendMode)) m_Controls->blendMode->setCurrentIndex(blendMode); if (usemip) m_Controls->blendMode->setCurrentIndex(vtkVolumeMapper::MAXIMUM_INTENSITY_BLEND); int mode = DEFAULT_RENDERMODE; if (useray) mode = RAYCAST_RENDERMODE; else if (usegpu) mode = GPU_RENDERMODE; m_Controls->renderMode->setCurrentIndex(mode); } - - m_Controls->transferFunctionWidget->SetDataNode(selectedNode); + auto time = this->GetRenderWindowPart()->GetTimeNavigationController()->GetSelectedTimeStep(); + m_Controls->transferFunctionWidget->SetDataNode(selectedNode, time); m_Controls->transferFunctionWidget->setEnabled(true); - m_Controls->transferFunctionGeneratorWidget->SetDataNode(selectedNode); + m_Controls->transferFunctionGeneratorWidget->SetDataNode(selectedNode, time); m_Controls->transferFunctionGeneratorWidget->setEnabled(true); } diff --git a/Plugins/org.mitk.gui.qt.volumevisualization/src/internal/QmitkVolumeVisualizationView.h b/Plugins/org.mitk.gui.qt.volumevisualization/src/internal/QmitkVolumeVisualizationView.h index 5d413576f2..658d5fc133 100755 --- a/Plugins/org.mitk.gui.qt.volumevisualization/src/internal/QmitkVolumeVisualizationView.h +++ b/Plugins/org.mitk.gui.qt.volumevisualization/src/internal/QmitkVolumeVisualizationView.h @@ -1,61 +1,69 @@ /*============================================================================ 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 QMITKVOLUMEVISUALIZATIONVIEW_H #define QMITKVOLUMEVISUALIZATIONVIEW_H #include "ui_QmitkVolumeVisualizationViewControls.h" // mitk core #include #include #include +#include +#include /** * @brief */ -class QmitkVolumeVisualizationView : public QmitkAbstractView +class QmitkVolumeVisualizationView : public QmitkAbstractView, public mitk::IRenderWindowPartListener { Q_OBJECT public: static const std::string VIEW_ID; QmitkVolumeVisualizationView(); ~QmitkVolumeVisualizationView() override = default; void SetFocus() override; private Q_SLOTS: void OnCurrentSelectionChanged(QList nodes); void OnMitkInternalPreset(int mode); void OnEnableRendering(bool state); void OnRenderMode(int mode); void OnBlendMode(int mode); + void OnSelectedTimePointChanged(const mitk::TimePointType &); + +protected: + void RenderWindowPartActivated(mitk::IRenderWindowPart *renderWindowPart) override; + void RenderWindowPartDeactivated(mitk::IRenderWindowPart *renderWindowPart) override; private: void CreateQtPartControl(QWidget* parent) override; void UpdateInterface(); Ui::QmitkVolumeVisualizationViewControls* m_Controls; mitk::WeakPointer m_SelectedNode; + QmitkSliceNavigationListener m_TimePointChangeListener; }; #endif // QMITKVOLUMEVISUALIZATIONVIEW_H