diff --git a/Modules/C3js/resource/C3js.qrc b/Modules/C3js/resource/C3js.qrc
index b968c60d12..4ebbe5d81c 100644
--- a/Modules/C3js/resource/C3js.qrc
+++ b/Modules/C3js/resource/C3js.qrc
@@ -1,14 +1,14 @@
c3.min.css
Histogram.css
Histogram_dark.css
c3.min.js
d3.min.js
empty.html
- empty_dark.html
+ empty.js
QmitkC3jsWidget.html
Histogram.js
diff --git a/Modules/C3js/resource/QmitkC3jsWidget.html b/Modules/C3js/resource/QmitkC3jsWidget.html
index 81e4f0c89a..40b2ce4942 100644
--- a/Modules/C3js/resource/QmitkC3jsWidget.html
+++ b/Modules/C3js/resource/QmitkC3jsWidget.html
@@ -1,16 +1,16 @@
-
+
diff --git a/Modules/C3js/resource/empty.html b/Modules/C3js/resource/empty.html
index 31ee449e24..011d8e9980 100644
--- a/Modules/C3js/resource/empty.html
+++ b/Modules/C3js/resource/empty.html
@@ -1,10 +1,16 @@
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Modules/C3js/resource/empty.js b/Modules/C3js/resource/empty.js
new file mode 100644
index 0000000000..8f84f04ed6
--- /dev/null
+++ b/Modules/C3js/resource/empty.js
@@ -0,0 +1,11 @@
+function changeTheme(color) {
+ if (color == 'dark') {
+ link = document.getElementsByTagName("link")[0];
+ link.href = "Histogram_dark.css";
+ }
+ else
+ {
+ link = document.getElementsByTagName("link")[0];
+ link.href = "Histogram.css";
+ }
+};
diff --git a/Modules/C3js/src/QmitkC3jsWidget.cpp b/Modules/C3js/src/QmitkC3jsWidget.cpp
index ba13e9c3aa..939c06bc09 100644
--- a/Modules/C3js/src/QmitkC3jsWidget.cpp
+++ b/Modules/C3js/src/QmitkC3jsWidget.cpp
@@ -1,285 +1,285 @@
/*===================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.
This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.
See LICENSE.txt or http://www.mitk.org for details.
===================================================================*/
#include
#include
#include
#include
#include
#include
#include "mitkImageTimeSelector.h"
class QmitkC3jsWidget::Impl final
{
public:
explicit Impl(QWidget* parent);
~Impl();
Impl(const Impl&) = delete;
Impl& operator=(const Impl&) = delete;
QWebChannel* GetWebChannel();
void ClearJavaScriptChart();
void initializeJavaScriptChart();
void callJavaScriptFuntion(QString command);
QmitkC3Data* GetC3Data() { return &m_c3Data; };
mitk::Image::Pointer GetImage() { return m_Image; }; const
void SetImage(const mitk::Image::Pointer image) { m_Image = image; };
mitk::PlanarFigure::ConstPointer GetPlanarFigure() { return m_PlanarFigure; }; const
void SetPlanarFigure(const mitk::PlanarFigure::ConstPointer planarFigure) { m_PlanarFigure = planarFigure; };
private:
QWidget* m_Parent;
QWebChannel* m_WebChannel;
QWebEngineView* m_WebEngineView;
QmitkC3Data m_c3Data;
/**
* \brief Reference image.
*
* Holds the image to calculate an intensity profile.
*/
mitk::Image::Pointer m_Image;
/**
* \brief Pathelement.
*
* Holds a not closed planar figure to calculate an intensity profile.
*/
mitk::PlanarFigure::ConstPointer m_PlanarFigure;
};
QmitkC3jsWidget::Impl::Impl(QWidget* parent)
: m_WebChannel(new QWebChannel(parent)),
m_WebEngineView(new QWebEngineView(parent)),
m_Parent(parent)
{
//disable context menu for QWebEngineView
m_WebEngineView->setContextMenuPolicy(Qt::NoContextMenu);
//Set the webengineview to an initial empty page. The actual chart will be loaded once the data is calculated.
m_WebEngineView->setUrl(QUrl(QStringLiteral("qrc:///C3js/empty.html")));
m_WebEngineView->page()->setWebChannel(m_WebChannel);
connect( m_WebEngineView, SIGNAL( loadFinished(bool) ), parent, SLOT( OnLoadFinished(bool) ) );
auto layout = new QGridLayout(parent);
layout->setMargin(0);
layout->addWidget(m_WebEngineView);
parent->setLayout(layout);
}
QmitkC3jsWidget::Impl::~Impl()
{
}
QWebChannel* QmitkC3jsWidget::Impl::GetWebChannel()
{
return m_WebChannel;
}
QmitkC3jsWidget::QmitkC3jsWidget(QWidget* parent)
: QWidget(parent),
m_Impl(new Impl(this))
{
m_Statistics = mitk::ImageStatisticsCalculator::StatisticsContainer::New();
}
void QmitkC3jsWidget::Impl::callJavaScriptFuntion(QString command)
{
m_WebEngineView->page()->runJavaScript(command);
}
void QmitkC3jsWidget::Impl::ClearJavaScriptChart()
{
- m_WebEngineView->setUrl(QUrl(QStringLiteral("qrc:///C3js/empty.html")));
+ m_WebEngineView->setUrl(QUrl(QStringLiteral("qrc:///C3js/empty.html")));
}
void QmitkC3jsWidget::Impl::initializeJavaScriptChart()
{
m_WebChannel->registerObject(QStringLiteral("initValues"), &m_c3Data);
m_WebEngineView->setUrl(QUrl(QStringLiteral("qrc:///C3js/QmitkC3jsWidget.html")));
}
QmitkC3jsWidget::QmitkC3jsWidget(const QString& id, QObject* object, QWidget* parent)
: QWidget(parent),
m_Impl(new Impl(this))
{
if (!id.isEmpty() && object != nullptr)
m_Impl->GetWebChannel()->registerObject(id, object);
m_Statistics = mitk::ImageStatisticsCalculator::StatisticsContainer::New();
}
QmitkC3jsWidget::~QmitkC3jsWidget()
{
delete m_Impl;
}
void QmitkC3jsWidget::OnLoadFinished(bool isLoadSuccessfull)
{
emit PageSuccessfullyLoaded();
}
void QmitkC3jsWidget::TransformView(QString transformTo)
{
QString command = QString("transformView('" + transformTo + "')");
m_Impl->callJavaScriptFuntion(command);
}
void QmitkC3jsWidget::SendCommand(QString command)
{
m_Impl->callJavaScriptFuntion(command);
}
void QmitkC3jsWidget::SetAppearance(bool useLineChart, bool showSubChart)
{
this->m_Impl->GetC3Data()->SetAppearance(useLineChart, showSubChart);
}
// method to expose data to JavaScript by using properties
void QmitkC3jsWidget::ComputeHistogram(HistogramType* histogram, bool useLineChart, bool showSubChart)
{
this->m_Impl->GetC3Data()->SetHistogram(histogram);
SetAppearance(useLineChart, showSubChart);
HistogramConstIteratorType startIt = this->m_Impl->GetC3Data()->GetHistogram()->End();
HistogramConstIteratorType endIt = this->m_Impl->GetC3Data()->GetHistogram()->End();
HistogramConstIteratorType it = this->m_Impl->GetC3Data()->GetHistogram()->Begin();
//Clear old data befor loading new data.
this->m_Impl->GetC3Data()->ClearData();
unsigned int i = 0;
bool firstValue = false;
// removes frequencies of 0, which are outside the first and last bin
for (; it != this->m_Impl->GetC3Data()->GetHistogram()->End(); ++it)
{
if (it.GetFrequency() > 0.0)
{
endIt = it;
if (!firstValue)
{
firstValue = true;
startIt = it;
}
}
}
++endIt;
// generating Lists of measurement and frequencies
for (it = startIt; it != endIt; ++it, ++i)
{
QVariant frequency = QVariant::fromValue(it.GetFrequency());
QVariant measurement = it.GetMeasurementVector()[0];
this->m_Impl->GetC3Data()->GetYDataPointer()->insert(i, frequency);
this->m_Impl->GetC3Data()->GetXDataPointer()->insert(i, measurement);
}
m_Impl->initializeJavaScriptChart();
}
void QmitkC3jsWidget::ComputeIntensityProfile(unsigned int timeStep, bool computeStatistics)
{
this->ClearHistogram();
//m_Impl->GetC3Data()->ClearData();
//m_ParametricPath->Initialize();
if (m_Impl->GetPlanarFigure().IsNull())
{
mitkThrow() << "PlanarFigure not set!";
}
if (m_Impl->GetImage().IsNull())
{
mitkThrow() << "Image not set!";
}
mitk::Image::Pointer image;
if (m_Impl->GetImage()->GetDimension() == 4)
{
mitk::ImageTimeSelector::Pointer timeSelector = mitk::ImageTimeSelector::New();
timeSelector->SetInput(m_Impl->GetImage());
timeSelector->SetTimeNr(timeStep);
timeSelector->Update();
image = timeSelector->GetOutput();
}
else
{
image = m_Impl->GetImage();
}
mitk::IntensityProfile::Pointer intensityProfile = mitk::ComputeIntensityProfile(
image, const_cast(m_Impl->GetPlanarFigure().GetPointer()));
//m_Frequency.clear();
//m_Measurement.clear();
int i = -1;
mitk::IntensityProfile::ConstIterator end = intensityProfile->End();
for (mitk::IntensityProfile::ConstIterator it = intensityProfile->Begin(); it != end; ++it)
{
m_Impl->GetC3Data()->GetYDataPointer()->push_back(it.GetMeasurementVector()[0]);
//m_Impl->GetC3Data()->GetFrequencyPointer()->push_back(50000);
m_Impl->GetC3Data()->GetXDataPointer()->push_back(++i);
}
if (computeStatistics)
{
mitk::ComputeIntensityProfileStatistics(intensityProfile, m_Statistics);
}
m_Impl->initializeJavaScriptChart();
}
void QmitkC3jsWidget::ClearHistogram()
{
m_Impl->GetC3Data()->ClearData();
m_Impl->ClearJavaScriptChart();
}
mitk::Image::Pointer QmitkC3jsWidget::GetImage() const
{
return m_Impl->GetImage();
}
void QmitkC3jsWidget::SetImage(const mitk::Image::Pointer image)
{
m_Impl->SetImage(image);
}
mitk::PlanarFigure::ConstPointer QmitkC3jsWidget::GetPlanarFigure() const
{
return m_Impl->GetPlanarFigure();
}
void QmitkC3jsWidget::SetPlanarFigure(const mitk::PlanarFigure::ConstPointer planarFigure)
{
m_Impl->SetPlanarFigure(planarFigure);
}
\ No newline at end of file
diff --git a/Plugins/org.blueberry.ui.qt/src/internal/berryQtStyleManager.cpp.autosave b/Plugins/org.blueberry.ui.qt/src/internal/berryQtStyleManager.cpp.autosave
new file mode 100644
index 0000000000..520209821f
--- /dev/null
+++ b/Plugins/org.blueberry.ui.qt/src/internal/berryQtStyleManager.cpp.autosave
@@ -0,0 +1,410 @@
+/*===================================================================
+
+BlueBerry Platform
+
+Copyright (c) German Cancer Research Center,
+Division of Medical and Biological Informatics.
+All rights reserved.
+
+This software is distributed WITHOUT ANY WARRANTY; without
+even the implied warranty of MERCHANTABILITY or FITNESS FOR
+A PARTICULAR PURPOSE.
+
+See LICENSE.txt or http://www.mitk.org for details.
+
+===================================================================*/
+
+#include "berryQtStyleManager.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#include "berryQtPreferences.h"
+#include "berryWorkbenchPlugin.h"
+
+namespace berry
+{
+
+QtStyleManager::QtStyleManager()
+{
+ AddDefaultStyle();
+ AddDefaultFonts();
+ ReadPreferences();
+}
+
+void QtStyleManager::ReadPreferences()
+{
+ IPreferencesService* prefService = WorkbenchPlugin::GetDefault()->GetPreferencesService();
+ IPreferences::Pointer stylePref = prefService->GetSystemPreferences()->Node(QtPreferences::QT_STYLES_NODE);
+
+ QString paths = stylePref->Get(QtPreferences::QT_STYLE_SEARCHPATHS, "");
+ QStringList pathList = paths.split(";", QString::SkipEmptyParts);
+ QStringListIterator it(pathList);
+ while (it.hasNext())
+ {
+ AddStyles(it.next());
+ }
+
+ QString styleName = stylePref->Get(QtPreferences::QT_STYLE_NAME, "");
+ // if a style is contributed via the Qt resource mechanism, it may not be
+ // registered yet.
+ if (Contains(styleName))
+ // do not update the style in the QApplication instance,
+ // since it might not be created yet
+ SetStyle(styleName, false);
+ else
+ SetDefaultStyle(false);
+}
+
+QtStyleManager::~QtStyleManager()
+{
+ for (FileNameToStyleMap::const_iterator i = styles.begin(); i != styles.end(); ++i)
+ {
+ delete i.value();
+ }
+}
+
+void QtStyleManager::AddDefaultStyle()
+{
+#ifndef _APPLE_
+ AddStyle(":/org.blueberry.ui.qt/defaultstyle.qss", "Default");
+ AddStyle(":/org.blueberry.ui.qt/darkstyle.qss", "Dark");
+ defaultStyle = styles[":/org.blueberry.ui.qt/defaultstyle.qss"];
+#endif
+}
+
+void QtStyleManager::AddDefaultFonts()
+{
+ m_customFontNames.append(QString("<>"));
+
+// m_customFontNames.append(QString("Fira Sans"));
+// QFontDatabase::addApplicationFont(":/org.blueberry.ui.qt/fonts/FiraSans/FiraSans.ttc");
+
+// m_customFontNames.append(QString("Light Fira Sans"));
+// QFontDatabase::addApplicationFont(":/org.blueberry.ui.qt/fonts/LightFiraSans/LightFiraSans.ttc");
+
+// m_customFontNames.append(QString("Roboto"));
+// QFontDatabase::addApplicationFont(":/org.blueberry.ui.qt/fonts/Roboto/Roboto.ttf");
+
+// m_customFontNames.push_back(QString("Open Sans"));
+// QFontDatabase::addApplicationFont(":/org.blueberry.ui.qt/fonts/OpenSans/OpenSans-Bold.ttf");
+// QFontDatabase::addApplicationFont(":/org.blueberry.ui.qt/fonts/OpenSans/OpenSans-BoldItalic.ttf");
+// QFontDatabase::addApplicationFont(":/org.blueberry.ui.qt/fonts/OpenSans/OpenSans-Italic.ttf");
+// QFontDatabase::addApplicationFont(":/org.blueberry.ui.qt/fonts/OpenSans/OpenSans-Light.ttf");
+// QFontDatabase::addApplicationFont(":/org.blueberry.ui.qt/fonts/OpenSans/OpenSans-Regular.ttf");
+
+// m_customFontNames.push_back(QString("xkcd"));
+// QFontDatabase::addApplicationFont(":/org.blueberry.ui.qt/fonts/xkcd/xkcd.ttf");
+}
+
+void QtStyleManager::ClearStyles()
+{
+ for (FileNameToStyleMap::iterator i = styles.begin(); i != styles.end(); )
+ {
+ if (!i.value()->fileName.startsWith(':'))
+ {
+ delete i.value();
+ i = styles.erase(i);
+ }
+ else ++i;
+ }
+ SetDefaultStyle();
+}
+
+QtStyleManager::Style QtStyleManager::GetStyle() const
+{
+ return Style(currentStyle->name, currentStyle->fileName);
+}
+
+QString QtStyleManager::GetStylesheet() const
+{
+ return currentStyle->stylesheet;
+}
+
+QString QtStyleManager::GetActiveTabStylesheet() const
+{
+ return currentStyle->activeTabStylesheet;
+}
+
+QString QtStyleManager::GetTabStylesheet() const
+{
+ return currentStyle->tabStylesheet;
+}
+
+void QtStyleManager::AddStyle(const QString& styleFileName,
+ const QString& styleName)
+{
+ auto newStyle = new ExtStyle();
+
+ if (styleName.isEmpty())
+ {
+ QFileInfo info(styleFileName);
+ newStyle->name = info.completeBaseName();
+ }
+ else
+ {
+ newStyle->name = styleName;
+ }
+
+ newStyle->fileName = styleFileName;
+
+ styles.insert(newStyle->fileName, newStyle);
+}
+
+void QtStyleManager::GetFonts(QStringList& fontNames) const
+{
+ fontNames = m_customFontNames;
+}
+
+QString QtStyleManager::GetFont() const
+{
+ return currentFont;
+}
+
+void QtStyleManager::AddStyles(const QString& path)
+{
+ QDirIterator dirIt(path);
+ while (dirIt.hasNext())
+ {
+ QString current = dirIt.next();
+ QFileInfo info = dirIt.fileInfo();
+ if (info.isFile() && info.isReadable())
+ {
+ QString fileName = info.fileName();
+ if (fileName.endsWith("-tab.qss") || fileName.endsWith("-activetab.qss"))
+ continue;
+
+ if (fileName.endsWith(".qss"))
+ AddStyle(current);
+ }
+ }
+}
+
+void QtStyleManager::ReadStyleData(ExtStyle* style)
+{
+ QString tabStyleFileName(style->fileName);
+ QString activeTabStyleFileName(style->fileName);
+
+ int index = style->fileName.lastIndexOf(".qss");
+ tabStyleFileName.replace(index, 4, "-tab.qss");
+ activeTabStyleFileName.replace(index, 4, "-activetab.qss");
+
+ QFile styleFile(style->fileName);
+ if (styleFile.open(QIODevice::ReadOnly))
+ {
+ QTextStream in(&styleFile);
+ style->stylesheet = in.readAll();
+ }
+ else
+ {
+ BERRY_WARN << "Could not read " << style->fileName.toStdString();
+ }
+
+ QFile tabStyleFile(tabStyleFileName);
+ if (tabStyleFile.open(QIODevice::ReadOnly))
+ {
+ QTextStream in(&tabStyleFile);
+ style->tabStylesheet = in.readAll();
+ }
+ else
+ {
+ BERRY_WARN << "Could not read " << tabStyleFileName.toStdString();
+ }
+
+ QFile activeTabStyleFile(activeTabStyleFileName);
+ if (activeTabStyleFile.open(QIODevice::ReadOnly))
+ {
+ QTextStream in(&activeTabStyleFile);
+ style->activeTabStylesheet = in.readAll();
+ }
+ else
+ {
+ BERRY_WARN << "Could not read " << activeTabStyleFileName.toStdString();
+ }
+}
+
+void QtStyleManager::RemoveStyle(const QString& styleFileName)
+{
+ if (currentStyle->fileName == styleFileName)
+ {
+ SetDefaultStyle();
+ }
+
+ delete styles.take(styleFileName);
+}
+
+void QtStyleManager::RemoveStyles(const QString& repo)
+{
+ if (repo.isEmpty())
+ {
+ ClearStyles();
+ return;
+ }
+
+ for (FileNameToStyleMap::iterator i = styles.begin(); i != styles.end();)
+ {
+ ExtStyle* style = i.value();
+ QFileInfo info(style->fileName);
+ if (info.absolutePath() == repo)
+ {
+ if (style->name == currentStyle->name)
+ {
+ SetDefaultStyle();
+ }
+
+ i = styles.erase(i);
+ delete style;
+ }
+ else
+ {
+ ++i;
+ }
+ }
+}
+
+void QtStyleManager::GetStyles(StyleList& styleNames) const
+{
+ for (FileNameToStyleMap::const_iterator i = styles.begin(); i != styles.end(); ++i)
+ styleNames.push_back(Style(i.value()->name, i.value()->fileName));
+}
+
+void QtStyleManager::GetIconThemes(IconThemeList& iconThemes) const
+{
+ iconThemes.clear();
+ iconThemes.push_back(IconTheme(QString( "<>" )));
+
+ QStringList iconSearchPaths = QIcon::themeSearchPaths();
+
+ for(QStringList::Iterator pathIt = iconSearchPaths.begin(); pathIt != iconSearchPaths.end(); ++pathIt)
+ {
+ QDirIterator dirIt(*pathIt);
+ while (dirIt.hasNext())
+ {
+ QString current = dirIt.next();
+ QFileInfo info = dirIt.fileInfo();
+ if (info.isDir() && info.isReadable())
+ {
+ QFileInfo themeFile( info.filePath() + QString("/index.theme") );
+ if( themeFile.exists() && themeFile.isFile() && themeFile.isReadable() )
+ {
+ QString fileName = info.fileName();
+ iconThemes.push_back( IconTheme(fileName) );
+ }
+ }
+ }
+ }
+}
+
+void QtStyleManager::SetStyle(const QString& fileName)
+{
+ SetStyle(fileName, true);
+}
+
+void QtStyleManager::SetStyle(const QString& fileName, bool update)
+{
+ if (fileName.isEmpty())
+ {
+ SetDefaultStyle();
+ return;
+ }
+
+ FileNameToStyleMap::const_iterator i = styles.find(fileName);
+
+ ExtStyle* style = nullptr;
+ if (i == styles.end())
+ {
+ BERRY_WARN << "Style " + fileName.toStdString() << " does not exist";
+ style = defaultStyle;
+ }
+ else
+ {
+ style = i.value();
+ }
+ currentStyle = style;
+
+ ReadStyleData(style);
+
+ if (update)
+ {
+ qApp->setStyleSheet(currentStyle->stylesheet);
+ PlatformUI::GetWorkbench()->UpdateTheme();
+ }
+}
+
+void QtStyleManager::SetFont(const QString& fontName)
+{
+ if( fontName == QString( "<>" ) || fontName == QString( "" ))
+ {
+ qApp->setFont(QFontDatabase::systemFont(QFontDatabase::GeneralFont));
+ }
+ else
+ {
+ QFont font;
+ font.setFamily(fontName);
+ font.setPointSize(11);
+ std::cout << "[FONT DEBUG] bold?: " << font.bold() << std::endl;
+
+ QStringList foo = QFontDatabase::applicationFontFamilies(1);
+ for(size_t i = 0; i < foo.size(); ++i)
+ {
+ std::cout << "[FONT DEBUG]applicationFontFamilies?: " << foo[i] << std::endl;
+ }
+
+ qApp->setFont(font);
+ }
+ currentFont = fontName;
+ qApp->setStyleSheet(currentStyle->stylesheet);
+ PlatformUI::GetWorkbench()->UpdateTheme();
+}
+
+void QtStyleManager::SetIconTheme(const QString& themeName)
+{
+ if( themeName == QString( "<>" ) )
+ {
+ SetIconTheme( QString("tango"), true);
+ }
+ else
+ {
+ SetIconTheme(themeName, true);
+ }
+}
+
+void QtStyleManager::SetIconTheme(const QString& themeName, bool /*update*/)
+{
+ QIcon::setThemeName( themeName );
+}
+
+QtStyleManager::Style QtStyleManager::GetDefaultStyle() const
+{
+ return Style(defaultStyle->name, defaultStyle->fileName);
+}
+
+void QtStyleManager::SetDefaultStyle()
+{
+ SetDefaultStyle(true);
+}
+
+void QtStyleManager::SetDefaultStyle(bool update)
+{
+ SetStyle(defaultStyle->fileName, update);
+}
+
+bool QtStyleManager::Contains(const QString& fileName) const
+{
+ return styles.contains(fileName);
+}
+
+}
diff --git a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsView.cpp b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsView.cpp
index 0242b73dd3..96cb80d89e 100644
--- a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsView.cpp
+++ b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsView.cpp
@@ -1,1401 +1,1390 @@
/*===================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.
This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.
See LICENSE.txt or http://www.mitk.org for details.
===================================================================*/
#include "QmitkImageStatisticsView.h"
// Qt includes
#include
#include
#include
// berry includes
#include
// mitk includes
#include "mitkNodePredicateDataType.h"
#include "mitkNodePredicateOr.h"
#include "mitkPlanarFigureInteractor.h"
// itk includes
#include "itksys/SystemTools.hxx"
#include
#include
#include
//blueberry includes
#include
#include
const std::string QmitkImageStatisticsView::VIEW_ID = "org.mitk.views.imagestatistics";
const int QmitkImageStatisticsView::STAT_TABLE_BASE_HEIGHT = 180;
QmitkImageStatisticsView::QmitkImageStatisticsView(QObject* /*parent*/, const char* /*name*/)
: m_Controls( NULL ),
m_TimeStepperAdapter( NULL ),
m_SelectedImage( NULL ),
m_SelectedImageMask( NULL ),
m_SelectedPlanarFigure( NULL ),
m_ImageObserverTag( -1 ),
m_ImageMaskObserverTag( -1 ),
m_PlanarFigureObserverTag( -1 ),
m_TimeObserverTag( -1 ),
m_CurrentStatisticsValid( false ),
m_StatisticsUpdatePending( false ),
m_DataNodeSelectionChanged ( false ),
m_Visible(false)
{
this->m_CalculationThread = new QmitkImageStatisticsCalculationThread;
}
QmitkImageStatisticsView::~QmitkImageStatisticsView()
{
if ( m_SelectedImage != NULL )
m_SelectedImage->RemoveObserver( m_ImageObserverTag );
if ( m_SelectedImageMask != NULL )
m_SelectedImageMask->RemoveObserver( m_ImageMaskObserverTag );
if ( m_SelectedPlanarFigure != NULL )
m_SelectedPlanarFigure->RemoveObserver( m_PlanarFigureObserverTag );
while(this->m_CalculationThread->isRunning()) // wait until thread has finished
{
itksys::SystemTools::Delay(100);
}
delete this->m_CalculationThread;
}
void QmitkImageStatisticsView::CreateQtPartControl(QWidget *parent)
{
if (m_Controls == NULL)
{
m_Controls = new Ui::QmitkImageStatisticsViewControls;
m_Controls->setupUi(parent);
CreateConnections();
m_Controls->m_ErrorMessageLabel->hide();
m_Controls->m_StatisticsWidgetStack->setCurrentIndex(0);
m_Controls->m_BinSizeFrame->setVisible(false);
}
}
-void QmitkImageStatisticsView::OnPreferencesChanged()
+void QmitkImageStatisticsView::OnPageSuccessfullyLoaded()
{
berry::IPreferencesService* prefService = berry::WorkbenchPlugin::GetDefault()->GetPreferencesService();
m_StylePref = prefService->GetSystemPreferences()->Node(berry::QtPreferences::QT_STYLES_NODE);
+
+ QString styleName = m_StylePref->Get(berry::QtPreferences::QT_STYLE_NAME, "");
+
+ if (styleName == ":/org.blueberry.ui.qt/darkstyle.qss")
+ {
+ this->m_Controls->m_JSHistogram->SendCommand(
+ "changeTheme('dark')");
+ }
+ else
+ {
+ this->m_Controls->m_JSHistogram->SendCommand(
+ "changeTheme(default)");
+ }
}
void QmitkImageStatisticsView::CreateConnections()
{
if ( m_Controls )
{
connect( (QObject*)(this->m_Controls->m_ButtonCopyHistogramToClipboard), SIGNAL(clicked()),(QObject*) this, SLOT(OnClipboardHistogramButtonClicked()) );
connect( (QObject*)(this->m_Controls->m_ButtonCopyStatisticsToClipboard), SIGNAL(clicked()),(QObject*) this, SLOT(OnClipboardStatisticsButtonClicked()) );
connect( (QObject*)(this->m_Controls->m_IgnoreZerosCheckbox), SIGNAL(clicked()),(QObject*) this, SLOT(OnIgnoreZerosCheckboxClicked()) );
connect( (QObject*) this->m_CalculationThread, SIGNAL(finished()),this, SLOT( OnThreadedStatisticsCalculationEnds()),Qt::QueuedConnection);
connect( (QObject*) this, SIGNAL(StatisticsUpdate()),this, SLOT( RequestStatisticsUpdate()), Qt::QueuedConnection);
connect( (QObject*) this->m_Controls->m_StatisticsTable, SIGNAL(cellDoubleClicked(int,int)),this, SLOT( JumpToCoordinates(int,int)) );
connect((QObject*)(this->m_Controls->m_barRadioButton), SIGNAL(clicked()), (QObject*)(this), SLOT(OnBarRadioButtonSelected()));
connect((QObject*)(this->m_Controls->m_lineRadioButton), SIGNAL(clicked()), (QObject*)(this), SLOT(OnLineRadioButtonSelected()));
connect( (QObject*) (this->m_Controls->m_HistogramBinSizeSpinbox), SIGNAL(editingFinished()), this, SLOT(OnHistogramBinSizeBoxValueChanged()));
connect((QObject*)(this->m_Controls->m_UseDefaultBinSizeBox), SIGNAL(clicked()), (QObject*) this, SLOT(OnDefaultBinSizeBoxChanged()));
connect((QObject*)(this->m_Controls->m_ShowSubchartCheckBox), SIGNAL(clicked()), (QObject*) this, SLOT(OnShowSubchartBoxChanged()));
+ connect((QObject*)(this->m_Controls->m_JSHistogram), SIGNAL(PageSuccessfullyLoaded()), (QObject*) this, SLOT(OnPageSuccessfullyLoaded()));
}
}
void QmitkImageStatisticsView::OnDefaultBinSizeBoxChanged()
{
m_Controls->m_BinSizeFrame->setVisible(!m_Controls->m_UseDefaultBinSizeBox->isChecked());
if (m_CalculationThread != NULL){
m_Controls->m_HistogramBinSizeSpinbox->setValue(m_CalculationThread->GetHistogramBinSize());
m_CalculationThread->SetUseDefaultNBins(m_Controls->m_UseDefaultBinSizeBox->isChecked());
}
this->UpdateStatistics();
}
void QmitkImageStatisticsView::OnShowSubchartBoxChanged()
{
this->m_Controls->m_JSHistogram->SetAppearance(
this->m_Controls->m_lineRadioButton->isChecked(), this->m_Controls->m_ShowSubchartCheckBox->isChecked());
QString useLineChart = "false";
if (this->m_Controls->m_lineRadioButton->isChecked())
useLineChart = "true";
QString showSubchart = "false";
if (this->m_Controls->m_ShowSubchartCheckBox->isChecked())
showSubchart = "true";
this->m_Controls->m_JSHistogram->SendCommand(
"ReloadChart(" + useLineChart + "," + showSubchart + ")");
-
- QString styleName = m_StylePref->Get(berry::QtPreferences::QT_STYLE_NAME, "");
-
- if (styleName == ":/org.blueberry.ui.qt/darkstyle.qss")
- {
- this->m_Controls->m_JSHistogram->SendCommand(
- "changeTheme('dark')");
- }
- else
- {
- this->m_Controls->m_JSHistogram->SendCommand(
- "changeTheme(default)");
- }
}
void QmitkImageStatisticsView::OnBarRadioButtonSelected()
{
this->m_Controls->m_JSHistogram->TransformView("bar");
-
- QString styleName = m_StylePref->Get(berry::QtPreferences::QT_STYLE_NAME, "");
-
- if (styleName == ":/org.blueberry.ui.qt/darkstyle.qss")
- {
- this->m_Controls->m_JSHistogram->SendCommand(
- "changeTheme('dark')");
- }
- else
- {
- this->m_Controls->m_JSHistogram->SendCommand(
- "changeTheme(default)");
- }
}
void QmitkImageStatisticsView::OnLineRadioButtonSelected()
{
this->m_Controls->m_JSHistogram->TransformView("line");
}
void QmitkImageStatisticsView::PartClosed(const berry::IWorkbenchPartReference::Pointer& )
{
}
void QmitkImageStatisticsView::OnTimeChanged(const itk::EventObject& e)
{
if (this->m_SelectedDataNodes.isEmpty() || this->m_SelectedImage == NULL)
return;
const mitk::SliceNavigationController::GeometryTimeEvent* timeEvent =
dynamic_cast(&e);
assert(timeEvent != NULL);
unsigned int timestep = timeEvent->GetPos();
if (this->m_SelectedImage->GetTimeSteps() > 1)
{
for (int x = 0; x < this->m_Controls->m_StatisticsTable->columnCount(); x++)
{
for (int y = 0; y < this->m_Controls->m_StatisticsTable->rowCount(); y++)
{
QTableWidgetItem* item = this->m_Controls->m_StatisticsTable->item(y, x);
if (item == NULL)
break;
if (x == timestep)
{
item->setBackgroundColor(Qt::yellow);
}
else
{
if (y % 2 == 0)
item->setBackground(this->m_Controls->m_StatisticsTable->palette().base());
else
item->setBackground(this->m_Controls->m_StatisticsTable->palette().alternateBase());
}
}
}
this->m_Controls->m_StatisticsTable->viewport()->update();
}
if ((this->m_SelectedImage->GetTimeSteps() == 1 && timestep == 0) ||
this->m_SelectedImage->GetTimeSteps() > 1)
{
// display histogram for selected timestep
this->m_Controls->m_JSHistogram->ClearHistogram();
QmitkImageStatisticsCalculationThread::HistogramType::Pointer histogram =
this->m_CalculationThread->GetTimeStepHistogram(timestep);
if (histogram.IsNotNull())
{
bool closedFigure = this->m_CalculationThread->GetStatisticsUpdateSuccessFlag();
if ( closedFigure )
{
this->m_Controls->m_JSHistogram->ComputeHistogram(
- histogram.GetPointer(), this->m_Controls->m_lineRadioButton->isChecked(), this->m_Controls->m_ShowSubchartCheckBox->isChecked() );
+ histogram.GetPointer(), this->m_Controls->m_lineRadioButton->isChecked(), this->m_Controls->m_ShowSubchartCheckBox->isChecked());
}
//this->m_Controls->m_JSHistogram->ComputeHistogram(histogram.GetPointer());
/*else
{
m_Controls->m_JSHistogram->ComputeIntensityProfile(timestep, true);
}*/
// this->m_Controls->m_JSHistogram->SignalGraphChanged();
// hacky way to make sure the protected SignalGraphChanged() is called
//if (this->m_Controls->m_JSHistogram->GetUseLineGraph())
//{
//this->m_Controls->m_JSHistogram->OnBarRadioButtonSelected();
//this->m_Controls->m_JSHistogram->OnLineRadioButtonSelected();
//}
//else
//{
//this->m_Controls->m_JSHistogram->OnLineRadioButtonSelected();
//this->m_Controls->m_JSHistogram->OnBarRadioButtonSelected();
//}
}
}
}
void QmitkImageStatisticsView::JumpToCoordinates(int row ,int col)
{
if(m_SelectedDataNodes.isEmpty())
{
MITK_WARN("QmitkImageStatisticsView") << "No data node selected for statistics calculation." ;
return;
}
mitk::Point3D world;
if (row==4 && !m_WorldMinList.empty())
world = m_WorldMinList[col];
else if (row==3 && !m_WorldMaxList.empty())
world = m_WorldMaxList[col];
else
return;
mitk::IRenderWindowPart* part = this->GetRenderWindowPart();
if (part)
{
part->GetQmitkRenderWindow("axial")->GetSliceNavigationController()->SelectSliceByPoint(world);
part->GetQmitkRenderWindow("sagittal")->GetSliceNavigationController()->SelectSliceByPoint(world);
part->GetQmitkRenderWindow("coronal")->GetSliceNavigationController()->SelectSliceByPoint(world);
mitk::SliceNavigationController::GeometryTimeEvent timeEvent(this->m_SelectedImage->GetTimeGeometry(), col);
part->GetQmitkRenderWindow("axial")->GetSliceNavigationController()->SetGeometryTime(timeEvent);
}
}
void QmitkImageStatisticsView::OnIgnoreZerosCheckboxClicked()
{
emit StatisticsUpdate();
}
void QmitkImageStatisticsView::OnClipboardHistogramButtonClicked()
{
if ( m_CurrentStatisticsValid && !( m_SelectedPlanarFigure != NULL))
{
const unsigned int t = this->GetRenderWindowPart()->GetTimeNavigationController()->GetTime()->GetPos();
typedef mitk::ImageStatisticsCalculator::HistogramType HistogramType;
const HistogramType *histogram = this->m_CalculationThread->GetTimeStepHistogram(t).GetPointer();
QString clipboard( "Measurement \t Frequency\n" );
for ( HistogramType::ConstIterator it = histogram->Begin();
it != histogram->End();
++it )
{
if( m_Controls->m_HistogramBinSizeSpinbox->value() == 1.0)
{
clipboard = clipboard.append( "%L1 \t %L2\n" )
.arg( it.GetMeasurementVector()[0], 0, 'f', 0 )
.arg( it.GetFrequency() );
}
else
{
clipboard = clipboard.append( "%L1 \t %L2\n" )
.arg( it.GetMeasurementVector()[0], 0, 'f', 2 )
.arg( it.GetFrequency() );
}
}
QApplication::clipboard()->setText(
clipboard, QClipboard::Clipboard );
}
// If a (non-closed) PlanarFigure is selected, display a line profile widget
else if ( m_CurrentStatisticsValid && (m_SelectedPlanarFigure != NULL ))
{
/*auto intensity = m_Controls->m_JSHistogram->GetFrequency();
auto pixel = m_Controls->m_JSHistogram->GetMeasurement();
QString clipboard( "Pixel \t Intensity\n" );
auto j = pixel.begin();
for (auto i = intensity.begin(); i < intensity.end(); i++)
{
assert(j != pixel.end());
clipboard = clipboard.append( "%L1 \t %L2\n" )
.arg( (*j).toString())
.arg( (*i).toString());
j++;
}
QApplication::clipboard()->setText(
clipboard, QClipboard::Clipboard );
*/
}
else
{
QApplication::clipboard()->clear();
}
}
void QmitkImageStatisticsView::OnClipboardStatisticsButtonClicked()
{
QLocale tempLocal;
QLocale::setDefault(QLocale(QLocale::English, QLocale::UnitedStates));
if ( m_CurrentStatisticsValid && !( m_SelectedPlanarFigure != NULL))
{
const std::vector &statistics =
this->m_CalculationThread->GetStatisticsData();
// Set time borders for for loop ;)
unsigned int startT, endT;
if(this->m_Controls->m_CheckBox4dCompleteTable->checkState()==Qt::CheckState::Unchecked)
{
startT = this->GetRenderWindowPart()->GetTimeNavigationController()->GetTime()->
GetPos();
endT = startT+1;
}
else
{
startT = 0;
endT = statistics.size();
}
QVector< QVector > statisticsTable;
QStringList headline;
// Create Headline
headline << " "
<< "Mean"
<< "Median"
<< "StdDev"
<< "RMS"
<< "Max"
<< "Min"
<< "NumberOfVoxels"
<< "Skewness"
<< "Kurtosis"
<< "Uniformity"
<< "Entropy"
<< "MPP"
<< "UPP"
<< "V [mm³]";
for(int i=0;i row;
row.append(headline.at(i));
statisticsTable.append(row);
}
// Fill Table
for(unsigned int t=startT;tGetMean())
<< QString::number(statistics[t]->GetMedian())
<< QString::number(statistics[t]->GetStd())
<< QString::number(statistics[t]->GetRMS())
<< QString::number(statistics[t]->GetMax())
<< QString::number(statistics[t]->GetMin())
<< QString::number(statistics[t]->GetN())
<< QString::number(statistics[t]->GetSkewness())
<< QString::number(statistics[t]->GetKurtosis())
<< QString::number(statistics[t]->GetUniformity())
<< QString::number(statistics[t]->GetEntropy())
<< QString::number(statistics[t]->GetMPP())
<< QString::number(statistics[t]->GetUPP())
<< QString::number(m_Controls->m_StatisticsTable->item(7, 0)->data(Qt::DisplayRole).toDouble());
for(int z=0;zsetText(clipboard, QClipboard::Clipboard);
}
else
{
QApplication::clipboard()->clear();
}
QLocale::setDefault(tempLocal);
}
void QmitkImageStatisticsView::OnSelectionChanged( berry::IWorkbenchPart::Pointer /*part*/,
const QList &selectedNodes )
{
if (this->m_Visible)
{
this->SelectionChanged( selectedNodes );
}
else
{
this->m_DataNodeSelectionChanged = true;
}
}
void QmitkImageStatisticsView::SelectionChanged(const QList &selectedNodes)
{
if( this->m_StatisticsUpdatePending )
{
this->m_DataNodeSelectionChanged = true;
return; // not ready for new data now!
}
if (selectedNodes.size() == this->m_SelectedDataNodes.size())
{
int i = 0;
for (; i < selectedNodes.size(); ++i)
{
if (selectedNodes.at(i) != this->m_SelectedDataNodes.at(i))
{
break;
}
}
// node selection did not change
if (i == selectedNodes.size()) return;
}
//reset the feature image and image mask field
m_Controls->m_SelectedFeatureImageLabel->setText("None");
m_Controls->m_SelectedMaskLabel->setText("None");
this->ReinitData();
if (selectedNodes.isEmpty())
{
m_Controls->m_JSHistogram->ClearHistogram();
m_Controls->m_lineRadioButton->setEnabled(true);
m_Controls->m_barRadioButton->setEnabled(true);
m_Controls->m_HistogramBinSizeSpinbox->setEnabled(true);
m_Controls->m_HistogramBinSizeCaptionLabel->setEnabled(true);
// m_Controls->m_HistogramBinSizeLabel->setEnabled(true);
m_Controls->m_InfoLabel->setText(QString(""));
// m_Controls->horizontalLayout_3->setEnabled(false);
m_Controls->groupBox->setEnabled(false);
m_Controls->groupBox_3->setEnabled(false);
}
else
{
// m_Controls->horizontalLayout_3->setEnabled(true);
m_Controls->groupBox->setEnabled(true);
m_Controls->groupBox_3->setEnabled(true);
}
if(selectedNodes.size() == 1 || selectedNodes.size() == 2)
{
bool isBinary = false;
selectedNodes.value(0)->GetBoolProperty("binary",isBinary);
mitk::NodePredicateDataType::Pointer isLabelSet = mitk::NodePredicateDataType::New("LabelSetImage");
isBinary |= isLabelSet->CheckNode(selectedNodes.value(0));
if(isBinary)
{
m_Controls->m_JSHistogram->ClearHistogram();
m_Controls->m_lineRadioButton->setEnabled(true);
m_Controls->m_barRadioButton->setEnabled(true);
m_Controls->m_HistogramBinSizeSpinbox->setEnabled(true);
m_Controls->m_HistogramBinSizeCaptionLabel->setEnabled(true);
// m_Controls->m_HistogramBinSizeLabel->setEnabled(true);
m_Controls->m_InfoLabel->setText(QString(""));
}
for (int i= 0; i< selectedNodes.size(); ++i)
{
this->m_SelectedDataNodes.push_back(selectedNodes.at(i));
}
this->m_DataNodeSelectionChanged = false;
this->m_Controls->m_ErrorMessageLabel->setText( "" );
this->m_Controls->m_ErrorMessageLabel->hide();
emit StatisticsUpdate();
}
else
{
this->m_DataNodeSelectionChanged = false;
}
}
void QmitkImageStatisticsView::ReinitData()
{
while( this->m_CalculationThread->isRunning()) // wait until thread has finished
{
itksys::SystemTools::Delay(100);
}
if(this->m_SelectedImage != NULL)
{
this->m_SelectedImage->RemoveObserver( this->m_ImageObserverTag);
this->m_SelectedImage = NULL;
}
if(this->m_SelectedImageMask != NULL)
{
this->m_SelectedImageMask->RemoveObserver( this->m_ImageMaskObserverTag);
this->m_SelectedImageMask = NULL;
}
if(this->m_SelectedPlanarFigure != NULL)
{
this->m_SelectedPlanarFigure->RemoveObserver( this->m_PlanarFigureObserverTag);
this->m_SelectedPlanarFigure = NULL;
}
this->m_SelectedDataNodes.clear();
this->m_StatisticsUpdatePending = false;
m_Controls->m_ErrorMessageLabel->setText( "" );
m_Controls->m_ErrorMessageLabel->hide();
this->InvalidateStatisticsTableView();
m_Controls->m_JSHistogram->ClearHistogram();
m_Controls->m_StatisticsWidgetStack->setCurrentIndex( 0 );
}
void QmitkImageStatisticsView::OnThreadedStatisticsCalculationEnds()
{
std::stringstream message;
message << "";
m_Controls->m_ErrorMessageLabel->setText( message.str().c_str() );
m_Controls->m_ErrorMessageLabel->hide();
this->WriteStatisticsToGUI();
}
void QmitkImageStatisticsView::UpdateStatistics()
{
mitk::IRenderWindowPart* renderPart = this->GetRenderWindowPart();
if ( renderPart == NULL )
{
this->m_StatisticsUpdatePending = false;
return;
}
m_WorldMinList.clear();
m_WorldMaxList.clear();
// classify selected nodes
mitk::NodePredicateDataType::Pointer isImage = mitk::NodePredicateDataType::New("Image");
mitk::NodePredicateDataType::Pointer isLabelSet = mitk::NodePredicateDataType::New("LabelSetImage");
mitk::NodePredicateOr::Pointer imagePredicate = mitk::NodePredicateOr::New(isImage, isLabelSet);
std::string maskName = std::string();
std::string maskType = std::string();
std::string featureImageName = std::string();
unsigned int maskDimension = 0;
// reset data from last run
ITKCommandType::Pointer changeListener = ITKCommandType::New();
changeListener->SetCallbackFunction( this, &QmitkImageStatisticsView::SelectedDataModified );
mitk::DataNode::Pointer planarFigureNode;
for( int i= 0 ; i < this->m_SelectedDataNodes.size(); ++i)
{
mitk::PlanarFigure::Pointer planarFig = dynamic_cast(this->m_SelectedDataNodes.at(i)->GetData());
if( imagePredicate->CheckNode(this->m_SelectedDataNodes.at(i)) )
{
bool isMask = false;
this->m_SelectedDataNodes.at(i)->GetPropertyValue("binary", isMask);
isMask |= isLabelSet->CheckNode(this->m_SelectedDataNodes.at(i));
if( this->m_SelectedImageMask == NULL && isMask)
{
this->m_SelectedImageMask = dynamic_cast(this->m_SelectedDataNodes.at(i)->GetData());
this->m_ImageMaskObserverTag = this->m_SelectedImageMask->AddObserver(itk::ModifiedEvent(), changeListener);
maskName = this->m_SelectedDataNodes.at(i)->GetName();
maskType = m_SelectedImageMask->GetNameOfClass();
maskDimension = 3;
}
else if( !isMask )
{
if(this->m_SelectedImage == NULL)
{
this->m_SelectedImage = static_cast(this->m_SelectedDataNodes.at(i)->GetData());
this->m_ImageObserverTag = this->m_SelectedImage->AddObserver(itk::ModifiedEvent(), changeListener);
}
featureImageName = this->m_SelectedDataNodes.at(i)->GetName();
}
}
else if (planarFig.IsNotNull())
{
if(this->m_SelectedPlanarFigure == NULL)
{
this->m_SelectedPlanarFigure = planarFig;
this->m_PlanarFigureObserverTag =
this->m_SelectedPlanarFigure->AddObserver(mitk::EndInteractionPlanarFigureEvent(), changeListener);
maskName = this->m_SelectedDataNodes.at(i)->GetName();
maskType = this->m_SelectedPlanarFigure->GetNameOfClass();
maskDimension = 2;
planarFigureNode = m_SelectedDataNodes.at(i);
}
}
else
{
std::stringstream message;
message << "" << "Invalid data node type!" << "";
m_Controls->m_ErrorMessageLabel->setText( message.str().c_str() );
m_Controls->m_ErrorMessageLabel->show();
}
}
if(maskName == "")
{
maskName = "None";
maskType = "";
maskDimension = 0;
}
if(featureImageName == "")
{
featureImageName = "None";
}
if (m_SelectedPlanarFigure != NULL && m_SelectedImage == NULL)
{
mitk::DataStorage::SetOfObjects::ConstPointer parentSet = this->GetDataStorage()->GetSources(planarFigureNode);
for (int i=0; iSize(); i++)
{
mitk::DataNode::Pointer node = parentSet->ElementAt(i);
if( imagePredicate->CheckNode(node) )
{
bool isMask = false;
node->GetPropertyValue("binary", isMask);
isMask |= isLabelSet->CheckNode(node);
if( !isMask )
{
if(this->m_SelectedImage == NULL)
{
this->m_SelectedImage = static_cast(node->GetData());
this->m_ImageObserverTag = this->m_SelectedImage->AddObserver(itk::ModifiedEvent(), changeListener);
}
}
}
}
}
unsigned int timeStep = renderPart->GetTimeNavigationController()->GetTime()->GetPos();
if ( m_SelectedImage != NULL && m_SelectedImage->IsInitialized())
{
// Check if a the selected image is a multi-channel image. If yes, statistics
// cannot be calculated currently.
if ( m_SelectedImage->GetPixelType().GetNumberOfComponents() > 1 )
{
std::stringstream message;
message << "Multi-component images not supported.";
m_Controls->m_ErrorMessageLabel->setText( message.str().c_str() );
m_Controls->m_ErrorMessageLabel->show();
this->InvalidateStatisticsTableView();
m_Controls->m_StatisticsWidgetStack->setCurrentIndex( 0 );
m_Controls->m_JSHistogram->ClearHistogram();
m_CurrentStatisticsValid = false;
this->m_StatisticsUpdatePending = false;
m_Controls->m_lineRadioButton->setEnabled(true);
m_Controls->m_barRadioButton->setEnabled(true);
m_Controls->m_HistogramBinSizeSpinbox->setEnabled(true);
m_Controls->m_HistogramBinSizeCaptionLabel->setEnabled(true);
// m_Controls->m_HistogramBinSizeLabel->setEnabled(true);
m_Controls->m_InfoLabel->setText(QString(""));
return;
}
std::stringstream maskLabel;
maskLabel << maskName;
if ( maskDimension > 0 )
{
maskLabel << " [" << maskDimension << "D " << maskType << "]";
}
m_Controls->m_SelectedMaskLabel->setText( maskLabel.str().c_str() );
m_Controls->m_SelectedFeatureImageLabel->setText(featureImageName.c_str());
// check time step validity
if(m_SelectedImage->GetDimension() <= 3 && timeStep > m_SelectedImage->GetDimension(3)-1)
{
timeStep = m_SelectedImage->GetDimension(3)-1;
}
// Add the used mask time step to the mask label so the user knows which mask time step was used
// if the image time step is bigger than the total number of mask time steps (see
// ImageStatisticsCalculator::ExtractImageAndMask)
if (m_SelectedImageMask != NULL)
{
unsigned int maskTimeStep = timeStep;
if (maskTimeStep >= m_SelectedImageMask->GetTimeSteps())
{
maskTimeStep = m_SelectedImageMask->GetTimeSteps() - 1;
}
m_Controls->m_SelectedMaskLabel->setText(m_Controls->m_SelectedMaskLabel->text() +
QString(" (t=") +
QString::number(maskTimeStep) +
QString(")"));
}
//// initialize thread and trigger it
this->m_CalculationThread->SetIgnoreZeroValueVoxel( m_Controls->m_IgnoreZerosCheckbox->isChecked() );
this->m_CalculationThread->Initialize( m_SelectedImage, m_SelectedImageMask, m_SelectedPlanarFigure );
this->m_CalculationThread->SetTimeStep( timeStep );
std::stringstream message;
message << "Calculating statistics...";
m_Controls->m_ErrorMessageLabel->setText( message.str().c_str() );
m_Controls->m_ErrorMessageLabel->show();
try
{
// Compute statistics
// this->m_CalculationThread->SetUseDefaultBinSize(m_Controls->m_UseDefaultBinSizeBox->isChecked());
this->m_CalculationThread->start();
}
catch ( const mitk::Exception& e)
{
std::stringstream message;
message << "" << e.GetDescription() << "";
m_Controls->m_ErrorMessageLabel->setText( message.str().c_str() );
m_Controls->m_ErrorMessageLabel->show();
this->m_StatisticsUpdatePending = false;
}
catch ( const std::runtime_error &e )
{
// In case of exception, print error message on GUI
std::stringstream message;
message << "" << e.what() << "";
m_Controls->m_ErrorMessageLabel->setText( message.str().c_str() );
m_Controls->m_ErrorMessageLabel->show();
this->m_StatisticsUpdatePending = false;
}
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->m_ErrorMessageLabel->setText( message.str().c_str() );
m_Controls->m_ErrorMessageLabel->show();
this->m_StatisticsUpdatePending = false;
}
}
else
{
this->m_StatisticsUpdatePending = false;
}
}
void QmitkImageStatisticsView::SelectedDataModified()
{
if( !m_StatisticsUpdatePending )
{
emit StatisticsUpdate();
}
}
void QmitkImageStatisticsView::NodeRemoved(const mitk::DataNode *node)
{
while(this->m_CalculationThread->isRunning()) // wait until thread has finished
{
itksys::SystemTools::Delay(100);
}
if (node->GetData() == m_SelectedImage)
{
m_SelectedImage = NULL;
}
}
void QmitkImageStatisticsView::RequestStatisticsUpdate()
{
if ( !m_StatisticsUpdatePending )
{
if(this->m_DataNodeSelectionChanged)
{
this->SelectionChanged(this->GetCurrentSelection());
}
else
{
this->m_StatisticsUpdatePending = true;
this->UpdateStatistics();
}
}
if (this->GetRenderWindowPart())
this->GetRenderWindowPart()->RequestUpdate();
}
void QmitkImageStatisticsView::OnHistogramBinSizeBoxValueChanged()
{
if (m_Controls->m_HistogramBinSizeSpinbox->value() != m_HistogramBinSize)
{
m_HistogramBinSize = m_Controls->m_HistogramBinSizeSpinbox->value();
this->m_CalculationThread->SetHistogramBinSize(m_Controls->m_HistogramBinSizeSpinbox->value());
this->UpdateStatistics();
}
}
void QmitkImageStatisticsView::WriteStatisticsToGUI()
{
disconnect((QObject*)(this->m_Controls->m_JSHistogram), SIGNAL(PageSuccessfullyLoaded()), 0, 0);
+ connect((QObject*)(this->m_Controls->m_JSHistogram), SIGNAL(PageSuccessfullyLoaded()), (QObject*) this, SLOT(OnPageSuccessfullyLoaded()));
m_Controls->m_lineRadioButton->setEnabled(true);
m_Controls->m_barRadioButton->setEnabled(true);
m_Controls->m_HistogramBinSizeSpinbox->setEnabled(true);
m_Controls->m_HistogramBinSizeCaptionLabel->setEnabled(true);
// m_Controls->m_HistogramBinSizeLabel->setEnabled(true);
m_Controls->m_InfoLabel->setText(QString(""));
if(m_DataNodeSelectionChanged)
{
this->m_StatisticsUpdatePending = false;
this->RequestStatisticsUpdate();
return; // stop visualization of results and calculate statistics of new selection
}
if ( this->m_CalculationThread->GetStatisticsUpdateSuccessFlag())
{
if ( this->m_CalculationThread->GetStatisticsChangedFlag() )
{
// Do not show any error messages
m_Controls->m_ErrorMessageLabel->hide();
m_CurrentStatisticsValid = true;
}
if (m_Controls->m_barRadioButton->isChecked())
{
//m_Controls->m_JSHistogram->OnBarRadioButtonSelected();
}
m_Controls->m_StatisticsWidgetStack->setCurrentIndex( 0 );
m_Controls->m_HistogramBinSizeSpinbox->setValue( this->m_CalculationThread->GetHistogramBinSize() );
//m_Controls->m_JSHistogram->ComputeHistogram( this->m_CalculationThread->GetTimeStepHistogram(this->m_CalculationThread->GetTimeStep()).GetPointer() );
this->FillStatisticsTableView( this->m_CalculationThread->GetStatisticsData(), this->m_CalculationThread->GetStatisticsImage());
m_CurrentStatisticsValid = true;
}
else
{
m_Controls->m_SelectedMaskLabel->setText( "None" );
m_Controls->m_ErrorMessageLabel->setText( m_CalculationThread->GetLastErrorMessage().c_str() );
m_Controls->m_ErrorMessageLabel->show();
// Clear statistics and histogram
this->InvalidateStatisticsTableView();
m_Controls->m_StatisticsWidgetStack->setCurrentIndex( 0 );
//m_Controls->m_JSHistogram->clearHistogram();
m_CurrentStatisticsValid = false;
// If a (non-closed) PlanarFigure is selected, display a line profile widget
if ( m_SelectedPlanarFigure != NULL )
{
// Check if the (closed) planar figure is out of bounds and so no image mask could be calculated--> Intensity Profile can not be calculated
bool outOfBounds = false;
if ( m_SelectedPlanarFigure->IsClosed() && m_SelectedImageMask == NULL)
{
outOfBounds = true;
std::stringstream message;
message << "Planar figure is on a rotated image plane or outside the image bounds.";
m_Controls->m_InfoLabel->setText(message.str().c_str());
}
// check whether PlanarFigure is initialized
const mitk::PlaneGeometry *planarFigurePlaneGeometry = m_SelectedPlanarFigure->GetPlaneGeometry();
if ( !(planarFigurePlaneGeometry == NULL || outOfBounds))
{
unsigned int timeStep = this->GetRenderWindowPart()->GetTimeNavigationController()->GetTime()->GetPos();
m_Controls->m_JSHistogram->SetImage(this->m_CalculationThread->GetStatisticsImage());
m_Controls->m_JSHistogram->SetPlanarFigure(m_SelectedPlanarFigure);
connect((QObject*)(this->m_Controls->m_JSHistogram), SIGNAL(PageSuccessfullyLoaded()), (QObject*) this, SLOT(OnLineRadioButtonSelected()));
m_Controls->m_JSHistogram->ComputeIntensityProfile(timeStep, true);
//m_Controls->m_JSHistogram->ComputeIntensityProfile(timeStep);
//this->ComputeIntensityProfile(m_SelectedPlanarFigure, this->m_CalculationThread->GetStatisticsImage(), timeStep, true);
m_Controls->m_lineRadioButton->setChecked(true);
m_Controls->m_lineRadioButton->setEnabled(false);
m_Controls->m_barRadioButton->setEnabled(false);
m_Controls->m_HistogramBinSizeSpinbox->setEnabled(false);
m_Controls->m_HistogramBinSizeCaptionLabel->setEnabled(false);
// m_Controls->m_HistogramBinSizeLabel->setEnabled(false);
this->FillLinearProfileStatisticsTableView( this->m_CalculationThread->GetStatisticsImage() );
std::stringstream message;
message << "Only linegraph available for an intensity profile!";
m_Controls->m_InfoLabel->setText(message.str().c_str());
m_CurrentStatisticsValid = true;
}
else
{
// Clear statistics, histogram, and GUI
this->InvalidateStatisticsTableView();
m_Controls->m_StatisticsWidgetStack->setCurrentIndex( 0 );
m_Controls->m_JSHistogram->ClearHistogram();
m_CurrentStatisticsValid = false;
m_Controls->m_ErrorMessageLabel->hide();
m_Controls->m_SelectedMaskLabel->setText( "None" );
this->m_StatisticsUpdatePending = false;
m_Controls->m_lineRadioButton->setEnabled(true);
m_Controls->m_barRadioButton->setEnabled(true);
m_Controls->m_HistogramBinSizeSpinbox->setEnabled(true);
m_Controls->m_HistogramBinSizeCaptionLabel->setEnabled(true);
// m_Controls->m_HistogramBinSizeLabel->setEnabled(true);
if (!outOfBounds)
m_Controls->m_InfoLabel->setText(QString(""));
return; // Sebastian Wirkert: would suggest to remove this return, since it is an artifact of previous
// code architecture. However, removing it will cause m_StatisticsUpdatePending to be set to false
// in case of invalid statistics which it previously was not.
}
}
}
berry::IPreferencesService* prefService = berry::WorkbenchPlugin::GetDefault()->GetPreferencesService();
m_StylePref = prefService->GetSystemPreferences()->Node(berry::QtPreferences::QT_STYLES_NODE);
this->m_StatisticsUpdatePending = false;
}
void QmitkImageStatisticsView::FillStatisticsTableView(
const std::vector &s,
const mitk::Image *image )
{
this->m_Controls->m_StatisticsTable->setColumnCount(image->GetTimeSteps());
this->m_Controls->m_StatisticsTable->horizontalHeader()->setVisible(image->GetTimeSteps() > 1);
// Set Checkbox for complete copy of statistic table
if(image->GetTimeSteps()>1)
{
this->m_Controls->m_CheckBox4dCompleteTable->setEnabled(true);
}
else
{
this->m_Controls->m_CheckBox4dCompleteTable->setEnabled(false);
this->m_Controls->m_CheckBox4dCompleteTable->setChecked(false);
}
int decimals = 2;
mitk::PixelType doublePix = mitk::MakeScalarPixelType< double >();
mitk::PixelType floatPix = mitk::MakeScalarPixelType< float >();
if (image->GetPixelType()==doublePix || image->GetPixelType()==floatPix)
{
decimals = 5;
}
for (unsigned int t = 0; t < image->GetTimeSteps(); t++)
{
this->m_Controls->m_StatisticsTable->setHorizontalHeaderItem(t,
new QTableWidgetItem(QString::number(t)));
if (s[t]->GetMaxIndex().size()==3)
{
mitk::Point3D index, max, min;
index[0] = s[t]->GetMaxIndex()[0];
index[1] = s[t]->GetMaxIndex()[1];
index[2] = s[t]->GetMaxIndex()[2];
m_SelectedImage->GetGeometry()->IndexToWorld(index, max);
this->m_WorldMaxList.push_back(max);
index[0] = s[t]->GetMinIndex()[0];
index[1] = s[t]->GetMinIndex()[1];
index[2] = s[t]->GetMinIndex()[2];
m_SelectedImage->GetGeometry()->IndexToWorld(index, min);
this->m_WorldMinList.push_back(min);
}
typedef mitk::ImageStatisticsCalculator::StatisticsContainer::RealType RealType;
RealType maxVal = std::numeric_limits::max();
this->m_Controls->m_StatisticsTable->setItem( 0, t, new QTableWidgetItem(
QString("%1").arg(s[t]->GetMean(), 0, 'f', decimals) ) );
this->m_Controls->m_StatisticsTable->setItem( 1, t, new QTableWidgetItem(
QString("%1").arg(s[t]->GetMedian(), 0, 'f', decimals) ) );
this->m_Controls->m_StatisticsTable->setItem( 2, t, new QTableWidgetItem(
QString("%1").arg(s[t]->GetStd(), 0, 'f', decimals) ) );
this->m_Controls->m_StatisticsTable->setItem( 3, t, new QTableWidgetItem(
QString("%1").arg(s[t]->GetRMS(), 0, 'f', decimals) ) );
QString max; max.append(QString("%1").arg(s[t]->GetMax(), 0, 'f', decimals));
max += " (";
for (int i=0; iGetMaxIndex().size(); i++)
{
max += QString::number(s[t]->GetMaxIndex()[i]);
if (iGetMaxIndex().size()-1)
max += ",";
}
max += ")";
this->m_Controls->m_StatisticsTable->setItem( 4, t, new QTableWidgetItem( max ) );
QString min; min.append(QString("%1").arg(s[t]->GetMin(), 0, 'f', decimals));
min += " (";
for (int i=0; iGetMinIndex().size(); i++)
{
min += QString::number(s[t]->GetMinIndex()[i]);
if (iGetMinIndex().size()-1)
min += ",";
}
min += ")";
this->m_Controls->m_StatisticsTable->setItem( 5, t, new QTableWidgetItem( min ) );
this->m_Controls->m_StatisticsTable->setItem( 6, t, new QTableWidgetItem(
QString("%1").arg(s[t]->GetN()) ) );
const mitk::BaseGeometry *geometry = image->GetGeometry();
if ( geometry != NULL )
{
const mitk::Vector3D &spacing = image->GetGeometry()->GetSpacing();
double volume = spacing[0] * spacing[1] * spacing[2] * (double) s[t]->GetN();
this->m_Controls->m_StatisticsTable->setItem( 7, t, new QTableWidgetItem(
QString("%1").arg(volume, 0, 'f', decimals) ) );
}
else
{
this->m_Controls->m_StatisticsTable->setItem( 7, t, new QTableWidgetItem(
"NA" ) );
}
//statistics of higher order should have 5 decimal places because they used to be very small
this->m_Controls->m_StatisticsTable->setItem( 8, t, new QTableWidgetItem(
QString("%1").arg(s[t]->GetSkewness(), 0, 'f', 5) ) );
this->m_Controls->m_StatisticsTable->setItem( 9, t, new QTableWidgetItem(
QString("%1").arg(s[t]->GetKurtosis(), 0, 'f', 5) ) );
this->m_Controls->m_StatisticsTable->setItem( 10, t, new QTableWidgetItem(
QString("%1").arg(s[t]->GetUniformity(), 0, 'f', 5) ) );
this->m_Controls->m_StatisticsTable->setItem( 11, t, new QTableWidgetItem(
QString("%1").arg(s[t]->GetEntropy(), 0, 'f', 5) ) );
this->m_Controls->m_StatisticsTable->setItem( 12, t, new QTableWidgetItem(
QString("%1").arg(s[t]->GetMPP(), 0, 'f', decimals) ) );
this->m_Controls->m_StatisticsTable->setItem( 13, t, new QTableWidgetItem(
QString("%1").arg(s[t]->GetUPP(), 0, 'f', 5) ) );
}
this->m_Controls->m_StatisticsTable->resizeColumnsToContents();
int height = STAT_TABLE_BASE_HEIGHT;
if (this->m_Controls->m_StatisticsTable->horizontalHeader()->isVisible())
height += this->m_Controls->m_StatisticsTable->horizontalHeader()->height();
if (this->m_Controls->m_StatisticsTable->horizontalScrollBar()->isVisible())
height += this->m_Controls->m_StatisticsTable->horizontalScrollBar()->height();
this->m_Controls->m_StatisticsTable->setMinimumHeight(height);
// make sure the current timestep's column is highlighted (and the correct histogram is displayed)
unsigned int t = this->GetRenderWindowPart()->GetTimeNavigationController()->GetTime()->
GetPos();
mitk::SliceNavigationController::GeometryTimeEvent timeEvent(this->m_SelectedImage->GetTimeGeometry(),
t);
this->OnTimeChanged(timeEvent);
t = std::min(image->GetTimeSteps() - 1, t);
// See bug 18340
/*QString hotspotMean; hotspotMean.append(QString("%1").arg(s[t].GetHotspotStatistics().GetMean(), 0, 'f', decimals));
hotspotMean += " (";
for (int i=0; im_Controls->m_StatisticsTable->setItem( 7, t, new QTableWidgetItem( hotspotMean ) );
QString hotspotMax; hotspotMax.append(QString("%1").arg(s[t].GetHotspotStatistics().GetMax(), 0, 'f', decimals));
hotspotMax += " (";
for (int i=0; im_Controls->m_StatisticsTable->setItem( 8, t, new QTableWidgetItem( hotspotMax ) );
QString hotspotMin; hotspotMin.append(QString("%1").arg(s[t].GetHotspotStatistics().GetMin(), 0, 'f', decimals));
hotspotMin += " (";
for (int i=0; im_Controls->m_StatisticsTable->setItem( 9, t, new QTableWidgetItem( hotspotMin ) );*/
}
std::vector QmitkImageStatisticsView::CalculateStatisticsForPlanarFigure( const mitk::Image *image)
{
std::vector result;
int decimals = 2;
mitk::PixelType doublePix = mitk::MakeScalarPixelType< double >();
mitk::PixelType floatPix = mitk::MakeScalarPixelType< float >();
if (image->GetPixelType()==doublePix || image->GetPixelType()==floatPix)
{
decimals = 5;
}
mitk::ImageStatisticsCalculator::StatisticsContainer::Pointer stats = m_Controls->m_JSHistogram->GetStatistics();
typedef mitk::ImageStatisticsCalculator::StatisticsContainer::RealType RealType;
RealType maxVal = std::numeric_limits::max();
if (stats->GetMean() == maxVal)
{
result.push_back(QString("NA"));
}
else
{
result.push_back(QString("%1").arg(stats->GetMean(), 0, 'f', decimals));
}
if (stats->GetMedian() == maxVal)
{
result.push_back(QString("NA"));
}
else
{
result.push_back(QString("%1").arg(stats->GetMedian(), 0, 'f', decimals));
}
if (stats->GetStd() == maxVal)
{
result.push_back(QString("NA"));
}
else
{
result.push_back( QString("%1").arg( stats->GetStd(), 0, 'f', decimals));
}
if (stats->GetRMS() == maxVal)
{
result.push_back(QString("NA"));
}
else
{
result.push_back(QString("%1").arg( stats->GetRMS(), 0, 'f', decimals));
}
if (stats->GetMax() == maxVal)
{
result.push_back(QString("NA"));
}
else
{
QString max;
max.append(QString("%1").arg(stats->GetMax(), 0, 'f', decimals));
result.push_back(max);
}
if (stats->GetMin() == maxVal)
{
result.push_back(QString("NA"));
}
else
{
QString min;
min.append(QString("%1").arg(stats->GetMin(), 0, 'f', decimals));
result.push_back(min);
}
if (stats->GetN() == maxVal)
{
result.push_back(QString("NA"));
}
else
{
result.push_back(QString("%1").arg(stats->GetN()));
}
result.push_back(QString("NA"));
//statistics of higher order should have 5 decimal places because they used to be very small
if (stats->GetSkewness() == maxVal)
{
result.push_back(QString("NA"));
}
else
{
result.push_back(QString("%1").arg(stats->GetSkewness(), 0, 'f', 5 ));
}
if (stats->GetKurtosis() == maxVal)
{
result.push_back(QString("NA"));
}
else
{
result.push_back(QString("%1").arg(stats->GetKurtosis(), 0, 'f', 5) );
}
if (stats->GetUniformity() == maxVal)
{
result.push_back(QString("NA"));
}
else
{
result.push_back(QString("%1").arg(stats->GetUniformity(), 0, 'f', 5) );
}
if (stats->GetEntropy() == maxVal)
{
result.push_back(QString("NA"));
}
else
{
result.push_back(QString("%1").arg(stats->GetEntropy(), 0, 'f', 5) );
}
if (stats->GetMPP() == maxVal)
{
result.push_back(QString("NA"));
}
else
{
result.push_back(QString("%1").arg(stats->GetMPP(), 0, 'f', decimals) );
}
if (stats->GetUPP() == maxVal)
{
result.push_back(QString("NA"));
}
else
{
result.push_back(QString("%1").arg(stats->GetUPP(), 0, 'f', 5) );
}
return result;
}
void QmitkImageStatisticsView::FillLinearProfileStatisticsTableView( const mitk::Image *image )
{
this->m_Controls->m_StatisticsTable->setColumnCount(1);
this->m_Controls->m_StatisticsTable->horizontalHeader()->setVisible(false);
m_PlanarFigureStatistics = this->CalculateStatisticsForPlanarFigure(image);
for (int i = 0; i< m_PlanarFigureStatistics.size(); i++)
{
this->m_Controls->m_StatisticsTable->setItem( i, 0, new QTableWidgetItem(m_PlanarFigureStatistics[i] ));
}
this->m_Controls->m_StatisticsTable->resizeColumnsToContents();
int height = STAT_TABLE_BASE_HEIGHT;
if (this->m_Controls->m_StatisticsTable->horizontalHeader()->isVisible())
height += this->m_Controls->m_StatisticsTable->horizontalHeader()->height();
if (this->m_Controls->m_StatisticsTable->horizontalScrollBar()->isVisible())
height += this->m_Controls->m_StatisticsTable->horizontalScrollBar()->height();
this->m_Controls->m_StatisticsTable->setMinimumHeight(height);
}
void QmitkImageStatisticsView::InvalidateStatisticsTableView()
{
this->m_Controls->m_StatisticsTable->horizontalHeader()->setVisible(false);
this->m_Controls->m_StatisticsTable->setColumnCount(1);
for ( unsigned int i = 0; i < this->m_Controls->m_StatisticsTable->rowCount(); ++i )
{
{
this->m_Controls->m_StatisticsTable->setItem( i, 0, new QTableWidgetItem( "NA" ) );
}
}
this->m_Controls->m_StatisticsTable->setMinimumHeight(STAT_TABLE_BASE_HEIGHT);
}
void QmitkImageStatisticsView::Activated()
{
}
void QmitkImageStatisticsView::Deactivated()
{
}
void QmitkImageStatisticsView::Visible()
{
m_Visible = true;
mitk::IRenderWindowPart* renderWindow = GetRenderWindowPart();
if (renderWindow)
{
itk::ReceptorMemberCommand::Pointer cmdTimeEvent =
itk::ReceptorMemberCommand::New();
cmdTimeEvent->SetCallbackFunction(this, &QmitkImageStatisticsView::OnTimeChanged);
// It is sufficient to add the observer to the axial render window since the GeometryTimeEvent
// is always triggered by all views.
m_TimeObserverTag = renderWindow->GetQmitkRenderWindow("axial")->
GetSliceNavigationController()->
AddObserver(mitk::SliceNavigationController::GeometryTimeEvent(NULL, 0), cmdTimeEvent);
}
if (m_DataNodeSelectionChanged)
{
if (this->IsCurrentSelectionValid())
{
this->SelectionChanged(this->GetCurrentSelection());
}
else
{
this->SelectionChanged(this->GetDataManagerSelection());
}
m_DataNodeSelectionChanged = false;
}
}
void QmitkImageStatisticsView::Hidden()
{
m_Visible = false;
// The slice navigation controller observer is removed here instead of in the destructor.
// If it was called in the destructor, the application would freeze because the view's
// destructor gets called after the render windows have been destructed.
if ( m_TimeObserverTag != NULL )
{
mitk::IRenderWindowPart* renderWindow = GetRenderWindowPart();
if (renderWindow)
{
renderWindow->GetQmitkRenderWindow("axial")->GetSliceNavigationController()->
RemoveObserver( m_TimeObserverTag );
}
m_TimeObserverTag = NULL;
}
}
void QmitkImageStatisticsView::SetFocus()
{
}
diff --git a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsView.h b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsView.h
index 2ed8e2abd7..c5ab3a3cd5 100644
--- a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsView.h
+++ b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsView.h
@@ -1,203 +1,203 @@
/*===================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.
This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.
See LICENSE.txt or http://www.mitk.org for details.
===================================================================*/
#ifndef QmitkImageStatisticsView_H__INCLUDED
#define QmitkImageStatisticsView_H__INCLUDED
#include "ui_QmitkImageStatisticsViewControls.h"
// Qmitk includes
#include
#include "QmitkStepperAdapter.h"
#include "QmitkImageStatisticsCalculationThread.h"
#include
// mitk includes
#include "mitkImageStatisticsCalculator.h"
#include "mitkILifecycleAwarePart.h"
#include "mitkPlanarLine.h"
#include
/*!
\brief QmitkImageStatisticsView is a bundle that allows statistics calculation from images. Three modes
are supported: 1. Statistics of one image, 2. Statistics of an image and a segmentation, 3. Statistics
of an image and a Planar Figure. The statistics calculation is realized in a seperate thread to keep the
gui accessable during calculation.
\ingroup Plugins/org.mitk.gui.qt.measurementtoolbox
*/
class QmitkImageStatisticsView : public QmitkAbstractView, public mitk::ILifecycleAwarePart, public berry::IPartListener
{
Q_OBJECT
private:
/*!
\ Convenient typedefs */
typedef mitk::DataStorage::SetOfObjects ConstVector;
typedef ConstVector::ConstPointer ConstVectorPointer;
typedef ConstVector::ConstIterator ConstVectorIterator;
typedef std::map< mitk::Image *, mitk::ImageStatisticsCalculator::Pointer > ImageStatisticsMapType;
typedef QList SelectedDataNodeVectorType;
typedef itk::SimpleMemberCommand< QmitkImageStatisticsView > ITKCommandType;
public:
/*!
\brief default constructor */
QmitkImageStatisticsView(QObject *parent=nullptr, const char *name=nullptr);
/*!
\brief default destructor */
virtual ~QmitkImageStatisticsView();
/*!
\brief method for creating the widget containing the application controls, like sliders, buttons etc. */
virtual void CreateQtPartControl(QWidget *parent) override;
/*!
\brief method for creating the connections of main and control widget */
virtual void CreateConnections();
/*!
\brief not implemented*/
//bool IsExclusiveFunctionality() const;
/*!
\brief Is called from the selection mechanism once the data manager selection has changed*/
void OnSelectionChanged( berry::IWorkbenchPart::Pointer part, const QList &nodes ) override;
static const std::string VIEW_ID;
static const int STAT_TABLE_BASE_HEIGHT;
public slots:
/** \brief Called when the statistics update is finished, sets the results to GUI.*/
void OnThreadedStatisticsCalculationEnds();
/** \brief Update bin size for histogram resolution. */
void OnHistogramBinSizeBoxValueChanged();
protected slots:
/** \brief Saves the histogram to the clipboard */
void OnClipboardHistogramButtonClicked();
/** \brief Saves the statistics to the clipboard */
void OnClipboardStatisticsButtonClicked();
/** \brief Indicates if zeros should be excluded from statistics calculation */
void OnIgnoreZerosCheckboxClicked( );
/** \brief Checks if update is possible and calls StatisticsUpdate() possible */
void RequestStatisticsUpdate();
/** \brief Jump to coordinates stored in the double clicked cell */
void JumpToCoordinates(int row, int col);
/** \brief Toogle GUI elements if histogram default bin size checkbox value changed. */
void OnDefaultBinSizeBoxChanged();
void OnShowSubchartBoxChanged();
void OnBarRadioButtonSelected();
void OnLineRadioButtonSelected();
- void OnPreferencesChanged();
+ void OnPageSuccessfullyLoaded();
signals:
/** \brief Method to set the data to the member and start the threaded statistics update */
void StatisticsUpdate();
protected:
/** \brief Writes the calculated statistics to the GUI */
void FillStatisticsTableView(const std::vector &s,
const mitk::Image *image );
std::vector CalculateStatisticsForPlanarFigure( const mitk::Image *image);
void FillLinearProfileStatisticsTableView( const mitk::Image *image );
/** \brief Removes statistics from the GUI */
void InvalidateStatisticsTableView();
/** \brief Recalculate statistics for currently selected image and mask and
* update the GUI. */
void UpdateStatistics();
/** \brief Listener for progress events to update progress bar. */
void UpdateProgressBar();
/** \brief Removes any cached images which are no longer referenced elsewhere. */
void RemoveOrphanImages();
/** \brief Computes an Intensity Profile along line and updates the histogram widget with it. */
void ComputeIntensityProfile( mitk::PlanarLine* line );
/** \brief Removes all Observers to images, masks and planar figures and sets corresponding members to zero */
void ClearObservers();
void Activated() override;
void Deactivated() override;
void Visible() override;
void Hidden() override;
void SetFocus() override;
/** \brief Method called when itkModifiedEvent is called by selected data. */
void SelectedDataModified();
/** \brief Method called when the data manager selection changes */
void SelectionChanged(const QList &selectedNodes);
/** \brief Method called to remove old selection when a new selection is present */
void ReinitData();
/** \brief writes the statistics to the gui*/
void WriteStatisticsToGUI();
void NodeRemoved(const mitk::DataNode *node) override;
/** \brief Is called right before the view closes (before the destructor) */
virtual void PartClosed(const berry::IWorkbenchPartReference::Pointer& ) override;
/** \brief Is called from the image navigator once the time step has changed */
void OnTimeChanged( const itk::EventObject& );
/** \brief Required for berry::IPartListener */
virtual Events::Types GetPartEventTypes() const override { return Events::CLOSED; }
// member variables
Ui::QmitkImageStatisticsViewControls *m_Controls;
// if you have a planar figure selected, the statistics values will be saved in this one.
std::vector m_PlanarFigureStatistics;
QmitkImageStatisticsCalculationThread* m_CalculationThread;
QmitkStepperAdapter* m_TimeStepperAdapter;
unsigned int m_CurrentTime;
QString m_Clipboard;
// Image and mask data
mitk::Image* m_SelectedImage;
mitk::Image* m_SelectedImageMask;
mitk::PlanarFigure* m_SelectedPlanarFigure;
// observer tags
long m_ImageObserverTag;
long m_ImageMaskObserverTag;
long m_PlanarFigureObserverTag;
long m_TimeObserverTag;
SelectedDataNodeVectorType m_SelectedDataNodes;
bool m_CurrentStatisticsValid;
bool m_StatisticsUpdatePending;
bool m_StatisticsIntegrationPending;
bool m_DataNodeSelectionChanged;
bool m_Visible;
double m_HistogramBinSize;
std::vector m_WorldMinList;
std::vector m_WorldMaxList;
berry::IPreferences::Pointer m_StylePref;
};
#endif // QmitkImageStatisticsView_H__INCLUDED