diff --git a/Core/Code/DataManagement/mitkDataNode.cpp b/Core/Code/DataManagement/mitkDataNode.cpp index deb3eaf96a..99dbc965c9 100644 --- a/Core/Code/DataManagement/mitkDataNode.cpp +++ b/Core/Code/DataManagement/mitkDataNode.cpp @@ -1,552 +1,552 @@ -/*=================================================================== + /*=================================================================== 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 "mitkDataNode.h" #include "mitkCoreObjectFactory.h" #include #include "mitkProperties.h" #include "mitkStringProperty.h" #include "mitkGroupTagProperty.h" #include "mitkSmartPointerProperty.h" //#include "mitkMaterialProperty.h" #include "mitkColorProperty.h" #include "mitkLevelWindowProperty.h" #include "mitkGeometry3D.h" #include "mitkRenderingManager.h" #include "mitkGlobalInteraction.h" #include "mitkEventMapper.h" #include "mitkGenericProperty.h" #include "mitkCoreObjectFactory.h" mitk::Mapper* mitk::DataNode::GetMapper(MapperSlotId id) const { if( (id >= m_Mappers.size()) || (m_Mappers[id].IsNull()) ) { if(id >= m_Mappers.capacity()) { // int i, size=id-m_Mappers.capacity()+10; m_Mappers.resize(id+10); } m_Mappers[id] = CoreObjectFactory::GetInstance()->CreateMapper(const_cast(this),id); } return m_Mappers[id]; } mitk::BaseData* mitk::DataNode::GetData() const { return m_Data; } mitk::Interactor* mitk::DataNode::GetInteractor() const { return m_Interactor; } void mitk::DataNode::SetData(mitk::BaseData* baseData) { if(m_Data!=baseData) { m_Data=baseData; m_Mappers.clear(); m_Mappers.resize(10); mitk::CoreObjectFactory::GetInstance()->SetDefaultProperties(this); m_DataReferenceChangedTime.Modified(); Modified(); //inform the interactor about the change if (m_Interactor.IsNotNull()) m_Interactor->DataChanged(); } } void mitk::DataNode::SetInteractor(mitk::Interactor* interactor) { m_Interactor = interactor; if(m_Interactor.IsNotNull()) m_Interactor->SetDataNode(this); } mitk::DataNode::DataNode() : m_Data(NULL), m_PropertyListModifiedObserverTag(0) { m_Mappers.resize(10); m_PropertyList = PropertyList::New(); // subscribe for modified event itk::MemberCommand::Pointer _PropertyListModifiedCommand = itk::MemberCommand::New(); _PropertyListModifiedCommand->SetCallbackFunction(this, &mitk::DataNode::PropertyListModified); m_PropertyListModifiedObserverTag = m_PropertyList->AddObserver(itk::ModifiedEvent(), _PropertyListModifiedCommand); } mitk::DataNode::~DataNode() { if(m_PropertyList.IsNotNull()) // remove modified event listener m_PropertyList->RemoveObserver(m_PropertyListModifiedObserverTag); Interactor* interactor = this->GetInteractor(); if ( interactor ) { mitk::GlobalInteraction::GetInstance()->RemoveInteractor( interactor ); } m_Mappers.clear(); m_Data = NULL; } mitk::DataNode& mitk::DataNode::operator=(const DataNode& right) { mitk::DataNode* node=mitk::DataNode::New(); node->SetData(right.GetData()); return *node; } mitk::DataNode& mitk::DataNode::operator=(mitk::BaseData* right) { mitk::DataNode* node=mitk::DataNode::New(); node->SetData(right); return *node; } #if (_MSC_VER > 1200) || !defined(_MSC_VER) MBI_STD::istream& mitk::operator>>( MBI_STD::istream& i, mitk::DataNode::Pointer& dtn ) #endif #if ((defined(_MSC_VER)) && (_MSC_VER <= 1200)) MBI_STD::istream& operator>>( MBI_STD::istream& i, mitk::DataNode::Pointer& dtn ) #endif { dtn = mitk::DataNode::New(); //i >> av.get(); return i; } #if (_MSC_VER > 1200) || !defined(_MSC_VER) MBI_STD::ostream& mitk::operator<<( MBI_STD::ostream& o, mitk::DataNode::Pointer& dtn) #endif #if ((defined(_MSC_VER)) && (_MSC_VER <= 1200)) MBI_STD::ostream& operator<<( MBI_STD::ostream& o, mitk::DataNode::Pointer& dtn) #endif { if(dtn->GetData()!=NULL) o<GetData()->GetNameOfClass(); else o<<"empty data"; return o; } void mitk::DataNode::SetMapper(MapperSlotId id, mitk::Mapper* mapper) { m_Mappers[id] = mapper; if (mapper!=NULL) mapper->SetDataNode(this); } void mitk::DataNode::UpdateOutputInformation() { if (this->GetSource()) { this->GetSource()->UpdateOutputInformation(); } } void mitk::DataNode::SetRequestedRegionToLargestPossibleRegion() { } bool mitk::DataNode::RequestedRegionIsOutsideOfTheBufferedRegion() { return false; } bool mitk::DataNode::VerifyRequestedRegion() { return true; } void mitk::DataNode::SetRequestedRegion(itk::DataObject * /*data*/) { } void mitk::DataNode::CopyInformation(const itk::DataObject * /*data*/) { } mitk::PropertyList* mitk::DataNode::GetPropertyList(const mitk::BaseRenderer* renderer) const { if(renderer==NULL) return m_PropertyList; mitk::PropertyList::Pointer & propertyList = m_MapOfPropertyLists[renderer]; if(propertyList.IsNull()) propertyList = mitk::PropertyList::New(); assert(m_MapOfPropertyLists[renderer].IsNotNull()); return propertyList; } void mitk::DataNode::ConcatenatePropertyList(PropertyList *pList, bool replace) { m_PropertyList->ConcatenatePropertyList(pList, replace); } mitk::BaseProperty* mitk::DataNode::GetProperty(const char *propertyKey, const mitk::BaseRenderer* renderer) const { if(propertyKey==NULL) return NULL; //renderer specified? if (renderer) { std::map::const_iterator it; //check for the renderer specific property it=m_MapOfPropertyLists.find(renderer); if(it!=m_MapOfPropertyLists.end()) //found { mitk::BaseProperty::Pointer property; property=it->second->GetProperty(propertyKey); if(property.IsNotNull())//found an enabled property in the render specific list return property; else //found a renderer specific list, but not the desired property return m_PropertyList->GetProperty(propertyKey); //return renderer unspecific property } else //didn't find the property list of the given renderer { //return the renderer unspecific property if there is one return m_PropertyList->GetProperty(propertyKey); } } else //no specific renderer given; use the renderer independent one { mitk::BaseProperty::Pointer property; property=m_PropertyList->GetProperty(propertyKey); if(property.IsNotNull()) return property; } //only to satisfy compiler! return NULL; } mitk::DataNode::GroupTagList mitk::DataNode::GetGroupTags() const { GroupTagList groups; const PropertyList::PropertyMap* propertyMap = m_PropertyList->GetMap(); for ( PropertyList::PropertyMap::const_iterator groupIter = propertyMap->begin(); // m_PropertyList is created in the constructor, so we don't check it here groupIter != propertyMap->end(); ++groupIter ) { const BaseProperty* bp = groupIter->second; if ( dynamic_cast(bp) ) { groups.insert( groupIter->first ); } } return groups; } bool mitk::DataNode::GetBoolProperty(const char* propertyKey, bool& boolValue, mitk::BaseRenderer* renderer) const { mitk::BoolProperty::Pointer boolprop = dynamic_cast(GetProperty(propertyKey, renderer)); if(boolprop.IsNull()) return false; boolValue = boolprop->GetValue(); return true; } bool mitk::DataNode::GetIntProperty(const char* propertyKey, int &intValue, mitk::BaseRenderer* renderer) const { mitk::IntProperty::Pointer intprop = dynamic_cast(GetProperty(propertyKey, renderer)); if(intprop.IsNull()) return false; intValue = intprop->GetValue(); return true; } bool mitk::DataNode::GetFloatProperty(const char* propertyKey, float &floatValue, mitk::BaseRenderer* renderer) const { mitk::FloatProperty::Pointer floatprop = dynamic_cast(GetProperty(propertyKey, renderer)); if(floatprop.IsNull()) return false; floatValue = floatprop->GetValue(); return true; } bool mitk::DataNode::GetStringProperty(const char* propertyKey, std::string& string, mitk::BaseRenderer* renderer) const { mitk::StringProperty::Pointer stringProp = dynamic_cast(GetProperty(propertyKey, renderer)); if(stringProp.IsNull()) { return false; } else { //memcpy((void*)string, stringProp->GetValue(), strlen(stringProp->GetValue()) + 1 ); // looks dangerous string = stringProp->GetValue(); return true; } } bool mitk::DataNode::GetColor(float rgb[3], mitk::BaseRenderer* renderer, const char* propertyKey) const { mitk::ColorProperty::Pointer colorprop = dynamic_cast(GetProperty(propertyKey, renderer)); if(colorprop.IsNull()) return false; memcpy(rgb, colorprop->GetColor().GetDataPointer(), 3*sizeof(float)); return true; } bool mitk::DataNode::GetOpacity(float &opacity, mitk::BaseRenderer* renderer, const char* propertyKey) const { mitk::FloatProperty::Pointer opacityprop = dynamic_cast(GetProperty(propertyKey, renderer)); if(opacityprop.IsNull()) return false; opacity=opacityprop->GetValue(); return true; } bool mitk::DataNode::GetLevelWindow(mitk::LevelWindow &levelWindow, mitk::BaseRenderer* renderer, const char* propertyKey) const { mitk::LevelWindowProperty::Pointer levWinProp = dynamic_cast(GetProperty(propertyKey, renderer)); if(levWinProp.IsNull()) return false; levelWindow=levWinProp->GetLevelWindow(); return true; } void mitk::DataNode::SetColor(const mitk::Color &color, mitk::BaseRenderer* renderer, const char* propertyKey) { mitk::ColorProperty::Pointer prop; prop = mitk::ColorProperty::New(color); GetPropertyList(renderer)->SetProperty(propertyKey, prop); } void mitk::DataNode::SetColor(float red, float green, float blue, mitk::BaseRenderer* renderer, const char* propertyKey) { float color[3]; color[0]=red; color[1]=green; color[2]=blue; SetColor(color, renderer, propertyKey); } void mitk::DataNode::SetColor(const float rgb[3], mitk::BaseRenderer* renderer, const char* propertyKey) { mitk::ColorProperty::Pointer prop; prop = mitk::ColorProperty::New(rgb); GetPropertyList(renderer)->SetProperty(propertyKey, prop); } void mitk::DataNode::SetVisibility(bool visible, mitk::BaseRenderer* renderer, const char* propertyKey) { mitk::BoolProperty::Pointer prop; prop = mitk::BoolProperty::New(visible); GetPropertyList(renderer)->SetProperty(propertyKey, prop); } void mitk::DataNode::SetOpacity(float opacity, mitk::BaseRenderer* renderer, const char* propertyKey) { mitk::FloatProperty::Pointer prop; prop = mitk::FloatProperty::New(opacity); GetPropertyList(renderer)->SetProperty(propertyKey, prop); } void mitk::DataNode::SetLevelWindow(mitk::LevelWindow levelWindow, mitk::BaseRenderer* renderer, const char* propertyKey) { mitk::LevelWindowProperty::Pointer prop; prop = mitk::LevelWindowProperty::New(levelWindow); GetPropertyList(renderer)->SetProperty(propertyKey, prop); } void mitk::DataNode::SetIntProperty(const char* propertyKey, int intValue, mitk::BaseRenderer* renderer) { GetPropertyList(renderer)->SetProperty(propertyKey, mitk::IntProperty::New(intValue)); } void mitk::DataNode::SetBoolProperty( const char* propertyKey, bool boolValue, mitk::BaseRenderer* renderer/*=NULL*/ ) { GetPropertyList(renderer)->SetProperty(propertyKey, mitk::BoolProperty::New(boolValue)); } void mitk::DataNode::SetFloatProperty( const char* propertyKey, float floatValue, mitk::BaseRenderer* renderer/*=NULL*/ ) { GetPropertyList(renderer)->SetProperty(propertyKey, mitk::FloatProperty::New(floatValue)); } void mitk::DataNode::SetStringProperty( const char* propertyKey, const char* stringValue, mitk::BaseRenderer* renderer/*=NULL*/ ) { GetPropertyList(renderer)->SetProperty(propertyKey, mitk::StringProperty::New(stringValue)); } void mitk::DataNode::SetProperty(const char *propertyKey, BaseProperty* propertyValue, const mitk::BaseRenderer* renderer) { GetPropertyList(renderer)->SetProperty(propertyKey, propertyValue); } void mitk::DataNode::ReplaceProperty(const char *propertyKey, BaseProperty* propertyValue, const mitk::BaseRenderer* renderer) { GetPropertyList(renderer)->ReplaceProperty(propertyKey, propertyValue); } void mitk::DataNode::AddProperty(const char *propertyKey, BaseProperty* propertyValue, const mitk::BaseRenderer* renderer, bool overwrite) { if((overwrite) || (GetProperty(propertyKey, renderer) == NULL)) { SetProperty(propertyKey, propertyValue, renderer); } } vtkLinearTransform* mitk::DataNode::GetVtkTransform(int t) const { assert(m_Data.IsNotNull()); mitk::Geometry3D* geometry = m_Data->GetGeometry(t); if(geometry == NULL) return NULL; return geometry->GetVtkTransform(); } unsigned long mitk::DataNode::GetMTime() const { unsigned long time = Superclass::GetMTime(); if(m_Data.IsNotNull()) { if((time < m_Data->GetMTime()) || ((m_Data->GetSource().IsNotNull()) && (time < m_Data->GetSource()->GetMTime())) ) { Modified(); return Superclass::GetMTime(); } } return time; } void mitk::DataNode::SetSelected(bool selected, mitk::BaseRenderer* renderer) { mitk::BoolProperty::Pointer selectedProperty = dynamic_cast(GetProperty("selected")); if ( selectedProperty.IsNull() ) { selectedProperty = mitk::BoolProperty::New(); selectedProperty->SetValue(false); SetProperty("selected", selectedProperty, renderer); } if( selectedProperty->GetValue() != selected ) { selectedProperty->SetValue(selected); itk::ModifiedEvent event; InvokeEvent( event ); } } /* class SelectedEvent : public itk::ModifiedEvent { public: typedef SelectedEvent Self; typedef itk::ModifiedEvent Superclass; SelectedEvent(DataNode* dataNode) { m_DataNode = dataNode; }; DataNode* GetDataNode() { return m_DataNode; }; virtual const char * GetEventName() const { return "SelectedEvent"; } virtual bool CheckEvent(const ::itk::EventObject* e) const { return dynamic_cast(e); } virtual ::itk::EventObject* MakeObject() const { return new Self(m_DataNode); } private: DataNode* m_DataNode; SelectedEvent(const Self& event) { m_DataNode = event.m_DataNode; }; void operator=(const Self& event) { m_DataNode = event.m_DataNode; } }; */ bool mitk::DataNode::IsSelected(mitk::BaseRenderer* renderer) { bool selected; if ( !GetBoolProperty("selected", selected, renderer) ) return false; return selected; } void mitk::DataNode::SetInteractorEnabled( const bool& enabled ) { if ( m_Interactor.IsNull() ) { itkWarningMacro("Interactor is NULL. Couldn't enable or disable interaction."); return; } if ( enabled ) mitk::GlobalInteraction::GetInstance()->AddInteractor( m_Interactor.GetPointer() ); else mitk::GlobalInteraction::GetInstance()->RemoveInteractor( m_Interactor.GetPointer() ); } void mitk::DataNode::EnableInteractor() { SetInteractorEnabled( true ); } void mitk::DataNode::DisableInteractor() { SetInteractorEnabled( false ); } bool mitk::DataNode::IsInteractorEnabled() const { return mitk::GlobalInteraction::GetInstance()->InteractorRegistered( m_Interactor.GetPointer() ); } void mitk::DataNode::PropertyListModified( const itk::Object* /*caller*/, const itk::EventObject& ) { Modified(); } diff --git a/Plugins/org.mitk.gui.qt.measurementtoolbox/files.cmake b/Plugins/org.mitk.gui.qt.measurementtoolbox/files.cmake index 4fd1dd2406..74776764d3 100644 --- a/Plugins/org.mitk.gui.qt.measurementtoolbox/files.cmake +++ b/Plugins/org.mitk.gui.qt.measurementtoolbox/files.cmake @@ -1,57 +1,59 @@ set(SRC_CPP_FILES ) set(INTERNAL_CPP_FILES QmitkMeasurementView.cpp QmitkPlanarFiguresTableModel.cpp QmitkImageStatisticsView.cpp + QmitkImageStatisticsCalculationThread.cpp mitkPluginActivator.cpp ) set(UI_FILES src/internal/QmitkImageStatisticsViewControls.ui ) set(MOC_H_FILES src/internal/QmitkMeasurementView.h src/internal/QmitkPlanarFiguresTableModel.h src/internal/QmitkImageStatisticsView.h + src/internal/QmitkImageStatisticsCalculationThread.h src/internal/mitkPluginActivator.h ) set(CACHED_RESOURCE_FILES resources/angle.png resources/arrow.png resources/circle.png resources/four-point-angle.png resources/ImageStatistic_24.png resources/ImageStatistic_48.png resources/ImageStatistic_64.png resources/lena.xpm resources/line.png resources/measurement.png resources/path.png resources/polygon.png resources/rectangle.png resources/stats.png resources/text.png plugin.xml ) set(QRC_FILES resources/measurement.qrc resources/QmitkImageStatisticsView.qrc ) set(CPP_FILES ) foreach(file ${SRC_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/${file}) endforeach(file ${SRC_CPP_FILES}) foreach(file ${INTERNAL_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/internal/${file}) endforeach(file ${INTERNAL_CPP_FILES}) diff --git a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsCalculationThread.cpp b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsCalculationThread.cpp new file mode 100644 index 0000000000..a553095843 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsCalculationThread.cpp @@ -0,0 +1,157 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Module: $RCSfile$ +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "QmitkImageStatisticsCalculationThread.h" + +//QT headers +#include +#include + +QmitkImageStatisticsCalculationThread::QmitkImageStatisticsCalculationThread():QThread(), + m_StatisticsImage(NULL), m_BinaryMask(NULL), m_PlanarFigureMask(NULL), m_TimeStep(0), + m_IgnoreZeros(false), m_CalculationSuccessful(false), m_StatisticChanged(false) +{ +} + +QmitkImageStatisticsCalculationThread::~QmitkImageStatisticsCalculationThread() +{ +} + +void QmitkImageStatisticsCalculationThread::Initialize( mitk::Image::Pointer image, mitk::Image::Pointer binaryImage, mitk::PlanarFigure::Pointer planarFig ) +{ + // reset old values + if( this->m_StatisticsImage.IsNotNull() ) + this->m_StatisticsImage = 0; + + if( this->m_BinaryMask.IsNotNull() ) + this->m_BinaryMask = 0; + + if( this->m_PlanarFigureMask.IsNotNull()) + this->m_PlanarFigureMask = 0; + + // set new values if passed in + if(image.IsNotNull()) + this->m_StatisticsImage = image->Clone(); + if(binaryImage.IsNotNull()) + this->m_BinaryMask = binaryImage->Clone(); + if(planarFig.IsNotNull()) + this->m_PlanarFigureMask = dynamic_cast(planarFig.GetPointer()); +} + +void QmitkImageStatisticsCalculationThread::SetTimeStep( int times ) +{ + this->m_TimeStep = times; +} + +int QmitkImageStatisticsCalculationThread::GetTimeStep() +{ + return this->m_TimeStep; +} + +mitk::ImageStatisticsCalculator::Statistics QmitkImageStatisticsCalculationThread::GetStatisticsData() +{ + return this->m_StatisticsStruct; +} + +mitk::Image::Pointer QmitkImageStatisticsCalculationThread::GetStatisticsImage() +{ + return this->m_StatisticsImage; +} + +void QmitkImageStatisticsCalculationThread::SetIgnoreZeroValueVoxel(bool _arg) +{ + this->m_IgnoreZeros = _arg; +} + +bool QmitkImageStatisticsCalculationThread::GetIgnoreZeroValueVoxel() +{ + return this->m_IgnoreZeros; +} + +QmitkImageStatisticsCalculationThread::HistogramType::Pointer +QmitkImageStatisticsCalculationThread::GetTimeStepHistogram() +{ + return this->m_TimeStepHistogram; +} + +bool QmitkImageStatisticsCalculationThread::GetStatisticsChangedFlag() +{ + return m_StatisticChanged; +} + +bool QmitkImageStatisticsCalculationThread::GetStatisticsUpdateSuccessFlag() +{ + return m_CalculationSuccessful; +} + +void QmitkImageStatisticsCalculationThread::run() +{ + bool statisticCalculationSuccessful = true; + mitk::ImageStatisticsCalculator::Pointer calculator = mitk::ImageStatisticsCalculator::New(); + + if(this->m_StatisticsImage.IsNotNull()) + { + calculator->SetImage(m_StatisticsImage); + calculator->SetMaskingModeToNone(); + } + else + { + statisticCalculationSuccessful = false; + } + if(this->m_BinaryMask.IsNotNull()) + { + calculator->SetImageMask(m_BinaryMask); + calculator->SetMaskingModeToImage(); + } + if(this->m_PlanarFigureMask.IsNotNull()) + { + calculator->SetPlanarFigure(m_PlanarFigureMask); + calculator->SetMaskingModeToPlanarFigure(); + } + bool statisticChanged = false; + + calculator->SetDoIgnorePixelValue(this->m_IgnoreZeros); + calculator->SetIgnorePixelValue(0); + try + { + statisticChanged = calculator->ComputeStatistics(m_TimeStep); + } + catch ( const std::runtime_error &e ) + { + MITK_ERROR<< "Runtime Exception: " << e.what(); + statisticCalculationSuccessful = false; + } + catch ( const std::exception &e ) + { + MITK_ERROR<< "Standard Exception: " << e.what(); + statisticCalculationSuccessful = false; + } + this->m_StatisticChanged = statisticChanged; + this->m_CalculationSuccessful = statisticCalculationSuccessful; + if(statisticCalculationSuccessful) + { + this->m_StatisticsStruct = calculator->GetStatistics(); + + if(this->m_TimeStepHistogram.IsNotNull()) + { + this->m_TimeStepHistogram = NULL; +} + this->m_TimeStepHistogram = (HistogramType*) calculator->GetHistogram(m_TimeStep); + } + emit CalculationFinished( statisticCalculationSuccessful, statisticChanged); +} diff --git a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsCalculationThread.h b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsCalculationThread.h new file mode 100644 index 0000000000..866bef3b6a --- /dev/null +++ b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsCalculationThread.h @@ -0,0 +1,118 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Module: $RCSfile$ +Language: C++ +Date: $Date$ +Version: $Revision$ + +Copyright (c) German Cancer Research Center, Division of Medical and +Biological Informatics. All rights reserved. +See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +#ifndef QMITKIMAGESTATISTICSCALCULATIONTHREAD_H_INCLUDED +#define QMITKIMAGESTATISTICSCALCULATIONTHREAD_H_INCLUDED + +//QT headers +#include +#include + +//mitk headers +#include "mitkImage.h" +#include "mitkPlanarFigure.h" +#include "mitkImageStatisticsCalculator.h" + +// itk headers +#ifndef __itkHistogram_h +#include +#endif + + +/** /brief This class is executed as background thread for image statistics calculation. + * Documentation: This class is derived from QThread and is intended to be used by QmitkImageStatisticsView + to run the image statistics calculation in a background thread to keep the + gui usable. + * \ingroup Plugins/MeasurementToolbox + */ + +//class QmitkStatisticsCalculatedEvent : public QEvent +//{ +//public: +// enum Type +// { +// StatisticsCalculated = QEvent::MaxUser - 1050 +// }; +// +// QmitkStatisticsCalculatedEvent() +// : QEvent( (QEvent::Type) StatisticsCalculated ) {}; +//}; + +class QmitkImageStatisticsCalculationThread : public QThread +{ + Q_OBJECT + +public: + + typedef itk::Statistics::Histogram HistogramType; + + /*! + /brief standard constructor. */ + QmitkImageStatisticsCalculationThread(); + /*! + /brief standard destructor. */ + ~QmitkImageStatisticsCalculationThread(); + /*! + /brief Initializes the object with necessary data. */ + void Initialize( mitk::Image::Pointer image, mitk::Image::Pointer binaryImage, mitk::PlanarFigure::Pointer planarFig ); + /*! + /brief returns the calculated image statistics. */ + mitk::ImageStatisticsCalculator::Statistics GetStatisticsData(); + /*! + /brief */ + mitk::Image::Pointer GetStatisticsImage(); + /*! + /brief Set the time step of the image you want to process. */ + void SetTimeStep( int times ); + /*! + /brief Get the time step of the image you want to process. */ + int GetTimeStep(); + /*! + /brief Set flag to ignore zero valued voxels */ + void SetIgnoreZeroValueVoxel( bool _arg ); + /*! + /brief Get status of zero value voxel ignoring. */ + bool GetIgnoreZeroValueVoxel(); + /*! + /brief Returns the histogram of the currently selected time step. */ + HistogramType::Pointer GetTimeStepHistogram(); + /*! + /brief */ + bool GetStatisticsChangedFlag(); + /*! + /brief */ + bool GetStatisticsUpdateSuccessFlag(); + /*! + /brief Method called once the thread is executed. */ + void run(); + +signals: + void CalculationFinished(bool calculationSuccessful, bool statisticsChanged); + +private: + //member declaration + mitk::Image::Pointer m_StatisticsImage; ///< member variable holds the input image for which the statistics need to be calculated. + mitk::Image::Pointer m_BinaryMask; ///< member variable holds the binary mask image for segmentation image statistics calculation. + mitk::PlanarFigure::Pointer m_PlanarFigureMask; ///< member variable holds the planar figure for segmentation image statistics calculation. + mitk::ImageStatisticsCalculator::Statistics m_StatisticsStruct; ///< member variable holds the result struct. + int m_TimeStep; ///< member variable holds the time step for statistics calculation + bool m_IgnoreZeros; ///< member variable holds flag to indicate if zero valued voxel should be suppressed + bool m_StatisticChanged; + bool m_CalculationSuccessful; + HistogramType::Pointer m_TimeStepHistogram; ///< member holds the histogram of the current time step. +}; +#endif // QMITKIMAGESTATISTICSCALCULATIONTHREAD_H_INCLUDED 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 5bd8ecd3f1..fd0791863e 100644 --- a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsView.cpp +++ b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsView.cpp @@ -1,794 +1,1056 @@ /*=================================================================== 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" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "QmitkStdMultiWidget.h" #include "QmitkSliderNavigatorWidget.h" #include "mitkNodePredicateDataType.h" #include "mitkImageTimeSelector.h" #include "mitkProperties.h" #include "mitkProgressBar.h" // Includes for image processing #include "mitkImageCast.h" #include "mitkITKImageImport.h" #include "mitkDataNodeObject.h" #include "mitkNodePredicateData.h" #include "mitkPlanarFigureInteractor.h" #include - -const std::string QmitkImageStatisticsView::VIEW_ID = -"org.mitk.views.imagestatistics"; - -class QmitkRequestStatisticsUpdateEvent : public QEvent -{ -public: - enum Type - { - StatisticsUpdateRequest = QEvent::MaxUser - 1025 - }; - - QmitkRequestStatisticsUpdateEvent() - : QEvent( (QEvent::Type) StatisticsUpdateRequest ) {}; -}; - - - -typedef itk::Image ImageType; -typedef itk::Image FloatImageType; -typedef itk::Image, 3> VectorImageType; - -inline bool my_isnan(float x) - { - volatile float d = x; - - if(d!=d) - return true; - - if(d==d) - return false; - return d != d; - - } +#include "itksys/SystemTools.hxx" + +const std::string QmitkImageStatisticsView::VIEW_ID = "org.mitk.views.imagestatistics"; + +//class QmitkRequestStatisticsUpdateEvent : public QEvent +//{ +//public: +// enum Type +// { +// StatisticsUpdateRequest = QEvent::MaxUser - 1025 +// }; +// +// QmitkRequestStatisticsUpdateEvent() +// : QEvent( (QEvent::Type) StatisticsUpdateRequest ) {}; +//}; + + + +//typedef itk::Image ImageType; +//typedef itk::Image FloatImageType; +//typedef itk::Image, 3> VectorImageType; +// +//inline bool my_isnan(float x) +//{ +// volatile float d = x; +// +// if(d!=d) +// return true; +// +// if(d==d) +// return false; +// return d != d; +// +//} QmitkImageStatisticsView::QmitkImageStatisticsView(QObject* /*parent*/, const char* /*name*/) : m_Controls( NULL ), - m_TimeStepperAdapter( NULL ), - m_SelectedImageNode( NULL ), - m_SelectedImage( NULL ), - m_SelectedMaskNode( NULL ), - m_SelectedImageMask( NULL ), - m_SelectedPlanarFigure( NULL ), - m_ImageObserverTag( -1 ), - m_ImageMaskObserverTag( -1 ), - m_PlanarFigureObserverTag( -1 ), - m_CurrentStatisticsValid( false ), - m_StatisticsUpdatePending( false ), - m_Visible(false) +m_TimeStepperAdapter( NULL ), +//m_SelectedImageNode( NULL ), +m_SelectedImage( NULL ), +//m_SelectedMaskNode( NULL ), +m_SelectedImageMask( NULL ), +m_SelectedPlanarFigure( NULL ), +m_ImageObserverTag( -1 ), +m_ImageMaskObserverTag( -1 ), +m_PlanarFigureObserverTag( -1 ), +m_CurrentStatisticsValid( false ), +m_StatisticsUpdatePending( false ), +//m_StatisticsIntegrationPending( false ), +m_DataNodeSelectionChanged ( false ), +m_Visible(false) { + this->m_CalculationThread = new QmitkImageStatisticsCalculationThread; + this->m_QThreadMutex = new QMutex; + this->m_SelectedDataNodes = SelectedDataNodeVectorType(2); // maximum number of selected nodes is exactly two! } - 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); this->CreateConnections(); m_Controls->m_ErrorMessageLabel->hide(); - m_Controls->m_StatisticsWidgetStack->setCurrentIndex( 0 ); m_Controls->m_LineProfileWidget->SetPathModeToPlanarFigure(); } } - - void QmitkImageStatisticsView::CreateConnections() { if ( m_Controls ) { - connect( (QObject*)(m_Controls->m_ButtonCopyHistogramToClipboard), SIGNAL(clicked()),(QObject*) this, SLOT(ClipboardHistogramButtonClicked())); - connect( (QObject*)(m_Controls->m_ButtonCopyStatisticsToClipboard), SIGNAL(clicked()),(QObject*) this, SLOT(ClipboardStatisticsButtonClicked())); - connect( (QObject*)(m_Controls->m_IgnoreZerosCheckbox), SIGNAL(clicked()),(QObject*) this, SLOT(IgnoreZerosCheckboxClicked())); + 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(CalculationFinished(bool, bool)),this, SLOT( OnThreadedStatisticsCalculationEnds(bool, bool)),Qt::QueuedConnection); + connect( (QObject*) this, SIGNAL(StatisticsUpdate()),this, SLOT( RequestStatisticsUpdate()), Qt::QueuedConnection); } } -void QmitkImageStatisticsView::IgnoreZerosCheckboxClicked( ) +void QmitkImageStatisticsView::OnIgnoreZerosCheckboxClicked() { - UpdateStatistics(); + emit StatisticsUpdate(); } -void QmitkImageStatisticsView::ClipboardHistogramButtonClicked() +void QmitkImageStatisticsView::OnClipboardHistogramButtonClicked() { - if ( m_CurrentStatisticsValid && (m_CurrentStatisticsCalculator.IsNotNull()) ) + if ( m_CurrentStatisticsValid ) { typedef mitk::ImageStatisticsCalculator::HistogramType HistogramType; - const HistogramType *histogram = m_CurrentStatisticsCalculator->GetHistogram(); + const HistogramType *histogram = this->m_CalculationThread->GetTimeStepHistogram().GetPointer(); QString clipboard( "Measurement \t Frequency\n" ); for ( HistogramType::ConstIterator it = histogram->Begin(); - it != histogram->End(); - ++it ) + it != histogram->End(); + ++it ) { clipboard = clipboard.append( "%L1 \t %L2\n" ) .arg( it.GetMeasurementVector()[0], 0, 'f', 2 ) .arg( it.GetFrequency() ); } QApplication::clipboard()->setText( clipboard, QClipboard::Clipboard ); } else { QApplication::clipboard()->clear(); } } - -void QmitkImageStatisticsView::ClipboardStatisticsButtonClicked() +void QmitkImageStatisticsView::OnClipboardStatisticsButtonClicked() { - if ( m_CurrentStatisticsValid && (m_CurrentStatisticsCalculator.IsNotNull()) ) + if ( this->m_CurrentStatisticsValid ) { const mitk::ImageStatisticsCalculator::Statistics &statistics = - m_CurrentStatisticsCalculator->GetStatistics(); + this->m_CalculationThread->GetStatisticsData(); // Copy statistics to clipboard ("%Ln" will use the default locale for // number formatting) QString clipboard( "Mean \t StdDev \t RMS \t Max \t Min \t N \t V (mm³)\n" ); clipboard = clipboard.append( "%L1 \t %L2 \t %L3 \t %L4 \t %L5 \t %L6 \t %L7" ) .arg( statistics.Mean, 0, 'f', 10 ) .arg( statistics.Sigma, 0, 'f', 10 ) .arg( statistics.RMS, 0, 'f', 10 ) .arg( statistics.Max, 0, 'f', 10 ) .arg( statistics.Min, 0, 'f', 10 ) .arg( statistics.N ) .arg( m_Controls->m_StatisticsTable->item( 0, 6 )->text() ); QApplication::clipboard()->setText( clipboard, QClipboard::Clipboard ); } else { QApplication::clipboard()->clear(); } } - -void QmitkImageStatisticsView::FillStatisticsTableView( - const mitk::ImageStatisticsCalculator::Statistics &s, - const mitk::Image *image ) +void QmitkImageStatisticsView::OnSelectionChanged( berry::IWorkbenchPart::Pointer /*part*/, + const QList &selectedNodes ) { - m_Controls->m_StatisticsTable->setItem( 0, 0, new QTableWidgetItem( - QString("%1").arg(s.Mean, 0, 'f', 2) ) ); - - m_Controls->m_StatisticsTable->setItem( 0, 1, new QTableWidgetItem( - QString("%1").arg(s.Sigma, 0, 'f', 2) ) ); - - m_Controls->m_StatisticsTable->setItem( 0, 2, new QTableWidgetItem( - QString("%1").arg(s.RMS, 0, 'f', 2) ) ); - - m_Controls->m_StatisticsTable->setItem( 0, 3, new QTableWidgetItem( - QString("%1").arg(s.Max, 0, 'f', 2) ) ); - - m_Controls->m_StatisticsTable->setItem( 0, 4, new QTableWidgetItem( - QString("%1").arg(s.Min, 0, 'f', 2) ) ); + this->SelectionChanged( selectedNodes ); +} - m_Controls->m_StatisticsTable->setItem( 0, 5, new QTableWidgetItem( - QString("%1").arg(s.N) ) ); +void QmitkImageStatisticsView::SelectionChanged(const QList &selectedNodes) +{ + //MITK_INFO<<"Start SelectionChanged!"; - const mitk::Geometry3D *geometry = image->GetGeometry(); - if ( geometry != NULL ) + if( this->m_StatisticsUpdatePending ) { - const mitk::Vector3D &spacing = image->GetGeometry()->GetSpacing(); - double volume = spacing[0] * spacing[1] * spacing[2] * (double) s.N; - m_Controls->m_StatisticsTable->setItem( 0, 6, new QTableWidgetItem( - QString("%1").arg(volume, 0, 'f', 2) ) ); + this->m_DataNodeSelectionChanged = true; + return; // not ready for new data now! } - else + this->ReinitData(); + if(selectedNodes.size() == 1 || selectedNodes.size() == 2) { - m_Controls->m_StatisticsTable->setItem( 0, 6, new QTableWidgetItem( - "NA" ) ); + 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(); } -} - - -void QmitkImageStatisticsView::InvalidateStatisticsTableView() -{ - for ( unsigned int i = 0; i < 7; ++i ) + else { - m_Controls->m_StatisticsTable->setItem( 0, i, new QTableWidgetItem( "NA" ) ); + this->m_DataNodeSelectionChanged = false; } } - -void QmitkImageStatisticsView::OnSelectionChanged( berry::IWorkbenchPart::Pointer /*part*/, - const QList &selectedNodes ) +void QmitkImageStatisticsView::ReinitData() { - // Clear any unreferenced images - this->RemoveOrphanImages(); - if ( !m_Visible ) + while( this->m_CalculationThread->isRunning()) // wait until thread has finished { - return; + itksys::SystemTools::Delay(100); } - // Check if selection makeup consists only of valid nodes: - // One image, segmentation or planarFigure - // One image and one of the other two - bool tooManyNodes( true ); - bool invalidNodes( true ); - - if ( selectedNodes.size() < 3 ) + if(this->m_SelectedImage != NULL) { - tooManyNodes = false; + this->m_SelectedImage->RemoveObserver( this->m_ImageObserverTag); + this->m_SelectedImage = NULL; } - - QList nodes(selectedNodes); - if( !tooManyNodes ) + if(this->m_SelectedImageMask != NULL) { - unsigned int numberImages = 0; - unsigned int numberSegmentations = 0; - unsigned int numberPlanarFigures = 0; - - for ( int index = 0; index < nodes.size(); index++ ) - { - m_SelectedImageMask = dynamic_cast< mitk::Image * >( nodes[ index ]->GetData() ); - m_SelectedPlanarFigure = dynamic_cast< mitk::PlanarFigure * >( nodes[ index ]->GetData() ); - - if ( m_SelectedImageMask != NULL ) - { - bool isMask( false ); - nodes[ index ]->GetPropertyValue("binary", isMask); - if ( !isMask ) - { - numberImages++; - } - else - { - numberSegmentations++; - if ( numberImages != 0 ) // image should be last element - { - std::swap( nodes[ index ], nodes[ index - 1 ] ); - } - } - } - else if ( m_SelectedPlanarFigure != NULL ) - { - numberPlanarFigures++; - if ( numberImages != 0 ) // image should be last element - { - std::swap( nodes[ index ], nodes[ index - 1 ] ); - } - } - } - - if ( ( numberPlanarFigures + numberSegmentations + numberImages ) == nodes.size() && //No invalid nodes - ( numberPlanarFigures + numberSegmentations ) < 2 && numberImages < 2 - // maximum of one image and/or one of either planar figure or segmentation - ) - { - invalidNodes = false; - } - } - - if ( nodes.empty() || tooManyNodes || invalidNodes ) + this->m_SelectedImageMask->RemoveObserver( this->m_ImageMaskObserverTag); + this->m_SelectedImageMask = NULL; + } + if(this->m_SelectedPlanarFigure != NULL) { - // Nothing to do: invalidate image, clear statistics, histogram, and GUI - m_SelectedImage = NULL; - this->InvalidateStatisticsTableView() ; - m_Controls->m_HistogramWidget->ClearItemModel(); - m_Controls->m_LineProfileWidget->ClearItemModel(); - - m_CurrentStatisticsValid = false; - m_Controls->m_ErrorMessageLabel->hide(); - m_Controls->m_SelectedMaskLabel->setText( "None" ); - return; + 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_HistogramWidget->ClearItemModel(); + m_Controls->m_LineProfileWidget->ClearItemModel(); +} - // Get selected element - - mitk::DataNode *selectedNode = nodes.front(); - mitk::Image *selectedImage = dynamic_cast< mitk::Image * >( selectedNode->GetData() ); - - // Find the next parent/grand-parent node containing an image, if any - mitk::DataStorage::SetOfObjects::ConstPointer parentObjects; - mitk::DataNode *parentNode = NULL; - mitk::Image *parentImage = NULL; +void QmitkImageStatisticsView::OnThreadedStatisticsCalculationEnds( bool calculationSuccessful, bool statisticsChanged ) +{ + this->WriteStatisticsToGUI(); +} - // Possibly previous change listeners - if ( (m_SelectedPlanarFigure != NULL) && (m_PlanarFigureObserverTag >= 0) ) - { - m_SelectedPlanarFigure->RemoveObserver( m_PlanarFigureObserverTag ); - m_PlanarFigureObserverTag = -1; - } - if ( (m_SelectedImage != NULL) && (m_ImageObserverTag >= 0) ) - { - m_SelectedImage->RemoveObserver( m_ImageObserverTag ); - m_ImageObserverTag = -1; - } - if ( (m_SelectedImageMask != NULL) && (m_ImageMaskObserverTag >= 0) ) +void QmitkImageStatisticsView::UpdateStatistics() +{ + mitk::IRenderWindowPart* renderPart = this->GetRenderWindowPart(); + if ( renderPart == NULL ) { - m_SelectedImageMask->RemoveObserver( m_ImageMaskObserverTag ); - m_ImageMaskObserverTag = -1; + this->m_StatisticsUpdatePending = false; + return; } - - // Deselect all images and masks by default - m_SelectedImageNode = NULL; - m_SelectedImage = NULL; - m_SelectedMaskNode = NULL; - m_SelectedImageMask = NULL; - m_SelectedPlanarFigure = NULL; - - { - unsigned int parentObjectIndex = 0; - parentObjects = this->GetDataStorage()->GetSources( selectedNode ); - while( parentObjectIndex < parentObjects->Size() ) + // classify selected nodes + mitk::NodePredicateDataType::Pointer imagePredicate = mitk::NodePredicateDataType::New("Image"); + + std::string maskName = std::string(); + std::string maskType = std::string(); + unsigned int maskDimension = 0; + + // reset data from last run + ITKCommandType::Pointer changeListener = ITKCommandType::New(); + changeListener->SetCallbackFunction( this, &QmitkImageStatisticsView::SelectedDataModified ); + + mitk::Image::Pointer selectedImage = mitk::Image::New(); + 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)) ) { - // Use first parent object (if multiple parents are present) - parentNode = parentObjects->ElementAt( parentObjectIndex ); - parentImage = dynamic_cast< mitk::Image * >( parentNode->GetData() ); - if( parentImage != NULL ) + bool isMask = false; + this->m_SelectedDataNodes.at(i)->GetPropertyValue("binary", isMask); + + if( this->m_SelectedImageMask == NULL && isMask) { - break; + 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; } - parentObjectIndex++; - } - } - - if ( nodes.size() == 2 ) - { - parentNode = nodes.back(); - parentImage = dynamic_cast< mitk::Image * >( parentNode->GetData() ); - } - - if ( parentImage != NULL ) - { - m_SelectedImageNode = parentNode; - m_SelectedImage = parentImage; - - // Check if a valid mask has been selected (Image or PlanarFigure) - m_SelectedImageMask = dynamic_cast< mitk::Image * >( selectedNode->GetData() ); - m_SelectedPlanarFigure = dynamic_cast< mitk::PlanarFigure * >( selectedNode->GetData() ); - - // Check whether ImageMask is a binary segmentation - - if ( (m_SelectedImageMask != NULL) ) - { - bool isMask( false ); - selectedNode->GetPropertyValue("binary", isMask); - if ( !isMask ) + else if( !isMask ) { - m_SelectedImageNode = selectedNode; - m_SelectedImage = selectedImage; - m_SelectedImageMask = NULL; + //this->m_QThreadMutex->lock(); + 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); + } + //this->m_QThreadMutex->unlock(); } - else + } + else if (planarFig.IsNotNull()) + { + if(this->m_SelectedPlanarFigure == NULL) { - m_SelectedMaskNode = selectedNode; + 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; } } - else if ( (m_SelectedPlanarFigure != NULL) ) + else { - m_SelectedMaskNode = selectedNode; + std::stringstream message; + message << "" << "Invalid data node type!" << ""; + m_Controls->m_ErrorMessageLabel->setText( message.str().c_str() ); + m_Controls->m_ErrorMessageLabel->show(); } } - else if ( selectedImage != NULL ) - { - m_SelectedImageNode = selectedNode; - m_SelectedImage = selectedImage; - } - - - typedef itk::SimpleMemberCommand< QmitkImageStatisticsView > ITKCommandType; - ITKCommandType::Pointer changeListener; - changeListener = ITKCommandType::New(); - changeListener->SetCallbackFunction( this, &QmitkImageStatisticsView::RequestStatisticsUpdate ); - - // Add change listeners to selected objects - if ( m_SelectedImage != NULL ) - { - m_ImageObserverTag = m_SelectedImage->AddObserver( - itk::ModifiedEvent(), changeListener ); - } - if ( m_SelectedImageMask != NULL ) + if(maskName == "") { - m_ImageMaskObserverTag = m_SelectedImageMask->AddObserver( - itk::ModifiedEvent(), changeListener ); - } - - if ( m_SelectedPlanarFigure != NULL ) - { - m_PlanarFigureObserverTag = m_SelectedPlanarFigure->AddObserver( - mitk::EndInteractionPlanarFigureEvent(), changeListener ); - } - - - // Clear statistics / histogram GUI if nothing is selected - if ( m_SelectedImage == NULL ) - { - // Clear statistics, histogram, and GUI - this->InvalidateStatisticsTableView(); - m_Controls->m_HistogramWidget->ClearItemModel(); - m_Controls->m_LineProfileWidget->ClearItemModel(); - m_CurrentStatisticsValid = false; - m_Controls->m_ErrorMessageLabel->hide(); - m_Controls->m_SelectedMaskLabel->setText( "None" ); - } - else - { - // Else, request statistics and GUI update - this->RequestStatisticsUpdate(); - } -} - - -void QmitkImageStatisticsView::UpdateStatistics() -{ - - // Remove any cached images that are no longer referenced elsewhere - this->RemoveOrphanImages(); - - mitk::IRenderWindowPart* renderPart = this->GetRenderWindowPart(); - if ( renderPart == NULL ) - { - return; + maskName = "None"; + maskType = ""; + maskDimension = 0; } unsigned int timeStep = renderPart->GetTimeNavigationController()->GetTime()->GetPos(); - if ( m_SelectedImage != NULL ) + 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_HistogramWidget->ClearItemModel(); m_CurrentStatisticsValid = false; + this->m_StatisticsUpdatePending = false; return; } - // Retrieve ImageStatisticsCalculator from has map (or create a new one - // for this image if non-existant) - ImageStatisticsMapType::iterator it = - m_ImageStatisticsMap.find( m_SelectedImage ); - - if ( it != m_ImageStatisticsMap.end() ) - { - m_CurrentStatisticsCalculator = it->second; - MITK_INFO << "Retrieving StatisticsCalculator"; - } - else - { - m_CurrentStatisticsCalculator = mitk::ImageStatisticsCalculator::New(); - m_CurrentStatisticsCalculator->SetImage( m_SelectedImage ); - m_ImageStatisticsMap[m_SelectedImage] = m_CurrentStatisticsCalculator; - MITK_INFO << "Creating StatisticsCalculator"; - } - - std::string maskName; - std::string maskType; - unsigned int maskDimension; - - if ( m_SelectedImageMask != NULL ) - { - m_CurrentStatisticsCalculator->SetImageMask( m_SelectedImageMask ); - m_CurrentStatisticsCalculator->SetMaskingModeToImage(); - - maskName = m_SelectedMaskNode->GetName(); - maskType = m_SelectedImageMask->GetNameOfClass(); - maskDimension = 3; - } - else if ( m_SelectedPlanarFigure != NULL ) - { - m_CurrentStatisticsCalculator->SetPlanarFigure( m_SelectedPlanarFigure ); - m_CurrentStatisticsCalculator->SetMaskingModeToPlanarFigure(); - - maskName = m_SelectedMaskNode->GetName(); - maskType = m_SelectedPlanarFigure->GetNameOfClass(); - maskDimension = 2; - } - else - { - m_CurrentStatisticsCalculator->SetMaskingModeToNone(); - - maskName = "None"; - maskType = ""; - maskDimension = 0; - } - - if(m_Controls->m_IgnoreZerosCheckbox->isChecked()) - { - m_CurrentStatisticsCalculator->SetIgnorePixelValue(0); - m_CurrentStatisticsCalculator->SetDoIgnorePixelValue(true); - } - else - { - m_CurrentStatisticsCalculator->SetDoIgnorePixelValue(false); - } - std::stringstream maskLabel; maskLabel << maskName; if ( maskDimension > 0 ) { maskLabel << " [" << maskDimension << "D " << maskType << "]"; } - m_Controls->m_SelectedMaskLabel->setText( maskLabel.str().c_str() ); - bool statisticsChanged = false; - bool statisticsCalculationSuccessful = false; - - // Initialize progress bar - mitk::ProgressBar::GetInstance()->AddStepsToDo( 100 ); - - // Install listener for progress events and initialize progress bar - typedef itk::SimpleMemberCommand< QmitkImageStatisticsView > ITKCommandType; - ITKCommandType::Pointer progressListener; - progressListener = ITKCommandType::New(); - progressListener->SetCallbackFunction( this, &QmitkImageStatisticsView::UpdateProgressBar ); - unsigned long progressObserverTag = m_CurrentStatisticsCalculator - ->AddObserver( itk::ProgressEvent(), progressListener ); - - // show wait cursor - this->WaitCursorOn(); + //// initialize thread and trigger it + this-> m_QThreadMutex->lock(); + this->m_CalculationThread->SetIgnoreZeroValueVoxel( m_Controls->m_IgnoreZerosCheckbox->isChecked() ); + this->m_CalculationThread->Initialize( m_SelectedImage, m_SelectedImageMask, m_SelectedPlanarFigure ); + this->m_CalculationThread->SetTimeStep( timeStep ); + this-> m_QThreadMutex->unlock(); try { // Compute statistics - statisticsChanged = - m_CurrentStatisticsCalculator->ComputeStatistics( timeStep ); - - statisticsCalculationSuccessful = true; + this->m_CalculationThread->start(); } 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(); - } - - m_CurrentStatisticsCalculator->RemoveObserver( progressObserverTag ); - - // Make sure that progress bar closes - mitk::ProgressBar::GetInstance()->Progress( 100 ); - - // remove wait cursor - this->WaitCursorOff(); - - if ( statisticsCalculationSuccessful ) - { - if ( statisticsChanged ) - { - // Do not show any error messages - m_Controls->m_ErrorMessageLabel->hide(); - - m_CurrentStatisticsValid = true; - } - - m_Controls->m_StatisticsWidgetStack->setCurrentIndex( 0 ); - m_Controls->m_HistogramWidget->SetHistogramModeToDirectHistogram(); - m_Controls->m_HistogramWidget->SetHistogram( - m_CurrentStatisticsCalculator->GetHistogram( timeStep ) ); - m_Controls->m_HistogramWidget->UpdateItemModelFromHistogram(); - - MITK_INFO << "UpdateItemModelFromHistogram()"; - - this->FillStatisticsTableView( - m_CurrentStatisticsCalculator->GetStatistics( timeStep ), - m_SelectedImage ); - } - else - { - m_Controls->m_SelectedMaskLabel->setText( "None" ); - - // Clear statistics and histogram - this->InvalidateStatisticsTableView(); - m_Controls->m_HistogramWidget->ClearItemModel(); - m_CurrentStatisticsValid = false; - - - // If a (non-closed) PlanarFigure is selected, display a line profile widget - if ( m_SelectedPlanarFigure != NULL ) - { - // check whether PlanarFigure is initialized - const mitk::Geometry2D *planarFigureGeometry2D = m_SelectedPlanarFigure->GetGeometry2D(); - if ( planarFigureGeometry2D == NULL ) - { - // Clear statistics, histogram, and GUI - this->InvalidateStatisticsTableView(); - m_Controls->m_HistogramWidget->ClearItemModel(); - m_Controls->m_LineProfileWidget->ClearItemModel(); - m_CurrentStatisticsValid = false; - m_Controls->m_ErrorMessageLabel->hide(); - m_Controls->m_SelectedMaskLabel->setText( "None" ); - return; - } - // TODO: enable line profile widget - m_Controls->m_StatisticsWidgetStack->setCurrentIndex( 1 ); - m_Controls->m_LineProfileWidget->SetImage( m_SelectedImage ); - m_Controls->m_LineProfileWidget->SetPlanarFigure( m_SelectedPlanarFigure ); - m_Controls->m_LineProfileWidget->UpdateItemModelFromPath(); - } + this->m_StatisticsUpdatePending = false; } } + else + { + this->m_StatisticsUpdatePending = false; + } } -void QmitkImageStatisticsView::UpdateProgressBar() +void QmitkImageStatisticsView::SelectedDataModified() { - mitk::ProgressBar::GetInstance()->Progress(); + if( !m_StatisticsUpdatePending ) + { + emit StatisticsUpdate(); + } } - void QmitkImageStatisticsView::RequestStatisticsUpdate() { if ( !m_StatisticsUpdatePending ) { - QApplication::postEvent( this, new QmitkRequestStatisticsUpdateEvent ); - m_StatisticsUpdatePending = true; + if(this->m_DataNodeSelectionChanged) + { + this->SelectionChanged( this->GetDataManagerSelection()); + } + else + { + this->m_StatisticsUpdatePending = true; + this->UpdateStatistics(); + } } + this->GetRenderWindowPart()->RequestUpdate(); } - -void QmitkImageStatisticsView::RemoveOrphanImages() +void QmitkImageStatisticsView::WriteStatisticsToGUI() { - ImageStatisticsMapType::iterator it = m_ImageStatisticsMap.begin(); + if ( this->m_CalculationThread->GetStatisticsUpdateSuccessFlag() && !m_DataNodeSelectionChanged ) + { + if ( this->m_CalculationThread->GetStatisticsChangedFlag() ) + { + // Do not show any error messages + m_Controls->m_ErrorMessageLabel->hide(); + m_CurrentStatisticsValid = true; + } - while ( it != m_ImageStatisticsMap.end() ) + m_Controls->m_StatisticsWidgetStack->setCurrentIndex( 0 ); + m_Controls->m_HistogramWidget->SetHistogramModeToDirectHistogram(); + m_Controls->m_HistogramWidget->UpdateItemModelFromHistogram(); + m_Controls->m_HistogramWidget->SetHistogram( this->m_CalculationThread->GetTimeStepHistogram().GetPointer() ); + int timeStep = this->m_CalculationThread->GetTimeStep(); + this->FillStatisticsTableView( this->m_CalculationThread->GetStatisticsData(), this->m_CalculationThread->GetStatisticsImage()); + } + else { - mitk::Image *image = it->first; - mitk::ImageStatisticsCalculator *calculator = it->second; - ++it; + m_Controls->m_SelectedMaskLabel->setText( "None" ); + std::stringstream message; + message << "Error calculating statistics!"; + m_Controls->m_ErrorMessageLabel->setText( message.str().c_str() ); + m_Controls->m_ErrorMessageLabel->show(); + // Clear statistics and histogram + this->InvalidateStatisticsTableView(); + m_Controls->m_HistogramWidget->ClearItemModel(); + m_CurrentStatisticsValid = false; - mitk::NodePredicateData::Pointer hasImage = mitk::NodePredicateData::New( image ); - if ( this->GetDataStorage()->GetNode( hasImage ) == NULL ) + // If a (non-closed) PlanarFigure is selected, display a line profile widget + if ( m_SelectedPlanarFigure != NULL ) { - if ( m_SelectedImage == image ) - { - m_SelectedImage = NULL; - m_SelectedImageNode = NULL; - } - if ( m_CurrentStatisticsCalculator == calculator ) + // check whether PlanarFigure is initialized + const mitk::Geometry2D *planarFigureGeometry2D = m_SelectedPlanarFigure->GetGeometry2D(); + if ( planarFigureGeometry2D == NULL ) { - m_CurrentStatisticsCalculator = NULL; + // Clear statistics, histogram, and GUI + this->InvalidateStatisticsTableView(); + m_Controls->m_HistogramWidget->ClearItemModel(); + m_Controls->m_LineProfileWidget->ClearItemModel(); + m_CurrentStatisticsValid = false; + m_Controls->m_ErrorMessageLabel->hide(); + m_Controls->m_SelectedMaskLabel->setText( "None" ); + this->m_StatisticsUpdatePending = false; + return; } - m_ImageStatisticsMap.erase( image ); - it = m_ImageStatisticsMap.begin(); + // TODO: enable line profile widget + m_Controls->m_StatisticsWidgetStack->setCurrentIndex( 1 ); + m_Controls->m_LineProfileWidget->SetImage( this->m_CalculationThread->GetStatisticsImage() ); + m_Controls->m_LineProfileWidget->SetPlanarFigure( m_SelectedPlanarFigure ); + m_Controls->m_LineProfileWidget->UpdateItemModelFromPath(); } } -} - - -bool QmitkImageStatisticsView::event( QEvent *event ) -{ - if ( event->type() == (QEvent::Type) QmitkRequestStatisticsUpdateEvent::StatisticsUpdateRequest ) - { - // Update statistics - - m_StatisticsUpdatePending = false; - - this->UpdateStatistics(); - return true; - } - - return false; + this->m_StatisticsUpdatePending = false; } void QmitkImageStatisticsView::ComputeIntensityProfile( mitk::PlanarLine* line ) { double sampling = 300; QmitkVtkHistogramWidget::HistogramType::Pointer histogram = QmitkVtkHistogramWidget::HistogramType::New(); itk::Size<1> siz; siz[0] = sampling; itk::FixedArray lower, higher; lower.Fill(0); - mitk::Point3D begin = line->GetWorldControlPoint(0); + mitk::Point3D begin = line->GetWorldControlPoint(0); mitk::Point3D end = line->GetWorldControlPoint(1); itk::Vector direction = (end - begin); higher.Fill(direction.GetNorm()); histogram->Initialize(siz, lower, higher); for(int i = 0; i < sampling; i++) { - //mitk::Point3D location = begin + double(i)/sampling * direction; double d = m_SelectedImage->GetPixelValueByWorldCoordinate(begin + double(i)/sampling * direction); histogram->SetFrequency(i,d); } m_Controls->m_HistogramWidget->SetHistogramModeToDirectHistogram(); m_Controls->m_HistogramWidget->SetHistogram( histogram ); m_Controls->m_HistogramWidget->UpdateItemModelFromHistogram(); +} + +void QmitkImageStatisticsView::FillStatisticsTableView( + const mitk::ImageStatisticsCalculator::Statistics &s, + const mitk::Image *image ) +{ + this->m_Controls->m_StatisticsTable->setItem( 0, 0, new QTableWidgetItem( + QString("%1").arg(s.Mean, 0, 'f', 2) ) ); + this->m_Controls->m_StatisticsTable->setItem( 0, 1, new QTableWidgetItem( + QString("%1").arg(s.Sigma, 0, 'f', 2) ) ); + + this->m_Controls->m_StatisticsTable->setItem( 0, 2, new QTableWidgetItem( + QString("%1").arg(s.RMS, 0, 'f', 2) ) ); + + this->m_Controls->m_StatisticsTable->setItem( 0, 3, new QTableWidgetItem( + QString("%1").arg(s.Max, 0, 'f', 2) ) ); + this->m_Controls->m_StatisticsTable->setItem( 0, 4, new QTableWidgetItem( + QString("%1").arg(s.Min, 0, 'f', 2) ) ); + + this->m_Controls->m_StatisticsTable->setItem( 0, 5, new QTableWidgetItem( + QString("%1").arg(s.N) ) ); + + const mitk::Geometry3D *geometry = image->GetGeometry(); + if ( geometry != NULL ) + { + const mitk::Vector3D &spacing = image->GetGeometry()->GetSpacing(); + double volume = spacing[0] * spacing[1] * spacing[2] * (double) s.N; + this->m_Controls->m_StatisticsTable->setItem( 0, 6, new QTableWidgetItem( + QString("%1").arg(volume, 0, 'f', 2) ) ); + } + else + { + this->m_Controls->m_StatisticsTable->setItem( 0, 6, new QTableWidgetItem( + "NA" ) ); + } } +void QmitkImageStatisticsView::InvalidateStatisticsTableView() +{ + for ( unsigned int i = 0; i < 7; ++i ) + { + this->m_Controls->m_StatisticsTable->setItem( 0, i, new QTableWidgetItem( "NA" ) ); + } +} + void QmitkImageStatisticsView::Activated() { } void QmitkImageStatisticsView::Deactivated() { } void QmitkImageStatisticsView::Visible() { m_Visible = true; this->OnSelectionChanged(this->GetSite()->GetPage()->FindView("org.mitk.views.datamanager"), - this->GetDataManagerSelection()); + this->GetDataManagerSelection()); } void QmitkImageStatisticsView::Hidden() { m_Visible = false; } void QmitkImageStatisticsView::SetFocus() { - } + + + + +//void QmitkImageStatisticsView::UpdateProgressBar() +//{ +// mitk::ProgressBar::GetInstance()->Progress(); +//} + +// if ( !m_StatisticsUpdatePending ) +// { +// if(this->m_DataNodeSelectionChanged) +// { +// this->ReinitData(); +// this->SelectionChanged( this->GetDataManagerSelection()); +//while( this->m_CalculationThread->isRunning() ) +//{ +// itksys::SystemTools::Delay(100); +//} + +//this->m_CalculationThread->terminate(); +//this->m_StatisticsUpdatePending = false; + +//if(this->m_SelectedImage != NULL) +//{ +// this->m_SelectedImage->RemoveObserver( this->m_ImageObserverTag); +// this->m_ImageObserverTag = -1; +// this->m_SelectedImage = NULL; +//} +//if(this->m_SelectedImageMask != NULL) +//{ +// this->m_SelectedImageMask->RemoveObserver( this->m_ImageMaskObserverTag); +// this->m_ImageMaskObserverTag = -1; +// this->m_SelectedImageMask = NULL; +//} +//if(this->m_SelectedPlanarFigure != NULL) +//{ +// this->m_SelectedPlanarFigure->RemoveObserver( this->m_PlanarFigureObserverTag); +// this->m_PlanarFigureObserverTag = -1; +// this->m_SelectedPlanarFigure = NULL; +//} +// } +// else +// { +// emit StatisticsUpdate(); +// } +// } +//} +//void QmitkImageStatisticsView::RemoveOrphanImages() +//{ +// ImageStatisticsMapType::iterator it = m_ImageStatisticsMap.begin(); +// +// while ( it != m_ImageStatisticsMap.end() ) +// { +// mitk::Image *image = it->first; +// mitk::ImageStatisticsCalculator *calculator = it->second; +// ++it; +// +// mitk::NodePredicateData::Pointer hasImage = mitk::NodePredicateData::New( image ); +// if ( this->GetDataStorage()->GetNode( hasImage ) == NULL ) +// { +// if ( m_SelectedImage == image ) +// { +// m_SelectedImage = NULL; +// //m_SelectedImageNode = NULL; +// } +// if ( m_CurrentStatisticsCalculator == calculator ) +// { +// m_CurrentStatisticsCalculator = NULL; +// } +// m_ImageStatisticsMap.erase( image ); +// it = m_ImageStatisticsMap.begin(); +// } +// } +//} + +//bool QmitkImageStatisticsView::event( QEvent *event ) +//{ +// if ( event->type() == (QEvent::Type) QmitkRequestStatisticsUpdateEvent::StatisticsUpdateRequest ) +// { +// // Update statistics +// +// m_StatisticsUpdatePending = false; +// +// this->UpdateStatistics(); +// return true; +// } +// else if(event->type() == (QEvent::Type) QmitkStatisticsCalculatedEvent::StatisticsCalculated ) +// { +// this->OnThreadedStatisticsCalculationEnds(); +// } +// +// return false; +//} +//void QmitkImageStatisticsView::OnSelectionChanged( berry::IWorkbenchPart::Pointer /*part*/, +// const QList &selectedNodes ) +//{ +// MITK_INFO<<"SelectionChanged!"; +// // Clear any unreferenced images +// this->RemoveOrphanImages(); +// +// if ( !m_Visible ) +// { +// return; +// } +// +// // Check if selection makeup consists only of valid nodes: +// // One image, segmentation or planarFigure +// // One image and one of the other two +// bool tooManyNodes( true ); +// bool invalidNodes( true ); +// +// if ( selectedNodes.size() < 3 ) +// { +// tooManyNodes = false; +// } +// +// QList nodes(selectedNodes); +// if( !tooManyNodes ) +// { +// unsigned int numberImages = 0; +// unsigned int numberSegmentations = 0; +// unsigned int numberPlanarFigures = 0; +// +// for ( int index = 0; index < nodes.size(); index++ ) +// { +// m_SelectedImageMask = dynamic_cast< mitk::Image * >( nodes[ index ]->GetData() ); +// m_SelectedPlanarFigure = dynamic_cast< mitk::PlanarFigure * >( nodes[ index ]->GetData() ); +// +// if ( m_SelectedImageMask != NULL ) +// { +// bool isMask( false ); +// nodes[ index ]->GetPropertyValue("binary", isMask); +// if ( !isMask ) +// { +// numberImages++; +// } +// else +// { +// numberSegmentations++; +// if ( numberImages != 0 ) // image should be last element +// { +// std::swap( nodes[ index ], nodes[ index - 1 ] ); +// } +// } +// } +// else if ( m_SelectedPlanarFigure != NULL ) +// { +// numberPlanarFigures++; +// if ( numberImages != 0 ) // image should be last element +// { +// std::swap( nodes[ index ], nodes[ index - 1 ] ); +// } +// } +// } +// +// if ( ( numberPlanarFigures + numberSegmentations + numberImages ) == nodes.size() && //No invalid nodes +// ( numberPlanarFigures + numberSegmentations ) < 2 && numberImages < 2 +// // maximum of one image and/or one of either planar figure or segmentation +// ) +// { +// invalidNodes = false; +// } +// } +// +// if ( nodes.empty() || tooManyNodes || invalidNodes ) +// { +// // Nothing to do: invalidate image, clear statistics, histogram, and GUI +// m_SelectedImage = NULL; +// this->InvalidateStatisticsTableView() ; +// m_Controls->m_HistogramWidget->ClearItemModel(); +// m_Controls->m_LineProfileWidget->ClearItemModel(); +// +// m_CurrentStatisticsValid = false; +// m_Controls->m_ErrorMessageLabel->hide(); +// m_Controls->m_SelectedMaskLabel->setText( "None" ); +// return; +// } +// +// // Get selected element +// +// mitk::DataNode *selectedNode = nodes.front(); +// mitk::Image *selectedImage = dynamic_cast< mitk::Image * >( selectedNode->GetData() ); +// +// // Find the next parent/grand-parent node containing an image, if any +// mitk::DataStorage::SetOfObjects::ConstPointer parentObjects; +// mitk::DataNode *parentNode = NULL; +// mitk::Image *parentImage = NULL; +// +// // Possibly previous change listeners +// if ( (m_SelectedPlanarFigure != NULL) && (m_PlanarFigureObserverTag >= 0) ) +// { +// m_SelectedPlanarFigure->RemoveObserver( m_PlanarFigureObserverTag ); +// m_PlanarFigureObserverTag = -1; +// } +// if ( (m_SelectedImage != NULL) && (m_ImageObserverTag >= 0) ) +// { +// m_SelectedImage->RemoveObserver( m_ImageObserverTag ); +// m_ImageObserverTag = -1; +// } +// if ( (m_SelectedImageMask != NULL) && (m_ImageMaskObserverTag >= 0) ) +// { +// m_SelectedImageMask->RemoveObserver( m_ImageMaskObserverTag ); +// m_ImageMaskObserverTag = -1; +// } +// +// // Deselect all images and masks by default +// m_SelectedImageNode = NULL; +// m_SelectedImage = NULL; +// m_SelectedMaskNode = NULL; +// m_SelectedImageMask = NULL; +// m_SelectedPlanarFigure = NULL; +// +// { +// unsigned int parentObjectIndex = 0; +// parentObjects = this->GetDataStorage()->GetSources( selectedNode ); +// while( parentObjectIndex < parentObjects->Size() ) +// { +// // Use first parent object (if multiple parents are present) +// parentNode = parentObjects->ElementAt( parentObjectIndex ); +// parentImage = dynamic_cast< mitk::Image * >( parentNode->GetData() ); +// if( parentImage != NULL ) +// { +// break; +// } +// parentObjectIndex++; +// } +// } +// +// if ( nodes.size() == 2 ) +// { +// parentNode = nodes.back(); +// parentImage = dynamic_cast< mitk::Image * >( parentNode->GetData() ); +// } +// +// if ( parentImage != NULL ) +// { +// m_SelectedImageNode = parentNode; +// m_SelectedImage = parentImage; +// +// // Check if a valid mask has been selected (Image or PlanarFigure) +// m_SelectedImageMask = dynamic_cast< mitk::Image * >( selectedNode->GetData() ); +// m_SelectedPlanarFigure = dynamic_cast< mitk::PlanarFigure * >( selectedNode->GetData() ); +// +// // Check whether ImageMask is a binary segmentation +// +// if ( (m_SelectedImageMask != NULL) ) +// { +// bool isMask( false ); +// selectedNode->GetPropertyValue("binary", isMask); +// if ( !isMask ) +// { +// m_SelectedImageNode = selectedNode; +// m_SelectedImage = selectedImage; +// m_SelectedImageMask = NULL; +// } +// else +// { +// m_SelectedMaskNode = selectedNode; +// } +// } +// else if ( (m_SelectedPlanarFigure != NULL) ) +// { +// m_SelectedMaskNode = selectedNode; +// } +// } +// else if ( selectedImage != NULL ) +// { +// m_SelectedImageNode = selectedNode; +// m_SelectedImage = selectedImage; +// } +// +// +// typedef itk::SimpleMemberCommand< QmitkImageStatisticsView > ITKCommandType; +// ITKCommandType::Pointer changeListener; +// changeListener = ITKCommandType::New(); +// changeListener->SetCallbackFunction( this, &QmitkImageStatisticsView::RequestStatisticsUpdate ); +// +// // Add change listeners to selected objects +// if ( m_SelectedImage != NULL ) +// { +// m_ImageObserverTag = m_SelectedImage->AddObserver( +// itk::ModifiedEvent(), changeListener ); +// } +// +// if ( m_SelectedImageMask != NULL ) +// { +// m_ImageMaskObserverTag = m_SelectedImageMask->AddObserver( +// itk::ModifiedEvent(), changeListener ); +// } +// +// if ( m_SelectedPlanarFigure != NULL ) +// { +// m_PlanarFigureObserverTag = m_SelectedPlanarFigure->AddObserver( +// mitk::EndInteractionPlanarFigureEvent(), changeListener ); +// } +// +// // Clear statistics / histogram GUI if nothing is selected +// if ( m_SelectedImage == NULL ) +// { +// // Clear statistics, histogram, and GUI +// this->InvalidateStatisticsTableView(); +// m_Controls->m_HistogramWidget->ClearItemModel(); +// m_Controls->m_LineProfileWidget->ClearItemModel(); +// m_CurrentStatisticsValid = false; +// m_Controls->m_ErrorMessageLabel->hide(); +// m_Controls->m_SelectedMaskLabel->setText( "None" ); +// } +// else +// { +// // Else, request statistics and GUI update +// emit StatisticsUpdate(); +// } +//} +// + + + +// Retrieve ImageStatisticsCalculator from hash map (or create a new one +// for this image if non-existent) +//ImageStatisticsMapType::iterator it = +// m_ImageStatisticsMap.find( m_SelectedImage ); + +//if ( it != m_ImageStatisticsMap.end() ) +//{ +// m_CurrentStatisticsCalculator = it->second; +// //MITK_INFO << "Retrieving StatisticsCalculator"; +//} +//else +//{ +// m_CurrentStatisticsCalculator = mitk::ImageStatisticsCalculator::New(); +// m_CurrentStatisticsCalculator->SetImage( m_SelectedImage ); +// m_ImageStatisticsMap[m_SelectedImage] = m_CurrentStatisticsCalculator; +// //MITK_INFO << "Creating StatisticsCalculator"; +//} + +//std::string maskName; +//std::string maskType; + +//if ( m_SelectedImageMask != NULL ) +//{ +// m_CurrentStatisticsCalculator->SetImageMask( m_SelectedImageMask ); +// m_CurrentStatisticsCalculator->SetMaskingModeToImage(); + +// //maskName = m_SelectedMaskNode->GetName(); +// //maskType = m_SelectedImageMask->GetNameOfClass(); +// //maskDimension = 3; +//} +//else if ( m_SelectedPlanarFigure != NULL ) +//{ +// m_CurrentStatisticsCalculator->SetPlanarFigure( m_SelectedPlanarFigure ); +// m_CurrentStatisticsCalculator->SetMaskingModeToPlanarFigure(); + +// //maskName = m_SelectedMaskNode->GetName(); +// //maskType = m_SelectedPlanarFigure->GetNameOfClass(); +// //maskDimension = 2; +//} +//else +//{ +// m_CurrentStatisticsCalculator->SetMaskingModeToNone(); + +// //maskName = "None"; +// //maskType = ""; +// //maskDimension = 0; +//} + +//if(m_Controls->m_IgnoreZerosCheckbox->isChecked()) +//{ +// m_CurrentStatisticsCalculator->SetIgnorePixelValue(0); +// m_CurrentStatisticsCalculator->SetDoIgnorePixelValue(true); +//} +//else +//{ +// m_CurrentStatisticsCalculator->SetDoIgnorePixelValue(false); +//} + + +//bool statisticsChanged = false; +//bool statisticsCalculationSuccessful = false; + +// Initialize progress bar +//mitk::ProgressBar::GetInstance()->AddStepsToDo( 100 ); + +// Install listener for progress events and initialize progress bar +//typedef itk::SimpleMemberCommand< QmitkImageStatisticsView > ITKCommandType; +//ITKCommandType::Pointer progressListener; +//progressListener = ITKCommandType::New(); +//progressListener->SetCallbackFunction( this, &QmitkImageStatisticsView::UpdateProgressBar ); +//unsigned long progressObserverTag = m_CurrentStatisticsCalculator +// ->AddObserver( itk::ProgressEvent(), progressListener ); + +// show wait cursor +//this->WaitCursorOn(); + +//m_CurrentStatisticsCalculator->RemoveObserver( progressObserverTag ); + +// Make sure that progress bar closes +//mitk::ProgressBar::GetInstance()->Progress( 100 ); + +// remove wait cursor +//this->WaitCursorOff(); + +// if ( statisticsCalculationSuccessful ) +// { +// if ( statisticsChanged ) +// { +// // Do not show any error messages +// m_Controls->m_ErrorMessageLabel->hide(); + +// m_CurrentStatisticsValid = true; +// } + +// m_Controls->m_StatisticsWidgetStack->setCurrentIndex( 0 ); +// m_Controls->m_HistogramWidget->SetHistogramModeToDirectHistogram(); +// m_Controls->m_HistogramWidget->SetHistogram( +// m_CurrentStatisticsCalculator->GetHistogram( timeStep ) ); +// m_Controls->m_HistogramWidget->UpdateItemModelFromHistogram(); + +// MITK_INFO << "UpdateItemModelFromHistogram()"; + +// this->FillStatisticsTableView( +// m_CurrentStatisticsCalculator->GetStatistics( timeStep ), +// m_SelectedImage ); +// } +// else +// { +// m_Controls->m_SelectedMaskLabel->setText( "None" ); + +// // Clear statistics and histogram +// this->InvalidateStatisticsTableView(); +// m_Controls->m_HistogramWidget->ClearItemModel(); +// m_CurrentStatisticsValid = false; + +// // If a (non-closed) PlanarFigure is selected, display a line profile widget +// if ( m_SelectedPlanarFigure != NULL ) +// { +// // check whether PlanarFigure is initialized +// const mitk::Geometry2D *planarFigureGeometry2D = m_SelectedPlanarFigure->GetGeometry2D(); +// if ( planarFigureGeometry2D == NULL ) +// { +// // Clear statistics, histogram, and GUI +// this->InvalidateStatisticsTableView(); +// m_Controls->m_HistogramWidget->ClearItemModel(); +// m_Controls->m_LineProfileWidget->ClearItemModel(); +// m_CurrentStatisticsValid = false; +// m_Controls->m_ErrorMessageLabel->hide(); +// m_Controls->m_SelectedMaskLabel->setText( "None" ); +// return; +// } +// // TODO: enable line profile widget +// m_Controls->m_Sta tisticsWidgetStack->setCurrentIndex( 1 ); +// m_Controls->m_LineProfileWidget->SetImage( m_SelectedImage ); +// m_Controls->m_LineProfileWidget->SetPlanarFigure( m_SelectedPlanarFigure ); +// m_Controls->m_LineProfileWidget->UpdateItemModelFromPath(); +// } +// } \ No newline at end of file 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 b6b8f81b42..f9f257908a 100644 --- a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsView.h +++ b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsView.h @@ -1,166 +1,187 @@ /*=================================================================== 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" #include #include #include "QmitkStepperAdapter.h" #include "mitkImageStatisticsCalculator.h" #include #include "mitkPlanarLine.h" +#include "QmitkImageStatisticsCalculationThread.h" +#include /*! \brief QmitkImageStatisticsView \sa QmitkFunctionality \ingroup Functionalities */ class QmitkImageStatisticsView : public QmitkAbstractView, public mitk::ILifecycleAwarePart { Q_OBJECT public: /*! \ 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 std::vector SelectedDataNodeVectorType; + typedef itk::SimpleMemberCommand< QmitkImageStatisticsView > ITKCommandType; /*! \brief default constructor */ QmitkImageStatisticsView(QObject *parent=0, const char *name=0); /*! \brief default destructor */ virtual ~QmitkImageStatisticsView(); /*! \brief method for creating the widget containing the application controls, like sliders, buttons etc. */ virtual void CreateQtPartControl(QWidget *parent); /*! \brief method for creating the connections of main and control widget */ virtual void CreateConnections(); bool IsExclusiveFunctionality() const; - - virtual bool event( QEvent *event ); + /*! + \brief */ + //void SetStatisticsUpdatePendingFlag( bool flag); + //virtual bool event( QEvent *event ); void OnSelectionChanged( berry::IWorkbenchPart::Pointer part, const QList &nodes ); static const std::string VIEW_ID; +public slots: + void OnThreadedStatisticsCalculationEnds(bool , bool ); + protected slots: - void ClipboardHistogramButtonClicked(); + void OnClipboardHistogramButtonClicked(); + + void OnClipboardStatisticsButtonClicked(); - void ClipboardStatisticsButtonClicked(); + void OnIgnoreZerosCheckboxClicked( ); - void IgnoreZerosCheckboxClicked( ); + void RequestStatisticsUpdate(); +signals: + void StatisticsUpdate(); protected: void FillStatisticsTableView( const mitk::ImageStatisticsCalculator::Statistics &s, const mitk::Image *image ); void InvalidateStatisticsTableView(); /** \brief Issues a request to update statistics by sending an event to the * Qt event processing queue. * * Statistics update should only be executed after program execution returns * to the Qt main loop. This mechanism also prevents multiple execution of * updates where only one is required.*/ - void RequestStatisticsUpdate(); + //void RequestStatisticsUpdate(); /** \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 ); void Activated(); void Deactivated(); void Visible(); void Hidden(); void SetFocus(); - - - typedef std::map< mitk::Image *, mitk::ImageStatisticsCalculator::Pointer > - ImageStatisticsMapType; - + /** \brief Method called when itkModifiedEvent is called by selected data. */ + void SelectedDataModified(); + /** \brief */ + void SelectionChanged(const QList &selectedNodes); + /** \brief */ + void ReinitData(); + /** \brief */ + void WriteStatisticsToGUI(); + /** \brief Classifies the selected data node for image, segmentation and planar figure. */ + //void ClassifySelectedNodes(); /*! * controls containing sliders for scrolling through the slices */ Ui::QmitkImageStatisticsViewControls *m_Controls; + QmitkImageStatisticsCalculationThread* m_CalculationThread; + QmitkStepperAdapter* m_TimeStepperAdapter; unsigned int m_CurrentTime; - QString m_Clipboard; + QString m_Clipboard; // Image and mask data - mitk::DataNode *m_SelectedImageNode; - mitk::Image *m_SelectedImage; + //mitk::DataNode::Pointer m_SelectedImageNode; + mitk::Image* m_SelectedImage; - mitk::DataNode *m_SelectedMaskNode; - mitk::Image *m_SelectedImageMask; - mitk::PlanarFigure *m_SelectedPlanarFigure; + //mitk::DataNode::Pointer m_SelectedMaskNode; + mitk::Image* m_SelectedImageMask; + mitk::PlanarFigure* m_SelectedPlanarFigure; long m_ImageObserverTag; long m_ImageMaskObserverTag; long m_PlanarFigureObserverTag; - // Hash map for associating one image statistics calculator with each iamge + // Hash map for associating one image statistics calculator with each image // (so that previously calculated histograms / statistics can be recovered // if a recalculation is not required) ImageStatisticsMapType m_ImageStatisticsMap; - + SelectedDataNodeVectorType m_SelectedDataNodes; mitk::ImageStatisticsCalculator::Pointer m_CurrentStatisticsCalculator; - + bool m_CurrentStatisticsValid; bool m_StatisticsUpdatePending; - + bool m_StatisticsIntegrationPending; + bool m_DataNodeSelectionChanged; bool m_Visible; + QMutex* m_QThreadMutex; }; - #endif // QmitkImageStatisticsView_H__INCLUDED diff --git a/Plugins/org.mitk.gui.qt.tofutil/src/internal/QmitkToFUtilView.cpp b/Plugins/org.mitk.gui.qt.tofutil/src/internal/QmitkToFUtilView.cpp index 51127b9dc8..89c7ffc952 100644 --- a/Plugins/org.mitk.gui.qt.tofutil/src/internal/QmitkToFUtilView.cpp +++ b/Plugins/org.mitk.gui.qt.tofutil/src/internal/QmitkToFUtilView.cpp @@ -1,520 +1,525 @@ /*=================================================================== 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. ===================================================================*/ // Qmitk #include "QmitkToFUtilView.h" #include #include // Qt #include #include // MITK #include #include #include #include #include #include // VTK #include // ITK #include const std::string QmitkToFUtilView::VIEW_ID = "org.mitk.views.tofutil"; QmitkToFUtilView::QmitkToFUtilView() : QmitkFunctionality() , m_Controls(NULL), m_MultiWidget( NULL ) , m_MitkDistanceImage(NULL), m_MitkAmplitudeImage(NULL), m_MitkIntensityImage(NULL), m_Surface(NULL) , m_DistanceImageNode(NULL), m_AmplitudeImageNode(NULL), m_IntensityImageNode(NULL), m_SurfaceNode(NULL) , m_ToFImageRecorder(NULL), m_ToFImageGrabber(NULL), m_ToFDistanceImageToSurfaceFilter(NULL), m_ToFCompositeFilter(NULL) , m_SurfaceDisplayCount(0), m_2DDisplayCount(0) , m_RealTimeClock(NULL) , m_StepsForFramerate(100) , m_2DTimeBefore(0.0) , m_2DTimeAfter(0.0) , m_VideoEnabled(false) { this->m_Frametimer = new QTimer(this); this->m_ToFDistanceImageToSurfaceFilter = mitk::ToFDistanceImageToSurfaceFilter::New(); this->m_ToFCompositeFilter = mitk::ToFCompositeFilter::New(); this->m_ToFImageRecorder = mitk::ToFImageRecorder::New(); this->m_ToFSurfaceVtkMapper3D = mitk::ToFSurfaceVtkMapper3D::New(); + + this->m_UpdateMutex = new QMutex; } QmitkToFUtilView::~QmitkToFUtilView() { OnToFCameraStopped(); OnToFCameraDisconnected(); + delete this->m_UpdateMutex; } void QmitkToFUtilView::CreateQtPartControl( QWidget *parent ) { // build up qt view, unless already done if ( !m_Controls ) { // create GUI widgets from the Qt Designer's .ui file m_Controls = new Ui::QmitkToFUtilViewControls; m_Controls->setupUi( parent ); connect(m_Frametimer, SIGNAL(timeout()), this, SLOT(OnUpdateCamera())); connect( (QObject*)(m_Controls->m_ToFConnectionWidget), SIGNAL(ToFCameraConnected()), this, SLOT(OnToFCameraConnected()) ); connect( (QObject*)(m_Controls->m_ToFConnectionWidget), SIGNAL(ToFCameraDisconnected()), this, SLOT(OnToFCameraDisconnected()) ); connect( (QObject*)(m_Controls->m_ToFConnectionWidget), SIGNAL(ToFCameraSelected(const QString)), this, SLOT(OnToFCameraSelected(const QString)) ); connect( (QObject*)(m_Controls->m_ToFRecorderWidget), SIGNAL(ToFCameraStarted()), this, SLOT(OnToFCameraStarted()) ); connect( (QObject*)(m_Controls->m_ToFRecorderWidget), SIGNAL(ToFCameraStopped()), this, SLOT(OnToFCameraStopped()) ); connect( (QObject*)(m_Controls->m_ToFRecorderWidget), SIGNAL(RecordingStarted()), this, SLOT(OnToFCameraStopped()) ); connect( (QObject*)(m_Controls->m_ToFRecorderWidget), SIGNAL(RecordingStopped()), this, SLOT(OnToFCameraStarted()) ); connect( (QObject*)(m_Controls->m_TextureCheckBox), SIGNAL(toggled(bool)), this, SLOT(OnTextureCheckBoxChecked(bool)) ); connect( (QObject*)(m_Controls->m_VideoTextureCheckBox), SIGNAL(toggled(bool)), this, SLOT(OnVideoTextureCheckBoxChecked(bool)) ); } } void QmitkToFUtilView::StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget) { m_MultiWidget = &stdMultiWidget; } void QmitkToFUtilView::StdMultiWidgetNotAvailable() { m_MultiWidget = NULL; } void QmitkToFUtilView::Activated() { QmitkFunctionality::Activated(); // configure views m_MultiWidget->SetWidgetPlanesVisibility(false); m_MultiWidget->mitkWidget1->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Transversal); m_MultiWidget->mitkWidget1->GetSliceNavigationController()->SliceLockedOn(); m_MultiWidget->mitkWidget2->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Transversal); m_MultiWidget->mitkWidget2->GetSliceNavigationController()->SliceLockedOn(); m_MultiWidget->mitkWidget3->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Transversal); m_MultiWidget->mitkWidget3->GetSliceNavigationController()->SliceLockedOn(); m_MultiWidget->ResetCrosshair(); mitk::RenderingManager::GetInstance()->InitializeViews(); this->UseToFVisibilitySettings(true); m_Controls->m_ToFCompositeFilterWidget->SetToFCompositeFilter(this->m_ToFCompositeFilter); m_Controls->m_ToFCompositeFilterWidget->SetDataStorage(this->GetDefaultDataStorage()); if (this->m_ToFImageGrabber.IsNull()) { m_Controls->m_ToFRecorderWidget->setEnabled(false); m_Controls->m_ToFVisualisationSettingsWidget->setEnabled(false); } } void QmitkToFUtilView::Deactivated() { m_MultiWidget->SetWidgetPlanesVisibility(true); m_MultiWidget->mitkWidget1->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Transversal); m_MultiWidget->mitkWidget1->GetSliceNavigationController()->SliceLockedOff(); m_MultiWidget->mitkWidget2->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Sagittal); m_MultiWidget->mitkWidget2->GetSliceNavigationController()->SliceLockedOff(); m_MultiWidget->mitkWidget3->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Frontal); m_MultiWidget->mitkWidget3->GetSliceNavigationController()->SliceLockedOff(); m_MultiWidget->ResetCrosshair(); this->UseToFVisibilitySettings(false); mitk::RenderingManager::GetInstance()->InitializeViews(); QmitkFunctionality::Deactivated(); } void QmitkToFUtilView::OnToFCameraConnected() { this->m_SurfaceDisplayCount = 0; this->m_2DDisplayCount = 0; this->m_ToFImageGrabber = m_Controls->m_ToFConnectionWidget->GetToFImageGrabber(); this->m_ToFImageRecorder->SetCameraDevice(this->m_ToFImageGrabber->GetCameraDevice()); m_Controls->m_ToFRecorderWidget->SetParameter(this->m_ToFImageGrabber, this->m_ToFImageRecorder); m_Controls->m_ToFRecorderWidget->setEnabled(true); m_Controls->m_ToFRecorderWidget->ResetGUIToInitial(); m_Controls->m_ToFVisualisationSettingsWidget->setEnabled(true); //TODO this->m_RealTimeClock = mitk::RealTimeClock::New(); this->m_2DTimeBefore = this->m_RealTimeClock->GetCurrentStamp(); try { this->m_VideoSource = mitk::OpenCVVideoSource::New(); this->m_VideoSource->SetVideoCameraInput(0, false); this->m_VideoSource->StartCapturing(); if(!this->m_VideoSource->IsCapturingEnabled()) { MITK_INFO << "unable to initialize video grabbing/playback"; this->m_VideoEnabled = false; m_Controls->m_VideoTextureCheckBox->setEnabled(false); } else { this->m_VideoEnabled = true; m_Controls->m_VideoTextureCheckBox->setEnabled(true); } if (this->m_VideoEnabled) { this->m_VideoSource->FetchFrame(); this->m_VideoCaptureHeight = this->m_VideoSource->GetImageHeight(); this->m_VideoCaptureWidth = this->m_VideoSource->GetImageWidth(); int videoTexSize = this->m_VideoCaptureWidth * this->m_VideoCaptureHeight * 3; // for each pixel three values for rgb are needed!! this->m_VideoTexture = this->m_VideoSource->GetVideoTexture(); unsigned int dimensions[2]; dimensions[0] = this->m_VideoCaptureWidth; dimensions[1] = this->m_VideoCaptureHeight; this->m_ToFDistanceImageToSurfaceFilter->SetTextureImageWidth(this->m_VideoCaptureWidth); this->m_ToFDistanceImageToSurfaceFilter->SetTextureImageHeight(this->m_VideoCaptureHeight); this->m_ToFSurfaceVtkMapper3D->SetTextureWidth(this->m_VideoCaptureWidth); this->m_ToFSurfaceVtkMapper3D->SetTextureHeight(this->m_VideoCaptureHeight); } m_MultiWidget->DisableGradientBackground(); } catch (std::logic_error& e) { QMessageBox::warning(NULL, "Warning", QString(e.what())); MITK_ERROR << e.what(); return; } mitk::RenderingManager::GetInstance()->ForceImmediateUpdateAll(); } void QmitkToFUtilView::OnToFCameraDisconnected() { m_Controls->m_ToFRecorderWidget->OnStop(); m_Controls->m_ToFRecorderWidget->setEnabled(false); m_Controls->m_ToFVisualisationSettingsWidget->setEnabled(false); if(this->m_VideoSource) { this->m_VideoSource->StopCapturing(); this->m_VideoSource = NULL; } mitk::RenderingManager::GetInstance()->ForceImmediateUpdateAll(); } void QmitkToFUtilView::OnToFCameraStarted() { if (m_ToFImageGrabber.IsNotNull()) { // initial update of image grabber this->m_ToFImageGrabber->Update(); this->m_ToFCompositeFilter->SetInput(0,this->m_ToFImageGrabber->GetOutput(0)); this->m_ToFCompositeFilter->SetInput(1,this->m_ToFImageGrabber->GetOutput(1)); this->m_ToFCompositeFilter->SetInput(2,this->m_ToFImageGrabber->GetOutput(2)); // initial update of composite filter this->m_ToFCompositeFilter->Update(); this->m_MitkDistanceImage = m_ToFCompositeFilter->GetOutput(0); this->m_DistanceImageNode = ReplaceNodeData("Distance image",m_MitkDistanceImage); this->m_MitkAmplitudeImage = m_ToFCompositeFilter->GetOutput(1); this->m_AmplitudeImageNode = ReplaceNodeData("Amplitude image",m_MitkAmplitudeImage); this->m_MitkIntensityImage = m_ToFCompositeFilter->GetOutput(2); this->m_IntensityImageNode = ReplaceNodeData("Intensity image",m_MitkIntensityImage); this->m_ToFDistanceImageToSurfaceFilter->SetInput(0,m_MitkDistanceImage); this->m_ToFDistanceImageToSurfaceFilter->SetInput(1,m_MitkAmplitudeImage); this->m_ToFDistanceImageToSurfaceFilter->SetInput(2,m_MitkIntensityImage); this->m_Surface = this->m_ToFDistanceImageToSurfaceFilter->GetOutput(0); this->m_SurfaceNode = ReplaceNodeData("Surface",m_Surface); this->UseToFVisibilitySettings(true); this->m_Frametimer->start(0); m_Controls->m_ToFCompositeFilterWidget->UpdateFilterParameter(); // initialize visualization widget m_Controls->m_ToFVisualisationSettingsWidget->Initialize(this->m_MitkDistanceImage, this->m_MitkAmplitudeImage, this->m_MitkIntensityImage); if (m_Controls->m_TextureCheckBox->isChecked()) { OnTextureCheckBoxChecked(true); } if (m_Controls->m_VideoTextureCheckBox->isChecked()) { OnVideoTextureCheckBoxChecked(true); } } m_Controls->m_TextureCheckBox->setEnabled(true); // initialize point set measurement m_Controls->tofMeasurementWidget->InitializeWidget(m_MultiWidget,this->GetDefaultDataStorage(),m_MitkDistanceImage); } void QmitkToFUtilView::OnToFCameraStopped() { this->m_Frametimer->stop(); } void QmitkToFUtilView::OnToFCameraSelected(const QString selected) { if ((selected=="PMD CamBoard")||(selected=="PMD O3D")) { MITK_INFO<<"Surface representation currently not available for CamBoard and O3. Intrinsic parameters missing."; this->m_Controls->m_SurfaceCheckBox->setEnabled(false); this->m_Controls->m_TextureCheckBox->setEnabled(false); this->m_Controls->m_VideoTextureCheckBox->setEnabled(false); this->m_Controls->m_SurfaceCheckBox->setChecked(false); this->m_Controls->m_TextureCheckBox->setChecked(false); this->m_Controls->m_VideoTextureCheckBox->setChecked(false); } else { this->m_Controls->m_SurfaceCheckBox->setEnabled(true); this->m_Controls->m_TextureCheckBox->setEnabled(true); // TODO enable when bug 8106 is solved this->m_Controls->m_VideoTextureCheckBox->setEnabled(true); } } void QmitkToFUtilView::OnUpdateCamera() { if (m_Controls->m_VideoTextureCheckBox->isChecked() && this->m_VideoEnabled && this->m_VideoSource) { this->m_VideoTexture = this->m_VideoSource->GetVideoTexture(); ProcessVideoTransform(); } vtkColorTransferFunction* colorTransferFunction1; colorTransferFunction1 = m_Controls->m_ToFVisualisationSettingsWidget->GetWidget1ColorTransferFunction(); mitk::TransferFunction::Pointer tf1 = mitk::TransferFunction::New(); tf1->SetColorTransferFunction( colorTransferFunction1 ); m_DistanceImageNode->SetProperty("Image Rendering.Transfer Function",mitk::TransferFunctionProperty::New(tf1)); vtkColorTransferFunction* colorTransferFunction2; colorTransferFunction2 = m_Controls->m_ToFVisualisationSettingsWidget->GetWidget2ColorTransferFunction(); mitk::TransferFunction::Pointer tf2 = mitk::TransferFunction::New(); tf2->SetColorTransferFunction( colorTransferFunction2 ); m_AmplitudeImageNode->SetProperty("Image Rendering.Transfer Function",mitk::TransferFunctionProperty::New(tf2)); vtkColorTransferFunction* colorTransferFunction3; colorTransferFunction3 = m_Controls->m_ToFVisualisationSettingsWidget->GetWidget3ColorTransferFunction(); mitk::TransferFunction::Pointer tf3 = mitk::TransferFunction::New(); tf3->SetColorTransferFunction( colorTransferFunction3 ); m_IntensityImageNode->SetProperty("Image Rendering.Transfer Function",mitk::TransferFunctionProperty::New(tf3)); if (m_Controls->m_SurfaceCheckBox->isChecked()) { // update surface m_ToFDistanceImageToSurfaceFilter->SetTextureIndex(m_Controls->m_ToFVisualisationSettingsWidget->GetSelectedImageIndex()); this->m_Surface->Update(); vtkColorTransferFunction* colorTransferFunction = m_Controls->m_ToFVisualisationSettingsWidget->GetSelectedColorTransferFunction(); this->m_ToFSurfaceVtkMapper3D->SetVtkScalarsToColors(colorTransferFunction); if (this->m_SurfaceDisplayCount<2) { this->m_SurfaceNode->SetData(this->m_Surface); this->m_SurfaceNode->SetMapper(mitk::BaseRenderer::Standard3D, m_ToFSurfaceVtkMapper3D); mitk::RenderingManager::GetInstance()->InitializeViews( this->m_Surface->GetTimeSlicedGeometry(), mitk::RenderingManager::REQUEST_UPDATE_3DWINDOWS, true); mitk::Point3D surfaceCenter= this->m_Surface->GetGeometry()->GetCenter(); m_MultiWidget->mitkWidget4->GetRenderer()->GetVtkRenderer()->GetActiveCamera()->SetPosition(0,0,-50); m_MultiWidget->mitkWidget4->GetRenderer()->GetVtkRenderer()->GetActiveCamera()->SetViewUp(0,-1,0); m_MultiWidget->mitkWidget4->GetRenderer()->GetVtkRenderer()->GetActiveCamera()->SetFocalPoint(0,0,surfaceCenter[2]); m_MultiWidget->mitkWidget4->GetRenderer()->GetVtkRenderer()->GetActiveCamera()->SetViewAngle(40); m_MultiWidget->mitkWidget4->GetRenderer()->GetVtkRenderer()->GetActiveCamera()->SetClippingRange(1, 10000); } this->m_SurfaceDisplayCount++; } else { - // update pipeline - this->m_MitkDistanceImage->Update(); + // update pipeline + m_UpdateMutex->lock(); + this->m_MitkDistanceImage->Update(); + m_UpdateMutex->unlock(); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); this->m_2DDisplayCount++; if ((this->m_2DDisplayCount % this->m_StepsForFramerate) == 0) { this->m_2DTimeAfter = this->m_RealTimeClock->GetCurrentStamp() - this->m_2DTimeBefore; MITK_INFO << " 2D-Display-framerate (fps): " << this->m_StepsForFramerate / (this->m_2DTimeAfter/1000); this->m_2DTimeBefore = this->m_RealTimeClock->GetCurrentStamp(); } } void QmitkToFUtilView::ProcessVideoTransform() { IplImage *src, *dst; src = cvCreateImageHeader(cvSize(this->m_VideoCaptureWidth, this->m_VideoCaptureHeight), IPL_DEPTH_8U, 3); src->imageData = (char*)this->m_VideoTexture; CvPoint2D32f srcTri[3], dstTri[3]; CvMat* rot_mat = cvCreateMat(2,3,CV_32FC1); CvMat* warp_mat = cvCreateMat(2,3,CV_32FC1); dst = cvCloneImage(src); dst->origin = src->origin; cvZero( dst ); int xOffset = 0;//m_Controls->m_XOffsetSpinBox->value(); int yOffset = 0;//m_Controls->m_YOffsetSpinBox->value(); int zoom = 0;//m_Controls->m_ZoomSpinBox->value(); // Compute warp matrix srcTri[0].x = 0 + zoom; srcTri[0].y = 0 + zoom; srcTri[1].x = src->width - 1 - zoom; srcTri[1].y = 0 + zoom; srcTri[2].x = 0 + zoom; srcTri[2].y = src->height - 1 - zoom; dstTri[0].x = 0; dstTri[0].y = 0; dstTri[1].x = src->width - 1; dstTri[1].y = 0; dstTri[2].x = 0; dstTri[2].y = src->height - 1; cvGetAffineTransform( srcTri, dstTri, warp_mat ); cvWarpAffine( src, dst, warp_mat ); cvCopy ( dst, src ); // Compute warp matrix srcTri[0].x = 0; srcTri[0].y = 0; srcTri[1].x = src->width - 1; srcTri[1].y = 0; srcTri[2].x = 0; srcTri[2].y = src->height - 1; dstTri[0].x = srcTri[0].x + xOffset; dstTri[0].y = srcTri[0].y + yOffset; dstTri[1].x = srcTri[1].x + xOffset; dstTri[1].y = srcTri[1].y + yOffset; dstTri[2].x = srcTri[2].x + xOffset; dstTri[2].y = srcTri[2].y + yOffset; cvGetAffineTransform( srcTri, dstTri, warp_mat ); cvWarpAffine( src, dst, warp_mat ); cvCopy ( dst, src ); src->imageData = NULL; cvReleaseImage( &src ); cvReleaseImage( &dst ); cvReleaseMat( &rot_mat ); cvReleaseMat( &warp_mat ); } void QmitkToFUtilView::OnTextureCheckBoxChecked(bool checked) { if(m_SurfaceNode.IsNotNull()) { if (checked) { this->m_SurfaceNode->SetBoolProperty("scalar visibility", true); } else { this->m_SurfaceNode->SetBoolProperty("scalar visibility", false); } } } void QmitkToFUtilView::OnVideoTextureCheckBoxChecked(bool checked) { if (checked) { if (this->m_VideoEnabled) { this->m_ToFSurfaceVtkMapper3D->SetTexture(this->m_VideoTexture); } else { this->m_ToFSurfaceVtkMapper3D->SetTexture(NULL); } } else { this->m_ToFSurfaceVtkMapper3D->SetTexture(NULL); } } mitk::DataNode::Pointer QmitkToFUtilView::ReplaceNodeData( std::string nodeName, mitk::BaseData* data ) { mitk::DataNode::Pointer node = this->GetDefaultDataStorage()->GetNamedNode(nodeName); if (node.IsNull()) { node = mitk::DataNode::New(); node->SetData(data); node->SetName(nodeName); this->GetDefaultDataStorage()->Add(node); } else { node->SetData(data); } return node; } void QmitkToFUtilView::UseToFVisibilitySettings(bool useToF) { // set node properties if (m_DistanceImageNode.IsNotNull()) { this->m_DistanceImageNode->SetProperty( "visible" , mitk::BoolProperty::New( true )); this->m_DistanceImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetActiveStdMultiWidget()->mitkWidget2->GetRenderWindow() ) ); this->m_DistanceImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetActiveStdMultiWidget()->mitkWidget3->GetRenderWindow() ) ); this->m_DistanceImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetActiveStdMultiWidget()->mitkWidget4->GetRenderWindow() ) ); this->m_DistanceImageNode->SetBoolProperty("use color",!useToF); this->m_DistanceImageNode->GetPropertyList()->DeleteProperty("LookupTable"); } if (m_AmplitudeImageNode.IsNotNull()) { this->m_AmplitudeImageNode->SetProperty( "visible" , mitk::BoolProperty::New( true )); this->m_AmplitudeImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetActiveStdMultiWidget()->mitkWidget1->GetRenderWindow() ) ); this->m_AmplitudeImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetActiveStdMultiWidget()->mitkWidget3->GetRenderWindow() ) ); this->m_AmplitudeImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetActiveStdMultiWidget()->mitkWidget4->GetRenderWindow() ) ); this->m_AmplitudeImageNode->SetBoolProperty("use color",!useToF); this->m_AmplitudeImageNode->GetPropertyList()->DeleteProperty("LookupTable"); } if (m_IntensityImageNode.IsNotNull()) { this->m_IntensityImageNode->SetProperty( "visible" , mitk::BoolProperty::New( true )); this->m_IntensityImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetActiveStdMultiWidget()->mitkWidget1->GetRenderWindow() ) ); this->m_IntensityImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetActiveStdMultiWidget()->mitkWidget2->GetRenderWindow() ) ); this->m_IntensityImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetActiveStdMultiWidget()->mitkWidget4->GetRenderWindow() ) ); this->m_IntensityImageNode->SetBoolProperty("use color",!useToF); this->m_IntensityImageNode->GetPropertyList()->DeleteProperty("LookupTable"); } // initialize images if (m_MitkDistanceImage.IsNotNull()) { mitk::RenderingManager::GetInstance()->InitializeViews( this->m_MitkDistanceImage->GetTimeSlicedGeometry(), mitk::RenderingManager::REQUEST_UPDATE_2DWINDOWS, true); } } diff --git a/Plugins/org.mitk.gui.qt.tofutil/src/internal/QmitkToFUtilView.h b/Plugins/org.mitk.gui.qt.tofutil/src/internal/QmitkToFUtilView.h index fde34de736..c8dd7737da 100644 --- a/Plugins/org.mitk.gui.qt.tofutil/src/internal/QmitkToFUtilView.h +++ b/Plugins/org.mitk.gui.qt.tofutil/src/internal/QmitkToFUtilView.h @@ -1,169 +1,172 @@ /*=================================================================== 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 QmitkToFUtilView_h #define QmitkToFUtilView_h #include #include #include #include +#include #include #include #include #include #include #include #include #include /*! \brief QmitkToFUtilView Application that allows simple playing, recording, visualization, processing and measurement of Time-of-Flight (ToF) data. Currently the following features are implemented:
  • Connecting and showing ToF data from various cameras (PMD CamCube 2/3, PMD CamBoard, PMD O3, MESA SwissRanger)
  • Recording and playing of ToF data
  • Color coded visualization of ToF images
  • Preprocessing of the distance data: Threshold, median, average and bilateral filtering; surface generation
  • Simple measurement and PointSet definition
\sa QmitkFunctionality \ingroup Functionalities */ class QmitkToFUtilView : public QmitkFunctionality { // this is needed for all Qt objects that should have a Qt meta-object // (everything that derives from QObject and wants to have signal/slots) Q_OBJECT public: static const std::string VIEW_ID; QmitkToFUtilView(); ~QmitkToFUtilView(); virtual void CreateQtPartControl(QWidget *parent); /// \brief Called when the functionality is activated virtual void Activated(); /// \brief Called when the functionality is deactivated virtual void Deactivated(); virtual void StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget); virtual void StdMultiWidgetNotAvailable(); protected slots: /*! \brief Slot triggered from the timer to update the images and visualization */ void OnUpdateCamera(); /*! \brief Slot called when the "Connect" button of the ConnectionWidget is pressed */ void OnToFCameraConnected(); /*! \brief Slot called when the "Disconnect" button of the ConnectionWidget is pressed */ void OnToFCameraDisconnected(); /*! \brief Slot called when the camera selection in the ConnectionWidget has changed */ void OnToFCameraSelected(const QString selected); /*! \brief Slot called when the "Start" button of the RecorderWidget is pressed */ void OnToFCameraStarted(); /*! \brief Slot called when the "Stop" button of the RecorderWidget is pressed */ void OnToFCameraStopped(); /*! \brief Slot invoked when the texture checkbox is checked. Enables the scalar visibility of the surface */ void OnTextureCheckBoxChecked(bool checked); /*! \brief Slot invoked when the video texture checkbox is checked. Enables the texture of the surface */ void OnVideoTextureCheckBoxChecked(bool checked); protected: /*! \brief initialize the visibility settings of ToF data (images + surface) \param useToF true: distance image: widget1, amplitude image: widget 2, intensity image: widget 3; false: standard */ void UseToFVisibilitySettings(bool useToF); Ui::QmitkToFUtilViewControls* m_Controls; QmitkStdMultiWidget* m_MultiWidget; QTimer* m_Frametimer; ///< Timer used to continuously update the images mitk::Image::Pointer m_MitkDistanceImage; ///< member holding a pointer to the distance image of the selected camera mitk::Image::Pointer m_MitkAmplitudeImage; ///< member holding a pointer to the amplitude image of the selected camera mitk::Image::Pointer m_MitkIntensityImage; ///< member holding a pointer to the intensity image of the selected camera mitk::Surface::Pointer m_Surface; ///< member holding a pointer to the surface generated from the distance image of the selected camera mitk::DataNode::Pointer m_DistanceImageNode; ///< DataNode holding the distance image of the selected camera mitk::DataNode::Pointer m_AmplitudeImageNode; ///< DataNode holding the amplitude image of the selected camera mitk::DataNode::Pointer m_IntensityImageNode; ///< DataNode holding the intensity image of the selected camera mitk::DataNode::Pointer m_SurfaceNode; ///< DataNode holding the surface generated from the distanc image of the selected camera // ToF processing and recording filter mitk::ToFImageRecorder::Pointer m_ToFImageRecorder; ///< ToF image recorder used for lossless recording of ToF image data mitk::ToFImageGrabber::Pointer m_ToFImageGrabber; ///< Source of a ToF image processing pipeline. Provides pointers to distance, amplitude and intensity image mitk::ToFDistanceImageToSurfaceFilter::Pointer m_ToFDistanceImageToSurfaceFilter; ///< Filter for calculating a surface representation from a given distance image mitk::ToFCompositeFilter::Pointer m_ToFCompositeFilter; ///< Filter combining several processing steps (thresholding, Median filtering, Bilateral filtering) int m_SurfaceDisplayCount; ///< member used to determine whether surface is initialized or not int m_2DDisplayCount; ///< member used to determine whether frame rate output should be shown // members for calculating the frame rate mitk::RealTimeClock::Pointer m_RealTimeClock; ///< real time clock used to calculate the display framerate int m_StepsForFramerate; ///< number of steps used for calculating the display framerate double m_2DTimeBefore; ///< holds the time stamp at the beginning of the display framerate measurement double m_2DTimeAfter; ///< holds the time stamp at the end of the display framerate measurement // members used for displaying an external video source mitk::OpenCVVideoSource::Pointer m_VideoSource; ///< OpenCV video source to connect a video device unsigned char* m_VideoTexture; ///< texture used to show video image int m_VideoCaptureWidth; ///< width of the video image int m_VideoCaptureHeight; ///< height of the video image bool m_VideoEnabled; ///< flag indicating whether video grabbing is enabled. Set via the RGB texture checkbox private: /*! \brief helper method to replace data of the specified node. If node does not exist it will be created \param nodeName Name of the node \param data Data object to be replaced \return returns the node */ mitk::DataNode::Pointer ReplaceNodeData(std::string nodeName, mitk::BaseData* data); void ProcessVideoTransform(); mitk::ToFSurfaceVtkMapper3D::Pointer m_ToFSurfaceVtkMapper3D; + + QMutex* m_UpdateMutex; }; #endif // _QMITKTOFUTILVIEW_H_INCLUDED