diff --git a/Modules/ModelFit/autoload/IO/mitkModelFitIOActivator.cpp b/Modules/ModelFit/autoload/IO/mitkModelFitIOActivator.cpp index 9ce16f6958..7996edc836 100644 --- a/Modules/ModelFit/autoload/IO/mitkModelFitIOActivator.cpp +++ b/Modules/ModelFit/autoload/IO/mitkModelFitIOActivator.cpp @@ -1,100 +1,101 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include #include #include #include #include #include #include namespace mitk { /* * This is the module activator for the IO aspects of the "ModelFit" module. */ class ModelFitIOActivator : public us::ModuleActivator { public: void registerProperty(const std::string& name, const std::string& key, const std::string& description) { mitk::CoreServicePointer propDescService(mitk::CoreServices::GetPropertyDescriptions()); propDescService->AddDescription(name, description); mitk::PropertyPersistenceInfo::Pointer ppi = mitk::PropertyPersistenceInfo::New(); ppi->SetNameAndKey(name, key); mitk::CoreServicePointer propPersistenceService(mitk::CoreServices::GetPropertyPersistence()); propPersistenceService->AddInfo(ppi, true); } void registerProperty(const std::string& name, const std::string& key, const std::string& description, const PropertyPersistenceInfo::DeserializationFunctionType &deFnc, const PropertyPersistenceInfo::SerializationFunctionType &serFnc) { mitk::CoreServicePointer propDescService(mitk::CoreServices::GetPropertyDescriptions()); propDescService->AddDescription(name, description); mitk::PropertyPersistenceInfo::Pointer ppi = mitk::PropertyPersistenceInfo::New(); ppi->SetNameAndKey(name, key); ppi->SetDeserializationFunction(deFnc); ppi->SetSerializationFunction(serFnc); mitk::CoreServicePointer propPersistenceService(mitk::CoreServices::GetPropertyPersistence()); propPersistenceService->AddInfo(ppi, true); } void Load(us::ModuleContext* /*context*/) override { //register relevant properties - registerProperty(mitk::ModelFitConstants::UID_PROPERTY_NAME(), "data_uid", "UID used to identify data in an MITK session."); - registerProperty(mitk::ModelFitConstants::INPUT_VARIABLES_PROPERTY_NAME(), "modelfit_input_variables", "Array of input variables used in/for a model fit.", PropertyPersistenceDeserialization::deserializeXMLToScalarListLookupTableProperty, PropertyPersistenceSerialization::serializeScalarListLookupTablePropertyToXML); registerProperty(mitk::ModelFitConstants::PARAMETER_NAME_PROPERTY_NAME(), "modelfit_parameter_name", "Name of the parameter, that is represented by the data and how it is used in the function string (modelfit.model.function)."); registerProperty(mitk::ModelFitConstants::PARAMETER_UNIT_PROPERTY_NAME(), "modelfit_parameter_unit", "Unit string of the Parameter. Is only used for display. Default value: \"\" (no unit)"); registerProperty(mitk::ModelFitConstants::PARAMETER_SCALE_PROPERTY_NAME(), "modelfit_parameter_scale", "Scaling of the parameter. Default value: 1."); registerProperty(mitk::ModelFitConstants::PARAMETER_TYPE_PROPERTY_NAME(), "modelfit_parameter_type", "Type of the parameters. Default value: parameter. Other options: derived, criterion, evaluation."); registerProperty(mitk::ModelFitConstants::MODEL_TYPE_PROPERTY_NAME(), "modelfit_model_type", "Value specifies the type of model (helpfull for classification; e.g. MR perfusion)"); registerProperty(mitk::ModelFitConstants::MODEL_NAME_PROPERTY_NAME(), "modelfit_model_name", "Name of the specific fit. Only used for display."); registerProperty(mitk::ModelFitConstants::MODEL_FUNCTION_PROPERTY_NAME(), "modelfit_model_function", "Function string, that specifies the model and will be parsed, to plot the curves based on the parameter. Optional parameter that must not be set."); registerProperty(mitk::ModelFitConstants::MODEL_FUNCTION_CLASS_PROPERTY_NAME(), "modelfit_model_functionClass", "ID of the model class implementation."); registerProperty(mitk::ModelFitConstants::MODEL_X_PROPERTY_NAME(), "modelfit_model_x", "Name of the forumar parameter 'x', that is specified on the x axis. Only needed if model function string is set and formular must be parsed."); registerProperty(mitk::ModelFitConstants::XAXIS_NAME_PROPERTY_NAME(), "modelfit_xaxis_name", "Display name of the x axis."); registerProperty(mitk::ModelFitConstants::XAXIS_UNIT_PROPERTY_NAME(), "modelfit_xaxis_unit", "Unit of the x axis."); registerProperty(mitk::ModelFitConstants::YAXIS_NAME_PROPERTY_NAME(), "modelfit_yaxis_name", "Display name of the y axis."); registerProperty(mitk::ModelFitConstants::YAXIS_UNIT_PROPERTY_NAME(), "modelfit_yaxis_unit", "Unit of the y axis."); registerProperty(mitk::ModelFitConstants::FIT_UID_PROPERTY_NAME(), "modelfit_fit_uid", "UID of the fit."); registerProperty(mitk::ModelFitConstants::FIT_NAME_PROPERTY_NAME(), "modelfit_fit_name", "Human readable name for the fit."); registerProperty(mitk::ModelFitConstants::FIT_TYPE_PROPERTY_NAME(), "modelfit_fit_type", "Type of the fit (e.g. ROI based or pixel based)."); - registerProperty(mitk::ModelFitConstants::FIT_INPUT_IMAGEUID_PROPERTY_NAME(), "modelfit_fit_input_imageUID", "UID of the input image that used to fit the model."); registerProperty(mitk::ModelFitConstants::FIT_INPUT_ROIUID_PROPERTY_NAME(), "modelfit_fit_input_roiUID", "UID of the ROI used for the fit."); registerProperty(mitk::ModelFitConstants::FIT_INPUT_DATA_PROPERTY_NAME(), "modelfit_fit_input_data", "Property containing input data directly stored in the fit information."); registerProperty(mitk::ModelFitConstants::FIT_STATIC_PARAMETERS_PROPERTY_NAME(), "modelfit_fit_staticParameters", "Property containing static parameters used for the fit.", PropertyPersistenceDeserialization::deserializeXMLToScalarListLookupTableProperty, PropertyPersistenceSerialization::serializeScalarListLookupTablePropertyToXML); + + //legacy properties for backwards compatibility + registerProperty(mitk::ModelFitConstants::LEGACY_UID_PROPERTY_NAME(), "data_uid", "UID used to identify data in an MITK session."); + registerProperty(mitk::ModelFitConstants::LEGACY_FIT_INPUT_IMAGEUID_PROPERTY_NAME(), "modelfit_fit_input_imageUID", "UID of the input image that used to fit the model."); } void Unload(us::ModuleContext* ) override { } private: }; } US_EXPORT_MODULE_ACTIVATOR(mitk::ModelFitIOActivator) diff --git a/Modules/ModelFit/files.cmake b/Modules/ModelFit/files.cmake index 40d7ada4fc..85f16dc618 100644 --- a/Modules/ModelFit/files.cmake +++ b/Modules/ModelFit/files.cmake @@ -1,76 +1,76 @@ file(GLOB_RECURSE H_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/include/*") set(CPP_FILES Common/mitkExtractTimeGrid.cpp Common/mitkTimeGridHelper.cpp Common/mitkMaskedDynamicImageStatisticsGenerator.cpp Common/mitkModelFitConstants.cpp Common/mitkModelFitParameter.cpp Common/mitkModelFitCmdAppsHelper.cpp Common/mitkParameterFitImageGeneratorBase.cpp Common/mitkPixelBasedParameterFitImageGenerator.cpp Common/mitkROIBasedParameterFitImageGenerator.cpp Common/mitkModelFitInfo.cpp Common/mitkModelFitStaticParameterMap.cpp Common/mitkModelGenerator.cpp - Common/mitkModelFitUIDHelper.cpp Common/mitkModelFitResultHelper.cpp Common/mitkScalarListLookupTable.cpp Common/mitkScalarListLookupTableProperty.cpp Common/mitkScalarListLookupTablePropertySerializer.cpp Common/mitkIModelFitProvider.cpp Common/mitkModelFitParameterValueExtraction.cpp Common/mitkBinaryImageToLabelSetImageFilter.cpp Common/mitkFormulaParser.cpp Common/mitkFresnel.cpp Common/mitkModelFitPlotDataHelper.cpp Common/mitkModelSignalImageGenerator.cpp + Common/mitkModelFitResultRelationRule.cpp Functors/mitkSimpleFunctorBase.cpp Functors/mitkSimpleFunctorPolicy.cpp Functors/mitkChiSquareFitCostFunction.cpp Functors/mitkReducedChiSquareFitCostFunction.cpp Functors/mitkConstraintCheckerBase.cpp Functors/mitkSimpleBarrierConstraintChecker.cpp Functors/mitkSquaredDifferencesFitCostFunction.cpp Functors/mitkSumOfSquaredDifferencesFitCostFunction.cpp Functors/mitkMVConstrainedCostFunctionDecorator.cpp Functors/mitkMVModelFitCostFunction.cpp Functors/mitkNormalizedSumOfSquaredDifferencesFitCostFunction.cpp Functors/mitkSVModelFitCostFunction.cpp Functors/mitkModelFitFunctorBase.cpp Functors/mitkLevenbergMarquardtModelFitFunctor.cpp Functors/mitkDummyModelFitFunctor.cpp Functors/mitkModelFitInfoSignalGenerationFunctor.cpp Functors/mitkIndexedValueFunctorPolicy.cpp Functors/mitkModelDataGenerationFunctor.cpp Models/mitkModelBase.cpp Models/mitkModelFactoryBase.cpp Models/mitkModelParameterizerBase.cpp Models/mitkLinearModel.cpp Models/mitkLinearModelFactory.cpp Models/mitkInitialParameterizationDelegateBase.cpp Models/mitkImageBasedParameterizationDelegate.cpp Models/mitkGenericParamModel.cpp Models/mitkGenericParamModelFactory.cpp Models/mitkGenericParamModelParameterizer.cpp Models/mitkValueBasedParameterizationDelegate.cpp Models/mitkT2DecayModel.cpp Models/mitkT2DecayModelFactory.cpp Models/mitkT2DecayModelParameterizer.cpp TestingHelper/mitkTestModel.cpp TestingHelper/mitkTestModelFactory.cpp ) set(TPP_FILES include/itkMultiOutputNaryFunctorImageFilter.tpp include/itkMaskedStatisticsImageFilter.hxx include/itkMaskedNaryStatisticsImageFilter.hxx include/mitkModelFitProviderBase.tpp ) set(HXX_FILES ) set(MOC_H_FILES ) diff --git a/Modules/ModelFit/include/mitkModelFitConstants.h b/Modules/ModelFit/include/mitkModelFitConstants.h index cd46c07776..c211bb51b7 100644 --- a/Modules/ModelFit/include/mitkModelFitConstants.h +++ b/Modules/ModelFit/include/mitkModelFitConstants.h @@ -1,197 +1,202 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef _MITK_MODEL_FIT_CONSTANTS_H_ #define _MITK_MODEL_FIT_CONSTANTS_H_ #include #include "MitkModelFitExports.h" namespace mitk { struct MITKMODELFIT_EXPORT ModelFitConstants { /** * Name of the "root" property for all information concerning model fitting. */ static const std::string MODEL_FIT_PROPERTY_NAME(); - /** - * Name of the "uid" property for all data objects concerning model fitting. - */ - static const std::string UID_PROPERTY_NAME(); - /** * modelfit.input.variables ist eine Map der Variablennamen, die einem Eingabebild zu eigen sind und * unabhängig von einem Fit sind. * Deren Wert ist ein Array, welches die Variablenwerte für die einzelnen Zeitschritte enthält. * Die Länge eines solchen Arrays muss entweder der Anzahl der Zeitschritte dieses Bildes entsprechen * oder genau 1 sein, wenn der Wert für alle Zeitschritte dieses Bildes gleich ist. * Beispiele: * ["x1":[580], "x2":[3060], "x3":[41]] (1 Zeitschritt, 3 Variablen) * ["TE":[2.47, 5.85, 9.23, 12.61], "TI":[10.3]] (4 Zeitschritte, 2 Variablen) */ static const std::string INPUT_VARIABLES_PROPERTY_NAME(); /** * modelfit.parameter.name ist der Bezeichner des Parameters, wie es im Funktions-String (modelfit.model.function) vorkommt. */ static const std::string PARAMETER_NAME_PROPERTY_NAME(); /** * modelfit.parameter.unit ist die Einheit des Parameters und dient nur der formatierten Ausgabe. Standardwert: "" */ static const std::string PARAMETER_UNIT_PROPERTY_NAME(); /** * modelfit.parameter.scale ist die Skalierung des Parameters. Standardwert: 1 */ static const std::string PARAMETER_SCALE_PROPERTY_NAME(); /** * modelfit.parameter.type ist der type des parameters. Standardwert: PARAMETER_TYPE_VALUE_PARAMETER */ static const std::string PARAMETER_TYPE_PROPERTY_NAME(); /** * modelfit.parameter.type Wert für normale Parameters. */ static const std::string PARAMETER_TYPE_VALUE_PARAMETER(); /** * modelfit.parameter.type Wert für derived Parameters. */ static const std::string PARAMETER_TYPE_VALUE_DERIVED_PARAMETER(); /** * modelfit.parameter.type Wert für Crtierion-Parameters. */ static const std::string PARAMETER_TYPE_VALUE_CRITERION(); /** * modelfit.parameter.type Wert für Evaluation-Parameters. */ static const std::string PARAMETER_TYPE_VALUE_EVALUATION_PARAMETER(); /** * modelfit.model.type ist der Bezeichner des Modelltyps und dient nur der formatierten Ausgabe */ static const std::string MODEL_TYPE_PROPERTY_NAME(); /** * modelfit.model.name ist der Bezeichner des Fits und dient nur der formatierten Ausgabe. */ static const std::string MODEL_NAME_PROPERTY_NAME(); /** * modelfit.model.function ist der Funktions-String, der geparsed wird, um die Kurve zu plotten. */ static const std::string MODEL_FUNCTION_PROPERTY_NAME(); /** * modelfit.model.functionClass ist die ID der Modellklasse. */ static const std::string MODEL_FUNCTION_CLASS_PROPERTY_NAME(); /** * modelfit.model.x ist der Name der Variable, die die x-Werte stellt, wie sie im Funktions-String vorkommt. Wird nur gebraucht wenn modelfit.model.function definiert ist. */ static const std::string MODEL_X_PROPERTY_NAME(); /** * Default value for MODEL_X_PROPERTY_NAME. */ static const std::string MODEL_X_VALUE_DEFAULT(); /** * modelfit.xaxis.name ist der Bezeichner der x-Achse und dient nur der formatierten Ausgabe. Standardwert: "Time" */ static const std::string XAXIS_NAME_PROPERTY_NAME(); /** * Default value for XAXIS_NAME_PROPERTY_NAME. */ static const std::string XAXIS_NAME_VALUE_DEFAULT(); /** * modelfit.xaxis.unit ist die Einheit der x-Achse und dient nur der formatierten Ausgabe. Standardwert: "ms" */ static const std::string XAXIS_UNIT_PROPERTY_NAME(); /** * modelfit.xaxis.name ist der Bezeichner der x-Achse und dient nur der formatierten Ausgabe. Standardwert: "Intensity" */ static const std::string YAXIS_NAME_PROPERTY_NAME(); /** * Default value for YAXIS_NAME_PROPERTY_NAME. */ static const std::string YAXIS_NAME_VALUE_DEFAULT(); /** * modelfit.xaxis.unit ist die Einheit der x-Achse und dient nur der formatierten Ausgabe. Standardwert: "" */ static const std::string YAXIS_UNIT_PROPERTY_NAME(); /** * modelfit.fit.uid ist eine einzigartige ID (unabhängig von Ausführungsrechner, Session oder Applikationsinstanz), * die einem Fit vergeben wird um alle zugehörigen Bilder eindeutig zu kennzeichnen. */ static const std::string FIT_UID_PROPERTY_NAME(); /** * modelfit.fit.name is the human readable name of the fit. Use UID, if you want a unique identifier. This is just * used for visualization purposes. */ static const std::string FIT_NAME_PROPERTY_NAME(); /** * modelfit.fit.type defines the type of model fitting; e.g. pixel based or ROI based. Thus it determines the meaning of other fit specific informations. */ static const std::string FIT_TYPE_PROPERTY_NAME(); static const std::string FIT_TYPE_VALUE_PIXELBASED(); - static const std::string FIT_TYPE_VALUE_ROIBASED(); - - /** - * modelfit.fit.input.imageUID defines the UID of the image that is used directly or indirectly (then it is source for input.data) to make the fit. - */ - static const std::string FIT_INPUT_IMAGEUID_PROPERTY_NAME(); + static const std::string FIT_TYPE_VALUE_ROIBASED(); /** * modelfit.fit.input.roiUID defines the UID of the ROI that is used to make the fit. If not set no Mask was used or specified. */ static const std::string FIT_INPUT_ROIUID_PROPERTY_NAME(); /** * modelfit.fit.input.data defines the data signal that is used to make the fit and was extracted from the input image (e.g. in ROIbased fit). */ static const std::string FIT_INPUT_DATA_PROPERTY_NAME(); /** * modelfit.fit.staticParameters ist eine Map der Variablennamen, die im Funktions-String vorkommen und * nicht mit modelfit.input.variables abgedeckt sind. Dies können z.B. Konstanten sein oder Variablen, * die sich (abhängig vom Fit) über den Zeitverlauf ändern, wie z.B. der Mittelwert einer Maske über einen Arterienquerschnitt. * (Entspricht den StaticParameters in mitk::ModelBase) * Der Wert der Variablen ist ein Array, welches die Variablenwerte enthält. * Beispiel: * ["AIF":[2, 8, 8, 4, 5], "tau":[0.42]] (insgesamt 5 Zeitschritte, 2 Variablen) */ static const std::string FIT_STATIC_PARAMETERS_PROPERTY_NAME(); + /** + * Name of the "uid" property for all data objects concerning model fitting. + * @remark This was also known as UID_PROPRTY_NAME(). It was renamed to indicate + * that is only kept for backwards compatibility. Model fit now uses the Identifiable + * interface of BaseData and the PropertyRelationRules to identify/find data. + */ + static const std::string LEGACY_UID_PROPERTY_NAME(); + + /** + * modelfit.fit.input.imageUID defines the UID of the image that is used directly or indirectly (then it is source for input.data) to make the fit. + * @remark This was also known as FIT_INPUT_IMAGEUID_PROPERTY_NAME(). It was renamed to indicate + * that is only kept for backwards compatibility. Model fit now uses the Identifiable + * interface of BaseData and the ModelFitResultRelationRule to identify/find the input data. + */ + static const std::string LEGACY_FIT_INPUT_IMAGEUID_PROPERTY_NAME(); }; } #endif diff --git a/Modules/ModelFit/include/mitkModelFitInfo.h b/Modules/ModelFit/include/mitkModelFitInfo.h index 8189181357..fd88278c91 100644 --- a/Modules/ModelFit/include/mitkModelFitInfo.h +++ b/Modules/ModelFit/include/mitkModelFitInfo.h @@ -1,202 +1,199 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef mitkModelFitInfo_h #define mitkModelFitInfo_h #include #include #include #include "mitkModelFitConstants.h" #include "mitkModelFitParameter.h" #include "mitkModelFitStaticParameterMap.h" #include "mitkScalarListLookupTable.h" -#include "mitkModelFitUIDHelper.h" #include "mitkModelParameterizerBase.h" #include "mitkModelTraitsInterface.h" #include "MitkModelFitExports.h" namespace mitk { namespace modelFit { /** * @brief Data class that stores all information about a modelfit that is relevant to the * visualization and stored as properties in the result nodes. */ class MITKMODELFIT_EXPORT ModelFitInfo : public itk::LightObject { public: - typedef mitk::NodeUIDType UIDType; + typedef std::string UIDType; typedef std::vector ParamListType; typedef ParamListType::const_iterator ConstIterType; mitkClassMacroItkParent(ModelFitInfo, itk::LightObject); itkSimpleNewMacro(ModelFitInfo); ModelFitInfo() : x(mitk::ModelFitConstants::MODEL_X_VALUE_DEFAULT()), xAxisName(mitk::ModelFitConstants::XAXIS_NAME_VALUE_DEFAULT()), yAxisName(mitk::ModelFitConstants::YAXIS_NAME_VALUE_DEFAULT()) { } /** * @brief Adds the given parameter to this fit's parameter list if it doesn't * exist already. * @param p The param that should be added to this fit's parameter list. */ void AddParameter(Parameter::Pointer p); /** * @brief Searches for the parameter with the given name and type in the fit's * parameter list and returns it. * @param name The name of the desired parameter. * @param type The type of the desired parameter. * @return The parameter with the given name on success or NULL otherwise. */ Parameter::ConstPointer GetParameter(const std::string& name, const Parameter::Type& type) const; /** * @brief Searches for the parameter with the given name and type in the fit's * parameter list and deletes it if it exists. * @param name The name of the desired parameter. * @param type The type of the desired parameter. */ void DeleteParameter(const std::string& name, const Parameter::Type& type); /**Return const reference to the parameter list.*/ const ParamListType& GetParameters() const; /** ModelFitConstants::MODEL_NAME_PROPERTY_NAME */ std::string modelName; /** ModelFitConstants::MODEL_TYPE_PROPERTY_NAME */ std::string modelType; /** ModelFitConstants::MODEL_FUNCTION_PROPERTY_NAME */ std::string function; /** ModelFitConstants::MODEL_FUNCTION_CLASS_PROPERTY_NAME */ std::string functionClassID; /** ModelFitConstants::MODEL_X_PROPERTY_NAME */ std::string x; /** ModelFitConstants::XAXIS_NAME_PROPERTY_NAME */ std::string xAxisName; /** ModelFitConstants::XAXIS_UNIT_PROPERTY_NAME */ std::string xAxisUnit; /** ModelFitConstants::YAXIS_NAME_PROPERTY_NAME */ std::string yAxisName; /** ModelFitConstants::YAXIS_UNIT_PROPERTY_NAME */ std::string yAxisUnit; /** ModelFitConstants::FIT_UID_PROPERTY_NAME */ UIDType uid; /** ModelFitConstants::FIT_NAME_PROPERTY_NAME */ std::string fitName; /** ModelFitConstants::FIT_TYPE_PROPERTY_NAME */ std::string fitType; /** ModelFitConstants::FIT_STATIC_PARAMETERS_PROPERTY_NAME */ StaticParameterMap staticParamMap; /** ModelFitConstants::FIT_INPUT_ROIUID_PROPERTY_NAME */ UIDType roiUID; - /** ModelFitConstants::FIT_INPUT_IMAGEUID_PROPERTY_NAME */ - UIDType inputUID; /** ModelFitConstants::FIT_INPUT_DATA_PROPERTY_NAME */ ScalarListLookupTable inputData; - mitk::Image::Pointer inputImage; + mitk::Image::ConstPointer inputImage; private: typedef ParamListType::iterator IterType; typedef itk::MutexLockHolder LockType; ParamListType parameterList; itk::SimpleFastMutexLock mutex; }; /** * @brief Reads the string property with the given name from the data of the given node * and returns its value. Throws a ModelFitException if the property doesn't exist. * @param node The node whose property value should be returned. * @param prop The name of the property that should be read. * @return The value of the found property. * @throw ModelFitException If the property doesn't exist or returns an empty string. */ MITKMODELFIT_EXPORT const std::string GetMandatoryProperty(const mitk::DataNode* node, const std::string& prop); /** * @brief Reads the string property with the given name from the given base data and * returns its value. Throws a ModelFitException if the property doesn't exist. * @param data The data whose property value should be returned. * @param prop The name of the property that should be read. * @return The value of the found property. * @throw ModelFitException If the property doesn't exist or returns an empty string. */ MITKMODELFIT_EXPORT const std::string GetMandatoryProperty(const mitk::BaseData* data, const std::string& prop); /** * @brief Creates a new ModelFitInfo instance from the nodes in the passed storage. * The fit will be identified by the passed UID. Returns the instance on * success. * @param uid The uid of the fit that should get its ModelFitInfo created and which identifies the nodes in the storage. * @param storage Pointer to the data storage containing any potential relevantThe nodes. * @return The newly created modelfit on success or NULL otherwise. */ MITKMODELFIT_EXPORT ModelFitInfo::Pointer CreateFitInfoFromNode(const ModelFitInfo::UIDType& uid, const mitk::DataStorage* storage); /** creates a new ModelFitInfo instance from a passed modal instance and his traits instance* * @param usedModel Pointer to a model which was used for a fit, which should get a fit info created. * @param modelTraits Pointer to traits interface for the model that was used for the fit. * @param inputImage Pointer to the input image. If it has no UID yet, a property will be added to the node. * @param fitType String identifying the type of the fit (e.g. ROI based or voxel based) * @param fitName Optional human readable name of the fit. * @param roiUID UID of the ROI, if one was used. * @return The newly created modelfit on success or NULL otherwise.*/ MITKMODELFIT_EXPORT ModelFitInfo::Pointer CreateFitInfoFromModelParameterizer( const ModelParameterizerBase* usedParameterizer, mitk::BaseData* inputImage, - const std::string& fitType, const std::string& fitName = "", const NodeUIDType roiUID = ""); + const std::string& fitType, const std::string& fitName = "", const ModelFitInfo::UIDType& roiUID = ""); /** @overload Overloaded version that allows additional definition of optional input data for the fit.*/ MITKMODELFIT_EXPORT ModelFitInfo::Pointer CreateFitInfoFromModelParameterizer( const ModelParameterizerBase* usedParameterizer, mitk::BaseData* inputImage, const std::string& fitType, const ScalarListLookupTable& inputData, const std::string& fitName = "", - const NodeUIDType roiUID = ""); + const ModelFitInfo::UIDType& roiUID = ""); /** Returns all nodes that belong to the fit indicated by the passed UID. * @param fitUID The uid of the fit that is relevant for the query. * @param storage Pointer to the data storage containing any potential relevant nodes. * @return The set of found nodes or null if storage is not valid. */ MITKMODELFIT_EXPORT DataStorage::SetOfObjects::ConstPointer GetNodesOfFit( const ModelFitInfo::UIDType& fitUID, const mitk::DataStorage* storage); typedef std::set NodeUIDSetType; /** Returns the UIDs of all fits that are derived (directly or indirectly from the passed node). * @param node The node which defines the parent node. It will be searched in his derived nodes for fits. * @param storage Pointer to the data storage containing any potential relevant nodes. * @return The set of found uid will be returned. */ MITKMODELFIT_EXPORT NodeUIDSetType GetFitUIDsOfNode(const mitk::DataNode* node, const mitk::DataStorage* storage); } } #endif // mitkModelFit_h diff --git a/Modules/ModelFit/include/mitkModelFitParameter.h b/Modules/ModelFit/include/mitkModelFitParameter.h index 14cf751133..e87b1845ae 100644 --- a/Modules/ModelFit/include/mitkModelFitParameter.h +++ b/Modules/ModelFit/include/mitkModelFitParameter.h @@ -1,66 +1,65 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef mitkModelFitParameter_h #define mitkModelFitParameter_h #include -#include "mitkModelFitUIDHelper.h" #include "MitkModelFitExports.h" namespace mitk { namespace modelFit { /** * @brief Data class that stores all information about a modelfit parameter. * Such a parameter is going to be fitted for the according model. */ class MITKMODELFIT_EXPORT Parameter : public itk::LightObject { public: mitkClassMacroItkParent(Parameter, itk::LightObject); itkSimpleNewMacro(Parameter); enum Type { ParameterType, DerivedType, CriterionType, EvaluationType }; Parameter(); /** ModelFitConstants::PARAMETER_NAME_PROPERTY_NAME */ std::string name; /** ModelFitConstants::PARAMETER_TYPE_PROPERTY_NAME */ Type type; /** ModelFitConstants::PARAMETER_UNIT_PROPERTY_NAME */ std::string unit; /** ModelFitConstants::PARAMETER_SCALE_PROPERTY_NAME */ float scale; /** Corresponding image */ mitk::Image::ConstPointer image; }; /** Extracts the parameter information stored in the data instance and returns it as parameter instance. * If the data does not encode an parameter/fit result a Null pointer will be returned. * @param data The data instance that contains parameter information that should be extracted. * @return The newly created parameter instance on success or NULL otherwise. */ MITKMODELFIT_EXPORT Parameter::Pointer ExtractParameterFromData(const mitk::BaseData* data); } } #endif // mitkModelFitParameter_h diff --git a/Modules/ModelFit/include/mitkModelFitUIDHelper.h b/Modules/ModelFit/include/mitkModelFitUIDHelper.h deleted file mode 100644 index d601844ca3..0000000000 --- a/Modules/ModelFit/include/mitkModelFitUIDHelper.h +++ /dev/null @@ -1,55 +0,0 @@ -/*============================================================================ - -The Medical Imaging Interaction Toolkit (MITK) - -Copyright (c) German Cancer Research Center (DKFZ) -All rights reserved. - -Use of this source code is governed by a 3-clause BSD license that can be -found in the LICENSE file. - -============================================================================*/ - - -#ifndef mitkModelFitUIDHelper_h -#define mitkModelFitUIDHelper_h - -#include - -//MITK -#include - -#include "MitkModelFitExports.h" - -namespace mitk -{ - class BaseData; - class DataStorage; - - typedef std::string NodeUIDType; - - /** Helper that searches for the node in the storage that has a data object with the given uid. Returns NULL if no node was found.*/ - DataNode::Pointer MITKMODELFIT_EXPORT GetNodeByModelFitUID(const mitk::DataStorage* storage, const NodeUIDType& uid); - - /** Gets the UID of the passed data. The UID is stored in the property "data.uid". If this property does not exist the method will - check the existance of a property for the DICOM tag series instance UID (0x0020, 0x000e) and return the value as UID. If this does also - not exist, a UID will generated, the property "data.uid" will be added with a new UID and the new UID will be returned. - @pre Passed data is a valid pointer.*/ - NodeUIDType MITKMODELFIT_EXPORT EnsureModelFitUID(mitk::BaseData* data); - /** Convinience function that calls the overloaded EnsureModelFitUID() with the data of the passed node. - @pre Passed node is a valid pointer.*/ - NodeUIDType MITKMODELFIT_EXPORT EnsureModelFitUID(mitk::DataNode* node); - - /** Helper that checks if the data has the passed UID. Following strategy will be used for the check. - 1. Checks existance of property "data.uid" and if its content equals the passed uid. - 2. If 1 fails, it checks the existance of a property for the DICOM tag series instance UID (0x0020, 0x000e) and the equality of its value. - 3. If 2 also fails, return will be false.*/ - bool MITKMODELFIT_EXPORT CheckModelFitUID(const mitk::BaseData* data, const NodeUIDType& uid); - /** Convinience helper function that calls the overloaded CheckModelFitUID() with the data of the passed node.*/ - bool MITKMODELFIT_EXPORT CheckModelFitUID(const mitk::DataNode* node, const NodeUIDType& uid); - - -} - -#endif - diff --git a/Modules/ModelFit/src/Common/mitkModelFitConstants.cpp b/Modules/ModelFit/src/Common/mitkModelFitConstants.cpp index df83f5463a..64a506c507 100644 --- a/Modules/ModelFit/src/Common/mitkModelFitConstants.cpp +++ b/Modules/ModelFit/src/Common/mitkModelFitConstants.cpp @@ -1,47 +1,47 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkModelFitConstants.h" const std::string mitk::ModelFitConstants::MODEL_FIT_PROPERTY_NAME() { return "modelfit";} -const std::string mitk::ModelFitConstants::UID_PROPERTY_NAME() { return "data.uid";} +const std::string mitk::ModelFitConstants::LEGACY_UID_PROPERTY_NAME() { return "data.uid";} const std::string mitk::ModelFitConstants::INPUT_VARIABLES_PROPERTY_NAME() { return "modelfit.input.variables";} const std::string mitk::ModelFitConstants::PARAMETER_NAME_PROPERTY_NAME() { return "modelfit.parameter.name";} const std::string mitk::ModelFitConstants::PARAMETER_TYPE_PROPERTY_NAME() { return "modelfit.parameter.type";} const std::string mitk::ModelFitConstants::PARAMETER_TYPE_VALUE_PARAMETER() { return "parameter";} const std::string mitk::ModelFitConstants::PARAMETER_TYPE_VALUE_DERIVED_PARAMETER() { return "derived";} const std::string mitk::ModelFitConstants::PARAMETER_TYPE_VALUE_CRITERION() { return "criterion";} const std::string mitk::ModelFitConstants::PARAMETER_TYPE_VALUE_EVALUATION_PARAMETER() { return "evaluation";} const std::string mitk::ModelFitConstants::PARAMETER_UNIT_PROPERTY_NAME() { return "modelfit.parameter.unit";} const std::string mitk::ModelFitConstants::PARAMETER_SCALE_PROPERTY_NAME() { return "modelfit.parameter.scale";} const std::string mitk::ModelFitConstants::MODEL_TYPE_PROPERTY_NAME() { return "modelfit.model.type";} const std::string mitk::ModelFitConstants::MODEL_NAME_PROPERTY_NAME() { return "modelfit.model.name";} const std::string mitk::ModelFitConstants::MODEL_FUNCTION_PROPERTY_NAME() { return "modelfit.model.function";} const std::string mitk::ModelFitConstants::MODEL_FUNCTION_CLASS_PROPERTY_NAME() { return "modelfit.model.functionClass";} const std::string mitk::ModelFitConstants::MODEL_X_PROPERTY_NAME() { return "modelfit.model.x";} const std::string mitk::ModelFitConstants::MODEL_X_VALUE_DEFAULT() { return "x";} const std::string mitk::ModelFitConstants::XAXIS_NAME_PROPERTY_NAME() { return "modelfit.xaxis.name";} const std::string mitk::ModelFitConstants::XAXIS_NAME_VALUE_DEFAULT() { return "Time";} const std::string mitk::ModelFitConstants::XAXIS_UNIT_PROPERTY_NAME() { return "modelfit.xaxis.unit";} const std::string mitk::ModelFitConstants::YAXIS_NAME_PROPERTY_NAME() { return "modelfit.yaxis.name";} const std::string mitk::ModelFitConstants::YAXIS_NAME_VALUE_DEFAULT() { return "Intensity";} const std::string mitk::ModelFitConstants::YAXIS_UNIT_PROPERTY_NAME() { return "modelfit.yaxis.unit";} const std::string mitk::ModelFitConstants::FIT_UID_PROPERTY_NAME() { return "modelfit.fit.uid"; } const std::string mitk::ModelFitConstants::FIT_NAME_PROPERTY_NAME() { return "modelfit.fit.name"; } const std::string mitk::ModelFitConstants::FIT_TYPE_PROPERTY_NAME() { return "modelfit.fit.type";} const std::string mitk::ModelFitConstants::FIT_TYPE_VALUE_PIXELBASED() { return "pixelbased";} const std::string mitk::ModelFitConstants::FIT_TYPE_VALUE_ROIBASED() { return "ROIbased";} -const std::string mitk::ModelFitConstants::FIT_INPUT_IMAGEUID_PROPERTY_NAME() { return "modelfit.fit.input.imageUID";} +const std::string mitk::ModelFitConstants::LEGACY_FIT_INPUT_IMAGEUID_PROPERTY_NAME() { return "modelfit.fit.input.imageUID";} const std::string mitk::ModelFitConstants::FIT_INPUT_ROIUID_PROPERTY_NAME() { return "modelfit.fit.input.roiUID";} const std::string mitk::ModelFitConstants::FIT_INPUT_DATA_PROPERTY_NAME() { return "modelfit.fit.input.data";} const std::string mitk::ModelFitConstants::FIT_STATIC_PARAMETERS_PROPERTY_NAME() { return "modelfit.fit.staticParameters";} diff --git a/Modules/ModelFit/src/Common/mitkModelFitInfo.cpp b/Modules/ModelFit/src/Common/mitkModelFitInfo.cpp index 065868e971..b096c27417 100644 --- a/Modules/ModelFit/src/Common/mitkModelFitInfo.cpp +++ b/Modules/ModelFit/src/Common/mitkModelFitInfo.cpp @@ -1,429 +1,425 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include #include #include "mitkDataNode.h" #include "mitkDataStorage.h" #include "mitkModelFitInfo.h" #include "mitkScalarListLookupTableProperty.h" #include "mitkModelFitException.h" +#include "mitkModelFitResultRelationRule.h" void mitk::modelFit::ModelFitInfo::AddParameter(Parameter::Pointer p) { if (p.IsNull()) { mitkThrow() << "Given parameter must not be NULL"; } if (GetParameter(p->name, p->type).IsNull()) { MITK_DEBUG << "Adding parameter '" << p->name << "with type " << p->type << "' to modelFit '" << uid << "'."; LockType lock(mutex); parameterList.push_back(p); } else { MITK_DEBUG << "Parameter '" << p->name << "' of modelFit '" << uid << "' already exists. Aborting."; } } mitk::modelFit::Parameter::ConstPointer mitk::modelFit::ModelFitInfo::GetParameter(const std::string& name, const Parameter::Type& type) const { for (ConstIterType iter = parameterList.begin(); iter != parameterList.end(); ++iter) { Parameter::ConstPointer p = static_cast(*iter); if (p->name == name && p->type == type) { return p; } } return nullptr; } const mitk::modelFit::ModelFitInfo::ParamListType& mitk::modelFit::ModelFitInfo::GetParameters() const { return this->parameterList; }; void mitk::modelFit::ModelFitInfo::DeleteParameter(const std::string& name, const Parameter::Type& type) { for (IterType iter = parameterList.begin(); iter != parameterList.end(); ++iter) { Parameter::ConstPointer p = static_cast(*iter); if (p->name == name && p->type == type) { MITK_DEBUG << "Deleting parameter '" << name << " with type " << type << "' from modelFit '" << uid << "'."; LockType lock(mutex); parameterList.erase(iter); return; } } } const std::string mitk::modelFit::GetMandatoryProperty(const mitk::DataNode* node, const std::string& prop) { std::string result; if (!node || !node->GetData() || !node->GetData()->GetPropertyList()->GetStringProperty(prop.c_str(), result) || result.empty()) { mitkThrowException(mitk::modelFit::ModelFitException) << "Node " << node->GetName() << " is lacking the required " << "property '" << prop << "' or contains an empty string."; } return result; } const std::string mitk::modelFit::GetMandatoryProperty(const mitk::BaseData* data, const std::string& prop) { std::string result; if (!data || !data->GetPropertyList()->GetStringProperty(prop.c_str(), result) || result.empty()) { mitkThrowException(mitk::modelFit::ModelFitException) << "Data is lacking the required " << "property '" << prop << "' or contains an empty string."; } return result; } mitk::modelFit::ModelFitInfo::Pointer mitk::modelFit::CreateFitInfoFromNode(const ModelFitInfo::UIDType& uid, const mitk::DataStorage* storage) { if (!storage) { return nullptr; } mitk::DataStorage::SetOfObjects::ConstPointer nodes = GetNodesOfFit(uid, storage); if (nodes.IsNull() || nodes->empty()) { return nullptr; } mitk::DataNode::ConstPointer node = nodes->GetElement( 0).GetPointer(); //take one of the nodes as template if (!node->GetData()) { return nullptr; } ModelFitInfo::Pointer fit = ModelFitInfo::New(); fit->uid = uid; // Mandatory properties try { fit->fitType = GetMandatoryProperty(node, mitk::ModelFitConstants::FIT_TYPE_PROPERTY_NAME()); fit->modelType = GetMandatoryProperty(node, mitk::ModelFitConstants::MODEL_TYPE_PROPERTY_NAME()); fit->modelName = GetMandatoryProperty(node, mitk::ModelFitConstants::MODEL_NAME_PROPERTY_NAME()); } catch (const ModelFitException& e) { MITK_ERROR << e.what(); return nullptr; } // Either a function string or a function class must exist if (!node->GetData()->GetPropertyList()->GetStringProperty(mitk::ModelFitConstants::MODEL_FUNCTION_PROPERTY_NAME().c_str(), fit->function)) { fit->function = ""; } try { fit->functionClassID = GetMandatoryProperty(node, mitk::ModelFitConstants::MODEL_FUNCTION_CLASS_PROPERTY_NAME()); } catch (const ModelFitException&) { if (fit->function.empty()) { MITK_ERROR << "The properties '" << mitk::ModelFitConstants::MODEL_FUNCTION_PROPERTY_NAME() << "'and '" << mitk::ModelFitConstants::MODEL_FUNCTION_CLASS_PROPERTY_NAME() << "' are both empty or missing. One of these is required."; return nullptr; } } node->GetData()->GetPropertyList()->GetStringProperty(mitk::ModelFitConstants::FIT_NAME_PROPERTY_NAME().c_str(), fit->fitName); node->GetData()->GetPropertyList()->GetStringProperty(mitk::ModelFitConstants::MODEL_X_PROPERTY_NAME().c_str(), fit->x); node->GetData()->GetPropertyList()->GetStringProperty(mitk::ModelFitConstants::XAXIS_NAME_PROPERTY_NAME().c_str(), fit->xAxisName); node->GetData()->GetPropertyList()->GetStringProperty(mitk::ModelFitConstants::XAXIS_UNIT_PROPERTY_NAME().c_str(), fit->xAxisUnit); node->GetData()->GetPropertyList()->GetStringProperty(mitk::ModelFitConstants::YAXIS_NAME_PROPERTY_NAME().c_str(), fit->yAxisName); node->GetData()->GetPropertyList()->GetStringProperty(mitk::ModelFitConstants::YAXIS_UNIT_PROPERTY_NAME().c_str(), fit->yAxisUnit); // Parameter for (DataStorage::SetOfObjects::ConstIterator pos = nodes->Begin(); pos != nodes->End(); ++pos) { modelFit::Parameter::Pointer param = ExtractParameterFromData(pos->Value()->GetData()); if (param.IsNotNull()) { fit->AddParameter(param); } } // Static parameters mitk::ScalarListLookupTableProperty::ConstPointer varProp = dynamic_cast(node->GetData()->GetProperty(mitk::ModelFitConstants::FIT_STATIC_PARAMETERS_PROPERTY_NAME().c_str()).GetPointer()); if (varProp.IsNotNull()) { const mitk::ScalarListLookupTable lut = varProp->GetValue(); const mitk::ScalarListLookupTable::LookupTableType& varMap = lut.GetLookupTable(); for (mitk::ScalarListLookupTable::LookupTableType::const_iterator mapIter = varMap.begin(); mapIter != varMap.end(); ++mapIter) { fit->staticParamMap.Add(mapIter->first, mapIter->second); } } //fit input and ROI - try - { - fit->inputUID = GetMandatoryProperty(node, - mitk::ModelFitConstants::FIT_INPUT_IMAGEUID_PROPERTY_NAME()); - } - catch (const ModelFitException& e) - { - MITK_ERROR << e.what(); - return nullptr; - } - if (storage) { - mitk::DataNode::Pointer inputNode = GetNodeByModelFitUID(storage, fit->inputUID); - - if (inputNode.IsNull()) + auto inputRule = ModelFitResultRelationRule::New(); + auto inputPredicate = inputRule->GetDestinationsDetector(node); + auto inputNodes = storage->GetSubset(inputPredicate); + if (inputNodes->empty()) { - MITK_ERROR << "Cannot create valid model fit info. input node cannot be found."; + MITK_ERROR << "Cannot create valid model fit info. Input node cannot be found."; return nullptr; } + if (inputNodes->size()>1) + { + MITK_WARN << "More then one node found as input node. This could indicate an invalid state as only one input node should be present. Used first found input node."; + } + + auto inputNode = inputNodes->front(); - mitk::Image::Pointer inputImage = dynamic_cast(inputNode->GetData()); + mitk::Image::ConstPointer inputImage = dynamic_cast(inputNode->GetData()); if (inputImage.IsNull()) { MITK_ERROR << "Cannot create valid model fit info. input node does not contain an image."; return nullptr; } fit->inputImage = inputImage; } node->GetData()->GetPropertyList()->GetStringProperty(mitk::ModelFitConstants::FIT_INPUT_ROIUID_PROPERTY_NAME().c_str(), fit->roiUID); mitk::ScalarListLookupTableProperty::ConstPointer inputDataProp = dynamic_cast(node->GetData()->GetProperty(mitk::ModelFitConstants::FIT_INPUT_DATA_PROPERTY_NAME().c_str()).GetPointer()); if (inputDataProp.IsNotNull()) { fit->inputData = inputDataProp->GetValue(); } return fit; } mitk::modelFit::ModelFitInfo::Pointer mitk::modelFit::CreateFitInfoFromModelParameterizer(const ModelParameterizerBase* usedParameterizer, mitk::BaseData* inputImage, const std::string& fitType, const std::string& fitName, - const NodeUIDType roiUID) + const ModelFitInfo::UIDType& roiUID) { if (!usedParameterizer) { return nullptr; } UIDGenerator generator("FitUID_"); std::string uid = generator.GetUID(); ModelFitInfo::Pointer fit = ModelFitInfo::New(); fit->uid = uid; fit->fitType = fitType; fit->fitName = fitName; fit->inputImage = dynamic_cast(inputImage); - fit->inputUID = EnsureModelFitUID(inputImage); if (fit->inputImage.IsNull()) { mitkThrow() << "Cannot generate model fit info. Input node does not contain an image."; } fit->modelType = usedParameterizer->GetModelType(); fit->modelName = usedParameterizer->GetModelDisplayName(); fit->function = usedParameterizer->GetFunctionString(); fit->x = usedParameterizer->GetXName(); fit->functionClassID = usedParameterizer->GetClassID(); fit->xAxisName = usedParameterizer->GetXAxisName(); fit->xAxisUnit = usedParameterizer->GetXAxisUnit(); fit->yAxisName = usedParameterizer->GetYAxisName(); fit->yAxisUnit = usedParameterizer->GetYAxisUnit(); // Parameter ModelTraitsInterface::ParameterNamesType paramNames = usedParameterizer->GetParameterNames(); ModelTraitsInterface::ParamterScaleMapType paramScales = usedParameterizer->GetParameterScales(); ModelTraitsInterface::ParamterUnitMapType paramUnits = usedParameterizer->GetParameterUnits(); for (ModelTraitsInterface::ParameterNamesType::iterator pos = paramNames.begin(); pos != paramNames.end(); ++pos) { modelFit::Parameter::Pointer param = modelFit::Parameter::New(); param->name = *pos; param->type = Parameter::ParameterType; if (paramScales.find(*pos) == paramScales.end()) { mitkThrow() << "Cannot generate model fit info. Model traits invalid (scales do not include parameter). Parameter name: " << *pos; } if (paramUnits.find(*pos) == paramUnits.end()) { mitkThrow() << "Cannot generate model fit info. Model traits invalid (units do not include parameter). Parameter name: " << *pos; } param->scale = paramScales[*pos]; param->unit = paramUnits[*pos]; fit->AddParameter(param); } //derived parameter ModelTraitsInterface::DerivedParameterNamesType derivedNames = usedParameterizer->GetDerivedParameterNames(); ModelTraitsInterface::DerivedParamterScaleMapType derivedScales = usedParameterizer->GetDerivedParameterScales(); ModelTraitsInterface::DerivedParamterUnitMapType derivedUnits = usedParameterizer->GetDerivedParameterUnits(); for (ModelTraitsInterface::ParameterNamesType::iterator pos = derivedNames.begin(); pos != derivedNames.end(); ++pos) { modelFit::Parameter::Pointer param = modelFit::Parameter::New(); param->name = *pos; param->type = Parameter::DerivedType; if (derivedScales.find(*pos) == derivedScales.end()) { mitkThrow() << "Cannot generate model fit info. Model traits invalid (scales do not include parameter). Parameter name: " << *pos; } if (derivedUnits.find(*pos) == derivedUnits.end()) { mitkThrow() << "Cannot generate model fit info. Model traits invalid (units do not include parameter). Parameter name: " << *pos; } param->scale = derivedScales[*pos]; param->unit = derivedUnits[*pos]; fit->AddParameter(param); } // Static parameters (but transfer only the global ones) ModelParameterizerBase::StaticParameterMapType staticParamMap = usedParameterizer->GetGlobalStaticParameters(); for (ModelParameterizerBase::StaticParameterMapType::const_iterator pos = staticParamMap.begin(); pos != staticParamMap.end(); ++pos) { fit->staticParamMap.Add(pos->first, pos->second); } fit->roiUID = roiUID; return fit; } mitk::modelFit::ModelFitInfo::Pointer mitk::modelFit::CreateFitInfoFromModelParameterizer(const ModelParameterizerBase* usedParameterizer, mitk::BaseData* inputImage, const std::string& fitType, const ScalarListLookupTable& inputData, -const std::string& fitName, const NodeUIDType roiUID) +const std::string& fitName, const ModelFitInfo::UIDType& roiUID) { mitk::modelFit::ModelFitInfo::Pointer info = CreateFitInfoFromModelParameterizer(usedParameterizer, inputImage, fitType, fitName, roiUID); info->inputData = inputData; return info; } mitk::DataStorage::SetOfObjects::ConstPointer mitk::modelFit::GetNodesOfFit(const ModelFitInfo::UIDType& fitUID, const mitk::DataStorage* storage) { if (!storage) { return nullptr; } mitk::NodePredicateDataProperty::Pointer predicate = mitk::NodePredicateDataProperty::New( mitk::ModelFitConstants::FIT_UID_PROPERTY_NAME().c_str(), mitk::StringProperty::New(fitUID)); return storage->GetSubset(predicate); }; mitk::modelFit::NodeUIDSetType mitk::modelFit::GetFitUIDsOfNode(const mitk::DataNode* node, const mitk::DataStorage* storage) { mitk::modelFit::NodeUIDSetType result; if (node && storage) { mitk::NodePredicateDataProperty::Pointer predicate = mitk::NodePredicateDataProperty::New( mitk::ModelFitConstants::FIT_UID_PROPERTY_NAME().c_str()); mitk::DataStorage::SetOfObjects::ConstPointer nodes = storage->GetDerivations(node, predicate, false); for (mitk::DataStorage::SetOfObjects::ConstIterator pos = nodes->Begin(); pos != nodes->End(); ++pos) { mitk::modelFit::ModelFitInfo::UIDType uid; pos->Value()->GetData()->GetPropertyList()->GetStringProperty(mitk::ModelFitConstants::FIT_UID_PROPERTY_NAME().c_str(), uid); result.insert(uid); } } return result; }; diff --git a/Modules/ModelFit/src/Common/mitkModelFitPlotDataHelper.cpp b/Modules/ModelFit/src/Common/mitkModelFitPlotDataHelper.cpp index abeef72a37..a286aa8290 100644 --- a/Modules/ModelFit/src/Common/mitkModelFitPlotDataHelper.cpp +++ b/Modules/ModelFit/src/Common/mitkModelFitPlotDataHelper.cpp @@ -1,440 +1,438 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkModelFitPlotDataHelper.h" #include "mitkExceptionMacro.h" #include "mitkImage.h" #include "mitkModelFitParameterValueExtraction.h" #include "mitkModelGenerator.h" #include "mitkFormulaParser.h" const std::string mitk::MODEL_FIT_PLOT_SAMPLE_NAME() { return "Sample"; }; const std::string mitk::MODEL_FIT_PLOT_SIGNAL_NAME() { return "Signal"; } const std::string mitk::MODEL_FIT_PLOT_INTERPOLATED_SIGNAL_NAME() { return "INTERP_Signal"; }; void mitk::PlotDataCurve:: SetValues(const PlotDataValues& _arg) { if (this->m_Values != _arg) { this->m_Values = _arg; this->Modified(); } } void mitk::PlotDataCurve:: SetValues(PlotDataValues&& _arg) { if (this->m_Values != _arg) { this->m_Values = std::move(_arg); this->Modified(); } } mitk::PlotDataCurve & mitk::PlotDataCurve::operator=(const PlotDataCurve& rhs) { this->m_Values = rhs.m_Values; this->SetTimeStamp(rhs.GetTimeStamp()); return *this; }; mitk::PlotDataCurve& mitk::PlotDataCurve::operator=(PlotDataCurve&& rhs) noexcept { this->m_Values = std::move(rhs.m_Values); this->SetTimeStamp(rhs.GetTimeStamp()); return *this; }; void mitk::PlotDataCurve::Reset() { this->m_Values.clear(); this->Modified(); } mitk::PlotDataCurve::PlotDataCurve() { } const mitk::PlotDataCurve* GetPlotCurve(const mitk::PlotDataCurveCollection* collection, const std::string& key) { if (collection) { auto iter = collection->find(key); if (iter != collection->end()) { return iter->second.GetPointer(); } } return nullptr; }; const mitk::PlotDataCurve* mitk::ModelFitPlotData::GetSamplePlot(const PlotDataCurveCollection* coll) { if (coll) { return GetPlotCurve(coll, MODEL_FIT_PLOT_SAMPLE_NAME()); } return nullptr; }; const mitk::PlotDataCurve* mitk::ModelFitPlotData::GetSignalPlot(const PlotDataCurveCollection* coll) { if (coll) { return GetPlotCurve(coll, MODEL_FIT_PLOT_SIGNAL_NAME()); } return nullptr; }; const mitk::PlotDataCurve* mitk::ModelFitPlotData::GetInterpolatedSignalPlot(const PlotDataCurveCollection* coll) { if (coll) { return GetPlotCurve(coll, MODEL_FIT_PLOT_INTERPOLATED_SIGNAL_NAME()); } return nullptr; }; std::string mitk::ModelFitPlotData::GetPositionalCollectionName(const PositionalCollectionMap::value_type& mapValue) { std::ostringstream nameStrm; nameStrm.imbue(std::locale("C")); nameStrm << "Pos " << mapValue.first << std::endl << std::setprecision(3) << "(" << mapValue.second.first[0] << "|" << mapValue.second.first[1] << "|" << mapValue.second.first[2] << ")"; return nameStrm.str(); }; const mitk::PlotDataCurveCollection* mitk::ModelFitPlotData::GetPositionalPlot(const mitk::Point3D& point) const { auto predicate = [point](const PositionalCollectionMap::value_type& value) {return value.second.first == point; }; auto iter = std::find_if(std::begin(this->positionalPlots), std::end(this->positionalPlots), predicate); if (iter != positionalPlots.end()) { return iter->second.second.GetPointer(); } return nullptr; }; const mitk::PlotDataCurveCollection* mitk::ModelFitPlotData::GetPositionalPlot(mitk::PointSet::PointIdentifier id) const { auto iter = this->positionalPlots.find(id); if (iter != positionalPlots.end()) { return iter->second.second.GetPointer(); } return nullptr; }; mitk::PlotDataValues::value_type mitk::ModelFitPlotData::GetXMinMax() const { double max = itk::NumericTraits::NonpositiveMin(); double min = itk::NumericTraits::max(); //currently we assume that within a model fit, plot data does not exceed //the sample/signale on the x axis. auto sample = this->GetSamplePlot(this->currentPositionPlots); if (sample) { CheckXMinMaxFromPlotDataValues(sample->GetValues(), min, max); } for (const auto& posCollection : this->positionalPlots) { auto sample = this->GetSamplePlot(posCollection.second.second); if (sample) { CheckXMinMaxFromPlotDataValues(sample->GetValues(), min, max); } } return std::make_pair(min, max); }; mitk::PlotDataValues::value_type mitk::ModelFitPlotData::GetYMinMax() const { double max = itk::NumericTraits::NonpositiveMin(); double min = itk::NumericTraits::max(); for (const auto& plot : *(this->currentPositionPlots.GetPointer())) { CheckYMinMaxFromPlotDataValues(plot.second->GetValues(), min, max); } for (const auto& posCollection : this->positionalPlots) { for (const auto& plot : *(posCollection.second.second)) { CheckYMinMaxFromPlotDataValues(plot.second->GetValues(), min, max); } } for (const auto& plot : *(this->staticPlots)) { CheckYMinMaxFromPlotDataValues(plot.second->GetValues(), min, max); } return std::make_pair(min, max); }; mitk::ModelFitPlotData::ModelFitPlotData() { this->currentPositionPlots = PlotDataCurveCollection::New(); this->staticPlots = PlotDataCurveCollection::New(); }; void mitk::CheckYMinMaxFromPlotDataValues(const PlotDataValues& data, double& min, double& max) { for (const auto & pos : data) { if (max < pos.second) { max = pos.second; } if (min > pos.second) { min = pos.second; } } } void mitk::CheckXMinMaxFromPlotDataValues(const PlotDataValues& data, double& min, double& max) { for (const auto & pos : data) { if (max < pos.first) { max = pos.first; } if (min > pos.first) { min = pos.first; } } } /** Helper function that generates the curve based on a stored and on the fly parsed function string.*/ mitk::PlotDataCurve::Pointer CalcSignalFromFunction(const mitk::Point3D& position, const mitk::modelFit::ModelFitInfo* fitInfo, const mitk::ModelBase::TimeGridType& timeGrid) { if (!fitInfo) { mitkThrow() << "Cannot calc model curve from function for given fit. Passed ModelFitInfo instance is nullptr."; } - mitk::Image::Pointer inputImage = fitInfo->inputImage; - assert(inputImage.IsNotNull()); + assert(fitInfo->inputImage.IsNotNull()); mitk::PlotDataCurve::Pointer result = mitk::PlotDataCurve::New(); mitk::PlotDataCurve::ValuesType values; values.reserve(timeGrid.size()); // Calculate index ::itk::Index<3> index; - mitk::BaseGeometry::Pointer geometry = inputImage->GetTimeGeometry()->GetGeometryForTimeStep(0); + mitk::BaseGeometry::Pointer geometry = fitInfo->inputImage->GetTimeGeometry()->GetGeometryForTimeStep(0); geometry->WorldToIndex(position, index); mitk::ParameterValueMapType parameterMap = mitk::ExtractParameterValueMapFromModelFit(fitInfo, position); mitk::FormulaParser parser(¶meterMap); for (unsigned int t = 0; t < timeGrid.size(); ++t) { // Set up static parameters for (const auto& var : fitInfo->staticParamMap) { const auto& list = var.second; if (list.size() == 1) { parameterMap[var.first] = list.front(); } else { parameterMap[var.first] = list.at(t); } } // Calculate curve data double x = timeGrid[t]; parameterMap[fitInfo->x] = x; double y = parser.parse(fitInfo->function); values.emplace_back(std::make_pair(x, y)); } result->SetValues(std::move(values)); return result; } /** Helper function that generates the curve based on the model specified by the fit info.*/ mitk::PlotDataCurve::Pointer CalcSignalFromModel(const mitk::Point3D& position, const mitk::modelFit::ModelFitInfo* fitInfo, const mitk::ModelParameterizerBase* parameterizer = nullptr) { assert(fitInfo); if (!parameterizer) { parameterizer = mitk::ModelGenerator::GenerateModelParameterizer(*fitInfo); } - mitk::Image::Pointer inputImage = fitInfo->inputImage; - assert(inputImage.IsNotNull()); + assert(fitInfo->inputImage.IsNotNull()); // Calculate index ::itk::Index<3> index; - mitk::BaseGeometry::Pointer geometry = inputImage->GetTimeGeometry()->GetGeometryForTimeStep(0); + mitk::BaseGeometry::Pointer geometry = fitInfo->inputImage->GetTimeGeometry()->GetGeometryForTimeStep(0); geometry->WorldToIndex(position, index); //model generation mitk::ModelBase::Pointer model = parameterizer->GenerateParameterizedModel(index); mitk::ParameterValueMapType parameterMap = mitk::ExtractParameterValueMapFromModelFit(fitInfo, position); mitk::ModelBase::ParametersType paramArray = mitk::ConvertParameterMapToParameterVector(parameterMap, model); mitk::ModelBase::ModelResultType curveDataY = model->GetSignal(paramArray); mitk::PlotDataCurve::Pointer result = mitk::PlotDataCurve::New(); mitk::ModelBase::TimeGridType timeGrid = model->GetTimeGrid(); mitk::PlotDataCurve::ValuesType values; values.reserve(timeGrid.size()); for (unsigned int t = 0; t < timeGrid.size(); ++t) { double x = timeGrid[t]; double y = curveDataY[t]; values.emplace_back(std::make_pair(x, y)); } result->SetValues(std::move(values)); return result; } mitk::PlotDataCurve::Pointer mitk::GenerateModelSignalPlotData(const mitk::Point3D& position, const mitk::modelFit::ModelFitInfo* fitInfo, const mitk::ModelBase::TimeGridType& timeGrid, mitk::ModelParameterizerBase* parameterizer) { if (!fitInfo) { mitkThrow() << "Cannot calc model curve from function for given fit. Passed ModelFitInfo instance is nullptr."; } mitk::PlotDataCurve::Pointer result; if (!parameterizer) { parameterizer = ModelGenerator::GenerateModelParameterizer(*fitInfo); } if (parameterizer) { // Use model instead of formula parser parameterizer->SetDefaultTimeGrid(timeGrid); result = CalcSignalFromModel(position, fitInfo, parameterizer); } else { // Use formula parser to parse function string try { result = CalcSignalFromFunction(position, fitInfo, timeGrid); } catch (const mitk::FormulaParserException& e) { MITK_ERROR << "Error while parsing modelfit function: " << e.what(); } } return result; } mitk::PlotDataCurveCollection::Pointer mitk::GenerateAdditionalModelFitPlotData(const mitk::Point3D& /*position*/, const mitk::modelFit::ModelFitInfo* fitInfo, const mitk::ModelBase::TimeGridType& timeGrid) { if (!fitInfo) { mitkThrow() << "Cannot calc model curve from function for given fit. Passed ModelFitInfo instance is nullptr."; } mitk::PlotDataCurveCollection::Pointer result = mitk::PlotDataCurveCollection::New(); for (const auto& additionalInput : fitInfo->inputData.GetLookupTable()) { if (additionalInput.second.size() != timeGrid.size()) { MITK_ERROR << "Error while refreshing input data for visualization. Size of data and input image time grid differ. Invalid data name: " << additionalInput.first; } else { mitk::PlotDataCurve::Pointer pointData = mitk::PlotDataCurve::New();; mitk::PlotDataCurve::ValuesType values; values.reserve(timeGrid.size()); for (unsigned int t = 0; t < timeGrid.size(); ++t) { const double x = timeGrid[t]; const double y = additionalInput.second[t]; values.emplace_back(std::make_pair(x, y)); } pointData->SetValues(std::move(values)); result->CastToSTLContainer().emplace(additionalInput.first, std::move(pointData)); } } return result; } mitk::PlotDataCurve::Pointer mitk::GenerateImageSamplePlotData(const mitk::Point3D& position, const mitk::Image* image, const mitk::ModelBase::TimeGridType& timeGrid) { if (!image) { mitkThrow() << "Cannot generate sample plot data. Passed image instance is nullptr."; } mitk::PlotDataCurve::Pointer result = mitk::PlotDataCurve::New(); mitk::PlotDataCurve::ValuesType values; values.reserve(timeGrid.size()); for (unsigned int t = 0; t < timeGrid.size(); ++t) { const double x = timeGrid[t]; const double y = ReadVoxel(image, position, t); values.emplace_back(std::make_pair(x, y)); } result->SetValues(std::move(values)); return result; } diff --git a/Modules/ModelFit/src/Common/mitkModelFitResultHelper.cpp b/Modules/ModelFit/src/Common/mitkModelFitResultHelper.cpp index 5a18753ad0..72be8d9915 100644 --- a/Modules/ModelFit/src/Common/mitkModelFitResultHelper.cpp +++ b/Modules/ModelFit/src/Common/mitkModelFitResultHelper.cpp @@ -1,283 +1,280 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkModelFitResultHelper.h" #include #include #include "mitkModelTraitsInterface.h" #include "mitkModelFitConstants.h" #include "mitkModelFitInfo.h" +#include #include #include namespace mitk { namespace modelFit { void AdaptDataPropertyToParameter(mitk::BaseData* data, const ModelBase::ParameterNameType& name, modelFit::Parameter::Type dataType, const modelFit::ModelFitInfo* fitInfo) { assert(data); if (!data) { mitkThrow() << "Cannot add model or fit properties to data instance. Passed data instance is null. parameter name:" << name; } if (!fitInfo) { mitkThrow() << "Cannot add model or fit properties to data. Passed fit info instance is null. parameter name:" << name; } data->GetPropertyList()->SetStringProperty(ModelFitConstants::PARAMETER_NAME_PROPERTY_NAME().c_str(),name.c_str()); if (dataType == modelFit::Parameter::ParameterType) { data->GetPropertyList()->SetStringProperty(ModelFitConstants::PARAMETER_TYPE_PROPERTY_NAME().c_str(), ModelFitConstants::PARAMETER_TYPE_VALUE_PARAMETER().c_str()); } else if (dataType == modelFit::Parameter::DerivedType) { data->GetPropertyList()->SetStringProperty(ModelFitConstants::PARAMETER_TYPE_PROPERTY_NAME().c_str(), ModelFitConstants::PARAMETER_TYPE_VALUE_DERIVED_PARAMETER().c_str()); } else if (dataType == modelFit::Parameter::CriterionType) { data->GetPropertyList()->SetStringProperty(ModelFitConstants::PARAMETER_TYPE_PROPERTY_NAME().c_str(), ModelFitConstants::PARAMETER_TYPE_VALUE_CRITERION().c_str()); } else if (dataType == modelFit::Parameter::EvaluationType) { data->GetPropertyList()->SetStringProperty(ModelFitConstants::PARAMETER_TYPE_PROPERTY_NAME().c_str(), ModelFitConstants::PARAMETER_TYPE_VALUE_EVALUATION_PARAMETER().c_str()); } if (dataType == modelFit::Parameter::ParameterType || dataType == modelFit::Parameter::DerivedType) { modelFit::Parameter::ConstPointer param = fitInfo->GetParameter(name,dataType); if (param.IsNull()) { mitkThrow() << "Cannot generate model fit result data. Parameter name is not part of the model fit info. Parameter name: "<unit.empty()) { data->GetPropertyList()->SetStringProperty(ModelFitConstants::PARAMETER_UNIT_PROPERTY_NAME().c_str(), param->unit.c_str()); } if (param->scale != 1.0) { data->GetPropertyList()->SetFloatProperty(ModelFitConstants::PARAMETER_SCALE_PROPERTY_NAME().c_str(), param->scale); } } - }; + } void AdaptDataPropertyToModelFit(mitk::BaseData* data, const modelFit::ModelFitInfo* fitInfo) { assert(data); if (!data) { mitkThrow() << "Cannot add model or fit properties to data. Passed data instance is null."; } if (!fitInfo) { mitkThrow() << "Cannot add model or fit properties to data. Passed model traits instance is null."; } //model section data->GetPropertyList()->SetStringProperty(ModelFitConstants::MODEL_TYPE_PROPERTY_NAME().c_str(), fitInfo->modelType.c_str()); data->GetPropertyList()->SetStringProperty(ModelFitConstants::MODEL_NAME_PROPERTY_NAME().c_str(), fitInfo->modelName.c_str()); data->GetPropertyList()->SetStringProperty(ModelFitConstants::MODEL_FUNCTION_CLASS_PROPERTY_NAME().c_str(), fitInfo->functionClassID.c_str()); if(!(fitInfo->function.empty())) { data->GetPropertyList()->SetStringProperty(ModelFitConstants::MODEL_FUNCTION_PROPERTY_NAME().c_str(), fitInfo->function.c_str()); data->GetPropertyList()->SetStringProperty(ModelFitConstants::MODEL_X_PROPERTY_NAME().c_str(), fitInfo->x.c_str()); } //axis section if (!fitInfo->xAxisName.empty()) { data->GetPropertyList()->SetStringProperty(ModelFitConstants::XAXIS_NAME_PROPERTY_NAME().c_str(), fitInfo->xAxisName.c_str()); } if (!fitInfo->xAxisUnit.empty()) { data->GetPropertyList()->SetStringProperty(ModelFitConstants::XAXIS_UNIT_PROPERTY_NAME().c_str(), fitInfo->xAxisUnit.c_str()); } if (!fitInfo->yAxisName.empty()) { data->GetPropertyList()->SetStringProperty(ModelFitConstants::YAXIS_NAME_PROPERTY_NAME().c_str(), fitInfo->yAxisName.c_str()); } if (!fitInfo->yAxisUnit.empty()) { data->GetPropertyList()->SetStringProperty(ModelFitConstants::YAXIS_UNIT_PROPERTY_NAME().c_str(), fitInfo->yAxisUnit.c_str()); } //fit section data->GetPropertyList()->SetStringProperty(ModelFitConstants::FIT_UID_PROPERTY_NAME().c_str(), fitInfo->uid.c_str()); data->GetPropertyList()->SetStringProperty(ModelFitConstants::FIT_NAME_PROPERTY_NAME().c_str(), fitInfo->fitName.c_str()); data->GetPropertyList()->SetStringProperty(ModelFitConstants::FIT_TYPE_PROPERTY_NAME().c_str(), fitInfo->fitType.c_str()); - data->GetPropertyList()->SetStringProperty(ModelFitConstants::FIT_INPUT_IMAGEUID_PROPERTY_NAME().c_str(), fitInfo->inputUID.c_str()); + + const auto rule = ModelFitResultRelationRule::New(); + rule->Connect(dynamic_cast(data), fitInfo->inputImage); if (fitInfo->inputData.GetLookupTable().size() > 0) { mitk::ScalarListLookupTableProperty::Pointer inputDataProp = mitk::ScalarListLookupTableProperty::New(); inputDataProp->SetValue(fitInfo->inputData); data->SetProperty(ModelFitConstants::FIT_INPUT_DATA_PROPERTY_NAME().c_str(), inputDataProp); } if (!fitInfo->roiUID.empty()) { data->GetPropertyList()->SetStringProperty(ModelFitConstants::FIT_INPUT_ROIUID_PROPERTY_NAME().c_str(), fitInfo->roiUID.c_str()); } data->SetProperty(ModelFitConstants::FIT_STATIC_PARAMETERS_PROPERTY_NAME().c_str(), ConvertStaticParametersToProperty(fitInfo->staticParamMap)); - }; + } mitk::DataNode::Pointer CreateNode(const ModelBase::ParameterNameType& name, Image* parameterImage, const ModelFitInfo* fitInfo) { if (!parameterImage) { mitkThrow() << "Cannot generate model fit result node. Passed parameterImage is null. parameter name: "<SetData(parameterImage); std::string nodeName = name; if (!fitInfo->fitName.empty()) { nodeName = fitInfo->fitName + "_" + nodeName; } result->SetName(nodeName); result->SetVisibility(false); return result; - }; + } } } mitk::ScalarListLookupTableProperty::Pointer mitk::modelFit::ConvertStaticParametersToProperty(const mitk::modelFit::StaticParameterMap& params) { mitk::ScalarListLookupTableProperty::Pointer result = mitk::ScalarListLookupTableProperty::New(); ScalarListLookupTable table; for(mitk::modelFit::StaticParameterMap::const_iterator pos = params.begin(); pos != params.end(); ++pos) { table.SetTableValue(pos->first,pos->second); } result->SetValue(table); return result; -}; +} MITKMODELFIT_EXPORT void mitk::modelFit::SetModelFitDataProperties(mitk::BaseData* data, const ModelBase::ParameterNameType& name, modelFit::Parameter::Type dataType, const modelFit::ModelFitInfo* fitInfo) { AdaptDataPropertyToModelFit(data, fitInfo); AdaptDataPropertyToParameter(data, name, dataType, fitInfo); -}; +} MITKMODELFIT_EXPORT mitk::DataNode::Pointer mitk::modelFit::CreateResultNode( const ModelBase::ParameterNameType& name, modelFit::Parameter::Type nodeType, Image* parameterImage, const ModelFitInfo* modelFitInfo) { if (!parameterImage) { mitkThrow() << "Cannot generate model fit result node. Passed parameterImage is null. parameter name: "<inputImage, parameterImage); + mitk::DICOMPMPropertyHelper::DeriveDICOMPMProperties(parameterImage); + return result; -}; +} MITKMODELFIT_EXPORT mitk::modelFit::ModelFitResultNodeVectorType mitk::modelFit::CreateResultNodeMap( const ModelFitResultImageMapType& results, const ModelFitResultImageMapType& derivedResults, const ModelFitResultImageMapType& criterionResults, const ModelFitResultImageMapType& evaluationResults, const ModelFitInfo* fitInfo) { if (!fitInfo) { mitkThrow() << "Cannot store model fit results in data storage. Passed model traits instance is null."; } ModelFitResultNodeVectorType nodes; for (ModelFitResultImageMapType::const_iterator pos = results.begin(); pos!=results.end(); ++pos) { DataNode::Pointer newNode = CreateResultNode(pos->first, modelFit::Parameter::ParameterType, pos->second, fitInfo); nodes.push_back(newNode); } for (ModelFitResultImageMapType::const_iterator pos = derivedResults.begin(); pos!=derivedResults.end(); ++pos) { DataNode::Pointer newNode = CreateResultNode(pos->first, modelFit::Parameter::DerivedType, pos->second, fitInfo); nodes.push_back(newNode); } for (ModelFitResultImageMapType::const_iterator pos = criterionResults.begin(); pos!=criterionResults.end(); ++pos) { DataNode::Pointer newNode = CreateResultNode(pos->first, modelFit::Parameter::CriterionType, pos->second, fitInfo); nodes.push_back(newNode); } for (ModelFitResultImageMapType::const_iterator pos = evaluationResults.begin(); pos!=evaluationResults.end(); ++pos) { DataNode::Pointer newNode = CreateResultNode(pos->first, modelFit::Parameter::EvaluationType, pos->second, fitInfo); nodes.push_back(newNode); } return nodes; -}; +} MITKMODELFIT_EXPORT void mitk::modelFit::StoreResultsInDataStorage(DataStorage* storage, const ModelFitResultNodeVectorType& resultNodes, DataNode* parentNode) { if (!storage) { mitkThrow() << "Cannot store model fit results in data storage. Passed storage is null."; } for (ModelFitResultNodeVectorType::const_iterator pos = resultNodes.begin(); pos!=resultNodes.end(); ++pos) { storage->Add(*pos,parentNode); } - - // Set DICOM properties, paramap-secific (DICOMPM) and general properties from source data (DICOMQI) - - for (ModelFitResultNodeVectorType::const_iterator pos = resultNodes.begin(); pos != resultNodes.end(); pos++) - { - mitk::DICOMQIPropertyHelper::DeriveDICOMSourceProperties(parentNode->GetData(), pos->GetPointer()->GetData()); - mitk::DICOMPMPropertyHelper::DeriveDICOMPMProperties(pos->GetPointer()->GetData()); - } - - -}; +} diff --git a/Modules/ModelFit/src/Common/mitkModelFitUIDHelper.cpp b/Modules/ModelFit/src/Common/mitkModelFitUIDHelper.cpp deleted file mode 100644 index 1e9bda1e0e..0000000000 --- a/Modules/ModelFit/src/Common/mitkModelFitUIDHelper.cpp +++ /dev/null @@ -1,128 +0,0 @@ -/*============================================================================ - -The Medical Imaging Interaction Toolkit (MITK) - -Copyright (c) German Cancer Research Center (DKFZ) -All rights reserved. - -Use of this source code is governed by a 3-clause BSD license that can be -found in the LICENSE file. - -============================================================================*/ - -#include "mitkModelFitUIDHelper.h" - - -// Mitk -#include -#include -#include -#include -#include -#include -#include - -mitk::DataNode::Pointer mitk::GetNodeByModelFitUID(const mitk::DataStorage* storage, const NodeUIDType& uid) -{ - mitk::DataNode::Pointer result; - - if (storage) - { - auto nodes = storage->GetAll(); - for (auto node : *(nodes.GetPointer())) - { - if (CheckModelFitUID(node, uid)) - { - result = node; - break; - } - } - } - - return result; -} - -mitk::NodeUIDType mitk::EnsureModelFitUID(mitk::DataNode* node) -{ - if (!node) - { - mitkThrow() << "Cannot ensure node UID. Passed node pointer is NULL."; - } - - return EnsureModelFitUID(node->GetData()); -}; - -mitk::NodeUIDType mitk::EnsureModelFitUID(mitk::BaseData* data) -{ - if (!data) - { - mitkThrow() << "Cannot ensure node UID. Passed node pointer is NULL."; - } - - BaseProperty::Pointer uidProp = data->GetProperty(mitk::ModelFitConstants::UID_PROPERTY_NAME().c_str()); - std::string propUID = ""; - - - if (uidProp.IsNotNull()) - { - propUID = uidProp->GetValueAsString(); - } - else - { - //if the "user" defined UID is not found we will check if there is a DICOM series instance UID and use this value if available. - uidProp = data->GetProperty(GeneratePropertyNameForDICOMTag(0x0020, 0x000e).c_str()); - - if (uidProp.IsNotNull()) - { - propUID = uidProp->GetValueAsString(); - } - else - { - mitk::UIDGenerator generator; - propUID = generator.GetUID(); - - data->SetProperty(mitk::ModelFitConstants::UID_PROPERTY_NAME().c_str(), mitk::StringProperty::New(propUID)); - } - } - - return propUID; -}; - -bool mitk::CheckModelFitUID(const mitk::DataNode* node, const NodeUIDType& uid) -{ - if (node) - { - return CheckModelFitUID(node->GetData(), uid); - } - - return false; -}; - -bool mitk::CheckModelFitUID(const mitk::BaseData* data, const NodeUIDType& uid) -{ - bool result = false; - - if (data) - { - BaseProperty::Pointer uidProp = data->GetProperty(mitk::ModelFitConstants::UID_PROPERTY_NAME().c_str()); - - if (uidProp.IsNotNull()) - { - result = uidProp->GetValueAsString() == uid; - } - - if (!result) - { - //if the "user" defined UID does not match, we will check if there is a DICOM series instance UID and use this value for the check. - uidProp = data->GetProperty(GeneratePropertyNameForDICOMTag(0x0020, 0x000e).c_str()); - - if (uidProp.IsNotNull()) - { - result = uidProp->GetValueAsString() == uid; - } - } - } - - return result; -}; - diff --git a/Modules/ModelFit/test/files.cmake b/Modules/ModelFit/test/files.cmake index 8e408bd49c..acc20fa1d1 100644 --- a/Modules/ModelFit/test/files.cmake +++ b/Modules/ModelFit/test/files.cmake @@ -1,16 +1,15 @@ SET(MODULE_TESTS itkMultiOutputNaryFunctorImageFilterTest.cpp itkMaskedStatisticsImageFilterTest.cpp itkMaskedNaryStatisticsImageFilterTest.cpp mitkLevenbergMarquardtModelFitFunctorTest.cpp mitkPixelBasedParameterFitImageGeneratorTest.cpp mitkROIBasedParameterFitImageGeneratorTest.cpp mitkMaskedDynamicImageStatisticsGeneratorTest.cpp mitkModelFitInfoTest.cpp - mitkModelFitUIDHelperTest.cpp mitkModelFitStaticParameterMapTest.cpp mitkSimpleBarrierConstraintCheckerTest.cpp mitkMVConstrainedCostFunctionDecoratorTest.cpp mitkConcreteModelFactoryBaseTest.cpp mitkFormulaParserTest.cpp ) diff --git a/Modules/ModelFit/test/mitkModelFitInfoTest.cpp b/Modules/ModelFit/test/mitkModelFitInfoTest.cpp index 8ec84dca41..4793618497 100644 --- a/Modules/ModelFit/test/mitkModelFitInfoTest.cpp +++ b/Modules/ModelFit/test/mitkModelFitInfoTest.cpp @@ -1,267 +1,424 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include -#include "mitkTestingMacros.h" + #include "mitkProperties.h" #include "mitkStandaloneDataStorage.h" #include "mitkModelFitInfo.h" #include "mitkModelFitConstants.h" #include "mitkModelFitException.h" +#include "mitkModelFitResultRelationRule.h" +#include +#include + + +mitk::modelFit::ModelFitInfo::UIDType ensureModelFitUID(mitk::BaseData * data) +{ + mitk::BaseProperty::Pointer uidProp = data->GetProperty(mitk::ModelFitConstants::LEGACY_UID_PROPERTY_NAME().c_str()); + std::string propUID = ""; + + if (uidProp.IsNotNull()) + { + propUID = uidProp->GetValueAsString(); + } + else + { + mitk::UIDGenerator generator; + propUID = generator.GetUID(); + + data->SetProperty(mitk::ModelFitConstants::LEGACY_UID_PROPERTY_NAME().c_str(), mitk::StringProperty::New(propUID)); + } + return propUID; +}; mitk::DataNode::Pointer generateModelFitTestNode() { mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetName("Param1"); auto testImage = mitk::Image::New(); node->SetData(testImage); testImage->SetProperty("modelfit.testEmpty", mitk::StringProperty::New("")); testImage->SetProperty("modelfit.testValid", mitk::StringProperty::New("test")); - mitk::EnsureModelFitUID(node); + ensureModelFitUID(testImage); - testImage->SetProperty(mitk::ModelFitConstants::FIT_UID_PROPERTY_NAME().c_str(), mitk::StringProperty::New("Fit1")); + testImage->SetProperty(mitk::ModelFitConstants::FIT_UID_PROPERTY_NAME().c_str(), mitk::StringProperty::New("FitLegacy")); testImage->SetProperty(mitk::ModelFitConstants::FIT_NAME_PROPERTY_NAME().c_str(), mitk::StringProperty::New("MyName")); testImage->SetProperty(mitk::ModelFitConstants::FIT_TYPE_PROPERTY_NAME().c_str(), mitk::StringProperty::New(mitk::ModelFitConstants::FIT_TYPE_VALUE_PIXELBASED().c_str())); - testImage->SetProperty(mitk::ModelFitConstants::FIT_INPUT_IMAGEUID_PROPERTY_NAME().c_str(), mitk::StringProperty::New("input UID")); + testImage->SetProperty(mitk::ModelFitConstants::LEGACY_FIT_INPUT_IMAGEUID_PROPERTY_NAME().c_str(), mitk::StringProperty::New("input UID")); testImage->SetProperty(mitk::ModelFitConstants::MODEL_TYPE_PROPERTY_NAME().c_str(), mitk::StringProperty::New("TestModels")); testImage->SetProperty(mitk::ModelFitConstants::MODEL_NAME_PROPERTY_NAME().c_str(), mitk::StringProperty::New("TestModel_1")); testImage->SetProperty(mitk::ModelFitConstants::MODEL_FUNCTION_PROPERTY_NAME().c_str(), mitk::StringProperty::New("")); testImage->SetProperty(mitk::ModelFitConstants::MODEL_FUNCTION_CLASS_PROPERTY_NAME().c_str(), mitk::StringProperty::New("ModelClass")); testImage->SetProperty(mitk::ModelFitConstants::MODEL_X_PROPERTY_NAME().c_str(), mitk::StringProperty::New("myX")); testImage->SetProperty(mitk::ModelFitConstants::XAXIS_NAME_PROPERTY_NAME().c_str(), mitk::StringProperty::New(mitk::ModelFitConstants::XAXIS_NAME_VALUE_DEFAULT().c_str())); testImage->SetProperty(mitk::ModelFitConstants::XAXIS_UNIT_PROPERTY_NAME().c_str(), mitk::StringProperty::New("h")); testImage->SetProperty(mitk::ModelFitConstants::YAXIS_NAME_PROPERTY_NAME().c_str(), mitk::StringProperty::New(mitk::ModelFitConstants::YAXIS_NAME_VALUE_DEFAULT().c_str())); testImage->SetProperty(mitk::ModelFitConstants::YAXIS_UNIT_PROPERTY_NAME().c_str(), mitk::StringProperty::New("kg")); return node; } -mitk::StandaloneDataStorage::Pointer generateModelFitTestStorage() -{ - mitk::StandaloneDataStorage::Pointer storage = mitk::StandaloneDataStorage::New(); - - //create input node - mitk::DataNode::Pointer inputNode = mitk::DataNode::New(); - inputNode->SetName("Input"); - mitk::Image::Pointer image = mitk::Image::New(); - inputNode->SetData(image); - mitk::NodeUIDType inputUID = mitk::EnsureModelFitUID(inputNode); - - storage->Add(inputNode); - - mitk::DataStorage::SetOfObjects::Pointer parents = mitk::DataStorage::SetOfObjects::New(); - parents->push_back(inputNode); - - //create first result for Fit1 - mitk::DataNode::Pointer node1 = mitk::DataNode::New(); - mitk::Image::Pointer paramImage = mitk::Image::New(); - node1->SetData(paramImage); - node1->SetName("Param1"); - mitk::EnsureModelFitUID(node1); - paramImage->SetProperty(mitk::ModelFitConstants::FIT_UID_PROPERTY_NAME().c_str(), mitk::StringProperty::New("Fit1")); - paramImage->SetProperty(mitk::ModelFitConstants::FIT_NAME_PROPERTY_NAME().c_str(), mitk::StringProperty::New("MyName1")); - paramImage->SetProperty(mitk::ModelFitConstants::FIT_TYPE_PROPERTY_NAME().c_str(), mitk::StringProperty::New(mitk::ModelFitConstants::FIT_TYPE_VALUE_PIXELBASED().c_str())); - paramImage->SetProperty(mitk::ModelFitConstants::FIT_INPUT_IMAGEUID_PROPERTY_NAME().c_str(), mitk::StringProperty::New(inputUID.c_str())); - - paramImage->SetProperty(mitk::ModelFitConstants::MODEL_TYPE_PROPERTY_NAME().c_str(), mitk::StringProperty::New("TestModels")); - paramImage->SetProperty(mitk::ModelFitConstants::MODEL_NAME_PROPERTY_NAME().c_str(), mitk::StringProperty::New("TestModel_1")); - paramImage->SetProperty(mitk::ModelFitConstants::MODEL_FUNCTION_PROPERTY_NAME().c_str(), mitk::StringProperty::New("")); - paramImage->SetProperty(mitk::ModelFitConstants::MODEL_FUNCTION_CLASS_PROPERTY_NAME().c_str(), mitk::StringProperty::New("ModelClass")); - paramImage->SetProperty(mitk::ModelFitConstants::MODEL_X_PROPERTY_NAME().c_str(), mitk::StringProperty::New("myX")); - - paramImage->SetProperty(mitk::ModelFitConstants::XAXIS_NAME_PROPERTY_NAME().c_str(), mitk::StringProperty::New(mitk::ModelFitConstants::XAXIS_NAME_VALUE_DEFAULT().c_str())); - paramImage->SetProperty(mitk::ModelFitConstants::XAXIS_UNIT_PROPERTY_NAME().c_str(), mitk::StringProperty::New("h")); - paramImage->SetProperty(mitk::ModelFitConstants::YAXIS_NAME_PROPERTY_NAME().c_str(), mitk::StringProperty::New(mitk::ModelFitConstants::YAXIS_NAME_VALUE_DEFAULT().c_str())); - paramImage->SetProperty(mitk::ModelFitConstants::YAXIS_UNIT_PROPERTY_NAME().c_str(), mitk::StringProperty::New("kg")); - - paramImage->SetProperty(mitk::ModelFitConstants::PARAMETER_NAME_PROPERTY_NAME().c_str(), mitk::StringProperty::New("Param1")); - paramImage->SetProperty(mitk::ModelFitConstants::PARAMETER_UNIT_PROPERTY_NAME().c_str(), mitk::StringProperty::New("b")); - paramImage->SetProperty(mitk::ModelFitConstants::PARAMETER_TYPE_PROPERTY_NAME().c_str(), mitk::StringProperty::New(mitk::ModelFitConstants::PARAMETER_TYPE_VALUE_PARAMETER().c_str())); - - storage->Add(node1,parents); - - //create second result for Fit1 - mitk::DataNode::Pointer node2 = mitk::DataNode::New(); - node2->SetName("Param2"); - mitk::Image::Pointer paramImage2 = mitk::Image::New(); - node2->SetData(paramImage2); - mitk::EnsureModelFitUID(node2); - paramImage2->SetProperty(mitk::ModelFitConstants::FIT_UID_PROPERTY_NAME().c_str(), mitk::StringProperty::New("Fit1")); - paramImage2->SetProperty(mitk::ModelFitConstants::FIT_NAME_PROPERTY_NAME().c_str(), mitk::StringProperty::New("MyName1")); - paramImage2->SetProperty(mitk::ModelFitConstants::FIT_TYPE_PROPERTY_NAME().c_str(), mitk::StringProperty::New(mitk::ModelFitConstants::FIT_TYPE_VALUE_PIXELBASED().c_str())); - paramImage2->SetProperty(mitk::ModelFitConstants::FIT_INPUT_IMAGEUID_PROPERTY_NAME().c_str(), mitk::StringProperty::New(inputUID.c_str())); - - paramImage2->SetProperty(mitk::ModelFitConstants::MODEL_TYPE_PROPERTY_NAME().c_str(), mitk::StringProperty::New("TestModels")); - paramImage2->SetProperty(mitk::ModelFitConstants::MODEL_NAME_PROPERTY_NAME().c_str(), mitk::StringProperty::New("TestModel_1")); - paramImage2->SetProperty(mitk::ModelFitConstants::MODEL_FUNCTION_PROPERTY_NAME().c_str(), mitk::StringProperty::New("")); - paramImage2->SetProperty(mitk::ModelFitConstants::MODEL_FUNCTION_CLASS_PROPERTY_NAME().c_str(), mitk::StringProperty::New("ModelClass")); - paramImage2->SetProperty(mitk::ModelFitConstants::MODEL_X_PROPERTY_NAME().c_str(), mitk::StringProperty::New("myX")); - - paramImage2->SetProperty(mitk::ModelFitConstants::XAXIS_NAME_PROPERTY_NAME().c_str(), mitk::StringProperty::New(mitk::ModelFitConstants::XAXIS_NAME_VALUE_DEFAULT().c_str())); - paramImage2->SetProperty(mitk::ModelFitConstants::XAXIS_UNIT_PROPERTY_NAME().c_str(), mitk::StringProperty::New("h")); - paramImage2->SetProperty(mitk::ModelFitConstants::YAXIS_NAME_PROPERTY_NAME().c_str(), mitk::StringProperty::New(mitk::ModelFitConstants::YAXIS_NAME_VALUE_DEFAULT().c_str())); - paramImage2->SetProperty(mitk::ModelFitConstants::YAXIS_UNIT_PROPERTY_NAME().c_str(), mitk::StringProperty::New("kg")); - - paramImage2->SetProperty(mitk::ModelFitConstants::PARAMETER_NAME_PROPERTY_NAME().c_str(), mitk::StringProperty::New("Param2")); - paramImage2->SetProperty(mitk::ModelFitConstants::PARAMETER_UNIT_PROPERTY_NAME().c_str(), mitk::StringProperty::New("a")); - paramImage2->SetProperty(mitk::ModelFitConstants::PARAMETER_TYPE_PROPERTY_NAME().c_str(), mitk::StringProperty::New(mitk::ModelFitConstants::PARAMETER_TYPE_VALUE_DERIVED_PARAMETER().c_str())); - - storage->Add(node2, parents); - - //create result for Fit 2 - mitk::DataNode::Pointer node3 = mitk::DataNode::New(); - node3->SetName("Param_Other"); - mitk::Image::Pointer paramImage3 = mitk::Image::New(); - node3->SetData(paramImage3); - mitk::EnsureModelFitUID(node3); - paramImage3->SetProperty(mitk::ModelFitConstants::FIT_UID_PROPERTY_NAME().c_str(), mitk::StringProperty::New("Fit2")); - paramImage3->SetProperty(mitk::ModelFitConstants::FIT_NAME_PROPERTY_NAME().c_str(), mitk::StringProperty::New("MyName2")); - paramImage3->SetProperty(mitk::ModelFitConstants::FIT_TYPE_PROPERTY_NAME().c_str(), mitk::StringProperty::New(mitk::ModelFitConstants::FIT_TYPE_VALUE_PIXELBASED().c_str())); - paramImage3->SetProperty(mitk::ModelFitConstants::FIT_INPUT_IMAGEUID_PROPERTY_NAME().c_str(), mitk::StringProperty::New(inputUID.c_str())); - - paramImage3->SetProperty(mitk::ModelFitConstants::MODEL_TYPE_PROPERTY_NAME().c_str(), mitk::StringProperty::New("TestModels")); - paramImage3->SetProperty(mitk::ModelFitConstants::MODEL_NAME_PROPERTY_NAME().c_str(), mitk::StringProperty::New("TestModel_2")); - paramImage3->SetProperty(mitk::ModelFitConstants::MODEL_FUNCTION_PROPERTY_NAME().c_str(), mitk::StringProperty::New("")); - paramImage3->SetProperty(mitk::ModelFitConstants::MODEL_FUNCTION_CLASS_PROPERTY_NAME().c_str(), mitk::StringProperty::New("ModelClass_B")); - - paramImage3->SetProperty(mitk::ModelFitConstants::PARAMETER_NAME_PROPERTY_NAME().c_str(), mitk::StringProperty::New("Param_Other")); - paramImage3->SetProperty(mitk::ModelFitConstants::PARAMETER_UNIT_PROPERTY_NAME().c_str(), mitk::StringProperty::New("a")); - - storage->Add(node3, parents); - - return storage; -} - -int mitkModelFitInfoTest(int /*argc*/, char*[] /*argv[]*/) +class mitkModelFitInfoTestSuite : public mitk::TestFixture { - MITK_TEST_BEGIN("mitkModelFitTest") - - mitk::modelFit::Parameter::Pointer p = mitk::modelFit::Parameter::New(); - p->name = "p"; - mitk::modelFit::ModelFitInfo::Pointer fit = mitk::modelFit::ModelFitInfo::New(); - fit->AddParameter(p); - MITK_TEST_CONDITION_REQUIRED(fit->GetParameters().size() == 1, - "Testing if AddParameter successfully adds a parameter."); - - mitk::modelFit::Parameter::ConstPointer resultParam = fit->GetParameter("test", - mitk::modelFit::Parameter::ParameterType); - MITK_TEST_CONDITION_REQUIRED(resultParam.IsNull(), - "Testing if GetParameter returns NULL for wrong parameter."); - - resultParam = fit->GetParameter("p", mitk::modelFit::Parameter::ParameterType); - MITK_TEST_CONDITION_REQUIRED(resultParam == p, - "Testing if GetParameter returns the correct parameter."); - - p->type = mitk::modelFit::Parameter::CriterionType; - resultParam = fit->GetParameter("p", mitk::modelFit::Parameter::CriterionType); - MITK_TEST_CONDITION_REQUIRED(resultParam == p, - "Testing if GetParameter returns the correct parameter with a " << - "non-default type."); - - fit->DeleteParameter("test", mitk::modelFit::Parameter::CriterionType); - MITK_TEST_CONDITION_REQUIRED(fit->GetParameters().size() == 1, - "Testing if DeleteParameter fails for wrong parameter."); - - fit->DeleteParameter("p", mitk::modelFit::Parameter::CriterionType); - MITK_TEST_CONDITION_REQUIRED(fit->GetParameters().size() == 0, - "Testing if DeleteParameter successfully removes a parameter."); - - mitk::DataNode::Pointer node = generateModelFitTestNode(); - mitk::DataNode::Pointer invalideNode = mitk::DataNode::New(); - - MITK_TEST_FOR_EXCEPTION(mitk::modelFit::ModelFitException, - mitk::modelFit::GetMandatoryProperty(node.GetPointer(), "modelfit.testInvalid")); - MITK_TEST_FOR_EXCEPTION(mitk::modelFit::ModelFitException, - mitk::modelFit::GetMandatoryProperty(node.GetPointer(), "modelfit.testEmpty")); - - MITK_TEST_CONDITION_REQUIRED(mitk::modelFit::GetMandatoryProperty(node.GetPointer(), "modelfit.testValid") - == "test", - "Testing if GetMandatoryProperty returns the correct value."); - - mitk::StandaloneDataStorage::Pointer storage = generateModelFitTestStorage(); - - MITK_TEST_CONDITION_REQUIRED(mitk::modelFit::CreateFitInfoFromNode("Fit1",nullptr).IsNull(), - "Testing if CreateFitInfoFromNode returns NULL for invalid node."); - - MITK_TEST_CONDITION_REQUIRED(mitk::modelFit::CreateFitInfoFromNode("invalide_UID",storage).IsNull(), - "Testing if CreateFitInfoFromNode returns NULL for node with " << - "missing properties."); - - mitk::DataNode::Pointer testNode = storage->GetNamedNode("Param1"); - mitk::modelFit::ModelFitInfo::Pointer resultFit = mitk::modelFit::CreateFitInfoFromNode("Fit1", storage); - MITK_TEST_CONDITION_REQUIRED(resultFit.IsNotNull(), - "Testing if CreateFitInfoFromNode returns a valid model fit info."); - MITK_TEST_CONDITION_REQUIRED(resultFit->fitType == mitk::ModelFitConstants::FIT_TYPE_VALUE_PIXELBASED() && - resultFit->uid == "Fit1" && - resultFit->fitName == "MyName1" && - resultFit->modelType == "TestModels" && - resultFit->modelName == "TestModel_1" && - resultFit->function == ""&& - resultFit->functionClassID == "ModelClass" && - resultFit->x == "myX" && - resultFit->xAxisName == mitk::ModelFitConstants::XAXIS_NAME_VALUE_DEFAULT() && - resultFit->xAxisUnit == "h" && - resultFit->yAxisName == mitk::ModelFitConstants::YAXIS_NAME_VALUE_DEFAULT() && - resultFit->yAxisUnit == "kg" && - resultFit->GetParameters().size() == 2, - "Testing if CreateFitInfoFromNode creates a fit with correct attributes."); - - mitk::modelFit::Parameter::ConstPointer param = resultFit->GetParameter("Param1",mitk::modelFit::Parameter::ParameterType); - MITK_TEST_CONDITION_REQUIRED(param.IsNotNull(), - "Testing if param 1 exists."); - - MITK_TEST_CONDITION_REQUIRED(param->name == "Param1" && param->unit == "b" && param->image == testNode->GetData(), - "Testing if param 1 is configured correctly."); - - mitk::modelFit::Parameter::ConstPointer param2 = resultFit->GetParameter("Param2",mitk::modelFit::Parameter::DerivedType); - MITK_TEST_CONDITION_REQUIRED(param2.IsNotNull(), - "Testing if param 2 exists."); - - testNode = storage->GetNamedNode("Param2"); - MITK_TEST_CONDITION_REQUIRED(param2->name == "Param2" && param2->unit == "a" && param2->image == testNode->GetData(), - "Testing if param 2 is configured correctly."); - - MITK_TEST_CONDITION_REQUIRED(mitk::modelFit::GetNodesOfFit(resultFit->uid,storage)->Size() == 2, - "Testing if GetNodesOfFit works correctly for Fit1"); - - MITK_TEST_CONDITION_REQUIRED(mitk::modelFit::GetNodesOfFit("Fit2",storage)->Size() == 1, - "Testing if GetNodesOfFit works correctly for Fit1"); - - MITK_TEST_CONDITION_REQUIRED(mitk::modelFit::GetNodesOfFit("unkown_fit",storage)->Size() == 0, - "Testing if GetNodesOfFit works correctly for unkown fits."); - - MITK_TEST_CONDITION_REQUIRED(mitk::modelFit::GetNodesOfFit("unkown_fit",nullptr).IsNull(), - "Testing if GetNodesOfFit works correctly for illegal calls."); - - testNode = storage->GetNamedNode("Input"); - mitk::modelFit::NodeUIDSetType uidSet = mitk::modelFit::GetFitUIDsOfNode(testNode,storage); - - MITK_TEST_CONDITION_REQUIRED(uidSet.size() == 2 && - uidSet.find("Fit1")!=uidSet.end() && - uidSet.find("Fit2")!=uidSet.end(), - "Testing if GetFitUIDsOfNode works correctly."); - - uidSet = mitk::modelFit::GetFitUIDsOfNode(nullptr,storage); - - MITK_TEST_CONDITION_REQUIRED(uidSet.size() == 0, - "Testing if GetFitUIDsOfNode works correctly with invalid node."); + CPPUNIT_TEST_SUITE(mitkModelFitInfoTestSuite); + MITK_TEST(CheckModelFitInfo); + MITK_TEST(CheckGetMandatoryProperty); + MITK_TEST(CheckCreateFitInfoFromNode_Legacy); + MITK_TEST(CheckCreateFitInfoFromNode); + MITK_TEST(CheckGetNodesOfFit); + MITK_TEST(CheckGetFitUIDsOfNode); + + CPPUNIT_TEST_SUITE_END(); + + mitk::StandaloneDataStorage::Pointer m_Storage; + mitk::Image::Pointer m_ParamImage; + mitk::Image::Pointer m_ParamImage2; + mitk::Image::Pointer m_ParamImage_legacy; + mitk::Image::Pointer m_ParamImage2_legacy; + mitk::DataNode::Pointer m_ParamImageNode; + mitk::DataNode::Pointer m_ParamImageNode2; + mitk::DataNode::Pointer m_ParamImageNode_legacy; + mitk::DataNode::Pointer m_ParamImageNode2_legacy; + +public: + void setUp() override + { + m_Storage = mitk::StandaloneDataStorage::New(); + //create input node + mitk::DataNode::Pointer inputNode = mitk::DataNode::New(); + inputNode->SetName("Input"); + mitk::Image::Pointer image = mitk::Image::New(); + inputNode->SetData(image); + mitk::modelFit::ModelFitInfo::UIDType inputUID = ensureModelFitUID(image); + + m_Storage->Add(inputNode); + + mitk::DataStorage::SetOfObjects::Pointer parents = mitk::DataStorage::SetOfObjects::New(); + parents->push_back(inputNode); + + ///////////////////////////////////////////////////// + //Create nodes for a fit (new style using rules) + ///////////////////////////////////////////////////// + auto rule = mitk::ModelFitResultRelationRule::New(); + //create first result for FitLegacy + m_ParamImageNode = mitk::DataNode::New(); + m_ParamImage = mitk::Image::New(); + m_ParamImageNode->SetData(m_ParamImage); + m_ParamImageNode->SetName("Param1"); + m_ParamImage->SetProperty(mitk::ModelFitConstants::FIT_UID_PROPERTY_NAME().c_str(), mitk::StringProperty::New("Fit")); + m_ParamImage->SetProperty(mitk::ModelFitConstants::FIT_NAME_PROPERTY_NAME().c_str(), mitk::StringProperty::New("MyName1")); + m_ParamImage->SetProperty(mitk::ModelFitConstants::FIT_TYPE_PROPERTY_NAME().c_str(), mitk::StringProperty::New(mitk::ModelFitConstants::FIT_TYPE_VALUE_PIXELBASED().c_str())); + + m_ParamImage->SetProperty(mitk::ModelFitConstants::MODEL_TYPE_PROPERTY_NAME().c_str(), mitk::StringProperty::New("TestModels")); + m_ParamImage->SetProperty(mitk::ModelFitConstants::MODEL_NAME_PROPERTY_NAME().c_str(), mitk::StringProperty::New("TestModel_1")); + m_ParamImage->SetProperty(mitk::ModelFitConstants::MODEL_FUNCTION_PROPERTY_NAME().c_str(), mitk::StringProperty::New("")); + m_ParamImage->SetProperty(mitk::ModelFitConstants::MODEL_FUNCTION_CLASS_PROPERTY_NAME().c_str(), mitk::StringProperty::New("ModelClass")); + m_ParamImage->SetProperty(mitk::ModelFitConstants::MODEL_X_PROPERTY_NAME().c_str(), mitk::StringProperty::New("myX")); + + m_ParamImage->SetProperty(mitk::ModelFitConstants::XAXIS_NAME_PROPERTY_NAME().c_str(), mitk::StringProperty::New(mitk::ModelFitConstants::XAXIS_NAME_VALUE_DEFAULT().c_str())); + m_ParamImage->SetProperty(mitk::ModelFitConstants::XAXIS_UNIT_PROPERTY_NAME().c_str(), mitk::StringProperty::New("h")); + m_ParamImage->SetProperty(mitk::ModelFitConstants::YAXIS_NAME_PROPERTY_NAME().c_str(), mitk::StringProperty::New(mitk::ModelFitConstants::YAXIS_NAME_VALUE_DEFAULT().c_str())); + m_ParamImage->SetProperty(mitk::ModelFitConstants::YAXIS_UNIT_PROPERTY_NAME().c_str(), mitk::StringProperty::New("kg")); + + m_ParamImage->SetProperty(mitk::ModelFitConstants::PARAMETER_NAME_PROPERTY_NAME().c_str(), mitk::StringProperty::New("Param1")); + m_ParamImage->SetProperty(mitk::ModelFitConstants::PARAMETER_UNIT_PROPERTY_NAME().c_str(), mitk::StringProperty::New("b")); + m_ParamImage->SetProperty(mitk::ModelFitConstants::PARAMETER_TYPE_PROPERTY_NAME().c_str(), mitk::StringProperty::New(mitk::ModelFitConstants::PARAMETER_TYPE_VALUE_PARAMETER().c_str())); + rule->Connect(m_ParamImage, image); + m_Storage->Add(m_ParamImageNode, parents); + + //create second result for Fit + m_ParamImageNode2 = mitk::DataNode::New(); + m_ParamImageNode2->SetName("Param2"); + m_ParamImage2 = mitk::Image::New(); + m_ParamImageNode2->SetData(m_ParamImage2); + m_ParamImage2->SetProperty(mitk::ModelFitConstants::FIT_UID_PROPERTY_NAME().c_str(), mitk::StringProperty::New("Fit")); + m_ParamImage2->SetProperty(mitk::ModelFitConstants::FIT_NAME_PROPERTY_NAME().c_str(), mitk::StringProperty::New("MyName1")); + m_ParamImage2->SetProperty(mitk::ModelFitConstants::FIT_TYPE_PROPERTY_NAME().c_str(), mitk::StringProperty::New(mitk::ModelFitConstants::FIT_TYPE_VALUE_PIXELBASED().c_str())); + + m_ParamImage2->SetProperty(mitk::ModelFitConstants::MODEL_TYPE_PROPERTY_NAME().c_str(), mitk::StringProperty::New("TestModels")); + m_ParamImage2->SetProperty(mitk::ModelFitConstants::MODEL_NAME_PROPERTY_NAME().c_str(), mitk::StringProperty::New("TestModel_1")); + m_ParamImage2->SetProperty(mitk::ModelFitConstants::MODEL_FUNCTION_PROPERTY_NAME().c_str(), mitk::StringProperty::New("")); + m_ParamImage2->SetProperty(mitk::ModelFitConstants::MODEL_FUNCTION_CLASS_PROPERTY_NAME().c_str(), mitk::StringProperty::New("ModelClass")); + m_ParamImage2->SetProperty(mitk::ModelFitConstants::MODEL_X_PROPERTY_NAME().c_str(), mitk::StringProperty::New("myX")); + + m_ParamImage2->SetProperty(mitk::ModelFitConstants::XAXIS_NAME_PROPERTY_NAME().c_str(), mitk::StringProperty::New(mitk::ModelFitConstants::XAXIS_NAME_VALUE_DEFAULT().c_str())); + m_ParamImage2->SetProperty(mitk::ModelFitConstants::XAXIS_UNIT_PROPERTY_NAME().c_str(), mitk::StringProperty::New("h")); + m_ParamImage2->SetProperty(mitk::ModelFitConstants::YAXIS_NAME_PROPERTY_NAME().c_str(), mitk::StringProperty::New(mitk::ModelFitConstants::YAXIS_NAME_VALUE_DEFAULT().c_str())); + m_ParamImage2->SetProperty(mitk::ModelFitConstants::YAXIS_UNIT_PROPERTY_NAME().c_str(), mitk::StringProperty::New("kg")); + + m_ParamImage2->SetProperty(mitk::ModelFitConstants::PARAMETER_NAME_PROPERTY_NAME().c_str(), mitk::StringProperty::New("Param2")); + m_ParamImage2->SetProperty(mitk::ModelFitConstants::PARAMETER_UNIT_PROPERTY_NAME().c_str(), mitk::StringProperty::New("a")); + m_ParamImage2->SetProperty(mitk::ModelFitConstants::PARAMETER_TYPE_PROPERTY_NAME().c_str(), mitk::StringProperty::New(mitk::ModelFitConstants::PARAMETER_TYPE_VALUE_DERIVED_PARAMETER().c_str())); + rule->Connect(m_ParamImage2, image); + m_Storage->Add(m_ParamImageNode2, parents); + + ///////////////////////////////////////////////////// + //Create nodes for a fit in legacy mode (old fit uid) + ///////////////////////////////////////////////////// + + //create first result for FitLegacy + m_ParamImageNode_legacy = mitk::DataNode::New(); + m_ParamImage_legacy = mitk::Image::New(); + m_ParamImageNode_legacy->SetData(m_ParamImage_legacy); + m_ParamImageNode_legacy->SetName("Param1_legacy"); + ensureModelFitUID(m_ParamImage_legacy); + m_ParamImage_legacy->SetProperty(mitk::ModelFitConstants::FIT_UID_PROPERTY_NAME().c_str(), mitk::StringProperty::New("FitLegacy")); + m_ParamImage_legacy->SetProperty(mitk::ModelFitConstants::FIT_NAME_PROPERTY_NAME().c_str(), mitk::StringProperty::New("MyName1")); + m_ParamImage_legacy->SetProperty(mitk::ModelFitConstants::FIT_TYPE_PROPERTY_NAME().c_str(), mitk::StringProperty::New(mitk::ModelFitConstants::FIT_TYPE_VALUE_PIXELBASED().c_str())); + m_ParamImage_legacy->SetProperty(mitk::ModelFitConstants::LEGACY_FIT_INPUT_IMAGEUID_PROPERTY_NAME().c_str(), mitk::StringProperty::New(inputUID.c_str())); + + m_ParamImage_legacy->SetProperty(mitk::ModelFitConstants::MODEL_TYPE_PROPERTY_NAME().c_str(), mitk::StringProperty::New("TestModels")); + m_ParamImage_legacy->SetProperty(mitk::ModelFitConstants::MODEL_NAME_PROPERTY_NAME().c_str(), mitk::StringProperty::New("TestModel_1")); + m_ParamImage_legacy->SetProperty(mitk::ModelFitConstants::MODEL_FUNCTION_PROPERTY_NAME().c_str(), mitk::StringProperty::New("")); + m_ParamImage_legacy->SetProperty(mitk::ModelFitConstants::MODEL_FUNCTION_CLASS_PROPERTY_NAME().c_str(), mitk::StringProperty::New("ModelClass")); + m_ParamImage_legacy->SetProperty(mitk::ModelFitConstants::MODEL_X_PROPERTY_NAME().c_str(), mitk::StringProperty::New("myX")); + + m_ParamImage_legacy->SetProperty(mitk::ModelFitConstants::XAXIS_NAME_PROPERTY_NAME().c_str(), mitk::StringProperty::New(mitk::ModelFitConstants::XAXIS_NAME_VALUE_DEFAULT().c_str())); + m_ParamImage_legacy->SetProperty(mitk::ModelFitConstants::XAXIS_UNIT_PROPERTY_NAME().c_str(), mitk::StringProperty::New("h")); + m_ParamImage_legacy->SetProperty(mitk::ModelFitConstants::YAXIS_NAME_PROPERTY_NAME().c_str(), mitk::StringProperty::New(mitk::ModelFitConstants::YAXIS_NAME_VALUE_DEFAULT().c_str())); + m_ParamImage_legacy->SetProperty(mitk::ModelFitConstants::YAXIS_UNIT_PROPERTY_NAME().c_str(), mitk::StringProperty::New("kg")); + + m_ParamImage_legacy->SetProperty(mitk::ModelFitConstants::PARAMETER_NAME_PROPERTY_NAME().c_str(), mitk::StringProperty::New("Param1_legacy")); + m_ParamImage_legacy->SetProperty(mitk::ModelFitConstants::PARAMETER_UNIT_PROPERTY_NAME().c_str(), mitk::StringProperty::New("b")); + m_ParamImage_legacy->SetProperty(mitk::ModelFitConstants::PARAMETER_TYPE_PROPERTY_NAME().c_str(), mitk::StringProperty::New(mitk::ModelFitConstants::PARAMETER_TYPE_VALUE_PARAMETER().c_str())); + + m_Storage->Add(m_ParamImageNode_legacy, parents); + + //create second result for FitLegacy + m_ParamImageNode2_legacy = mitk::DataNode::New(); + m_ParamImageNode2_legacy->SetName("Param2_legacy"); + m_ParamImage2_legacy = mitk::Image::New(); + m_ParamImageNode2_legacy->SetData(m_ParamImage2_legacy); + ensureModelFitUID(m_ParamImage2_legacy); + m_ParamImage2_legacy->SetProperty(mitk::ModelFitConstants::FIT_UID_PROPERTY_NAME().c_str(), mitk::StringProperty::New("FitLegacy")); + m_ParamImage2_legacy->SetProperty(mitk::ModelFitConstants::FIT_NAME_PROPERTY_NAME().c_str(), mitk::StringProperty::New("MyName1")); + m_ParamImage2_legacy->SetProperty(mitk::ModelFitConstants::FIT_TYPE_PROPERTY_NAME().c_str(), mitk::StringProperty::New(mitk::ModelFitConstants::FIT_TYPE_VALUE_PIXELBASED().c_str())); + m_ParamImage2_legacy->SetProperty(mitk::ModelFitConstants::LEGACY_FIT_INPUT_IMAGEUID_PROPERTY_NAME().c_str(), mitk::StringProperty::New(inputUID.c_str())); + + m_ParamImage2_legacy->SetProperty(mitk::ModelFitConstants::MODEL_TYPE_PROPERTY_NAME().c_str(), mitk::StringProperty::New("TestModels")); + m_ParamImage2_legacy->SetProperty(mitk::ModelFitConstants::MODEL_NAME_PROPERTY_NAME().c_str(), mitk::StringProperty::New("TestModel_1")); + m_ParamImage2_legacy->SetProperty(mitk::ModelFitConstants::MODEL_FUNCTION_PROPERTY_NAME().c_str(), mitk::StringProperty::New("")); + m_ParamImage2_legacy->SetProperty(mitk::ModelFitConstants::MODEL_FUNCTION_CLASS_PROPERTY_NAME().c_str(), mitk::StringProperty::New("ModelClass")); + m_ParamImage2_legacy->SetProperty(mitk::ModelFitConstants::MODEL_X_PROPERTY_NAME().c_str(), mitk::StringProperty::New("myX")); + + m_ParamImage2_legacy->SetProperty(mitk::ModelFitConstants::XAXIS_NAME_PROPERTY_NAME().c_str(), mitk::StringProperty::New(mitk::ModelFitConstants::XAXIS_NAME_VALUE_DEFAULT().c_str())); + m_ParamImage2_legacy->SetProperty(mitk::ModelFitConstants::XAXIS_UNIT_PROPERTY_NAME().c_str(), mitk::StringProperty::New("h")); + m_ParamImage2_legacy->SetProperty(mitk::ModelFitConstants::YAXIS_NAME_PROPERTY_NAME().c_str(), mitk::StringProperty::New(mitk::ModelFitConstants::YAXIS_NAME_VALUE_DEFAULT().c_str())); + m_ParamImage2_legacy->SetProperty(mitk::ModelFitConstants::YAXIS_UNIT_PROPERTY_NAME().c_str(), mitk::StringProperty::New("kg")); + + m_ParamImage2_legacy->SetProperty(mitk::ModelFitConstants::PARAMETER_NAME_PROPERTY_NAME().c_str(), mitk::StringProperty::New("Param2_legacy")); + m_ParamImage2_legacy->SetProperty(mitk::ModelFitConstants::PARAMETER_UNIT_PROPERTY_NAME().c_str(), mitk::StringProperty::New("a")); + m_ParamImage2_legacy->SetProperty(mitk::ModelFitConstants::PARAMETER_TYPE_PROPERTY_NAME().c_str(), mitk::StringProperty::New(mitk::ModelFitConstants::PARAMETER_TYPE_VALUE_DERIVED_PARAMETER().c_str())); + + m_Storage->Add(m_ParamImageNode2_legacy, parents); + + ///////////////////////////////////////////////////// + //Create nodes for a fit on other input + auto anotherInputNode = mitk::DataNode::New(); + anotherInputNode->SetName("AnotherInput"); + auto anotherImage = mitk::Image::New(); + anotherInputNode->SetData(anotherImage); + + m_Storage->Add(anotherInputNode); + + parents = mitk::DataStorage::SetOfObjects::New(); + parents->push_back(anotherInputNode); + + mitk::DataNode::Pointer node3 = mitk::DataNode::New(); + node3->SetName("Param_Other"); + mitk::Image::Pointer paramImage3 = mitk::Image::New(); + node3->SetData(paramImage3); + paramImage3->SetProperty(mitk::ModelFitConstants::FIT_UID_PROPERTY_NAME().c_str(), mitk::StringProperty::New("Fit2")); + paramImage3->SetProperty(mitk::ModelFitConstants::FIT_NAME_PROPERTY_NAME().c_str(), mitk::StringProperty::New("MyName2")); + paramImage3->SetProperty(mitk::ModelFitConstants::FIT_TYPE_PROPERTY_NAME().c_str(), mitk::StringProperty::New(mitk::ModelFitConstants::FIT_TYPE_VALUE_PIXELBASED().c_str())); + + paramImage3->SetProperty(mitk::ModelFitConstants::MODEL_TYPE_PROPERTY_NAME().c_str(), mitk::StringProperty::New("TestModels")); + paramImage3->SetProperty(mitk::ModelFitConstants::MODEL_NAME_PROPERTY_NAME().c_str(), mitk::StringProperty::New("TestModel_2")); + paramImage3->SetProperty(mitk::ModelFitConstants::MODEL_FUNCTION_PROPERTY_NAME().c_str(), mitk::StringProperty::New("")); + paramImage3->SetProperty(mitk::ModelFitConstants::MODEL_FUNCTION_CLASS_PROPERTY_NAME().c_str(), mitk::StringProperty::New("ModelClass_B")); + + paramImage3->SetProperty(mitk::ModelFitConstants::PARAMETER_NAME_PROPERTY_NAME().c_str(), mitk::StringProperty::New("Param_Other")); + paramImage3->SetProperty(mitk::ModelFitConstants::PARAMETER_UNIT_PROPERTY_NAME().c_str(), mitk::StringProperty::New("a")); + rule->Connect(paramImage3, anotherImage); + m_Storage->Add(node3, parents); + + } + + void tearDown() override + { + } + + void CheckModelFitInfo() + { + mitk::modelFit::Parameter::Pointer p = mitk::modelFit::Parameter::New(); + p->name = "p"; + mitk::modelFit::ModelFitInfo::Pointer fit = mitk::modelFit::ModelFitInfo::New(); + fit->AddParameter(p); + CPPUNIT_ASSERT_MESSAGE("AddParameter unsuccessfully adds a parameter.", fit->GetParameters().size() == 1); + + mitk::modelFit::Parameter::ConstPointer resultParam = fit->GetParameter("test", + mitk::modelFit::Parameter::ParameterType); + CPPUNIT_ASSERT_MESSAGE("Testing if GetParameter returns NULL for wrong parameter.", resultParam.IsNull()); + + resultParam = fit->GetParameter("p", mitk::modelFit::Parameter::ParameterType); + CPPUNIT_ASSERT_MESSAGE("Testing if GetParameter returns the correct parameter.", resultParam == p); + + p->type = mitk::modelFit::Parameter::CriterionType; + resultParam = fit->GetParameter("p", mitk::modelFit::Parameter::CriterionType); + CPPUNIT_ASSERT_MESSAGE("Testing if GetParameter returns the correct parameter with a non-default type.", resultParam == p); + + fit->DeleteParameter("test", mitk::modelFit::Parameter::CriterionType); + CPPUNIT_ASSERT_MESSAGE("Testing if DeleteParameter fails for wrong parameter.", fit->GetParameters().size() == 1); + + fit->DeleteParameter("p", mitk::modelFit::Parameter::CriterionType); + CPPUNIT_ASSERT_MESSAGE("Testing if DeleteParameter successfully removes a parameter.", fit->GetParameters().size() == 0); + } + + void CheckGetMandatoryProperty() + { + mitk::DataNode::Pointer node = generateModelFitTestNode(); + mitk::DataNode::Pointer invalideNode = mitk::DataNode::New(); + + CPPUNIT_ASSERT_THROW(mitk::modelFit::GetMandatoryProperty(node.GetPointer(), "modelfit.testInvalid"), mitk::modelFit::ModelFitException); + CPPUNIT_ASSERT_THROW(mitk::modelFit::GetMandatoryProperty(node.GetPointer(), "modelfit.testEmpty"), mitk::modelFit::ModelFitException); + + CPPUNIT_ASSERT_MESSAGE("Testing if GetMandatoryProperty returns the correct value.", mitk::modelFit::GetMandatoryProperty(node.GetPointer(), "modelfit.testValid") + == "test"); + } + + void CheckCreateFitInfoFromNode_Legacy() + { + CPPUNIT_ASSERT_MESSAGE("Testing if CreateFitInfoFromNode returns NULL for invalid node.", mitk::modelFit::CreateFitInfoFromNode("FitLegacy", nullptr).IsNull()); + + CPPUNIT_ASSERT_MESSAGE("Testing if CreateFitInfoFromNode returns NULL for node with missing properties.", mitk::modelFit::CreateFitInfoFromNode("invalide_UID", m_Storage).IsNull()); + + mitk::modelFit::ModelFitInfo::Pointer resultFit = mitk::modelFit::CreateFitInfoFromNode("FitLegacy", m_Storage); + CPPUNIT_ASSERT_MESSAGE("Testing if CreateFitInfoFromNode returns a valid model fit info.", resultFit.IsNotNull()); + CPPUNIT_ASSERT_MESSAGE("Testing if CreateFitInfoFromNode creates a fit with correct attributes.", + resultFit->fitType == mitk::ModelFitConstants::FIT_TYPE_VALUE_PIXELBASED() && + resultFit->uid == "FitLegacy" && + resultFit->fitName == "MyName1" && + resultFit->modelType == "TestModels" && + resultFit->modelName == "TestModel_1" && + resultFit->function == "" && + resultFit->functionClassID == "ModelClass" && + resultFit->x == "myX" && + resultFit->xAxisName == mitk::ModelFitConstants::XAXIS_NAME_VALUE_DEFAULT() && + resultFit->xAxisUnit == "h" && + resultFit->yAxisName == mitk::ModelFitConstants::YAXIS_NAME_VALUE_DEFAULT() && + resultFit->yAxisUnit == "kg" && + resultFit->GetParameters().size() == 2); + + mitk::modelFit::Parameter::ConstPointer param = resultFit->GetParameter("Param1_legacy", mitk::modelFit::Parameter::ParameterType); + CPPUNIT_ASSERT_MESSAGE("Testing if param 1 exists.", param.IsNotNull()); + + CPPUNIT_ASSERT_MESSAGE("Testing if param 1 is configured correctly.", param->name == "Param1_legacy" && param->unit == "b" && param->image == m_ParamImage_legacy); + + mitk::modelFit::Parameter::ConstPointer param2 = resultFit->GetParameter("Param2_legacy", mitk::modelFit::Parameter::DerivedType); + CPPUNIT_ASSERT_MESSAGE("Testing if param 2 exists.", param2.IsNotNull()); + + CPPUNIT_ASSERT_MESSAGE("Testing if param 2 is configured correctly.", param2->name == "Param2_legacy" && param2->unit == "a" && param2->image == m_ParamImage2_legacy); + } + + void CheckCreateFitInfoFromNode() + { + CPPUNIT_ASSERT_MESSAGE("Testing if CreateFitInfoFromNode returns NULL for invalid node.", mitk::modelFit::CreateFitInfoFromNode("Fit", nullptr).IsNull()); + + CPPUNIT_ASSERT_MESSAGE("Testing if CreateFitInfoFromNode returns NULL for node with missing properties.", mitk::modelFit::CreateFitInfoFromNode("invalide_UID", m_Storage).IsNull()); + + mitk::modelFit::ModelFitInfo::Pointer resultFit = mitk::modelFit::CreateFitInfoFromNode("Fit", m_Storage); + CPPUNIT_ASSERT_MESSAGE("Testing if CreateFitInfoFromNode returns a valid model fit info.", resultFit.IsNotNull()); + CPPUNIT_ASSERT_MESSAGE("Testing if CreateFitInfoFromNode creates a fit with correct attributes.", + resultFit->fitType == mitk::ModelFitConstants::FIT_TYPE_VALUE_PIXELBASED() && + resultFit->uid == "Fit" && + resultFit->fitName == "MyName1" && + resultFit->modelType == "TestModels" && + resultFit->modelName == "TestModel_1" && + resultFit->function == "" && + resultFit->functionClassID == "ModelClass" && + resultFit->x == "myX" && + resultFit->xAxisName == mitk::ModelFitConstants::XAXIS_NAME_VALUE_DEFAULT() && + resultFit->xAxisUnit == "h" && + resultFit->yAxisName == mitk::ModelFitConstants::YAXIS_NAME_VALUE_DEFAULT() && + resultFit->yAxisUnit == "kg" && + resultFit->GetParameters().size() == 2); + + mitk::modelFit::Parameter::ConstPointer param = resultFit->GetParameter("Param1", mitk::modelFit::Parameter::ParameterType); + CPPUNIT_ASSERT_MESSAGE("Testing if param 1 exists.", param.IsNotNull()); + + CPPUNIT_ASSERT_MESSAGE("Testing if param 1 is configured correctly.", param->name == "Param1" && param->unit == "b" && param->image == m_ParamImage); + + mitk::modelFit::Parameter::ConstPointer param2 = resultFit->GetParameter("Param2", mitk::modelFit::Parameter::DerivedType); + CPPUNIT_ASSERT_MESSAGE("Testing if param 2 exists.", param2.IsNotNull()); + + CPPUNIT_ASSERT_MESSAGE("Testing if param 2 is configured correctly.", param2->name == "Param2" && param2->unit == "a" && param2->image == m_ParamImage2); + } + + void CheckGetNodesOfFit() + { + auto nodes = mitk::modelFit::GetNodesOfFit("Fit", m_Storage); + CPPUNIT_ASSERT_MESSAGE("Testing if GetNodesOfFit works correctly for Fit", + nodes->Size() == 2); + CPPUNIT_ASSERT(std::find(nodes->begin(), nodes->end(), m_ParamImageNode.GetPointer()) != nodes->end()); + CPPUNIT_ASSERT(std::find(nodes->begin(), nodes->end(), m_ParamImageNode2.GetPointer()) != nodes->end()); + + nodes = mitk::modelFit::GetNodesOfFit("FitLegacy", m_Storage); + CPPUNIT_ASSERT_MESSAGE("Testing if GetNodesOfFit works correctly for FitLegacy", + nodes->Size() == 2); + CPPUNIT_ASSERT(std::find(nodes->begin(), nodes->end(), m_ParamImageNode_legacy.GetPointer()) != nodes->end()); + CPPUNIT_ASSERT(std::find(nodes->begin(), nodes->end(), m_ParamImageNode2_legacy.GetPointer()) != nodes->end()); + + CPPUNIT_ASSERT_MESSAGE("Testing if GetNodesOfFit works correctly for Fit2", + mitk::modelFit::GetNodesOfFit("Fit2", m_Storage)->Size() == 1); + + CPPUNIT_ASSERT_MESSAGE("Testing if GetNodesOfFit works correctly for unkown fits.", + mitk::modelFit::GetNodesOfFit("unkown_fit", m_Storage)->Size() == 0); + + CPPUNIT_ASSERT_MESSAGE("Testing if GetNodesOfFit works correctly for illegal calls.", + mitk::modelFit::GetNodesOfFit("unkown_fit", nullptr).IsNull()); + } + + void CheckGetFitUIDsOfNode() + { + auto testNode = m_Storage->GetNamedNode("Input"); + mitk::modelFit::NodeUIDSetType uidSet = mitk::modelFit::GetFitUIDsOfNode(testNode, m_Storage); + + CPPUNIT_ASSERT_MESSAGE("Testing if GetFitUIDsOfNode works correctly.", + uidSet.size() == 2 && + uidSet.find("Fit") != uidSet.end() && + uidSet.find("FitLegacy") != uidSet.end()); + + testNode = m_Storage->GetNamedNode("AnotherInput"); + uidSet = mitk::modelFit::GetFitUIDsOfNode(testNode, m_Storage); + + CPPUNIT_ASSERT_MESSAGE("Testing if GetFitUIDsOfNode works correctly.", + uidSet.size() == 1 && + uidSet.find("Fit2") != uidSet.end()); + + uidSet = mitk::modelFit::GetFitUIDsOfNode(nullptr, m_Storage); + + CPPUNIT_ASSERT_MESSAGE("Testing if GetFitUIDsOfNode works correctly with invalid node.", + uidSet.size() == 0); + + uidSet = mitk::modelFit::GetFitUIDsOfNode(testNode, nullptr); + + CPPUNIT_ASSERT_MESSAGE("Testing if GetFitUIDsOfNode works correctly with invalid storage.", + uidSet.size() == 0); + } +}; - uidSet = mitk::modelFit::GetFitUIDsOfNode(testNode,nullptr); - MITK_TEST_CONDITION_REQUIRED(uidSet.size() == 0, - "Testing if GetFitUIDsOfNode works correctly with invalid storage."); - - MITK_TEST_END() -} +MITK_TEST_SUITE_REGISTRATION(mitkModelFitInfo) \ No newline at end of file diff --git a/Modules/ModelFit/test/mitkModelFitUIDHelperTest.cpp b/Modules/ModelFit/test/mitkModelFitUIDHelperTest.cpp deleted file mode 100644 index 19dcf8c8d0..0000000000 --- a/Modules/ModelFit/test/mitkModelFitUIDHelperTest.cpp +++ /dev/null @@ -1,71 +0,0 @@ -/*============================================================================ - -The Medical Imaging Interaction Toolkit (MITK) - -Copyright (c) German Cancer Research Center (DKFZ) -All rights reserved. - -Use of this source code is governed by a 3-clause BSD license that can be -found in the LICENSE file. - -============================================================================*/ - -#include -#include "mitkTestingMacros.h" -#include "mitkDataNode.h" -#include "mitkImage.h" -#include "mitkStandaloneDataStorage.h" - -#include "mitkModelFitUIDHelper.h" - -int mitkModelFitUIDHelperTest(int /*argc*/, char*[] /*argv[]*/) -{ - MITK_TEST_BEGIN("mitkModelFitUIDHelperTest") - - mitk::DataNode::Pointer node1 = mitk::DataNode::New(); - node1->SetData(mitk::Image::New()); - mitk::DataNode::Pointer node2 = mitk::DataNode::New(); - node2->SetData(mitk::Image::New()); - - mitk::DataNode* nullNode = nullptr; - mitk::BaseData* nullData = nullptr; - - MITK_TEST_FOR_EXCEPTION(mitk::Exception, mitk::EnsureModelFitUID(nullNode)); - MITK_TEST_CONDITION_REQUIRED(mitk::CheckModelFitUID(nullNode,"testUID") == false, - "Testing if CheckModelFitUID fails of null pointer is passed."); - MITK_TEST_FOR_EXCEPTION(mitk::Exception, mitk::EnsureModelFitUID(nullData)); - MITK_TEST_CONDITION_REQUIRED(mitk::CheckModelFitUID(nullData, "testUID") == false, - "Testing if CheckModelFitUID fails of null pointer is passed."); - - mitk::NodeUIDType uid = mitk::EnsureModelFitUID(node1); - - MITK_TEST_CONDITION_REQUIRED(mitk::CheckModelFitUID(node1,"testUID") == false, - "Testing if CheckModelFitUID fails of wrong UID is passed."); - MITK_TEST_CONDITION_REQUIRED(mitk::CheckModelFitUID(node1, uid) == true, - "Testing if CheckModelFitUID succeeds if correct UID is passed."); - - mitk::NodeUIDType uid2ndCall = mitk::EnsureModelFitUID(node1); - - MITK_TEST_CONDITION_REQUIRED(uid == uid2ndCall, - "Testing if EnsureModelFitUID does not create new UIDs on multiple calls."); - - mitk::NodeUIDType uid2 = mitk::EnsureModelFitUID(node2); - - MITK_TEST_CONDITION_REQUIRED(uid != uid2, - "Testing if EnsureModelFitUID does create different UIDs for different nodes."); - - mitk::StandaloneDataStorage::Pointer storage = mitk::StandaloneDataStorage::New(); - storage->Add(node1); - storage->Add(node2); - - MITK_TEST_CONDITION_REQUIRED(node1 == GetNodeByModelFitUID(storage,uid), - "Testing if GetNodeByModelFitUID finds node 1."); - - MITK_TEST_CONDITION_REQUIRED(node2 == GetNodeByModelFitUID(storage,uid2), - "Testing if GetNodeByModelFitUID finds node 2."); - - MITK_TEST_CONDITION_REQUIRED(GetNodeByModelFitUID(storage,"unkown_uid").IsNull(), - "Testing if GetNodeByModelFitUID returns NULL for unkown UID."); - - MITK_TEST_END() -} diff --git a/Modules/Pharmacokinetics/cmdapps/MRPerfusionMiniApp.cpp b/Modules/Pharmacokinetics/cmdapps/MRPerfusionMiniApp.cpp index 03af6417c2..5a44e08d26 100644 --- a/Modules/Pharmacokinetics/cmdapps/MRPerfusionMiniApp.cpp +++ b/Modules/Pharmacokinetics/cmdapps/MRPerfusionMiniApp.cpp @@ -1,890 +1,890 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // std includes #include // itk includes #include "itksys/SystemTools.hxx" // CTK includes #include "mitkCommandLineParser.h" // MITK includes #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include std::string inFilename; std::string outFileName; std::string maskFileName; std::string aifMaskFileName; std::string aifImageFileName; mitk::Image::Pointer image; mitk::Image::Pointer mask; mitk::Image::Pointer aifImage; mitk::Image::Pointer aifMask; bool useConstraints(false); bool verbose(false); bool roibased(false); bool preview(false); std::string modelName; float aifHematocritLevel(0); float brixInjectionTime(0); const std::string MODEL_NAME_2SL = "2SL"; const std::string MODEL_NAME_3SL = "3SL"; const std::string MODEL_NAME_descriptive = "descriptive"; const std::string MODEL_NAME_tofts = "tofts"; const std::string MODEL_NAME_2CX = "2CX"; void onFitEvent(::itk::Object* caller, const itk::EventObject & event, void* /*data*/) { itk::ProgressEvent progressEvent; if (progressEvent.CheckEvent(&event)) { mitk::ParameterFitImageGeneratorBase* castedReporter = dynamic_cast(caller); std::cout <GetProgress()*100 << "% "; } } void setupParser(mitkCommandLineParser& parser) { // set general information about your MiniApp parser.setCategory("Dynamic Data Analysis Tools"); parser.setTitle("MR Perfusion"); parser.setDescription("MiniApp that allows to fit MRI perfusion models and generates the according parameter maps. IMPORTANT!!!: The app assumes that the input images (signal and AIF) are concentration images. If your images do not hold this assumption, convert the image date before using this app (e.g. by using the signal-to-concentration-converter mini app."); parser.setContributor("DKFZ MIC"); //! [create parser] //! [add arguments] // how should arguments be prefixed parser.setArgumentPrefix("--", "-"); // add each argument, unless specified otherwise each argument is optional // see mitkCommandLineParser::addArgument for more information parser.beginGroup("Model parameters"); parser.addArgument( "model", "l", mitkCommandLineParser::String, "Model function", "Model that should be used to fit the concentration signal. Options are: \""+MODEL_NAME_descriptive+"\" (descriptive pharmacokinetic Brix model),\""+MODEL_NAME_3SL+"\" (three step linear model), \""+MODEL_NAME_tofts+"\" (extended tofts model) or \""+MODEL_NAME_2CX+"\" (two compartment exchange model).", us::Any(std::string(MODEL_NAME_tofts))); parser.addArgument( "injectiontime", "j", mitkCommandLineParser::Float, "Injection time [min]", "Injection time of the bolus. This information is needed for the descriptive pharmacokinetic Brix model.", us::Any()); parser.endGroup(); parser.beginGroup("Required I/O parameters"); parser.addArgument( "input", "i", mitkCommandLineParser::File, "Input file", "input 3D+t image file", us::Any(), false, false, false, mitkCommandLineParser::Input); parser.addArgument("output", "o", mitkCommandLineParser::File, "Output file template", "where to save the output parameter images. The specified path will be used as template to determine the format (via extension) and the name \"root\". For each parameter a suffix will be added to the name.", us::Any(), false, false, false, mitkCommandLineParser::Output); parser.endGroup(); parser.beginGroup("AIF parameters"); parser.addArgument( "aifmask", "n", mitkCommandLineParser::File, "AIF mask file", "Mask that defines the spatial image region that should be used as AIF for models that need one. Must have the same geometry as the AIF input image!", us::Any(), true, false, false, mitkCommandLineParser::Input); parser.addArgument( "aifimage", "a", mitkCommandLineParser::File, "AIF image file", "3D+t image that defines the image that containes the AIF signal. If this flag is not set and the model needs a AIF, the CLI will assume that the AIF is encoded in the normal image. Must have the same geometry as the AIF mask!", us::Any(), true, false, false, mitkCommandLineParser::Input); parser.addArgument( "hematocrit", "h", mitkCommandLineParser::Float, "Hematocrit Level", "Value needed for correct AIF computation. Only needed if model needs an AIF. Default value is 0.45.", us::Any(0.45)); parser.endGroup(); parser.beginGroup("Optional parameters"); parser.addArgument( "mask", "m", mitkCommandLineParser::File, "Mask file", "Mask that defines the spatial image region that should be fitted. Must have the same geometry as the input image!", us::Any(), true, false, false, mitkCommandLineParser::Input); parser.addArgument( "verbose", "v", mitkCommandLineParser::Bool, "Verbose Output", "Whether to produce verbose output"); parser.addArgument( "roibased", "r", mitkCommandLineParser::Bool, "Roi based fitting", "Will compute a mean intesity signal over the ROI before fitting it. If this mode is used a mask must be specified."); parser.addArgument( "constraints", "c", mitkCommandLineParser::Bool, "Constraints", "Indicates if constraints should be used for the fitting (if flag is set the default contraints will be used.).", us::Any(false)); parser.addArgument( "preview", "p", mitkCommandLineParser::Bool, "Preview outputs", "The application previews the outputs (filename, type) it would produce with the current settings."); parser.addArgument("help", "h", mitkCommandLineParser::Bool, "Help:", "Show this help text"); parser.endGroup(); //! [add arguments] } bool configureApplicationSettings(std::map parsedArgs) { if (parsedArgs.size() == 0) return false; // parse, cast and set required arguments modelName = MODEL_NAME_tofts; if (parsedArgs.count("model")) { modelName = us::any_cast(parsedArgs["model"]); } inFilename = us::any_cast(parsedArgs["input"]); outFileName = us::any_cast(parsedArgs["output"]); if (parsedArgs.count("mask")) { maskFileName = us::any_cast(parsedArgs["mask"]); } if (parsedArgs.count("aifimage")) { aifImageFileName = us::any_cast(parsedArgs["aifimage"]); } if (parsedArgs.count("aifmask")) { aifMaskFileName = us::any_cast(parsedArgs["aifmask"]); } verbose = false; if (parsedArgs.count("verbose")) { verbose = us::any_cast(parsedArgs["verbose"]); } preview = false; if (parsedArgs.count("preview")) { preview = us::any_cast(parsedArgs["preview"]); } roibased = false; if (parsedArgs.count("roibased")) { roibased = us::any_cast(parsedArgs["roibased"]); } useConstraints = false; if (parsedArgs.count("constraints")) { useConstraints = us::any_cast(parsedArgs["constraints"]); } aifHematocritLevel = 0.45; if (parsedArgs.count("hematocrit")) { aifHematocritLevel = us::any_cast(parsedArgs["hematocrit"]); } brixInjectionTime = 0.0; if (parsedArgs.count("injectiontime")) { brixInjectionTime = us::any_cast(parsedArgs["injectiontime"]); } return true; } mitk::ModelFitFunctorBase::Pointer createDefaultFitFunctor( const mitk::ModelParameterizerBase* parameterizer, const mitk::ModelFactoryBase* modelFactory) { mitk::LevenbergMarquardtModelFitFunctor::Pointer fitFunctor = mitk::LevenbergMarquardtModelFitFunctor::New(); mitk::NormalizedSumOfSquaredDifferencesFitCostFunction::Pointer chi2 = mitk::NormalizedSumOfSquaredDifferencesFitCostFunction::New(); fitFunctor->RegisterEvaluationParameter("Chi^2", chi2); if (useConstraints) { fitFunctor->SetConstraintChecker(modelFactory->CreateDefaultConstraints().GetPointer()); } mitk::ModelBase::Pointer refModel = parameterizer->GenerateParameterizedModel(); ::itk::LevenbergMarquardtOptimizer::ScalesType scales; scales.SetSize(refModel->GetNumberOfParameters()); scales.Fill(1.0); fitFunctor->SetScales(scales); fitFunctor->SetDebugParameterMaps(true); return fitFunctor.GetPointer(); } /**Helper that ensures that the mask (if it exists) is always 3D image. If the mask is originally an 4D image, the first time step will be used.*/ mitk::Image::Pointer getMask3D() { mitk::Image::Pointer result; if (mask.IsNotNull()) { result = mask; //mask settings if (mask->GetTimeSteps() > 1) { MITK_INFO << "Selected mask has multiple timesteps. Only use first timestep to mask model fit."; mitk::ImageTimeSelector::Pointer maskedImageTimeSelector = mitk::ImageTimeSelector::New(); maskedImageTimeSelector->SetInput(mask); maskedImageTimeSelector->SetTimeNr(0); maskedImageTimeSelector->UpdateLargestPossibleRegion(); result = maskedImageTimeSelector->GetOutput(); } } return result; } void getAIF(mitk::AIFBasedModelBase::AterialInputFunctionType& aif, mitk::AIFBasedModelBase::AterialInputFunctionType& aifTimeGrid) { if (aifMask.IsNotNull()) { aif.clear(); aifTimeGrid.clear(); mitk::AterialInputFunctionGenerator::Pointer aifGenerator = mitk::AterialInputFunctionGenerator::New(); //Hematocrit level aifGenerator->SetHCL(aifHematocritLevel); std::cout << "AIF hematocrit level: " << aifHematocritLevel << std::endl; mitk::Image::Pointer selectedAIFMask = aifMask; //mask settings if (aifMask->GetTimeSteps() > 1) { MITK_INFO << "Selected AIF mask has multiple timesteps. Only use first timestep to mask model fit."; mitk::ImageTimeSelector::Pointer maskedImageTimeSelector = mitk::ImageTimeSelector::New(); maskedImageTimeSelector->SetInput(aifMask); maskedImageTimeSelector->SetTimeNr(0); maskedImageTimeSelector->UpdateLargestPossibleRegion(); aifMask = maskedImageTimeSelector->GetOutput(); } aifGenerator->SetMask(aifMask); mitk::Image::Pointer selectedAIFImage = image; //image settings if (aifImage.IsNotNull()) { selectedAIFImage = aifImage; } aifGenerator->SetDynamicImage(selectedAIFImage); aif = aifGenerator->GetAterialInputFunction(); aifTimeGrid = aifGenerator->GetAterialInputFunctionTimeGrid(); } else { mitkThrow() << "Cannot generate AIF. AIF mask was not specified or correctly loaded."; } } void generateDescriptiveBrixModel_PixelBased(mitk::modelFit::ModelFitInfo::Pointer& modelFitInfo, mitk::ParameterFitImageGeneratorBase::Pointer& generator) { mitk::PixelBasedParameterFitImageGenerator::Pointer fitGenerator = mitk::PixelBasedParameterFitImageGenerator::New(); mitk::DescriptivePharmacokineticBrixModelParameterizer::Pointer modelParameterizer = mitk::DescriptivePharmacokineticBrixModelParameterizer::New(); mitk::Image::Pointer mask3D = getMask3D(); //Model configuration (static parameters) can be done now modelParameterizer->SetTau(brixInjectionTime); std::cout << "Injection time [min]: " << brixInjectionTime << std::endl; mitk::ImageTimeSelector::Pointer imageTimeSelector = mitk::ImageTimeSelector::New(); imageTimeSelector->SetInput(image); imageTimeSelector->SetTimeNr(0); imageTimeSelector->UpdateLargestPossibleRegion(); mitk::DescriptivePharmacokineticBrixModelParameterizer::BaseImageType::Pointer baseImage; mitk::CastToItkImage(imageTimeSelector->GetOutput(), baseImage); modelParameterizer->SetBaseImage(baseImage); //Specify fitting strategy and criterion parameters mitk::ModelFactoryBase::Pointer factory = mitk::DescriptivePharmacokineticBrixModelFactory::New().GetPointer(); mitk::ModelFitFunctorBase::Pointer fitFunctor = createDefaultFitFunctor(modelParameterizer, factory); //Parametrize fit generator fitGenerator->SetModelParameterizer(modelParameterizer); std::string roiUID = ""; if (mask3D.IsNotNull()) { fitGenerator->SetMask(mask3D); - roiUID = mitk::EnsureModelFitUID(mask); + roiUID = mask->GetUID(); } fitGenerator->SetDynamicImage(image); fitGenerator->SetFitFunctor(fitFunctor); generator = fitGenerator.GetPointer(); //Create model info modelFitInfo = mitk::modelFit::CreateFitInfoFromModelParameterizer(modelParameterizer, image, mitk::ModelFitConstants::FIT_TYPE_VALUE_PIXELBASED(), roiUID); } void generateDescriptiveBrixModel_ROIBased(mitk::modelFit::ModelFitInfo::Pointer& modelFitInfo, mitk::ParameterFitImageGeneratorBase::Pointer& generator) { mitk::Image::Pointer mask3D = getMask3D(); if (mask3D.IsNull()) { return; } mitk::ROIBasedParameterFitImageGenerator::Pointer fitGenerator = mitk::ROIBasedParameterFitImageGenerator::New(); mitk::DescriptivePharmacokineticBrixModelValueBasedParameterizer::Pointer modelParameterizer = mitk::DescriptivePharmacokineticBrixModelValueBasedParameterizer::New(); //Compute ROI signal mitk::MaskedDynamicImageStatisticsGenerator::Pointer signalGenerator = mitk::MaskedDynamicImageStatisticsGenerator::New(); signalGenerator->SetMask(mask3D); signalGenerator->SetDynamicImage(image); signalGenerator->Generate(); mitk::MaskedDynamicImageStatisticsGenerator::ResultType roiSignal = signalGenerator->GetMean(); //Model configuration (static parameters) can be done now modelParameterizer->SetTau(brixInjectionTime); std::cout << "Injection time [min]: " << brixInjectionTime << std::endl; modelParameterizer->SetBaseValue(roiSignal[0]); //Specify fitting strategy and criterion parameters mitk::ModelFactoryBase::Pointer factory = mitk::DescriptivePharmacokineticBrixModelFactory::New().GetPointer(); mitk::ModelFitFunctorBase::Pointer fitFunctor = createDefaultFitFunctor(modelParameterizer, factory); //Parametrize fit generator fitGenerator->SetModelParameterizer(modelParameterizer); fitGenerator->SetMask(mask3D); fitGenerator->SetFitFunctor(fitFunctor); fitGenerator->SetSignal(roiSignal); fitGenerator->SetTimeGrid(mitk::ExtractTimeGrid(image)); generator = fitGenerator.GetPointer(); - std::string roiUID = mitk::EnsureModelFitUID(mask); + std::string roiUID = mask->GetUID(); //Create model info modelFitInfo = mitk::modelFit::CreateFitInfoFromModelParameterizer(modelParameterizer, image, mitk::ModelFitConstants::FIT_TYPE_VALUE_ROIBASED(), roiUID); mitk::ScalarListLookupTable::ValueType infoSignal; for (mitk::MaskedDynamicImageStatisticsGenerator::ResultType::const_iterator pos = roiSignal.begin(); pos != roiSignal.end(); ++pos) { infoSignal.push_back(*pos); } modelFitInfo->inputData.SetTableValue("ROI", infoSignal); } template void GenerateLinearModelFit_PixelBased(mitk::modelFit::ModelFitInfo::Pointer& modelFitInfo, mitk::ParameterFitImageGeneratorBase::Pointer& generator) { mitk::PixelBasedParameterFitImageGenerator::Pointer fitGenerator = mitk::PixelBasedParameterFitImageGenerator::New(); typename TParameterizer::Pointer modelParameterizer = TParameterizer::New(); mitk::Image::Pointer mask3D = getMask3D(); //Specify fitting strategy and criterion parameters mitk::ModelFactoryBase::Pointer factory = TFactory::New().GetPointer(); mitk::ModelFitFunctorBase::Pointer fitFunctor = createDefaultFitFunctor(modelParameterizer, factory); //Parametrize fit generator fitGenerator->SetModelParameterizer(modelParameterizer); std::string roiUID = ""; if (mask3D.IsNotNull()) { fitGenerator->SetMask(mask3D); - roiUID = mitk::EnsureModelFitUID(mask); + roiUID = mask->GetUID(); } fitGenerator->SetDynamicImage(image); fitGenerator->SetFitFunctor(fitFunctor); generator = fitGenerator.GetPointer(); //Create model info modelFitInfo = mitk::modelFit::CreateFitInfoFromModelParameterizer(modelParameterizer, image, mitk::ModelFitConstants::FIT_TYPE_VALUE_PIXELBASED(), roiUID); } template void GenerateLinearModelFit_ROIBased(mitk::modelFit::ModelFitInfo::Pointer& modelFitInfo, mitk::ParameterFitImageGeneratorBase::Pointer& generator) { mitk::Image::Pointer mask3D = getMask3D(); if (mask3D.IsNull()) { return; } mitk::ROIBasedParameterFitImageGenerator::Pointer fitGenerator = mitk::ROIBasedParameterFitImageGenerator::New(); typename TParameterizer::Pointer modelParameterizer = TParameterizer::New(); //Compute ROI signal mitk::MaskedDynamicImageStatisticsGenerator::Pointer signalGenerator = mitk::MaskedDynamicImageStatisticsGenerator::New(); signalGenerator->SetMask(mask3D); signalGenerator->SetDynamicImage(image); signalGenerator->Generate(); mitk::MaskedDynamicImageStatisticsGenerator::ResultType roiSignal = signalGenerator->GetMean(); //Specify fitting strategy and criterion parameters mitk::ModelFactoryBase::Pointer factory = TFactory::New().GetPointer(); mitk::ModelFitFunctorBase::Pointer fitFunctor = createDefaultFitFunctor(modelParameterizer, factory); //Parametrize fit generator fitGenerator->SetModelParameterizer(modelParameterizer); fitGenerator->SetMask(mask3D); fitGenerator->SetFitFunctor(fitFunctor); fitGenerator->SetSignal(roiSignal); fitGenerator->SetTimeGrid(mitk::ExtractTimeGrid(image)); generator = fitGenerator.GetPointer(); - std::string roiUID = mitk::EnsureModelFitUID(mask); + std::string roiUID = mask->GetUID(); //Create model info modelFitInfo = mitk::modelFit::CreateFitInfoFromModelParameterizer(modelParameterizer, image, mitk::ModelFitConstants::FIT_TYPE_VALUE_ROIBASED(), roiUID); mitk::ScalarListLookupTable::ValueType infoSignal; for (mitk::MaskedDynamicImageStatisticsGenerator::ResultType::const_iterator pos = roiSignal.begin(); pos != roiSignal.end(); ++pos) { infoSignal.push_back(*pos); } modelFitInfo->inputData.SetTableValue("ROI", infoSignal); } template void generateAIFbasedModelFit_PixelBased(mitk::modelFit::ModelFitInfo::Pointer& modelFitInfo, mitk::ParameterFitImageGeneratorBase::Pointer& generator) { mitk::PixelBasedParameterFitImageGenerator::Pointer fitGenerator = mitk::PixelBasedParameterFitImageGenerator::New(); typename TParameterizer::Pointer modelParameterizer = TParameterizer::New(); mitk::AIFBasedModelBase::AterialInputFunctionType aif; mitk::AIFBasedModelBase::AterialInputFunctionType aifTimeGrid; getAIF(aif, aifTimeGrid); modelParameterizer->SetAIF(aif); modelParameterizer->SetAIFTimeGrid(aifTimeGrid); mitk::Image::Pointer mask3D = getMask3D(); //Specify fitting strategy and criterion parameters mitk::ModelFactoryBase::Pointer factory = TFactory::New().GetPointer(); mitk::ModelFitFunctorBase::Pointer fitFunctor = createDefaultFitFunctor(modelParameterizer, factory); //Parametrize fit generator fitGenerator->SetModelParameterizer(modelParameterizer); std::string roiUID = ""; if (mask3D.IsNotNull()) { fitGenerator->SetMask(mask3D); - roiUID = mitk::EnsureModelFitUID(mask); + roiUID = mask->GetUID(); } fitGenerator->SetDynamicImage(image); fitGenerator->SetFitFunctor(fitFunctor); generator = fitGenerator.GetPointer(); //Create model info modelFitInfo = mitk::modelFit::CreateFitInfoFromModelParameterizer(modelParameterizer, image, mitk::ModelFitConstants::FIT_TYPE_VALUE_PIXELBASED(), roiUID); mitk::ScalarListLookupTable::ValueType infoSignal; for (mitk::AIFBasedModelBase::AterialInputFunctionType::const_iterator pos = aif.begin(); pos != aif.end(); ++pos) { infoSignal.push_back(*pos); } modelFitInfo->inputData.SetTableValue("AIF", infoSignal); } template void generateAIFbasedModelFit_ROIBased( mitk::modelFit::ModelFitInfo::Pointer& modelFitInfo, mitk::ParameterFitImageGeneratorBase::Pointer& generator) { mitk::Image::Pointer mask3D = getMask3D(); if (mask3D.IsNull()) { return; } mitk::ROIBasedParameterFitImageGenerator::Pointer fitGenerator = mitk::ROIBasedParameterFitImageGenerator::New(); typename TParameterizer::Pointer modelParameterizer = TParameterizer::New(); mitk::AIFBasedModelBase::AterialInputFunctionType aif; mitk::AIFBasedModelBase::AterialInputFunctionType aifTimeGrid; getAIF(aif, aifTimeGrid); modelParameterizer->SetAIF(aif); modelParameterizer->SetAIFTimeGrid(aifTimeGrid); //Compute ROI signal mitk::MaskedDynamicImageStatisticsGenerator::Pointer signalGenerator = mitk::MaskedDynamicImageStatisticsGenerator::New(); signalGenerator->SetMask(mask3D); signalGenerator->SetDynamicImage(image); signalGenerator->Generate(); mitk::MaskedDynamicImageStatisticsGenerator::ResultType roiSignal = signalGenerator->GetMean(); //Specify fitting strategy and criterion parameters mitk::ModelFactoryBase::Pointer factory = TFactory::New().GetPointer(); mitk::ModelFitFunctorBase::Pointer fitFunctor = createDefaultFitFunctor(modelParameterizer, factory); //Parametrize fit generator fitGenerator->SetModelParameterizer(modelParameterizer); fitGenerator->SetMask(mask3D); fitGenerator->SetFitFunctor(fitFunctor); fitGenerator->SetSignal(roiSignal); fitGenerator->SetTimeGrid(mitk::ExtractTimeGrid(image)); generator = fitGenerator.GetPointer(); - std::string roiUID = mitk::EnsureModelFitUID(mask); + std::string roiUID = mask->GetUID(); //Create model info modelFitInfo = mitk::modelFit::CreateFitInfoFromModelParameterizer(modelParameterizer, image, mitk::ModelFitConstants::FIT_TYPE_VALUE_ROIBASED(), roiUID); mitk::ScalarListLookupTable::ValueType infoSignal; for (mitk::MaskedDynamicImageStatisticsGenerator::ResultType::const_iterator pos = roiSignal.begin(); pos != roiSignal.end(); ++pos) { infoSignal.push_back(*pos); } modelFitInfo->inputData.SetTableValue("ROI", infoSignal); infoSignal.clear(); for (mitk::AIFBasedModelBase::AterialInputFunctionType::const_iterator pos = aif.begin(); pos != aif.end(); ++pos) { infoSignal.push_back(*pos); } modelFitInfo->inputData.SetTableValue("AIF", infoSignal); } void storeResultImage(const std::string& name, mitk::Image* image, mitk::modelFit::Parameter::Type nodeType, const mitk::modelFit::ModelFitInfo* modelFitInfo) { mitk::modelFit::SetModelFitDataProperties(image, name, nodeType, modelFitInfo); std::string ext = ::itksys::SystemTools::GetFilenameLastExtension(outFileName); std::string dir = itksys::SystemTools::GetFilenamePath(outFileName); dir = itksys::SystemTools::ConvertToOutputPath(dir); std::string rootName = itksys::SystemTools::GetFilenameWithoutLastExtension(outFileName); std::string fileName = rootName + "_" + name + ext; std::vector pathElements; pathElements.push_back(dir); pathElements.push_back(fileName); std::string fullOutPath = itksys::SystemTools::ConvertToOutputPath(dir + "/" + fileName); mitk::IOUtil::Save(image, fullOutPath); std::cout << "Store result (parameter: "<(fitSession, generator); } else { GenerateLinearModelFit_ROIBased(fitSession, generator); } } else if (is2SLFactory) { std::cout << "Model: two step linear model" << std::endl; if (!roibased) { GenerateLinearModelFit_PixelBased(fitSession, generator); } else { GenerateLinearModelFit_ROIBased(fitSession, generator); } } else if (isToftsFactory) { std::cout << "Model: extended tofts model" << std::endl; if (!roibased) { generateAIFbasedModelFit_PixelBased(fitSession, generator); } else { generateAIFbasedModelFit_ROIBased(fitSession, generator); } } else if (is2CXMFactory) { std::cout << "Model: two compartment exchange model" << std::endl; if (!roibased) { generateAIFbasedModelFit_PixelBased(fitSession, generator); } else { generateAIFbasedModelFit_ROIBased(fitSession, generator); } } else { std::cerr << "ERROR. Model flag is unknown. Given flag: " << modelName << std::endl; } } void doFitting() { mitk::ParameterFitImageGeneratorBase::Pointer generator = nullptr; mitk::modelFit::ModelFitInfo::Pointer fitSession = nullptr; ::itk::CStyleCommand::Pointer command = ::itk::CStyleCommand::New(); command->SetCallback(onFitEvent); createFitGenerator(fitSession, generator); if (generator.IsNotNull() ) { std::cout << "Started fitting process..." << std::endl; generator->AddObserver(::itk::AnyEvent(), command); generator->Generate(); std::cout << std::endl << "Finished fitting process" << std::endl; mitk::storeModelFitGeneratorResults(outFileName, generator, fitSession); } else { mitkThrow() << "Fitting error! Could not initialize fitting job."; } } void doPreview() { mitk::ParameterFitImageGeneratorBase::Pointer generator = nullptr; mitk::modelFit::ModelFitInfo::Pointer fitSession = nullptr; createFitGenerator(fitSession, generator); if (generator.IsNotNull()) { mitk::previewModelFitGeneratorResults(outFileName, generator); } else { mitkThrow() << "Fitting error! Could not initialize fitting job."; } } int main(int argc, char* argv[]) { mitkCommandLineParser parser; setupParser(parser); const std::map& parsedArgs = parser.parseArguments(argc, argv); mitk::PreferenceListReaderOptionsFunctor readerFilterFunctor = mitk::PreferenceListReaderOptionsFunctor({ "MITK DICOM Reader v2 (classic config)" }, { "MITK DICOM Reader" }); if (!configureApplicationSettings(parsedArgs)) { return EXIT_FAILURE; }; // Show a help message if (parsedArgs.count("help") || parsedArgs.count("h")) { std::cout << parser.helpText(); return EXIT_SUCCESS; } //! [do processing] try { image = mitk::IOUtil::Load(inFilename, &readerFilterFunctor); std::cout << "Input: " << inFilename << std::endl; if (!maskFileName.empty()) { mask = mitk::IOUtil::Load(maskFileName, &readerFilterFunctor); std::cout << "Mask: " << maskFileName << std::endl; } else { std::cout << "Mask: none" << std::endl; } if (modelName != MODEL_NAME_descriptive && modelName != MODEL_NAME_3SL) { if (!aifMaskFileName.empty()) { aifMask = mitk::IOUtil::Load(aifMaskFileName, &readerFilterFunctor); std::cout << "AIF mask: " << aifMaskFileName << std::endl; } else { mitkThrow() << "Error. Cannot fit. Choosen model needs an AIF. Please specify AIF mask (--aifmask)."; } if (!aifImageFileName.empty()) { aifImage = mitk::IOUtil::Load(aifImageFileName, &readerFilterFunctor); std::cout << "AIF image: " << aifImageFileName << std::endl; } else { std::cout << "AIF image: none (using signal image)" << std::endl; } } if (roibased && mask.IsNull()) { mitkThrow() << "Error. Cannot fit. Please specify mask if you select roi based fitting."; } std::cout << "Style: "; if (roibased) { std::cout << "ROI based"; } else { std::cout << "pixel based"; } std::cout << std::endl; if (preview) { doPreview(); } else { doFitting(); } std::cout << "Processing finished." << std::endl; return EXIT_SUCCESS; } catch (const itk::ExceptionObject& e) { MITK_ERROR << e.what(); return EXIT_FAILURE; } catch (const std::exception& e) { MITK_ERROR << e.what(); return EXIT_FAILURE; } catch (...) { MITK_ERROR << "Unexpected error encountered."; return EXIT_FAILURE; } } diff --git a/Modules/Pharmacokinetics/cmdapps/MRSignal2ConcentrationMiniApp.cpp b/Modules/Pharmacokinetics/cmdapps/MRSignal2ConcentrationMiniApp.cpp index 60a0b67c80..bd517b3abb 100644 --- a/Modules/Pharmacokinetics/cmdapps/MRSignal2ConcentrationMiniApp.cpp +++ b/Modules/Pharmacokinetics/cmdapps/MRSignal2ConcentrationMiniApp.cpp @@ -1,289 +1,287 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // std includes #include // itk includes #include "itksys/SystemTools.hxx" // CTK includes #include "mitkCommandLineParser.h" // MITK includes #include #include #include #include -#include #include std::string inFilename; std::string outFileName; mitk::Image::Pointer image; bool verbose(false); bool t1_absolute(false); bool t1_relative(false); bool t1_flash(false); bool t2(false); float k(1.0); float te(0); float rec_time(0); float relaxivity(0); float rel_time(0); void setupParser(mitkCommandLineParser& parser) { // set general information about your MiniApp parser.setCategory("Dynamic Data Analysis Tools"); parser.setTitle("MR Signal to Concentration Converter"); parser.setDescription("MiniApp that allows to convert a T1 or T2 signal image into a concentration image for perfusion analysis."); parser.setContributor("DKFZ MIC"); //! [create parser] //! [add arguments] // how should arguments be prefixed parser.setArgumentPrefix("--", "-"); // add each argument, unless specified otherwise each argument is optional // see mitkCommandLineParser::addArgument for more information parser.beginGroup("Required I/O parameters"); parser.addArgument( "input", "i", mitkCommandLineParser::File, "Input file", "input 3D+t image file", us::Any(), false, false, false, mitkCommandLineParser::Input); parser.addArgument("output", "o", mitkCommandLineParser::File, "Output file", "where to save the output concentration image.", us::Any(), false, false, false, mitkCommandLineParser::Output); parser.endGroup(); parser.beginGroup("Conversion parameters"); parser.addArgument( "t1-absolute", "", mitkCommandLineParser::Bool, "T1 absolute signal enhancement", "Activate conversion for T1 absolute signal enhancement."); parser.addArgument( "t1-relative", "", mitkCommandLineParser::Bool, "T1 relative signal enhancement", "Activate conversion for T1 relative signal enhancement."); parser.addArgument( "t1-flash", "", mitkCommandLineParser::Bool, "T1 turbo flash", "Activate specific conversion for T1 turbo flash sequences."); parser.addArgument( "t2", "", mitkCommandLineParser::Bool, "T2 signal conversion", "Activate conversion for T2 signal enhancement to concentration."); parser.addArgument( "k", "k", mitkCommandLineParser::Float, "Conversion factor k", "Needed for the following conversion modes: T1-absolute, T1-relative, T2. Default value is 1.", us::Any(1)); parser.addArgument( "recovery-time", "", mitkCommandLineParser::Float, "Recovery time", "Needed for the following conversion modes: T1-flash."); parser.addArgument( "relaxivity", "", mitkCommandLineParser::Float, "Relaxivity", "Needed for the following conversion modes: T1-flash."); parser.addArgument( "relaxation-time", "", mitkCommandLineParser::Float, "Relaxation time", "Needed for the following conversion modes: T1-flash."); parser.addArgument( "te", "", mitkCommandLineParser::Float, "Echo time TE", "Needed for the following conversion modes: T2.", us::Any(1)); parser.beginGroup("Optional parameters"); parser.addArgument( "verbose", "v", mitkCommandLineParser::Bool, "Verbose Output", "Whether to produce verbose output"); parser.addArgument("help", "h", mitkCommandLineParser::Bool, "Help:", "Show this help text"); parser.endGroup(); //! [add arguments] } bool configureApplicationSettings(std::map parsedArgs) { if (parsedArgs.size() == 0) return false; inFilename = us::any_cast(parsedArgs["input"]); outFileName = us::any_cast(parsedArgs["output"]); verbose = false; if (parsedArgs.count("verbose")) { verbose = us::any_cast(parsedArgs["verbose"]); } t1_absolute = false; if (parsedArgs.count("t1-absolute")) { t1_absolute = us::any_cast(parsedArgs["t1-absolute"]); } t1_relative = false; if (parsedArgs.count("t1-relative")) { t1_relative = us::any_cast(parsedArgs["t1-relative"]); } t1_flash = false; if (parsedArgs.count("t1-flash")) { t1_flash = us::any_cast(parsedArgs["t1-flash"]); } t2 = false; if (parsedArgs.count("t2")) { t2 = us::any_cast(parsedArgs["t2"]); } k = 0.0; if (parsedArgs.count("k")) { k = us::any_cast(parsedArgs["k"]); } relaxivity = 0.0; if (parsedArgs.count("relaxivity")) { relaxivity = us::any_cast(parsedArgs["relaxivity"]); } rec_time = 0.0; if (parsedArgs.count("recovery-time")) { rec_time = us::any_cast(parsedArgs["recovery-time"]); } rel_time = 0.0; if (parsedArgs.count("relaxation-time")) { rel_time = us::any_cast(parsedArgs["relaxation-time"]); } te = 0.0; if (parsedArgs.count("te")) { te = us::any_cast(parsedArgs["te"]); } //consistency checks int modeCount = 0; if (t1_absolute) ++modeCount; if (t1_flash) ++modeCount; if (t1_relative) ++modeCount; if (t2) ++modeCount; if (modeCount==0) { mitkThrow() << "Invalid program call. Please select the type of conversion."; } if (modeCount >1) { mitkThrow() << "Invalid program call. Please select only ONE type of conversion."; } if (!k && (t2 || t1_absolute || t1_relative)) { mitkThrow() << "Invalid program call. Please set 'k', if you use t1-absolute, t1-relative or t2."; } if (!te && t2) { mitkThrow() << "Invalid program call. Please set 'te', if you use t2 mode."; } if ((!rec_time||!rel_time||!relaxivity) && t1_flash) { mitkThrow() << "Invalid program call. Please set 'recovery-time', 'relaxation-time' and 'relaxivity', if you use t1-flash mode."; } return true; } void doConversion() { mitk::ConcentrationCurveGenerator::Pointer concentrationGen = mitk::ConcentrationCurveGenerator::New(); concentrationGen->SetDynamicImage(image); concentrationGen->SetisTurboFlashSequence(t1_flash); concentrationGen->SetAbsoluteSignalEnhancement(t1_absolute); concentrationGen->SetRelativeSignalEnhancement(t1_relative); concentrationGen->SetisT2weightedImage(t2); if (t1_flash) { concentrationGen->SetRecoveryTime(rec_time); concentrationGen->SetRelaxationTime(rel_time); concentrationGen->SetRelaxivity(relaxivity); } else if (t2) { concentrationGen->SetT2Factor(k); concentrationGen->SetT2EchoTime(te); } else { concentrationGen->SetFactor(k); } mitk::Image::Pointer concentrationImage = concentrationGen->GetConvertedImage(); - mitk::EnsureModelFitUID(concentrationImage); mitk::IOUtil::Save(concentrationImage, outFileName); std::cout << "Store result: " << outFileName << std::endl; } int main(int argc, char* argv[]) { mitkCommandLineParser parser; setupParser(parser); const std::map& parsedArgs = parser.parseArguments(argc, argv); if (!configureApplicationSettings(parsedArgs)) { return EXIT_FAILURE; }; mitk::PreferenceListReaderOptionsFunctor readerFilterFunctor = mitk::PreferenceListReaderOptionsFunctor({ "MITK DICOM Reader v2 (classic config)" }, { "MITK DICOM Reader" }); // Show a help message if (parsedArgs.count("help") || parsedArgs.count("h")) { std::cout << parser.helpText(); return EXIT_SUCCESS; } //! [do processing] try { image = mitk::IOUtil::Load(inFilename, &readerFilterFunctor); std::cout << "Input: " << inFilename << std::endl; doConversion(); std::cout << "Processing finished." << std::endl; return EXIT_SUCCESS; } catch (const itk::ExceptionObject& e) { MITK_ERROR << e.what(); return EXIT_FAILURE; } catch (const std::exception& e) { MITK_ERROR << e.what(); return EXIT_FAILURE; } catch (...) { MITK_ERROR << "Unexpected error encountered."; return EXIT_FAILURE; } } diff --git a/Plugins/org.mitk.gui.qt.fit.genericfitting/src/internal/GenericDataFittingView.cpp b/Plugins/org.mitk.gui.qt.fit.genericfitting/src/internal/GenericDataFittingView.cpp index d61cc38065..3a8dfb2d14 100644 --- a/Plugins/org.mitk.gui.qt.fit.genericfitting/src/internal/GenericDataFittingView.cpp +++ b/Plugins/org.mitk.gui.qt.fit.genericfitting/src/internal/GenericDataFittingView.cpp @@ -1,642 +1,639 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "GenericDataFittingView.h" #include "mitkWorkbenchUtil.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Includes for image casting between ITK and MITK #include #include "mitkImageCast.h" #include "mitkITKImageImport.h" #include #include #include const std::string GenericDataFittingView::VIEW_ID = "org.mitk.gui.qt.fit.genericfitting"; void GenericDataFittingView::SetFocus() { m_Controls.btnModelling->setFocus(); } void GenericDataFittingView::CreateQtPartControl(QWidget* parent) { m_Controls.setupUi(parent); m_Controls.btnModelling->setEnabled(false); this->InitModelComboBox(); connect(m_Controls.btnModelling, SIGNAL(clicked()), this, SLOT(OnModellingButtonClicked())); connect(m_Controls.comboModel, SIGNAL(currentIndexChanged(int)), this, SLOT(OnModellSet(int))); connect(m_Controls.radioPixelBased, SIGNAL(toggled(bool)), this, SLOT(UpdateGUIControls())); //Gerneric setting m_Controls.groupGeneric->hide(); m_Controls.labelFormulaInfo->hide(); connect(m_Controls.editFormula, SIGNAL(textChanged(const QString&)), this, SLOT(UpdateGUIControls())); connect(m_Controls.checkFormulaInfo, SIGNAL(toggled(bool)), m_Controls.labelFormulaInfo, SLOT(setVisible(bool))); connect(m_Controls.nrOfParams, SIGNAL(valueChanged(int)), this, SLOT(OnNrOfParamsChanged())); //Model fit configuration m_Controls.groupBox_FitConfiguration->hide(); m_Controls.checkBox_Constraints->setEnabled(false); m_Controls.constraintManager->setEnabled(false); m_Controls.initialValuesManager->setEnabled(false); connect(m_Controls.radioButton_StartParameters, SIGNAL(toggled(bool)), this, SLOT(UpdateGUIControls())); connect(m_Controls.checkBox_Constraints, SIGNAL(toggled(bool)), this, SLOT(UpdateGUIControls())); connect(m_Controls.radioButton_StartParameters, SIGNAL(toggled(bool)), m_Controls.initialValuesManager, SLOT(setEnabled(bool))); connect(m_Controls.checkBox_Constraints, SIGNAL(toggled(bool)), m_Controls.constraintManager, SLOT(setEnabled(bool))); connect(m_Controls.checkBox_Constraints, SIGNAL(toggled(bool)), m_Controls.constraintManager, SLOT(setVisible(bool))); UpdateGUIControls(); } void GenericDataFittingView::UpdateGUIControls() { m_Controls.lineFitName->setPlaceholderText(QString::fromStdString(this->GetDefaultFitName())); m_Controls.lineFitName->setEnabled(!m_FittingInProgress); m_Controls.checkBox_Constraints->setEnabled(m_modelConstraints.IsNotNull()); bool isGenericFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; m_Controls.groupGeneric->setVisible(isGenericFactory); m_Controls.groupBox_FitConfiguration->setVisible(m_selectedModelFactory); m_Controls.groupBox->setEnabled(!m_FittingInProgress); m_Controls.comboModel->setEnabled(!m_FittingInProgress); m_Controls.groupGeneric->setEnabled(!m_FittingInProgress); m_Controls.groupBox_FitConfiguration->setEnabled(!m_FittingInProgress); m_Controls.radioROIbased->setEnabled(m_selectedMask.IsNotNull()); m_Controls.btnModelling->setEnabled(m_selectedImage.IsNotNull() && m_selectedModelFactory.IsNotNull() && !m_FittingInProgress && CheckModelSettings()); } std::string GenericDataFittingView::GetFitName() const { std::string fitName = m_Controls.lineFitName->text().toStdString(); if (fitName.empty()) { fitName = m_Controls.lineFitName->placeholderText().toStdString(); } return fitName; } std::string GenericDataFittingView::GetDefaultFitName() const { std::string defaultName = "undefined model"; if (this->m_selectedModelFactory.IsNotNull()) { defaultName = this->m_selectedModelFactory->GetClassID(); } if (this->m_Controls.radioPixelBased->isChecked()) { defaultName += "_pixel"; } else { defaultName += "_roi"; } return defaultName; } void GenericDataFittingView::OnNrOfParamsChanged() { PrepareFitConfiguration(); UpdateGUIControls(); } void GenericDataFittingView::OnModellSet(int index) { m_selectedModelFactory = nullptr; if (index > 0) { if (static_cast(index) <= m_FactoryStack.size() ) { m_selectedModelFactory = m_FactoryStack[index - 1]; } else { MITK_WARN << "Invalid model index. Index outside of the factory stack. Factory stack size: "<< m_FactoryStack.size() << "; invalid index: "<< index; } } UpdateGUIControls(); } bool GenericDataFittingView::IsGenericParamFactorySelected() const { return dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; } void GenericDataFittingView::PrepareFitConfiguration() { if (m_selectedModelFactory) { mitk::ModelBase::ParameterNamesType paramNames = m_selectedModelFactory->GetParameterNames(); unsigned int nrOfPools = this->m_Controls.nrOfParams->value(); //init values if (this->IsGenericParamFactorySelected()) { mitk::modelFit::ModelFitInfo::Pointer fitInfo = mitk::modelFit::ModelFitInfo::New(); fitInfo->staticParamMap.Add(mitk::GenericParamModel::NAME_STATIC_PARAMETER_number, { static_cast(nrOfPools) }); auto parameterizer = m_selectedModelFactory->CreateParameterizer(fitInfo); paramNames = parameterizer->GetParameterNames(); m_Controls.initialValuesManager->setInitialValues(paramNames, parameterizer->GetDefaultInitialParameterization()); } else { m_Controls.initialValuesManager->setInitialValues(paramNames, this->m_selectedModelFactory->GetDefaultInitialParameterization()); } //constraints this->m_modelConstraints = dynamic_cast (m_selectedModelFactory->CreateDefaultConstraints().GetPointer()); if (this->m_modelConstraints.IsNull()) { this->m_modelConstraints = mitk::SimpleBarrierConstraintChecker::New(); } m_Controls.constraintManager->setChecker(this->m_modelConstraints, paramNames); } }; void GenericDataFittingView::OnModellingButtonClicked() { //check if all static parameters set if (m_selectedModelFactory.IsNotNull() && CheckModelSettings()) { mitk::ParameterFitImageGeneratorBase::Pointer generator = nullptr; mitk::modelFit::ModelFitInfo::Pointer fitSession = nullptr; bool isLinearFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool isGenericFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool isT2DecayFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; if (isLinearFactory) { if (this->m_Controls.radioPixelBased->isChecked()) { GenerateModelFit_PixelBased(fitSession, generator); } else { GenerateModelFit_ROIBased(fitSession, generator); } } else if (isGenericFactory) { if (this->m_Controls.radioPixelBased->isChecked()) { GenerateModelFit_PixelBased(fitSession, generator); } else { GenerateModelFit_ROIBased(fitSession, generator); } } else if (isT2DecayFactory) { if (this->m_Controls.radioPixelBased->isChecked()) { GenerateModelFit_PixelBased(fitSession, generator); } else { GenerateModelFit_ROIBased(fitSession, generator); } } //add other models with else if if (generator.IsNotNull() && fitSession.IsNotNull()) { m_FittingInProgress = true; UpdateGUIControls(); DoFit(fitSession, generator); } else { QMessageBox box; box.setText("Fitting error!"); box.setInformativeText("Could not establish fitting job. Error when setting ab generator, model parameterizer or session info."); box.setStandardButtons(QMessageBox::Ok); box.setDefaultButton(QMessageBox::Ok); box.setIcon(QMessageBox::Warning); box.exec(); } } else { QMessageBox box; box.setText("Static parameters for model are not set!"); box.setInformativeText("Some static parameters, that are needed for calculation are not set and equal to zero. Modeling not possible"); box.setStandardButtons(QMessageBox::Ok); box.setDefaultButton(QMessageBox::Ok); box.setIcon(QMessageBox::Warning); box.exec(); } } void GenericDataFittingView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*source*/, const QList& selectedNodes) { m_selectedNode = nullptr; m_selectedImage = nullptr; m_selectedMaskNode = nullptr; m_selectedMask = nullptr; m_Controls.masklabel->setText("No (valid) mask selected."); m_Controls.timeserieslabel->setText("No (valid) series selected."); QList nodes = selectedNodes; mitk::NodePredicateDataType::Pointer isLabelSet = mitk::NodePredicateDataType::New("LabelSetImage"); mitk::NodePredicateDataType::Pointer isImage = mitk::NodePredicateDataType::New("Image"); mitk::NodePredicateProperty::Pointer isBinary = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); mitk::NodePredicateAnd::Pointer isLegacyMask = mitk::NodePredicateAnd::New(isImage, isBinary); mitk::NodePredicateOr::Pointer maskPredicate = mitk::NodePredicateOr::New(isLegacyMask, isLabelSet); if (nodes.size() > 0 && isImage->CheckNode(nodes.front())) { this->m_selectedNode = nodes.front(); this->m_selectedImage = dynamic_cast(this->m_selectedNode->GetData()); m_Controls.timeserieslabel->setText((this->m_selectedNode->GetName()).c_str()); nodes.pop_front(); } if (nodes.size() > 0 && maskPredicate->CheckNode(nodes.front())) { this->m_selectedMaskNode = nodes.front(); this->m_selectedMask = dynamic_cast(this->m_selectedMaskNode->GetData()); if (this->m_selectedMask->GetTimeSteps() > 1) { MITK_INFO << "Selected mask has multiple timesteps. Only use first timestep to mask model fit. Mask name: " << m_selectedMaskNode->GetName(); mitk::ImageTimeSelector::Pointer maskedImageTimeSelector = mitk::ImageTimeSelector::New(); maskedImageTimeSelector->SetInput(this->m_selectedMask); maskedImageTimeSelector->SetTimeNr(0); maskedImageTimeSelector->UpdateLargestPossibleRegion(); this->m_selectedMask = maskedImageTimeSelector->GetOutput(); } m_Controls.masklabel->setText((this->m_selectedMaskNode->GetName()).c_str()); } if (m_selectedMask.IsNull()) { this->m_Controls.radioPixelBased->setChecked(true); } UpdateGUIControls(); } bool GenericDataFittingView::CheckModelSettings() const { bool ok = true; //check wether any model is set at all. Otherwise exit with false if (m_selectedModelFactory.IsNotNull()) { bool isGenericFactory = dynamic_cast(m_selectedModelFactory.GetPointer()) != nullptr; if (isGenericFactory) { ok = !m_Controls.editFormula->text().isEmpty(); } } else { ok = false; } return ok; } void GenericDataFittingView::ConfigureInitialParametersOfParameterizer(mitk::ModelParameterizerBase* parameterizer) const { if (m_Controls.radioButton_StartParameters->isChecked()) { //use user defined initial parameters mitk::ValueBasedParameterizationDelegate::Pointer paramDelegate = mitk::ValueBasedParameterizationDelegate::New(); paramDelegate->SetInitialParameterization(m_Controls.initialValuesManager->getInitialValues()); parameterizer->SetInitialParameterizationDelegate(paramDelegate); } mitk::GenericParamModelParameterizer* genericParameterizer = dynamic_cast(parameterizer); if (genericParameterizer) { genericParameterizer->SetFunctionString(m_Controls.editFormula->text().toStdString()); } } template void GenericDataFittingView::GenerateModelFit_PixelBased(mitk::modelFit::ModelFitInfo::Pointer& modelFitInfo, mitk::ParameterFitImageGeneratorBase::Pointer& generator) { mitk::PixelBasedParameterFitImageGenerator::Pointer fitGenerator = mitk::PixelBasedParameterFitImageGenerator::New(); typename TParameterizer::Pointer modelParameterizer = TParameterizer::New(); auto genericParameterizer = dynamic_cast(modelParameterizer.GetPointer()); if (genericParameterizer) { genericParameterizer->SetNumberOfParameters(this->m_Controls.nrOfParams->value()); } this->ConfigureInitialParametersOfParameterizer(modelParameterizer); //Specify fitting strategy and criterion parameters mitk::ModelFitFunctorBase::Pointer fitFunctor = CreateDefaultFitFunctor(modelParameterizer); //Parametrize fit generator fitGenerator->SetModelParameterizer(modelParameterizer); std::string roiUID = ""; if (m_selectedMask.IsNotNull()) { fitGenerator->SetMask(m_selectedMask); - roiUID = mitk::EnsureModelFitUID(this->m_selectedMaskNode); + roiUID = m_selectedMask->GetUID(); } - mitk::EnsureModelFitUID(this->m_selectedNode); - fitGenerator->SetDynamicImage(this->m_selectedImage); fitGenerator->SetFitFunctor(fitFunctor); generator = fitGenerator.GetPointer(); //Create model info modelFitInfo = mitk::modelFit::CreateFitInfoFromModelParameterizer(modelParameterizer, m_selectedNode->GetData(), mitk::ModelFitConstants::FIT_TYPE_VALUE_PIXELBASED(), this->GetFitName(), roiUID); } template void GenericDataFittingView::GenerateModelFit_ROIBased( mitk::modelFit::ModelFitInfo::Pointer& modelFitInfo, mitk::ParameterFitImageGeneratorBase::Pointer& generator) { mitk::ROIBasedParameterFitImageGenerator::Pointer fitGenerator = mitk::ROIBasedParameterFitImageGenerator::New(); typename TParameterizer::Pointer modelParameterizer = TParameterizer::New(); auto genericParameterizer = dynamic_cast(modelParameterizer.GetPointer()); if (genericParameterizer) { genericParameterizer->SetNumberOfParameters(this->m_Controls.nrOfParams->value()); } this->ConfigureInitialParametersOfParameterizer(modelParameterizer); //Compute ROI signal mitk::MaskedDynamicImageStatisticsGenerator::Pointer signalGenerator = mitk::MaskedDynamicImageStatisticsGenerator::New(); signalGenerator->SetMask(m_selectedMask); signalGenerator->SetDynamicImage(m_selectedImage); signalGenerator->Generate(); mitk::MaskedDynamicImageStatisticsGenerator::ResultType roiSignal = signalGenerator->GetMean(); //Specify fitting strategy and criterion parameters mitk::ModelFitFunctorBase::Pointer fitFunctor = CreateDefaultFitFunctor(modelParameterizer); //Parametrize fit generator fitGenerator->SetModelParameterizer(modelParameterizer); fitGenerator->SetMask(m_selectedMask); fitGenerator->SetFitFunctor(fitFunctor); fitGenerator->SetSignal(roiSignal); fitGenerator->SetTimeGrid(mitk::ExtractTimeGrid(m_selectedImage)); generator = fitGenerator.GetPointer(); - mitk::EnsureModelFitUID(this->m_selectedNode); - std::string roiUID = mitk::EnsureModelFitUID(this->m_selectedMaskNode); + std::string roiUID = this->m_selectedMask->GetUID(); //Create model info modelFitInfo = mitk::modelFit::CreateFitInfoFromModelParameterizer(modelParameterizer, m_selectedNode->GetData(), mitk::ModelFitConstants::FIT_TYPE_VALUE_ROIBASED(), this->GetFitName(), roiUID); mitk::ScalarListLookupTable::ValueType infoSignal; for (mitk::MaskedDynamicImageStatisticsGenerator::ResultType::const_iterator pos = roiSignal.begin(); pos != roiSignal.end(); ++pos) { infoSignal.push_back(*pos); } modelFitInfo->inputData.SetTableValue("ROI", infoSignal); } void GenericDataFittingView::DoFit(const mitk::modelFit::ModelFitInfo* fitSession, mitk::ParameterFitImageGeneratorBase* generator) { QString message = "Fitting Data Set . . ."; m_Controls.infoBox->append(message); ///////////////////////// //create job and put it into the thread pool ParameterFitBackgroundJob* pJob = new ParameterFitBackgroundJob(generator, fitSession, this->m_selectedNode); pJob->setAutoDelete(true); connect(pJob, SIGNAL(Error(QString)), this, SLOT(OnJobError(QString))); connect(pJob, SIGNAL(Finished()), this, SLOT(OnJobFinished())); connect(pJob, SIGNAL(ResultsAreAvailable(mitk::modelFit::ModelFitResultNodeVectorType, const ParameterFitBackgroundJob*)), this, SLOT(OnJobResultsAreAvailable(mitk::modelFit::ModelFitResultNodeVectorType, const ParameterFitBackgroundJob*)), Qt::BlockingQueuedConnection); connect(pJob, SIGNAL(JobProgress(double)), this, SLOT(OnJobProgress(double))); connect(pJob, SIGNAL(JobStatusChanged(QString)), this, SLOT(OnJobStatusChanged(QString))); QThreadPool* threadPool = QThreadPool::globalInstance(); threadPool->start(pJob); } GenericDataFittingView::GenericDataFittingView() : m_FittingInProgress(false) { m_selectedImage = nullptr; m_selectedMask = nullptr; mitk::ModelFactoryBase::Pointer factory = mitk::LinearModelFactory::New().GetPointer(); m_FactoryStack.push_back(factory); factory = mitk::GenericParamModelFactory::New().GetPointer(); m_FactoryStack.push_back(factory); factory = mitk::T2DecayModelFactory::New().GetPointer(); m_FactoryStack.push_back(factory); this->m_IsNotABinaryImagePredicate = mitk::NodePredicateAnd::New( mitk::TNodePredicateDataType::New(), mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true))), mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object"))).GetPointer(); this->m_IsBinaryImagePredicate = mitk::NodePredicateAnd::New( mitk::TNodePredicateDataType::New(), mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)), mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object"))).GetPointer(); } void GenericDataFittingView::OnJobFinished() { this->m_Controls.infoBox->append(QString("Fitting finished")); this->m_FittingInProgress = false; this->UpdateGUIControls(); }; void GenericDataFittingView::OnJobError(QString err) { MITK_ERROR << err.toStdString().c_str(); m_Controls.infoBox->append(QString("") + err + QString("")); }; void GenericDataFittingView::OnJobResultsAreAvailable(mitk::modelFit::ModelFitResultNodeVectorType results, const ParameterFitBackgroundJob* pJob) { //Store the resulting parameter fit image via convenience helper function in data storage //(handles the correct generation of the nodes and their properties) mitk::modelFit::StoreResultsInDataStorage(this->GetDataStorage(), results, pJob->GetParentNode()); }; void GenericDataFittingView::OnJobProgress(double progress) { QString report = QString("Progress. ") + QString::number(progress); this->m_Controls.infoBox->append(report); }; void GenericDataFittingView::OnJobStatusChanged(QString info) { this->m_Controls.infoBox->append(info); } void GenericDataFittingView::InitModelComboBox() const { this->m_Controls.comboModel->clear(); this->m_Controls.comboModel->addItem(tr("No model selected")); for (ModelFactoryStackType::const_iterator pos = m_FactoryStack.begin(); pos != m_FactoryStack.end(); ++pos) { this->m_Controls.comboModel->addItem(QString::fromStdString((*pos)->GetClassID())); } this->m_Controls.comboModel->setCurrentIndex(0); }; mitk::ModelFitFunctorBase::Pointer GenericDataFittingView::CreateDefaultFitFunctor( const mitk::ModelParameterizerBase* parameterizer) const { mitk::LevenbergMarquardtModelFitFunctor::Pointer fitFunctor = mitk::LevenbergMarquardtModelFitFunctor::New(); mitk::NormalizedSumOfSquaredDifferencesFitCostFunction::Pointer chi2 = mitk::NormalizedSumOfSquaredDifferencesFitCostFunction::New(); fitFunctor->RegisterEvaluationParameter("Chi^2", chi2); if (m_Controls.checkBox_Constraints->isChecked()) { fitFunctor->SetConstraintChecker(m_modelConstraints); } mitk::ModelBase::Pointer refModel = parameterizer->GenerateParameterizedModel(); ::itk::LevenbergMarquardtOptimizer::ScalesType scales; scales.SetSize(refModel->GetNumberOfParameters()); scales.Fill(1.0); fitFunctor->SetScales(scales); fitFunctor->SetDebugParameterMaps(m_Controls.checkDebug->isChecked()); return fitFunctor.GetPointer(); } diff --git a/Plugins/org.mitk.gui.qt.fit.inspector/src/internal/ModelFitInspectorView.cpp b/Plugins/org.mitk.gui.qt.fit.inspector/src/internal/ModelFitInspectorView.cpp index fd09cd5415..a48a2fb8ae 100644 --- a/Plugins/org.mitk.gui.qt.fit.inspector/src/internal/ModelFitInspectorView.cpp +++ b/Plugins/org.mitk.gui.qt.fit.inspector/src/internal/ModelFitInspectorView.cpp @@ -1,905 +1,905 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // Blueberry #include #include #include // mitk #include // Qt #include #include #include #include #include "QmitkPlotWidget.h" #include "mitkNodePredicateFunction.h" #include "mitkScalarListLookupTableProperty.h" #include "mitkModelFitConstants.h" #include "mitkExtractTimeGrid.h" #include "mitkModelGenerator.h" #include "mitkModelFitException.h" #include "mitkModelFitParameterValueExtraction.h" #include "mitkTimeGridHelper.h" #include "mitkModelFitPlotDataHelper.h" #include "ModelFitInspectorView.h" const std::string ModelFitInspectorView::VIEW_ID = "org.mitk.gui.gt.fit.inspector"; const unsigned int ModelFitInspectorView::INTERPOLATION_STEPS = 10; const std::string DEFAULT_X_AXIS = "Time [s]"; ModelFitInspectorView::ModelFitInspectorView() : m_renderWindowPart(nullptr), m_internalUpdateFlag(false), m_currentFit(nullptr), m_currentModelParameterizer(nullptr), m_currentModelProviderService(nullptr), m_currentSelectedTimeStep(0), m_currentSelectedNode(nullptr) { m_currentSelectedPosition.Fill(0.0); m_modelfitList.clear(); } ModelFitInspectorView::~ModelFitInspectorView() { } void ModelFitInspectorView::RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) { if (m_renderWindowPart != renderWindowPart) { m_renderWindowPart = renderWindowPart; } this->m_SliceChangeListener.RenderWindowPartActivated(renderWindowPart); } void ModelFitInspectorView::RenderWindowPartDeactivated( mitk::IRenderWindowPart* renderWindowPart) { m_renderWindowPart = nullptr; this->m_SliceChangeListener.RenderWindowPartDeactivated(renderWindowPart); } void ModelFitInspectorView::CreateQtPartControl(QWidget* parent) { m_Controls.setupUi(parent); m_SelectionServiceConnector = std::make_unique(); m_SelectionServiceConnector->AddPostSelectionListener(this->GetSite()->GetWorkbenchWindow()->GetSelectionService()); m_Controls.inputNodeSelector->SetDataStorage(GetDataStorage()); m_Controls.inputNodeSelector->SetEmptyInfo(QString("Please select input data to be viewed.")); m_Controls.inputNodeSelector->SetInvalidInfo(QString("No input data is selected")); m_Controls.inputNodeSelector->SetPopUpTitel(QString("Choose 3D+t input data that should be viewed!")); m_Controls.inputNodeSelector->SetSelectionIsOptional(false); m_Controls.inputNodeSelector->SetSelectOnlyVisibleNodes(true); auto predicate = mitk::NodePredicateFunction::New([](const mitk::DataNode *node) { bool isModelFitNode = node->GetData() && node->GetData()->GetProperty(mitk::ModelFitConstants::FIT_UID_PROPERTY_NAME().c_str()).IsNotNull(); return isModelFitNode || (node && node->GetData() && node->GetData()->GetTimeSteps() > 1); }); m_Controls.inputNodeSelector->SetNodePredicate(predicate); connect(m_SelectionServiceConnector.get(), &QmitkSelectionServiceConnector::ServiceSelectionChanged, m_Controls.inputNodeSelector, &QmitkSingleNodeSelectionWidget::SetCurrentSelection); connect(m_Controls.inputNodeSelector, &QmitkAbstractNodeSelectionWidget::CurrentSelectionChanged, this, &ModelFitInspectorView::OnInputChanged); this->m_SliceChangeListener.RenderWindowPartActivated(this->GetRenderWindowPart()); connect(&m_SliceChangeListener, SIGNAL(SliceChanged()), this, SLOT(OnSliceChanged())); connect(m_Controls.cmbFit, SIGNAL(currentIndexChanged(int)), this, SLOT(OnFitSelectionChanged(int))); connect(m_Controls.radioScaleFixed, SIGNAL(toggled(bool)), m_Controls.sbFixMin, SLOT(setEnabled(bool))); connect(m_Controls.radioScaleFixed, SIGNAL(toggled(bool)), m_Controls.sbFixMax, SLOT(setEnabled(bool))); connect(m_Controls.radioScaleFixed, SIGNAL(toggled(bool)), m_Controls.labelFixMin, SLOT(setEnabled(bool))); connect(m_Controls.radioScaleFixed, SIGNAL(toggled(bool)), m_Controls.labelFixMax, SLOT(setEnabled(bool))); connect(m_Controls.radioScaleFixed, SIGNAL(toggled(bool)), m_Controls.btnScaleToData, SLOT(setEnabled(bool))); connect(m_Controls.radioScaleFixed, SIGNAL(toggled(bool)), this, SLOT(OnScaleFixedYChecked(bool))); connect(m_Controls.btnScaleToData, SIGNAL(clicked()), this, SLOT(OnScaleToDataYClicked())); connect(m_Controls.sbFixMax, SIGNAL(valueChanged(double)), this, SLOT(OnFixedScalingYChanged(double))); connect(m_Controls.sbFixMin, SIGNAL(valueChanged(double)), this, SLOT(OnFixedScalingYChanged(double))); connect(m_Controls.radioScaleFixed_x, SIGNAL(toggled(bool)), m_Controls.sbFixMin_x, SLOT(setEnabled(bool))); connect(m_Controls.radioScaleFixed_x, SIGNAL(toggled(bool)), m_Controls.sbFixMax_x, SLOT(setEnabled(bool))); connect(m_Controls.radioScaleFixed_x, SIGNAL(toggled(bool)), m_Controls.labelFixMin_x, SLOT(setEnabled(bool))); connect(m_Controls.radioScaleFixed_x, SIGNAL(toggled(bool)), m_Controls.labelFixMax_x, SLOT(setEnabled(bool))); connect(m_Controls.radioScaleFixed_x, SIGNAL(toggled(bool)), m_Controls.btnScaleToData_x, SLOT(setEnabled(bool))); connect(m_Controls.radioScaleFixed_x, SIGNAL(toggled(bool)), this, SLOT(OnScaleFixedXChecked(bool))); connect(m_Controls.btnScaleToData_x, SIGNAL(clicked()), this, SLOT(OnScaleToDataXClicked())); connect(m_Controls.sbFixMax_x, SIGNAL(valueChanged(double)), this, SLOT(OnFixedScalingXChanged(double))); connect(m_Controls.sbFixMin_x, SIGNAL(valueChanged(double)), this, SLOT(OnFixedScalingXChanged(double))); connect(m_Controls.btnFullPlot, SIGNAL(clicked(bool)), this, SLOT(OnFullPlotClicked(bool))); this->EnsureBookmarkPointSet(); m_Controls.inspectionPositionWidget->SetPositionBookmarkNode(m_PositionBookmarksNode.Lock()); connect(m_Controls.inspectionPositionWidget, SIGNAL(PositionBookmarksChanged()), this, SLOT(OnPositionBookmarksChanged())); // For some reason this needs to be called to set the plot widget's minimum width to an // acceptable level (since Qwt 6). // Otherwise it tries to keep both axes equal in length, resulting in a minimum width of // 400-500px which is way too much. m_Controls.widgetPlot->GetPlot()->updateAxes(); m_Controls.cmbFit->clear(); mitk::IRenderWindowPart* renderWindowPart = GetRenderWindowPart(); RenderWindowPartActivated(renderWindowPart); } void ModelFitInspectorView::SetFocus() { } void ModelFitInspectorView::NodeRemoved(const mitk::DataNode* node) { if (node == this->m_currentSelectedNode) { QmitkSingleNodeSelectionWidget::NodeList emptylist; this->m_Controls.inputNodeSelector->SetCurrentSelection(emptylist); } } void ModelFitInspectorView::OnScaleFixedYChecked(bool checked) { m_Controls.widgetPlot->GetPlot()->setAxisAutoScale(QwtPlot::yLeft, !checked); if (checked) { OnScaleToDataYClicked(); } m_Controls.widgetPlot->GetPlot()->replot(); }; void ModelFitInspectorView::OnScaleFixedXChecked(bool checked) { m_Controls.widgetPlot->GetPlot()->setAxisAutoScale(QwtPlot::xBottom, !checked); if (checked) { OnScaleToDataXClicked(); } m_Controls.widgetPlot->GetPlot()->replot(); }; void ModelFitInspectorView::OnScaleToDataYClicked() { auto minmax = this->m_PlotCurves.GetYMinMax(); auto min = minmax.first - std::abs(minmax.first) * 0.01; auto max = minmax.second + std::abs(minmax.second) * 0.01; m_Controls.sbFixMin->setValue(min); m_Controls.sbFixMax->setValue(max); }; void ModelFitInspectorView::OnScaleToDataXClicked() { auto minmax = this->m_PlotCurves.GetXMinMax(); auto min = minmax.first - std::abs(minmax.first) * 0.01; auto max = minmax.second + std::abs(minmax.second) * 0.01; m_Controls.sbFixMin_x->setValue(min); m_Controls.sbFixMax_x->setValue(max); }; void ModelFitInspectorView::OnFixedScalingYChanged(double /*value*/) { m_Controls.widgetPlot->GetPlot()->setAxisScale(QwtPlot::yLeft, m_Controls.sbFixMin->value(), m_Controls.sbFixMax->value()); m_Controls.widgetPlot->GetPlot()->replot(); }; void ModelFitInspectorView::OnFixedScalingXChanged(double /*value*/) { m_Controls.widgetPlot->GetPlot()->setAxisScale(QwtPlot::xBottom, m_Controls.sbFixMin_x->value(), m_Controls.sbFixMax_x->value()); m_Controls.widgetPlot->GetPlot()->replot(); }; void ModelFitInspectorView::OnFullPlotClicked(bool checked) { m_Controls.tabWidget->setVisible(!checked); }; int ModelFitInspectorView::ActualizeFitSelectionWidget() { - mitk::NodeUIDType selectedFitUD = ""; + mitk::modelFit::ModelFitInfo::UIDType selectedFitUD = ""; bool isModelFitNode = this->m_currentSelectedNode->GetData()->GetPropertyList()->GetStringProperty( mitk::ModelFitConstants::FIT_UID_PROPERTY_NAME().c_str(), selectedFitUD); mitk::DataStorage::Pointer storage = this->GetDataStorage(); mitk::modelFit::NodeUIDSetType fitUIDs = mitk::modelFit::GetFitUIDsOfNode( this->m_currentSelectedNode, storage); this->m_modelfitList.clear(); this->m_Controls.cmbFit->clear(); for (const auto & fitUID : fitUIDs) { mitk::modelFit::ModelFitInfo::ConstPointer info = mitk::modelFit::CreateFitInfoFromNode(fitUID, storage).GetPointer(); if (info.IsNotNull()) { this->m_modelfitList.insert(std::make_pair(info->uid, info)); std::ostringstream nameStrm; if (info->fitName.empty()) { nameStrm << info->uid; } else { nameStrm << info->fitName; } nameStrm << " (" << info->modelName << ")"; QVariant data(info->uid.c_str()); m_Controls.cmbFit->addItem(QString::fromStdString(nameStrm.str()), data); } else { MITK_ERROR << "Was not able to extract model fit information from storage. Node properties in storage may be invalid. Failed fit UID:" << fitUID; } } int cmbIndex = 0; if (m_modelfitList.empty()) { cmbIndex = -1; }; if (isModelFitNode) { //model was selected, thus select this one in combobox QVariant data(selectedFitUD.c_str()); cmbIndex = m_Controls.cmbFit->findData(data); if (cmbIndex == -1) { MITK_WARN << "Model fit Inspector in invalid state. Selected fit seems to be not avaible in plugin selection. Failed fit UID:" << selectedFitUD; } }; m_Controls.cmbFit->setCurrentIndex(cmbIndex); return cmbIndex; } void ModelFitInspectorView::OnInputChanged(const QList& nodes) { if (nodes.size() > 0) { if (nodes.front() != this->m_currentSelectedNode) { m_internalUpdateFlag = true; this->m_currentSelectedNode = nodes.front(); - mitk::NodeUIDType selectedFitUD = ""; + mitk::modelFit::ModelFitInfo::UIDType selectedFitUD = ""; bool isModelFitNode = this->m_currentSelectedNode->GetData()->GetPropertyList()->GetStringProperty( mitk::ModelFitConstants::FIT_UID_PROPERTY_NAME().c_str(), selectedFitUD); if (isModelFitNode) { this->m_currentSelectedNode = this->GetParentNode(this->m_currentSelectedNode); } auto cmbIndex = ActualizeFitSelectionWidget(); m_internalUpdateFlag = false; m_selectedNodeTime.Modified(); if (cmbIndex == -1) { //only raw 4D data selected. Just update plots for current position m_currentFit = nullptr; m_currentFitTime.Modified(); OnSliceChanged(); m_Controls.plotDataWidget->SetXName(DEFAULT_X_AXIS); } else { //refresh fit selection (and implicitly update plots) OnFitSelectionChanged(cmbIndex); } } } else { if (this->m_currentSelectedNode.IsNotNull()) { m_internalUpdateFlag = true; this->m_currentSelectedNode = nullptr; this->m_currentFit = nullptr; this->m_modelfitList.clear(); this->m_Controls.cmbFit->clear(); m_internalUpdateFlag = false; m_selectedNodeTime.Modified(); OnFitSelectionChanged(0); RefreshPlotData(); m_Controls.plotDataWidget->SetPlotData(&(this->m_PlotCurves)); m_Controls.fitParametersWidget->setFits(QmitkFitParameterModel::FitVectorType()); RenderPlot(); } } } mitk::DataNode::ConstPointer ModelFitInspectorView::GetParentNode(mitk::DataNode::ConstPointer node) { if (node.IsNotNull()) { mitk::DataStorage::SetOfObjects::ConstPointer parentNodeList = GetDataStorage()->GetSources(node); if (parentNodeList->size() > 0) { return parentNodeList->front().GetPointer(); } } return mitk::DataNode::ConstPointer(); } void ModelFitInspectorView::ValidateAndSetCurrentPosition() { mitk::Point3D currentSelectedPosition = GetRenderWindowPart()->GetSelectedPosition(nullptr); unsigned int currentSelectedTimestep = m_renderWindowPart->GetTimeNavigationController()->GetTime()-> GetPos(); if (m_currentSelectedPosition != currentSelectedPosition || m_currentSelectedTimeStep != currentSelectedTimestep || m_selectedNodeTime > m_currentPositionTime) { //the current position has been changed or the selected node has been changed since the last position validation -> check position m_currentSelectedPosition = currentSelectedPosition; m_currentSelectedTimeStep = currentSelectedTimestep; m_currentPositionTime.Modified(); m_validSelectedPosition = false; - mitk::Image::Pointer inputImage = this->GetCurrentInputImage(); + auto inputImage = this->GetCurrentInputImage(); if (inputImage.IsNull()) { return; } - mitk::BaseGeometry::Pointer geometry = inputImage->GetTimeGeometry()->GetGeometryForTimeStep( + mitk::BaseGeometry::ConstPointer geometry = inputImage->GetTimeGeometry()->GetGeometryForTimeStep( m_currentSelectedTimeStep); // check for invalid time step if (geometry.IsNull()) { geometry = inputImage->GetTimeGeometry()->GetGeometryForTimeStep(0); } if (geometry.IsNull()) { return; } m_validSelectedPosition = geometry->IsInside(m_currentSelectedPosition); } } -mitk::Image::Pointer ModelFitInspectorView::GetCurrentInputImage() const +mitk::Image::ConstPointer ModelFitInspectorView::GetCurrentInputImage() const { - mitk::Image::Pointer result = nullptr; + mitk::Image::ConstPointer result = nullptr; if (this->m_currentFit.IsNotNull()) { result = m_currentFit->inputImage; } else if (this->m_currentSelectedNode.IsNotNull()) { result = dynamic_cast(this->m_currentSelectedNode->GetData()); if (result.IsNotNull() && result->GetTimeSteps() <= 1) { //if the image is not dynamic, we can't use it. result = nullptr; } } return result; }; const mitk::ModelBase::TimeGridType ModelFitInspectorView::GetCurrentTimeGrid() const { if (m_currentModelProviderService && m_currentFit.IsNotNull()) { return m_currentModelProviderService->GetVariableGrid(m_currentFit); } else { //fall back if there is no model provider we assume to use the normal time grid. return ExtractTimeGrid(GetCurrentInputImage()); } }; void ModelFitInspectorView::OnSliceChanged() { ValidateAndSetCurrentPosition(); m_Controls.widgetPlot->setEnabled(m_validSelectedPosition); if (m_currentSelectedNode.IsNotNull()) { m_Controls.inspectionPositionWidget->SetCurrentPosition(m_currentSelectedPosition); if (RefreshPlotData()) { RenderPlot(); m_Controls.plotDataWidget->SetPlotData(&m_PlotCurves); RenderFitInfo(); } } } void ModelFitInspectorView::OnPositionBookmarksChanged() { if (RefreshPlotData()) { RenderPlot(); m_Controls.plotDataWidget->SetPlotData(&m_PlotCurves); RenderFitInfo(); } } void ModelFitInspectorView::OnFitSelectionChanged(int index) { if (!m_internalUpdateFlag) { MITK_DEBUG << "selected fit index: " << index; std::string uid = ""; if (m_Controls.cmbFit->count() > index) { uid = m_Controls.cmbFit->itemData(index).toString().toStdString(); } mitk::modelFit::ModelFitInfo::ConstPointer newFit = nullptr; ModelFitInfoListType::iterator finding = m_modelfitList.find(uid); if (finding != m_modelfitList.end()) { newFit = finding->second; } if (m_currentFit != newFit) { m_currentModelParameterizer = nullptr; m_currentModelProviderService = nullptr; if (newFit.IsNotNull()) { m_currentModelParameterizer = mitk::ModelGenerator::GenerateModelParameterizer(*newFit); m_currentModelProviderService = mitk::ModelGenerator::GetProviderService(newFit->functionClassID); } m_currentFit = newFit; m_currentFitTime.Modified(); auto name = m_currentFit->xAxisName; if (!m_currentFit->xAxisUnit.empty()) { name += " [" + m_currentFit->xAxisUnit + "]"; } m_Controls.plotDataWidget->SetXName(name); OnSliceChanged(); } } } mitk::PlotDataCurveCollection::Pointer ModelFitInspectorView::RefreshPlotDataCurveCollection(const mitk::Point3D& position, const mitk::Image* input, const mitk::modelFit::ModelFitInfo* fitInfo, const mitk::ModelBase::TimeGridType& timeGrid, mitk::ModelParameterizerBase* parameterizer) { mitk::PlotDataCurveCollection::Pointer result = mitk::PlotDataCurveCollection::New(); //sample curve if (input) { result->InsertElement(mitk::MODEL_FIT_PLOT_SAMPLE_NAME(), GenerateImageSamplePlotData(position, input, timeGrid)); } //model signal curve if (fitInfo) { // Interpolate time grid (x values) so the curve looks smooth const mitk::ModelBase::TimeGridType interpolatedTimeGrid = mitk::GenerateSupersampledTimeGrid(timeGrid, INTERPOLATION_STEPS); auto hires_curve = mitk::GenerateModelSignalPlotData(position, fitInfo, interpolatedTimeGrid, parameterizer); result->InsertElement(mitk::MODEL_FIT_PLOT_INTERPOLATED_SIGNAL_NAME(), hires_curve); auto curve = mitk::GenerateModelSignalPlotData(position, fitInfo, timeGrid, parameterizer); result->InsertElement(mitk::MODEL_FIT_PLOT_SIGNAL_NAME(), curve); } return result; }; bool ModelFitInspectorView::RefreshPlotData() { bool changed = false; if (m_currentSelectedNode.IsNull()) { this->m_PlotCurves = mitk::ModelFitPlotData(); changed = m_selectedNodeTime > m_lastRefreshTime; m_lastRefreshTime.Modified(); } else { assert(GetRenderWindowPart() != NULL); const mitk::Image* input = GetCurrentInputImage(); const mitk::ModelBase::TimeGridType timeGrid = GetCurrentTimeGrid(); if (m_currentFitTime > m_lastRefreshTime || m_currentPositionTime > m_lastRefreshTime) { if (m_validSelectedPosition) { m_PlotCurves.currentPositionPlots = RefreshPlotDataCurveCollection(m_currentSelectedPosition,input,m_currentFit, timeGrid, m_currentModelParameterizer); } else { m_PlotCurves.currentPositionPlots = mitk::PlotDataCurveCollection::New(); } changed = true; } auto bookmarks = m_PositionBookmarks.Lock(); if (bookmarks.IsNotNull()) { if (m_currentFitTime > m_lastRefreshTime || bookmarks->GetMTime() > m_lastRefreshTime) { m_PlotCurves.positionalPlots.clear(); auto endIter = bookmarks->End(); for (auto iter = bookmarks->Begin(); iter != endIter; iter++) { auto collection = RefreshPlotDataCurveCollection(iter.Value(), input, m_currentFit, timeGrid, m_currentModelParameterizer); m_PlotCurves.positionalPlots.emplace(iter.Index(), std::make_pair(iter.Value(), collection)); } changed = true; } } else { m_PlotCurves.positionalPlots.clear(); } // input data curve if (m_currentFitTime > m_lastRefreshTime) { m_PlotCurves.staticPlots->clear(); if (m_currentFit.IsNotNull()) { m_PlotCurves.staticPlots = GenerateAdditionalModelFitPlotData(m_currentSelectedPosition, m_currentFit, timeGrid); } changed = true; } m_lastRefreshTime.Modified(); } return changed; } void ModelFitInspectorView::RenderFitInfo() { assert(m_renderWindowPart != nullptr); // configure fit information if (m_currentFit.IsNull()) { m_Controls.lFitType->setText(""); m_Controls.lFitUID->setText(""); m_Controls.lModelName->setText(""); m_Controls.lModelType->setText(""); } else { m_Controls.lFitType->setText(QString::fromStdString(m_currentFit->fitType)); m_Controls.lFitUID->setText(QString::fromStdString(m_currentFit->uid)); m_Controls.lModelName->setText(QString::fromStdString(m_currentFit->modelName)); m_Controls.lModelType->setText(QString::fromStdString(m_currentFit->modelType)); } // print results std::stringstream infoOutput; m_Controls.fitParametersWidget->setVisible(false); m_Controls.groupSettings->setVisible(false); if (m_currentFit.IsNull()) { infoOutput << "No fit selected. Only raw image data is plotted."; } else if (!m_validSelectedPosition) { infoOutput << "Current position is outside of the input image of the selected fit.\nInspector is deactivated."; } else { m_Controls.fitParametersWidget->setVisible(true); m_Controls.fitParametersWidget->setFits({ m_currentFit }); m_Controls.fitParametersWidget->setPositionBookmarks(m_PositionBookmarks.Lock()); m_Controls.fitParametersWidget->setCurrentPosition(m_currentSelectedPosition); } // configure data table m_Controls.tableInputData->clearContents(); if (m_currentFit.IsNull()) { infoOutput << "No fit selected. Only raw image data is plotted."; } else { m_Controls.groupSettings->setVisible(true); m_Controls.tableInputData->setRowCount(m_PlotCurves.staticPlots->size()); unsigned int rowIndex = 0; for (mitk::PlotDataCurveCollection::const_iterator pos = m_PlotCurves.staticPlots->begin(); pos != m_PlotCurves.staticPlots->end(); ++pos, ++rowIndex) { QColor dataColor; if (pos->first == "ROI") { dataColor = QColor(0, 190, 0); } else { //Use HSV schema of QColor to calculate a different color depending on the //number of already existing free iso lines. dataColor.setHsv(((rowIndex + 1) * 85) % 360, 255, 255); } QTableWidgetItem* newItem = new QTableWidgetItem(QString::fromStdString(pos->first)); m_Controls.tableInputData->setItem(rowIndex, 0, newItem); newItem = new QTableWidgetItem(); newItem->setBackgroundColor(dataColor); m_Controls.tableInputData->setItem(rowIndex, 1, newItem); } } m_Controls.lInfo->setText(QString::fromStdString(infoOutput.str())); } void ModelFitInspectorView::RenderPlotCurve(const mitk::PlotDataCurveCollection* curveCollection, const QColor& sampleColor, const QColor& signalColor, const std::string& posString) { auto sampleCurve = mitk::ModelFitPlotData::GetSamplePlot(curveCollection); if (sampleCurve) { std::string name = mitk::MODEL_FIT_PLOT_SAMPLE_NAME() + posString; unsigned int curveId = m_Controls.widgetPlot->InsertCurve(name.c_str()); m_Controls.widgetPlot->SetCurveData(curveId, sampleCurve->GetValues()); m_Controls.widgetPlot->SetCurvePen(curveId, QPen(Qt::NoPen)); // QwtSymbol needs to passed as a real pointer from MITK v2013.09.0 on // (QwtPlotCurve deletes it on destruction and assignment). QwtSymbol* dataSymbol = new QwtSymbol(QwtSymbol::Diamond, sampleColor, sampleColor, QSize(8, 8)); m_Controls.widgetPlot->SetCurveSymbol(curveId, dataSymbol); // Again, there is no way to set a curve's legend attributes via QmitkPlotWidget so this // gets unnecessarily complicated. QwtPlotCurve* measurementCurve = dynamic_cast(m_Controls.widgetPlot-> GetPlot()->itemList(QwtPlotItem::Rtti_PlotCurve).back()); measurementCurve->setLegendAttribute(QwtPlotCurve::LegendShowSymbol); measurementCurve->setLegendIconSize(QSize(8, 8)); } //draw model curve auto signalCurve = mitk::ModelFitPlotData::GetInterpolatedSignalPlot(curveCollection); if (signalCurve) { std::string name = mitk::MODEL_FIT_PLOT_SIGNAL_NAME() + posString; QPen pen; pen.setColor(signalColor); pen.setWidth(2); unsigned int curveId = m_Controls.widgetPlot->InsertCurve(name.c_str()); m_Controls.widgetPlot->SetCurveData(curveId, signalCurve->GetValues()); m_Controls.widgetPlot->SetCurvePen(curveId, pen); // Manually set the legend attribute to use the symbol as the legend icon and alter its // size. Otherwise it would revert to default which is drawing a square which is the color // of the curve's pen, so in this case none which defaults to black. // Unfortunately, QmitkPlotWidget offers no way to set the legend attribute and icon size so // this looks a bit hacky. QwtPlotCurve* fitCurve = dynamic_cast(m_Controls.widgetPlot->GetPlot()-> itemList(QwtPlotItem::Rtti_PlotCurve).back()); fitCurve->setLegendAttribute(QwtPlotCurve::LegendShowLine); } } void ModelFitInspectorView::RenderPlot() { m_Controls.widgetPlot->Clear(); std::string xAxis = DEFAULT_X_AXIS; std::string yAxis = "Intensity"; std::string plotTitle = "Raw data plot: no data"; if (m_currentSelectedNode.IsNotNull()) { plotTitle = "Raw data plot: " + m_currentSelectedNode->GetName(); } if (m_currentFit.IsNotNull()) { plotTitle = m_currentFit->modelName.c_str(); xAxis = m_currentFit->xAxisName; if (!m_currentFit->xAxisUnit.empty()) { xAxis += " [" + m_currentFit->xAxisUnit + "]"; } yAxis = m_currentFit->yAxisName; if (!m_currentFit->yAxisUnit.empty()) { yAxis += " [" + m_currentFit->yAxisUnit + "]"; } } m_Controls.widgetPlot->SetAxisTitle(QwtPlot::xBottom, xAxis.c_str()); m_Controls.widgetPlot->SetAxisTitle(QwtPlot::yLeft, yAxis.c_str()); m_Controls.widgetPlot->SetPlotTitle(plotTitle.c_str()); // Draw static curves unsigned int colorIndex = 0; for (mitk::PlotDataCurveCollection::const_iterator pos = m_PlotCurves.staticPlots->begin(); pos != m_PlotCurves.staticPlots->end(); ++pos) { QColor dataColor; unsigned int curveId = m_Controls.widgetPlot->InsertCurve(pos->first.c_str()); m_Controls.widgetPlot->SetCurveData(curveId, pos->second->GetValues()); if (pos->first == "ROI") { dataColor = QColor(0, 190, 0); QPen pen; pen.setColor(dataColor); pen.setStyle(Qt::SolidLine); m_Controls.widgetPlot->SetCurvePen(curveId, pen); } else { //Use HSV schema of QColor to calculate a different color depending on the //number of already existing curves. dataColor.setHsv((++colorIndex * 85) % 360, 255, 150); m_Controls.widgetPlot->SetCurvePen(curveId, QPen(Qt::NoPen)); } // QwtSymbol needs to passed as a real pointer from MITK v2013.09.0 on // (QwtPlotCurve deletes it on destruction and assignment). QwtSymbol* dataSymbol = new QwtSymbol(QwtSymbol::Triangle, dataColor, dataColor, QSize(8, 8)); m_Controls.widgetPlot->SetCurveSymbol(curveId, dataSymbol); // Again, there is no way to set a curve's legend attributes via QmitkPlotWidget so this // gets unnecessarily complicated. QwtPlotCurve* measurementCurve = dynamic_cast(m_Controls.widgetPlot-> GetPlot()->itemList(QwtPlotItem::Rtti_PlotCurve).back()); measurementCurve->setLegendAttribute(QwtPlotCurve::LegendShowSymbol); measurementCurve->setLegendIconSize(QSize(8, 8)); } // Draw positional curves for (const auto& posIter : this->m_PlotCurves.positionalPlots) { QColor dataColor; dataColor.setHsv((++colorIndex * 85) % 360, 255, 150); this->RenderPlotCurve(posIter.second.second, dataColor, dataColor, " @ "+mitk::ModelFitPlotData::GetPositionalCollectionName(posIter)); } // Draw current pos curve this->RenderPlotCurve(m_PlotCurves.currentPositionPlots, QColor(Qt::red), QColor(Qt::black), ""); QwtLegend* legend = new QwtLegend(); legend->setFrameShape(QFrame::Box); legend->setFrameShadow(QFrame::Sunken); legend->setLineWidth(1); m_Controls.widgetPlot->SetLegend(legend, QwtPlot::BottomLegend); m_Controls.widgetPlot->Replot(); } void ModelFitInspectorView::EnsureBookmarkPointSet() { if (m_PositionBookmarks.IsExpired() || m_PositionBookmarksNode.IsExpired()) { const char* nodeName = "org.mitk.gui.qt.fit.inspector.positions"; mitk::DataNode::Pointer node = this->GetDataStorage()->GetNamedNode(nodeName); if (!node) { node = mitk::DataNode::New(); node->SetName(nodeName); node->SetBoolProperty("helper object", true); this->GetDataStorage()->Add(node); } m_PositionBookmarksNode = node; mitk::PointSet::Pointer pointSet = dynamic_cast(node->GetData()); if (pointSet.IsNull()) { pointSet = mitk::PointSet::New(); node->SetData(pointSet); } m_PositionBookmarks = pointSet; } } diff --git a/Plugins/org.mitk.gui.qt.fit.inspector/src/internal/ModelFitInspectorView.h b/Plugins/org.mitk.gui.qt.fit.inspector/src/internal/ModelFitInspectorView.h index 864bbc914c..c0e49afda6 100644 --- a/Plugins/org.mitk.gui.qt.fit.inspector/src/internal/ModelFitInspectorView.h +++ b/Plugins/org.mitk.gui.qt.fit.inspector/src/internal/ModelFitInspectorView.h @@ -1,201 +1,201 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef ModelFitInspectorView_h #define ModelFitInspectorView_h // Blueberry //#include #include // mitk #include #include #include "QmitkSliceNavigationListener.h" #include "mitkModelFitStaticParameterMap.h" #include "mitkModelParameterizerBase.h" #include "mitkModelFitInfo.h" #include "mitkIModelFitProvider.h" #include "mitkModelFitPlotDataHelper.h" #include "QmitkSelectionServiceConnector.h" #include "QmitkFitParameterModel.h" // Qt #include "ui_ModelFitInspectorViewControls.h" /** * @brief View class defining the UI part of the ModelFitInspector plug-in. */ class ModelFitInspectorView : public QmitkAbstractView, public mitk::IRenderWindowPartListener { // 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: ModelFitInspectorView(); ~ModelFitInspectorView() override; static const std::string VIEW_ID; protected slots: void OnSliceChanged(); /** * @brief Triggered when the selection of the "Modelfit" combo box changes. * Sets the selected fit as the current one. * @param index The index (in the combo box) of the selected item. */ void OnFitSelectionChanged(int index); void OnInputChanged(const QList& nodes); void OnPositionBookmarksChanged(); /** Triggered when the selection of "fixed" y axis scaling changes*/ void OnScaleFixedYChecked(bool checked); void OnScaleToDataYClicked(); void OnFixedScalingYChanged(double value); /** Triggered when the selection of "fixed" x axis scaling changes*/ void OnScaleFixedXChecked(bool checked); void OnScaleToDataXClicked(); void OnFixedScalingXChanged(double value); void OnFullPlotClicked(bool checked); protected: void CreateQtPartControl(QWidget* parent) override; void SetFocus() override; void NodeRemoved(const mitk::DataNode* node) override; /** Helper that actualizes the fit selection widget and returns the index of the currently selected * fit.*/ int ActualizeFitSelectionWidget(); void RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) override; void RenderWindowPartDeactivated(mitk::IRenderWindowPart* renderWindowPart) override; /** * @brief Calculates the curve data using the current fit's model and parameterizer. * @param position Indicating the point in the input image for which the model curve should be calculated. * @return A vector of points for the curve data. */ QmitkPlotWidget::XYDataVector CalcCurveFromModel(const mitk::Point3D& position); /** * @brief Calculates the curve data using the current fit's function string. * @param timeGrid The time grid containing the (interpolated) x values for the curve data. * @return A vector of points for the curve data. */ QmitkPlotWidget::XYDataVector CalcCurveFromFunction(const mitk::Point3D& position, const mitk::ModelBase::TimeGridType& timeGrid); /** * @brief Returns the parent node of the given node if it exists. * @param node The node whose parent node should be returned. * @return The parent node of the given node or NULL if it doesn't exist. */ mitk::DataNode::ConstPointer GetParentNode(mitk::DataNode::ConstPointer node); /** Sets m_currentSelectedPosition to the current selection and validates if this position is valid * for the input image of the currently selected fit. If it is valid, m_validSelectedPosition is set to true. * If the fit, his input image or geometry is not specified, it will also handled as invalid.*/ void ValidateAndSetCurrentPosition(); /** Returns the current input image. If a current fit is set it will be its input image. * Otherwise it will be the image stored in the currently selected node. If the node is not set, contains no image * or the image is not 4D, NULL will be returned.*/ - mitk::Image::Pointer GetCurrentInputImage() const; + mitk::Image::ConstPointer GetCurrentInputImage() const; /** Returns the variable/time grid of the GetCurrentInputImage(). If a model fit is selected its provider will be used to get the correct grid, otherwise just a simple time grid will be extracted.*/ const mitk::ModelBase::TimeGridType GetCurrentTimeGrid() const; Ui::ModelFitInspectorViewControls m_Controls; mitk::IRenderWindowPart* m_renderWindowPart; /** @brief Is a visualization currently running? */ bool m_internalUpdateFlag; /** @brief List of modelfits currently in the data manager */ typedef std::map ModelFitInfoListType; ModelFitInfoListType m_modelfitList; /** @brief The currently selected modelfit */ mitk::modelFit::ModelFitInfo::ConstPointer m_currentFit; /** @brief Pointer to the instance of the model parameterizer for the current fit */ mitk::ModelParameterizerBase::Pointer m_currentModelParameterizer; mitk::IModelFitProvider* m_currentModelProviderService; /** @brief currently valid selected position in the inspector*/ mitk::Point3D m_currentSelectedPosition; /** @brief indicates if the currently selected position is valid for the currently selected fit. * This it is within the input image */ bool m_validSelectedPosition; /** @brief currently selected time step of the selected node for the visualization logic*/ unsigned int m_currentSelectedTimeStep; /** @brief currently selected node for the visualization logic*/ mitk::DataNode::ConstPointer m_currentSelectedNode; mitk::WeakPointer m_PositionBookmarksNode; mitk::WeakPointer m_PositionBookmarks; /** @brief Number of interpolation steps between two x values */ static const unsigned int INTERPOLATION_STEPS; /*************************************/ /* Members for visualizing the model */ itk::TimeStamp m_selectedNodeTime; itk::TimeStamp m_currentFitTime; itk::TimeStamp m_currentPositionTime; itk::TimeStamp m_lastRefreshTime; mitk::ModelFitPlotData m_PlotCurves; std::unique_ptr m_SelectionServiceConnector; QmitkFitParameterModel* m_FitParameterModel; QmitkSliceNavigationListener m_SliceChangeListener; /** Check and updates the plot data if needed. * @return indicates if something was refreshed (true)*/ bool RefreshPlotData(); void RenderPlot(); void RenderPlotCurve(const mitk::PlotDataCurveCollection* curveCollection, const QColor& sampleColor, const QColor& signalColor, const std::string& posString); void RenderFitInfo(); void EnsureBookmarkPointSet(); static mitk::PlotDataCurveCollection::Pointer RefreshPlotDataCurveCollection(const mitk::Point3D& position, const mitk::Image* input, const mitk::modelFit::ModelFitInfo* fitInfo, const mitk::ModelBase::TimeGridType& timeGrid, mitk::ModelParameterizerBase* parameterizer); }; #endif // ModelFitInspectorView_h diff --git a/Plugins/org.mitk.gui.qt.pharmacokinetics.mri/src/internal/MRPerfusionView.cpp b/Plugins/org.mitk.gui.qt.pharmacokinetics.mri/src/internal/MRPerfusionView.cpp index 17c6f05ca9..586c31959a 100644 --- a/Plugins/org.mitk.gui.qt.pharmacokinetics.mri/src/internal/MRPerfusionView.cpp +++ b/Plugins/org.mitk.gui.qt.pharmacokinetics.mri/src/internal/MRPerfusionView.cpp @@ -1,1454 +1,1448 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "MRPerfusionView.h" #include "boost/tokenizer.hpp" #include "boost/math/constants/constants.hpp" #include #include "mitkWorkbenchUtil.h" #include "mitkAterialInputFunctionGenerator.h" #include "mitkConcentrationCurveGenerator.h" #include #include #include #include "mitkThreeStepLinearModelFactory.h" #include "mitkThreeStepLinearModelParameterizer.h" #include "mitkTwoStepLinearModelFactory.h" #include "mitkTwoStepLinearModelParameterizer.h" #include #include #include #include #include "mitkTwoCompartmentExchangeModelFactory.h" #include "mitkTwoCompartmentExchangeModelParameterizer.h" #include "mitkNumericTwoCompartmentExchangeModelFactory.h" #include "mitkNumericTwoCompartmentExchangeModelParameterizer.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Includes for image casting between ITK and MITK #include #include "mitkImageCast.h" #include "mitkITKImageImport.h" #include #include const std::string MRPerfusionView::VIEW_ID = "org.mitk.gui.qt.pharmacokinetics.mri"; inline double convertToDouble(const std::string& data) { std::istringstream stepStream(data); stepStream.imbue(std::locale("C")); double value = 0.0; if (!(stepStream >> value) || !(stepStream.eof())) { mitkThrow() << "Cannot convert string to double. String: " << data; } return value; } void MRPerfusionView::SetFocus() { m_Controls.btnModelling->setFocus(); } void MRPerfusionView::CreateQtPartControl(QWidget* parent) { m_Controls.setupUi(parent); m_Controls.btnModelling->setEnabled(false); this->InitModelComboBox(); connect(m_Controls.btnModelling, SIGNAL(clicked()), this, SLOT(OnModellingButtonClicked())); connect(m_Controls.comboModel, SIGNAL(currentIndexChanged(int)), this, SLOT(OnModellSet(int))); connect(m_Controls.radioPixelBased, SIGNAL(toggled(bool)), this, SLOT(UpdateGUIControls())); //AIF setting m_Controls.groupAIF->hide(); m_Controls.btnAIFFile->setEnabled(false); m_Controls.btnAIFFile->setEnabled(false); m_Controls.radioAIFImage->setChecked(true); m_Controls.comboAIFMask->SetDataStorage(this->GetDataStorage()); m_Controls.comboAIFMask->SetPredicate(m_IsMaskPredicate); m_Controls.comboAIFMask->setVisible(true); m_Controls.comboAIFMask->setEnabled(true); m_Controls.comboAIFImage->SetDataStorage(this->GetDataStorage()); m_Controls.comboAIFImage->SetPredicate(m_IsNoMaskImagePredicate); m_Controls.comboAIFImage->setEnabled(false); m_Controls.checkDedicatedAIFImage->setEnabled(true); m_Controls.HCLSpinBox->setValue(mitk::AterialInputFunctionGenerator::DEFAULT_HEMATOCRIT_LEVEL); m_Controls.spinBox_baselineEndTimeStep->setMinimum(0); m_Controls.spinBox_baselineStartTimeStep->setMinimum(0); connect(m_Controls.radioAIFImage, SIGNAL(toggled(bool)), m_Controls.comboAIFMask, SLOT(setVisible(bool))); connect(m_Controls.radioAIFImage, SIGNAL(toggled(bool)), m_Controls.labelAIFMask, SLOT(setVisible(bool))); connect(m_Controls.radioAIFImage, SIGNAL(toggled(bool)), m_Controls.checkDedicatedAIFImage, SLOT(setVisible(bool))); connect(m_Controls.radioAIFImage, SIGNAL(toggled(bool)), m_Controls.comboAIFMask, SLOT(setEnabled(bool))); connect(m_Controls.radioAIFImage, SIGNAL(toggled(bool)), m_Controls.checkDedicatedAIFImage, SLOT(setEnabled(bool))); connect(m_Controls.radioAIFImage, SIGNAL(toggled(bool)), m_Controls.checkDedicatedAIFImage, SLOT(setVisible(bool))); connect(m_Controls.radioAIFImage, SIGNAL(toggled(bool)), m_Controls.comboAIFImage, SLOT(setVisible(bool))); connect(m_Controls.checkDedicatedAIFImage, SIGNAL(toggled(bool)), m_Controls.comboAIFImage, SLOT(setEnabled(bool))); connect(m_Controls.radioAIFImage, SIGNAL(toggled(bool)), this, SLOT(UpdateGUIControls())); connect(m_Controls.radioAIFFile, SIGNAL(toggled(bool)), m_Controls.btnAIFFile, SLOT(setEnabled(bool))); connect(m_Controls.radioAIFFile, SIGNAL(toggled(bool)), m_Controls.aifFilePath, SLOT(setEnabled(bool))); connect(m_Controls.radioAIFFile, SIGNAL(toggled(bool)), this, SLOT(UpdateGUIControls())); connect(m_Controls.btnAIFFile, SIGNAL(clicked()), this, SLOT(LoadAIFfromFile())); //Brix setting m_Controls.groupDescBrix->hide(); connect(m_Controls.injectiontime, SIGNAL(valueChanged(double)), this, SLOT(UpdateGUIControls())); //Num2CX setting m_Controls.groupNum2CXM->hide(); connect(m_Controls.odeStepSize, SIGNAL(valueChanged(double)), this, SLOT(UpdateGUIControls())); //Model fit configuration m_Controls.groupBox_FitConfiguration->hide(); m_Controls.checkBox_Constraints->setEnabled(false); m_Controls.constraintManager->setEnabled(false); m_Controls.initialValuesManager->setEnabled(false); m_Controls.initialValuesManager->setDataStorage(this->GetDataStorage()); connect(m_Controls.radioButton_StartParameters, SIGNAL(toggled(bool)), this, SLOT(UpdateGUIControls())); connect(m_Controls.checkBox_Constraints, SIGNAL(toggled(bool)), this, SLOT(UpdateGUIControls())); connect(m_Controls.initialValuesManager, SIGNAL(initialValuesChanged(void)), this, SLOT(UpdateGUIControls())); connect(m_Controls.radioButton_StartParameters, SIGNAL(toggled(bool)), m_Controls.initialValuesManager, SLOT(setEnabled(bool))); connect(m_Controls.checkBox_Constraints, SIGNAL(toggled(bool)), m_Controls.constraintManager, SLOT(setEnabled(bool))); connect(m_Controls.checkBox_Constraints, SIGNAL(toggled(bool)), m_Controls.constraintManager, SLOT(setVisible(bool))); //Concentration m_Controls.groupConcentration->hide(); m_Controls.groupBoxEnhancement->hide(); m_Controls.groupBoxTurboFlash->hide(); m_Controls.radioButtonNoConversion->setChecked(true); m_Controls.groupBox_T1MapviaVFA->hide(); m_Controls.spinBox_baselineStartTimeStep->setValue(0); m_Controls.spinBox_baselineEndTimeStep->setValue(0); connect(m_Controls.radioButtonTurboFlash, SIGNAL(toggled(bool)), m_Controls.groupBoxTurboFlash, SLOT(setVisible(bool))); connect(m_Controls.radioButtonTurboFlash, SIGNAL(toggled(bool)), this, SLOT(UpdateGUIControls())); connect(m_Controls.relaxationtime, SIGNAL(valueChanged(double)), this, SLOT(UpdateGUIControls())); connect(m_Controls.recoverytime, SIGNAL(valueChanged(double)), this, SLOT(UpdateGUIControls())); connect(m_Controls.relaxivity, SIGNAL(valueChanged(double)), this, SLOT(UpdateGUIControls())); connect(m_Controls.radioButton_absoluteEnhancement, SIGNAL(toggled(bool)), this, SLOT(UpdateGUIControls())); connect(m_Controls.radioButton_relativeEnchancement, SIGNAL(toggled(bool)), this, SLOT(UpdateGUIControls())); connect(m_Controls.radioButton_absoluteEnhancement, SIGNAL(toggled(bool)), m_Controls.groupBoxEnhancement, SLOT(setVisible(bool))); connect(m_Controls.radioButton_relativeEnchancement, SIGNAL(toggled(bool)), m_Controls.groupBoxEnhancement, SLOT(setVisible(bool))); connect(m_Controls.factorSpinBox, SIGNAL(valueChanged(double)), this, SLOT(UpdateGUIControls())); connect(m_Controls.spinBox_baselineStartTimeStep, SIGNAL(valueChanged(int)), this, SLOT(UpdateGUIControls())); connect(m_Controls.spinBox_baselineEndTimeStep, SIGNAL(valueChanged(int)), this, SLOT(UpdateGUIControls())); connect(m_Controls.radioButtonUsingT1viaVFA, SIGNAL(toggled(bool)), m_Controls.groupBox_T1MapviaVFA, SLOT(setVisible(bool))); connect(m_Controls.radioButtonUsingT1viaVFA, SIGNAL(toggled(bool)), this, SLOT(UpdateGUIControls())); connect(m_Controls.FlipangleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(UpdateGUIControls())); connect(m_Controls.RelaxivitySpinBox, SIGNAL(valueChanged(double)), this, SLOT(UpdateGUIControls())); connect(m_Controls.TRSpinBox, SIGNAL(valueChanged(double)), this, SLOT(UpdateGUIControls())); m_Controls.ComboPDWImage->SetDataStorage(this->GetDataStorage()); m_Controls.ComboPDWImage->SetPredicate(m_IsNoMaskImagePredicate); m_Controls.ComboPDWImage->setEnabled(false); connect(m_Controls.radioButtonUsingT1viaVFA, SIGNAL(toggled(bool)), m_Controls.ComboPDWImage, SLOT(setEnabled(bool))); UpdateGUIControls(); } bool MRPerfusionView::IsTurboFlashSequenceFlag() const { return this->m_Controls.radioButtonTurboFlash->isChecked(); }; void MRPerfusionView::UpdateGUIControls() { m_Controls.lineFitName->setPlaceholderText(QString::fromStdString(this->GetDefaultFitName())); m_Controls.lineFitName->setEnabled(!m_FittingInProgress); m_Controls.checkBox_Constraints->setEnabled(m_modelConstraints.IsNotNull()); bool isDescBrixFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool isToftsFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr || dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool is2CXMFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr || dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool isNum2CXMFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool isSLFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr || dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; m_Controls.groupAIF->setVisible(isToftsFactory || is2CXMFactory); m_Controls.groupDescBrix->setVisible(isDescBrixFactory); m_Controls.groupNum2CXM->setVisible(isNum2CXMFactory); m_Controls.groupConcentration->setVisible(isToftsFactory || is2CXMFactory || isSLFactory); m_Controls.groupBox_FitConfiguration->setVisible(m_selectedModelFactory); m_Controls.groupBox->setEnabled(!m_FittingInProgress); m_Controls.comboModel->setEnabled(!m_FittingInProgress); m_Controls.groupAIF->setEnabled(!m_FittingInProgress); m_Controls.groupDescBrix->setEnabled(!m_FittingInProgress); m_Controls.groupNum2CXM->setEnabled(!m_FittingInProgress); m_Controls.groupConcentration->setEnabled(!m_FittingInProgress); m_Controls.groupBox_FitConfiguration->setEnabled(!m_FittingInProgress); m_Controls.radioROIbased->setEnabled(m_selectedMask.IsNotNull()); m_Controls.btnModelling->setEnabled(m_selectedImage.IsNotNull() && m_selectedModelFactory.IsNotNull() && !m_FittingInProgress && CheckModelSettings()); m_Controls.spinBox_baselineStartTimeStep->setEnabled(m_Controls.radioButtonTurboFlash->isChecked() || m_Controls.radioButton_absoluteEnhancement->isChecked() || m_Controls.radioButton_relativeEnchancement->isChecked() || m_Controls.radioButtonUsingT1viaVFA->isChecked()); m_Controls.spinBox_baselineEndTimeStep->setEnabled(m_Controls.radioButton_absoluteEnhancement->isChecked() || m_Controls.radioButton_relativeEnchancement->isChecked() || m_Controls.radioButtonUsingT1viaVFA->isChecked() || m_Controls.radioButtonTurboFlash->isChecked()); } void MRPerfusionView::OnModellSet(int index) { m_selectedModelFactory = nullptr; if (index > 0) { if (static_cast(index) <= m_FactoryStack.size() ) { m_selectedModelFactory = m_FactoryStack[index - 1]; } else { MITK_WARN << "Invalid model index. Index outside of the factory stack. Factory stack size: "<< m_FactoryStack.size() << "; invalid index: "<< index; } } if (m_selectedModelFactory) { this->m_modelConstraints = dynamic_cast (m_selectedModelFactory->CreateDefaultConstraints().GetPointer()); m_Controls.initialValuesManager->setInitialValues(m_selectedModelFactory->GetParameterNames(), m_selectedModelFactory->GetDefaultInitialParameterization()); if (this->m_modelConstraints.IsNull()) { this->m_modelConstraints = mitk::SimpleBarrierConstraintChecker::New(); } m_Controls.constraintManager->setChecker(this->m_modelConstraints, this->m_selectedModelFactory->GetParameterNames()); } UpdateGUIControls(); } std::string MRPerfusionView::GetFitName() const { std::string fitName = m_Controls.lineFitName->text().toStdString(); if (fitName.empty()) { fitName = m_Controls.lineFitName->placeholderText().toStdString(); } return fitName; } std::string MRPerfusionView::GetDefaultFitName() const { std::string defaultName = "undefined model"; if (this->m_selectedModelFactory.IsNotNull()) { defaultName = this->m_selectedModelFactory->GetClassID(); } if (this->m_Controls.radioPixelBased->isChecked()) { defaultName += "_pixel"; } else { defaultName += "_roi"; } return defaultName; } void MRPerfusionView::OnModellingButtonClicked() { //check if all static parameters set if (m_selectedModelFactory.IsNotNull() && CheckModelSettings()) { m_HasGeneratedNewInput = false; m_HasGeneratedNewInputAIF = false; mitk::ParameterFitImageGeneratorBase::Pointer generator = nullptr; mitk::modelFit::ModelFitInfo::Pointer fitSession = nullptr; bool isDescBrixFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool is3LinearFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool is2LinearFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool isExtToftsFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool isStanToftsFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool is2CXMFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool isNum2CXMFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; if (isDescBrixFactory) { if (this->m_Controls.radioPixelBased->isChecked()) { GenerateDescriptiveBrixModel_PixelBased(fitSession, generator); } else { GenerateDescriptiveBrixModel_ROIBased(fitSession, generator); } } else if (is2LinearFactory) { if (this->m_Controls.radioPixelBased->isChecked()) { GenerateLinearModelFit_PixelBased(fitSession, generator); } else { GenerateLinearModelFit_ROIBased(fitSession, generator); } } else if (is3LinearFactory) { if (this->m_Controls.radioPixelBased->isChecked()) { GenerateLinearModelFit_PixelBased(fitSession, generator); } else { GenerateLinearModelFit_ROIBased(fitSession, generator); } } else if (isStanToftsFactory) { if (this->m_Controls.radioPixelBased->isChecked()) { GenerateAIFbasedModelFit_PixelBased(fitSession, generator); } else { GenerateAIFbasedModelFit_ROIBased(fitSession, generator); } } else if (isExtToftsFactory) { if (this->m_Controls.radioPixelBased->isChecked()) { GenerateAIFbasedModelFit_PixelBased(fitSession, generator); } else { GenerateAIFbasedModelFit_ROIBased(fitSession, generator); } } else if (is2CXMFactory) { if (this->m_Controls.radioPixelBased->isChecked()) { GenerateAIFbasedModelFit_PixelBased(fitSession, generator); } else { GenerateAIFbasedModelFit_ROIBased(fitSession, generator); } } else if (isNum2CXMFactory) { if (this->m_Controls.radioPixelBased->isChecked()) { GenerateAIFbasedModelFit_PixelBased(fitSession, generator); } else { GenerateAIFbasedModelFit_ROIBased(fitSession, generator); } } //add other models with else if if (generator.IsNotNull() && fitSession.IsNotNull()) { m_FittingInProgress = true; UpdateGUIControls(); DoFit(fitSession, generator); } else { QMessageBox box; box.setText("Fitting error!"); box.setInformativeText("Could not establish fitting job. Error when setting ab generator, model parameterizer or session info."); box.setStandardButtons(QMessageBox::Ok); box.setDefaultButton(QMessageBox::Ok); box.setIcon(QMessageBox::Warning); box.exec(); } } else { QMessageBox box; box.setText("Static parameters for model are not set!"); box.setInformativeText("Some static parameters, that are needed for calculation are not set and equal to zero. Modeling not possible"); box.setStandardButtons(QMessageBox::Ok); box.setDefaultButton(QMessageBox::Ok); box.setIcon(QMessageBox::Warning); box.exec(); } } void MRPerfusionView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*source*/, const QList& selectedNodes) { m_selectedMaskNode = nullptr; m_selectedMask = nullptr; m_Controls.masklabel->setText("No (valid) mask selected."); m_Controls.timeserieslabel->setText("No (valid) series selected."); QList nodes = selectedNodes; if (nodes.size() > 0 && this->m_IsNoMaskImagePredicate->CheckNode(nodes.front())) { this->m_selectedNode = nodes.front(); auto selectedImage = dynamic_cast(this->m_selectedNode->GetData()); m_Controls.timeserieslabel->setText((this->m_selectedNode->GetName()).c_str()); if (selectedImage != this->m_selectedImage) { if (selectedImage) { this->m_Controls.initialValuesManager->setReferenceImageGeometry(selectedImage->GetGeometry()); } else { this->m_Controls.initialValuesManager->setReferenceImageGeometry(nullptr); } } this->m_selectedImage = selectedImage; nodes.pop_front(); } else { this->m_selectedNode = nullptr; this->m_selectedImage = nullptr; this->m_Controls.initialValuesManager->setReferenceImageGeometry(nullptr); } if (nodes.size() > 0 && this->m_IsMaskPredicate->CheckNode(nodes.front())) { this->m_selectedMaskNode = nodes.front(); this->m_selectedMask = dynamic_cast(this->m_selectedMaskNode->GetData()); if (this->m_selectedMask->GetTimeSteps() > 1) { MITK_INFO << "Selected mask has multiple timesteps. Only use first timestep to mask model fit. Mask name: " << m_selectedMaskNode->GetName(); mitk::ImageTimeSelector::Pointer maskedImageTimeSelector = mitk::ImageTimeSelector::New(); maskedImageTimeSelector->SetInput(this->m_selectedMask); maskedImageTimeSelector->SetTimeNr(0); maskedImageTimeSelector->UpdateLargestPossibleRegion(); this->m_selectedMask = maskedImageTimeSelector->GetOutput(); } m_Controls.masklabel->setText((this->m_selectedMaskNode->GetName()).c_str()); } if (m_selectedMask.IsNull()) { this->m_Controls.radioPixelBased->setChecked(true); } if (this->m_selectedImage.IsNotNull()) { m_Controls.spinBox_baselineStartTimeStep->setMaximum((this->m_selectedImage->GetDimension(3))-1); m_Controls.spinBox_baselineEndTimeStep->setMaximum((this->m_selectedImage->GetDimension(3)) - 1); } UpdateGUIControls(); } bool MRPerfusionView::CheckModelSettings() const { bool ok = true; //check wether any model is set at all. Otherwise exit with false if (m_selectedModelFactory.IsNotNull()) { bool isDescBrixFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool is3LinearFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool is2LinearFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool isToftsFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr|| dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool is2CXMFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool isNum2CXMFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; if (isDescBrixFactory) { //if all static parameters for this model are set, exit with true, Otherwise exit with false ok = m_Controls.injectiontime->value() > 0; } else if (is3LinearFactory || is2LinearFactory) { if (this->m_Controls.radioButtonTurboFlash->isChecked() ) { ok = ok && (m_Controls.recoverytime->value() > 0); ok = ok && (m_Controls.relaxationtime->value() > 0); ok = ok && (m_Controls.relaxivity->value() > 0); ok = ok && (m_Controls.AifRecoverytime->value() > 0); ok = ok && CheckBaselineSelectionSettings(); } else if (this->m_Controls.radioButton_absoluteEnhancement->isChecked() || this->m_Controls.radioButton_relativeEnchancement->isChecked() ) { ok = ok && (m_Controls.factorSpinBox->value() > 0); ok = ok && CheckBaselineSelectionSettings(); } else if (this->m_Controls.radioButtonUsingT1viaVFA->isChecked() ) { ok = ok && (m_Controls.FlipangleSpinBox->value() > 0); ok = ok && (m_Controls.TRSpinBox->value() > 0); ok = ok && (m_Controls.RelaxivitySpinBox->value() > 0); ok = ok && (m_Controls.ComboPDWImage->GetSelectedNode().IsNotNull()); ok = ok && CheckBaselineSelectionSettings(); } else if (this->m_Controls.radioButtonNoConversion->isChecked()) { ok = true; } else { ok = false; } } else if (isToftsFactory || is2CXMFactory || isNum2CXMFactory) { if (this->m_Controls.radioAIFImage->isChecked()) { ok = ok && m_Controls.comboAIFMask->GetSelectedNode().IsNotNull(); if (this->m_Controls.checkDedicatedAIFImage->isChecked()) { ok = ok && m_Controls.comboAIFImage->GetSelectedNode().IsNotNull(); } } else if (this->m_Controls.radioAIFFile->isChecked()) { ok = ok && (this->AIFinputGrid.size() != 0) && (this->AIFinputFunction.size() != 0); } else { ok = false; } if (this->m_Controls.radioButtonTurboFlash->isChecked() ) { ok = ok && (m_Controls.recoverytime->value() > 0); ok = ok && (m_Controls.relaxationtime->value() > 0); ok = ok && (m_Controls.relaxivity->value() > 0); ok = ok && (m_Controls.AifRecoverytime->value() > 0); ok = ok && CheckBaselineSelectionSettings(); } else if (this->m_Controls.radioButton_absoluteEnhancement->isChecked() || this->m_Controls.radioButton_relativeEnchancement->isChecked() ) { ok = ok && (m_Controls.factorSpinBox->value() > 0); ok = ok && CheckBaselineSelectionSettings(); } else if (this->m_Controls.radioButtonUsingT1viaVFA->isChecked() ) { ok = ok && (m_Controls.FlipangleSpinBox->value() > 0); ok = ok && (m_Controls.TRSpinBox->value() > 0); ok = ok && (m_Controls.RelaxivitySpinBox->value() > 0); ok = ok && (m_Controls.ComboPDWImage->GetSelectedNode().IsNotNull()); ok = ok && CheckBaselineSelectionSettings(); } else if (this->m_Controls.radioButtonNoConversion->isChecked()) { ok = ok && true; } else { ok = false; } if (isNum2CXMFactory) { ok = ok && (this->m_Controls.odeStepSize->value() > 0); } } //add other models as else if and check wether all needed static parameters are set else { ok = false; } if (this->m_Controls.radioButton_StartParameters->isChecked() && !this->m_Controls.initialValuesManager->hasValidInitialValues()) { std::string warning = "Warning. Invalid start parameters. At least one parameter as an invalid image setting as source."; MITK_ERROR << warning; m_Controls.infoBox->append(QString("") + QString::fromStdString(warning) + QString("")); ok = false; }; } else { ok = false; } return ok; } bool MRPerfusionView::CheckBaselineSelectionSettings() const { return m_Controls.spinBox_baselineStartTimeStep->value() <= m_Controls.spinBox_baselineEndTimeStep->value(); } void MRPerfusionView::ConfigureInitialParametersOfParameterizer(mitk::ModelParameterizerBase* parameterizer) const { if (m_Controls.radioButton_StartParameters->isChecked()) { //use user defined initial parameters mitk::InitialParameterizationDelegateBase::Pointer paramDelegate = m_Controls.initialValuesManager->getInitialParametrizationDelegate(); parameterizer->SetInitialParameterizationDelegate(paramDelegate); } } void MRPerfusionView::GenerateDescriptiveBrixModel_PixelBased(mitk::modelFit::ModelFitInfo::Pointer& modelFitInfo, mitk::ParameterFitImageGeneratorBase::Pointer& generator) { mitk::PixelBasedParameterFitImageGenerator::Pointer fitGenerator = mitk::PixelBasedParameterFitImageGenerator::New(); mitk::DescriptivePharmacokineticBrixModelParameterizer::Pointer modelParameterizer = mitk::DescriptivePharmacokineticBrixModelParameterizer::New(); //Model configuration (static parameters) can be done now modelParameterizer->SetTau(m_Controls.injectiontime->value()); mitk::ImageTimeSelector::Pointer imageTimeSelector = mitk::ImageTimeSelector::New(); imageTimeSelector->SetInput(this->m_selectedImage); imageTimeSelector->SetTimeNr(0); imageTimeSelector->UpdateLargestPossibleRegion(); mitk::DescriptivePharmacokineticBrixModelParameterizer::BaseImageType::Pointer baseImage; mitk::CastToItkImage(imageTimeSelector->GetOutput(), baseImage); modelParameterizer->SetBaseImage(baseImage); this->ConfigureInitialParametersOfParameterizer(modelParameterizer); //Specify fitting strategy and criterion parameters mitk::ModelFitFunctorBase::Pointer fitFunctor = CreateDefaultFitFunctor(modelParameterizer); //Parametrize fit generator fitGenerator->SetModelParameterizer(modelParameterizer); std::string roiUID = ""; if (m_selectedMask.IsNotNull()) { fitGenerator->SetMask(m_selectedMask); - roiUID = mitk::EnsureModelFitUID(this->m_selectedMaskNode); + roiUID = m_selectedMask->GetUID(); } fitGenerator->SetDynamicImage(m_selectedImage); fitGenerator->SetFitFunctor(fitFunctor); generator = fitGenerator.GetPointer(); //Create model info modelFitInfo = mitk::modelFit::CreateFitInfoFromModelParameterizer(modelParameterizer, m_selectedNode->GetData(), mitk::ModelFitConstants::FIT_TYPE_VALUE_PIXELBASED(), this->GetFitName(), roiUID); } void MRPerfusionView::GenerateDescriptiveBrixModel_ROIBased(mitk::modelFit::ModelFitInfo::Pointer& modelFitInfo, mitk::ParameterFitImageGeneratorBase::Pointer& generator) { if (m_selectedMask.IsNull()) { return; } mitk::ROIBasedParameterFitImageGenerator::Pointer fitGenerator = mitk::ROIBasedParameterFitImageGenerator::New(); mitk::DescriptivePharmacokineticBrixModelValueBasedParameterizer::Pointer modelParameterizer = mitk::DescriptivePharmacokineticBrixModelValueBasedParameterizer::New(); //Compute ROI signal mitk::MaskedDynamicImageStatisticsGenerator::Pointer signalGenerator = mitk::MaskedDynamicImageStatisticsGenerator::New(); signalGenerator->SetMask(m_selectedMask); signalGenerator->SetDynamicImage(m_selectedImage); signalGenerator->Generate(); mitk::MaskedDynamicImageStatisticsGenerator::ResultType roiSignal = signalGenerator->GetMean(); //Model configuration (static parameters) can be done now modelParameterizer->SetTau(m_Controls.injectiontime->value()); modelParameterizer->SetBaseValue(roiSignal[0]); this->ConfigureInitialParametersOfParameterizer(modelParameterizer); //Specify fitting strategy and criterion parameters mitk::ModelFitFunctorBase::Pointer fitFunctor = CreateDefaultFitFunctor(modelParameterizer); //Parametrize fit generator fitGenerator->SetModelParameterizer(modelParameterizer); fitGenerator->SetMask(m_selectedMask); fitGenerator->SetFitFunctor(fitFunctor); fitGenerator->SetSignal(roiSignal); fitGenerator->SetTimeGrid(mitk::ExtractTimeGrid(m_selectedImage)); generator = fitGenerator.GetPointer(); - std::string roiUID = mitk::EnsureModelFitUID(this->m_selectedMaskNode); + std::string roiUID = this->m_selectedMask->GetUID(); //Create model info modelFitInfo = mitk::modelFit::CreateFitInfoFromModelParameterizer(modelParameterizer, m_selectedNode->GetData(), mitk::ModelFitConstants::FIT_TYPE_VALUE_ROIBASED(), this->GetFitName(), roiUID); mitk::ScalarListLookupTable::ValueType infoSignal; for (mitk::MaskedDynamicImageStatisticsGenerator::ResultType::const_iterator pos = roiSignal.begin(); pos != roiSignal.end(); ++pos) { infoSignal.push_back(*pos); } modelFitInfo->inputData.SetTableValue("ROI", infoSignal); } template void MRPerfusionView::GenerateLinearModelFit_PixelBased(mitk::modelFit::ModelFitInfo::Pointer& modelFitInfo, mitk::ParameterFitImageGeneratorBase::Pointer& generator) { mitk::PixelBasedParameterFitImageGenerator::Pointer fitGenerator = mitk::PixelBasedParameterFitImageGenerator::New(); typename TParameterizer::Pointer modelParameterizer = TParameterizer::New(); this->ConfigureInitialParametersOfParameterizer(modelParameterizer); //Specify fitting strategy and criterion parameters mitk::ModelFitFunctorBase::Pointer fitFunctor = CreateDefaultFitFunctor(modelParameterizer); //Parametrize fit generator fitGenerator->SetModelParameterizer(modelParameterizer); std::string roiUID = ""; if (m_selectedMask.IsNotNull()) { fitGenerator->SetMask(m_selectedMask); - roiUID = mitk::EnsureModelFitUID(this->m_selectedMaskNode); + roiUID = this->m_selectedMask->GetUID(); } fitGenerator->SetDynamicImage(m_selectedImage); fitGenerator->SetFitFunctor(fitFunctor); generator = fitGenerator.GetPointer(); //Create model info modelFitInfo = mitk::modelFit::CreateFitInfoFromModelParameterizer(modelParameterizer, m_selectedNode->GetData(), mitk::ModelFitConstants::FIT_TYPE_VALUE_PIXELBASED(), this->GetFitName(), roiUID); } template void MRPerfusionView::GenerateLinearModelFit_ROIBased(mitk::modelFit::ModelFitInfo::Pointer& modelFitInfo, mitk::ParameterFitImageGeneratorBase::Pointer& generator) { if (m_selectedMask.IsNull()) { return; } mitk::ROIBasedParameterFitImageGenerator::Pointer fitGenerator = mitk::ROIBasedParameterFitImageGenerator::New(); typename TParameterizer::Pointer modelParameterizer = TParameterizer::New(); //Compute ROI signal mitk::MaskedDynamicImageStatisticsGenerator::Pointer signalGenerator = mitk::MaskedDynamicImageStatisticsGenerator::New(); signalGenerator->SetMask(m_selectedMask); signalGenerator->SetDynamicImage(m_selectedImage); signalGenerator->Generate(); mitk::MaskedDynamicImageStatisticsGenerator::ResultType roiSignal = signalGenerator->GetMean(); //Model configuration (static parameters) can be done now this->ConfigureInitialParametersOfParameterizer(modelParameterizer); //Specify fitting strategy and criterion parameters mitk::ModelFitFunctorBase::Pointer fitFunctor = CreateDefaultFitFunctor(modelParameterizer); //Parametrize fit generator fitGenerator->SetModelParameterizer(modelParameterizer); fitGenerator->SetMask(m_selectedMask); fitGenerator->SetFitFunctor(fitFunctor); fitGenerator->SetSignal(roiSignal); fitGenerator->SetTimeGrid(mitk::ExtractTimeGrid(m_selectedImage)); generator = fitGenerator.GetPointer(); - std::string roiUID = mitk::EnsureModelFitUID(this->m_selectedMaskNode); + std::string roiUID = this->m_selectedMask->GetUID(); //Create model info modelFitInfo = mitk::modelFit::CreateFitInfoFromModelParameterizer(modelParameterizer, m_selectedNode->GetData(), mitk::ModelFitConstants::FIT_TYPE_VALUE_ROIBASED(), this->GetFitName(), roiUID); mitk::ScalarListLookupTable::ValueType infoSignal; for (mitk::MaskedDynamicImageStatisticsGenerator::ResultType::const_iterator pos = roiSignal.begin(); pos != roiSignal.end(); ++pos) { infoSignal.push_back(*pos); } modelFitInfo->inputData.SetTableValue("ROI", infoSignal); } template void MRPerfusionView::GenerateAIFbasedModelFit_PixelBased(mitk::modelFit::ModelFitInfo::Pointer& modelFitInfo, mitk::ParameterFitImageGeneratorBase::Pointer& generator) { mitk::PixelBasedParameterFitImageGenerator::Pointer fitGenerator = mitk::PixelBasedParameterFitImageGenerator::New(); typename TParameterizer::Pointer modelParameterizer = TParameterizer::New(); PrepareConcentrationImage(); mitk::AIFBasedModelBase::AterialInputFunctionType aif; mitk::AIFBasedModelBase::AterialInputFunctionType aifTimeGrid; GetAIF(aif, aifTimeGrid); modelParameterizer->SetAIF(aif); modelParameterizer->SetAIFTimeGrid(aifTimeGrid); this->ConfigureInitialParametersOfParameterizer(modelParameterizer); mitk::NumericTwoCompartmentExchangeModelParameterizer* numTCXParametrizer = dynamic_cast (modelParameterizer.GetPointer()); if (numTCXParametrizer) { numTCXParametrizer->SetODEINTStepSize(this->m_Controls.odeStepSize->value()); } //Specify fitting strategy and criterion parameters mitk::ModelFitFunctorBase::Pointer fitFunctor = CreateDefaultFitFunctor(modelParameterizer); //Parametrize fit generator fitGenerator->SetModelParameterizer(modelParameterizer); std::string roiUID = ""; if (m_selectedMask.IsNotNull()) { fitGenerator->SetMask(m_selectedMask); - roiUID = mitk::EnsureModelFitUID(this->m_selectedMaskNode); + roiUID = this->m_selectedMask->GetUID(); } fitGenerator->SetDynamicImage(this->m_inputImage); fitGenerator->SetFitFunctor(fitFunctor); generator = fitGenerator.GetPointer(); //Create model info modelFitInfo = mitk::modelFit::CreateFitInfoFromModelParameterizer(modelParameterizer, this->m_inputImage, mitk::ModelFitConstants::FIT_TYPE_VALUE_PIXELBASED(), this->GetFitName(), roiUID); mitk::ScalarListLookupTable::ValueType infoSignal; for (mitk::AIFBasedModelBase::AterialInputFunctionType::const_iterator pos = aif.begin(); pos != aif.end(); ++pos) { infoSignal.push_back(*pos); } modelFitInfo->inputData.SetTableValue("AIF", infoSignal); } template void MRPerfusionView::GenerateAIFbasedModelFit_ROIBased( mitk::modelFit::ModelFitInfo::Pointer& modelFitInfo, mitk::ParameterFitImageGeneratorBase::Pointer& generator) { if (m_selectedMask.IsNull()) { return; } mitk::ROIBasedParameterFitImageGenerator::Pointer fitGenerator = mitk::ROIBasedParameterFitImageGenerator::New(); typename TParameterizer::Pointer modelParameterizer = TParameterizer::New(); PrepareConcentrationImage(); mitk::AIFBasedModelBase::AterialInputFunctionType aif; mitk::AIFBasedModelBase::AterialInputFunctionType aifTimeGrid; GetAIF(aif, aifTimeGrid); modelParameterizer->SetAIF(aif); modelParameterizer->SetAIFTimeGrid(aifTimeGrid); this->ConfigureInitialParametersOfParameterizer(modelParameterizer); mitk::NumericTwoCompartmentExchangeModelParameterizer* numTCXParametrizer = dynamic_cast (modelParameterizer.GetPointer()); if (numTCXParametrizer) { numTCXParametrizer->SetODEINTStepSize(this->m_Controls.odeStepSize->value()); } //Compute ROI signal mitk::MaskedDynamicImageStatisticsGenerator::Pointer signalGenerator = mitk::MaskedDynamicImageStatisticsGenerator::New(); signalGenerator->SetMask(m_selectedMask); signalGenerator->SetDynamicImage(this->m_inputImage); signalGenerator->Generate(); mitk::MaskedDynamicImageStatisticsGenerator::ResultType roiSignal = signalGenerator->GetMean(); //Specify fitting strategy and criterion parameters mitk::ModelFitFunctorBase::Pointer fitFunctor = CreateDefaultFitFunctor(modelParameterizer); //Parametrize fit generator fitGenerator->SetModelParameterizer(modelParameterizer); fitGenerator->SetMask(m_selectedMask); fitGenerator->SetFitFunctor(fitFunctor); fitGenerator->SetSignal(roiSignal); fitGenerator->SetTimeGrid(mitk::ExtractTimeGrid(this->m_inputImage)); generator = fitGenerator.GetPointer(); - std::string roiUID = mitk::EnsureModelFitUID(this->m_selectedMaskNode); + std::string roiUID = this->m_selectedMask->GetUID(); //Create model info modelFitInfo = mitk::modelFit::CreateFitInfoFromModelParameterizer(modelParameterizer, this->m_inputImage, mitk::ModelFitConstants::FIT_TYPE_VALUE_ROIBASED(), this->GetFitName(), roiUID); mitk::ScalarListLookupTable::ValueType infoSignal; for (mitk::MaskedDynamicImageStatisticsGenerator::ResultType::const_iterator pos = roiSignal.begin(); pos != roiSignal.end(); ++pos) { infoSignal.push_back(*pos); } modelFitInfo->inputData.SetTableValue("ROI", infoSignal); infoSignal.clear(); for (mitk::AIFBasedModelBase::AterialInputFunctionType::const_iterator pos = aif.begin(); pos != aif.end(); ++pos) { infoSignal.push_back(*pos); } modelFitInfo->inputData.SetTableValue("AIF", infoSignal); } void MRPerfusionView::DoFit(const mitk::modelFit::ModelFitInfo* fitSession, mitk::ParameterFitImageGeneratorBase* generator) { this->m_Controls.infoBox->append(QString("" + QString("Fitting Data Set . . .") + QString (""))); ///////////////////////// //create job and put it into the thread pool mitk::modelFit::ModelFitResultNodeVectorType additionalNodes; if (m_HasGeneratedNewInput) { additionalNodes.push_back(m_inputNode); } if (m_HasGeneratedNewInputAIF) { additionalNodes.push_back(m_inputAIFNode); } ParameterFitBackgroundJob* pJob = new ParameterFitBackgroundJob(generator, fitSession, this->m_selectedNode, additionalNodes); pJob->setAutoDelete(true); connect(pJob, SIGNAL(Error(QString)), this, SLOT(OnJobError(QString))); connect(pJob, SIGNAL(Finished()), this, SLOT(OnJobFinished())); connect(pJob, SIGNAL(ResultsAreAvailable(mitk::modelFit::ModelFitResultNodeVectorType, const ParameterFitBackgroundJob*)), this, SLOT(OnJobResultsAreAvailable(mitk::modelFit::ModelFitResultNodeVectorType, const ParameterFitBackgroundJob*)), Qt::BlockingQueuedConnection); connect(pJob, SIGNAL(JobProgress(double)), this, SLOT(OnJobProgress(double))); connect(pJob, SIGNAL(JobStatusChanged(QString)), this, SLOT(OnJobStatusChanged(QString))); QThreadPool* threadPool = QThreadPool::globalInstance(); threadPool->start(pJob); } MRPerfusionView::MRPerfusionView() : m_FittingInProgress(false), m_HasGeneratedNewInput(false), m_HasGeneratedNewInputAIF(false) { m_selectedImage = nullptr; m_selectedMask = nullptr; mitk::ModelFactoryBase::Pointer factory = mitk::DescriptivePharmacokineticBrixModelFactory::New().GetPointer(); m_FactoryStack.push_back(factory); factory = mitk::TwoStepLinearModelFactory::New().GetPointer(); m_FactoryStack.push_back(factory); factory = mitk::ThreeStepLinearModelFactory::New().GetPointer(); m_FactoryStack.push_back(factory); factory = mitk::StandardToftsModelFactory::New().GetPointer(); m_FactoryStack.push_back(factory); factory = mitk::ExtendedToftsModelFactory::New().GetPointer(); m_FactoryStack.push_back(factory); factory = mitk::TwoCompartmentExchangeModelFactory::New().GetPointer(); m_FactoryStack.push_back(factory); factory = mitk::NumericTwoCompartmentExchangeModelFactory::New().GetPointer(); m_FactoryStack.push_back(factory); mitk::NodePredicateDataType::Pointer isLabelSet = mitk::NodePredicateDataType::New("LabelSetImage"); mitk::NodePredicateDataType::Pointer isImage = mitk::NodePredicateDataType::New("Image"); mitk::NodePredicateProperty::Pointer isBinary = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); mitk::NodePredicateAnd::Pointer isLegacyMask = mitk::NodePredicateAnd::New(isImage, isBinary); mitk::NodePredicateOr::Pointer isMask = mitk::NodePredicateOr::New(isLegacyMask, isLabelSet); mitk::NodePredicateAnd::Pointer isNoMask = mitk::NodePredicateAnd::New(isImage, mitk::NodePredicateNot::New(isMask)); this->m_IsMaskPredicate = mitk::NodePredicateAnd::New(isMask, mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object"))).GetPointer(); this->m_IsNoMaskImagePredicate = mitk::NodePredicateAnd::New(isNoMask, mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object"))).GetPointer(); } void MRPerfusionView::OnJobFinished() { this->m_Controls.infoBox->append(QString("Fitting finished.")); this->m_FittingInProgress = false; this->UpdateGUIControls(); }; void MRPerfusionView::OnJobError(QString err) { MITK_ERROR << err.toStdString().c_str(); m_Controls.infoBox->append(QString("") + err + QString("")); }; void MRPerfusionView::OnJobResultsAreAvailable(mitk::modelFit::ModelFitResultNodeVectorType results, const ParameterFitBackgroundJob* pJob) { //Store the resulting parameter fit image via convenience helper function in data storage //(handles the correct generation of the nodes and their properties) mitk::modelFit::StoreResultsInDataStorage(this->GetDataStorage(), results, pJob->GetParentNode()); //this stores the concentration image and AIF concentration image, if generated for this fit in the storage. //if not generated for this fit, relevant nodes are empty. mitk::modelFit::StoreResultsInDataStorage(this->GetDataStorage(), pJob->GetAdditionalRelevantNodes(), pJob->GetParentNode()); }; void MRPerfusionView::OnJobProgress(double progress) { QString report = QString("Progress. ") + QString::number(progress); this->m_Controls.infoBox->append(report); }; void MRPerfusionView::OnJobStatusChanged(QString info) { this->m_Controls.infoBox->append(info); } void MRPerfusionView::InitModelComboBox() const { this->m_Controls.comboModel->clear(); this->m_Controls.comboModel->addItem(tr("No model selected")); for (ModelFactoryStackType::const_iterator pos = m_FactoryStack.begin(); pos != m_FactoryStack.end(); ++pos) { this->m_Controls.comboModel->addItem(QString::fromStdString((*pos)->GetClassID())); } this->m_Controls.comboModel->setCurrentIndex(0); }; mitk::DataNode::Pointer MRPerfusionView::GenerateConcentrationNode(mitk::Image* image, const std::string& nodeName) const { if (!image) { mitkThrow() << "Cannot generate concentration node. Passed image is null. parameter name: "; } mitk::DataNode::Pointer result = mitk::DataNode::New(); result->SetData(image); result->SetName(nodeName); result->SetVisibility(true); - mitk::EnsureModelFitUID(result); - return result; }; mitk::Image::Pointer MRPerfusionView::ConvertConcentrationImage(bool AIFMode) { //Compute Concentration image mitk::ConcentrationCurveGenerator::Pointer concentrationGen = mitk::ConcentrationCurveGenerator::New(); if (m_Controls.checkDedicatedAIFImage->isChecked() && AIFMode) { concentrationGen->SetDynamicImage(this->m_selectedAIFImage); } else { concentrationGen->SetDynamicImage(this->m_selectedImage); } concentrationGen->SetisTurboFlashSequence(IsTurboFlashSequenceFlag()); concentrationGen->SetAbsoluteSignalEnhancement(m_Controls.radioButton_absoluteEnhancement->isChecked()); concentrationGen->SetRelativeSignalEnhancement(m_Controls.radioButton_relativeEnchancement->isChecked()); concentrationGen->SetUsingT1Map(m_Controls.radioButtonUsingT1viaVFA->isChecked()); if (IsTurboFlashSequenceFlag()) { if (AIFMode) { concentrationGen->SetRecoveryTime(m_Controls.AifRecoverytime->value()); } else { concentrationGen->SetRecoveryTime(m_Controls.recoverytime->value()); } concentrationGen->SetRelaxationTime(m_Controls.relaxationtime->value()); concentrationGen->SetRelaxivity(m_Controls.relaxivity->value()); concentrationGen->SetBaselineStartTimeStep(m_Controls.spinBox_baselineStartTimeStep->value()); concentrationGen->SetBaselineEndTimeStep(m_Controls.spinBox_baselineEndTimeStep->value()); } else if (this->m_Controls.radioButtonUsingT1viaVFA->isChecked()) { concentrationGen->SetRecoveryTime(m_Controls.TRSpinBox->value()); concentrationGen->SetRelaxivity(m_Controls.RelaxivitySpinBox->value()); concentrationGen->SetT10Image(dynamic_cast(m_Controls.ComboPDWImage->GetSelectedNode()->GetData())); concentrationGen->SetBaselineStartTimeStep(m_Controls.spinBox_baselineStartTimeStep->value()); concentrationGen->SetBaselineEndTimeStep(m_Controls.spinBox_baselineEndTimeStep->value()); //Convert Flipangle from degree to radiant double alpha = m_Controls.FlipangleSpinBox->value()/360*2* boost::math::constants::pi(); concentrationGen->SetFlipAngle(alpha); } else { concentrationGen->SetFactor(m_Controls.factorSpinBox->value()); concentrationGen->SetBaselineStartTimeStep(m_Controls.spinBox_baselineStartTimeStep->value()); concentrationGen->SetBaselineEndTimeStep(m_Controls.spinBox_baselineEndTimeStep->value()); } mitk::Image::Pointer concentrationImage = concentrationGen->GetConvertedImage(); return concentrationImage; } void MRPerfusionView::GetAIF(mitk::AIFBasedModelBase::AterialInputFunctionType& aif, mitk::AIFBasedModelBase::AterialInputFunctionType& aifTimeGrid) { if (this->m_Controls.radioAIFFile->isChecked()) { aif.clear(); aifTimeGrid.clear(); aif.SetSize(AIFinputFunction.size()); aifTimeGrid.SetSize(AIFinputGrid.size()); aif.fill(0.0); aifTimeGrid.fill(0.0); itk::Array::iterator aifPos = aif.begin(); for (std::vector::const_iterator pos = AIFinputFunction.begin(); pos != AIFinputFunction.end(); ++pos, ++aifPos) { *aifPos = *pos; } itk::Array::iterator gridPos = aifTimeGrid.begin(); for (std::vector::const_iterator pos = AIFinputGrid.begin(); pos != AIFinputGrid.end(); ++pos, ++gridPos) { *gridPos = *pos; } } else if (this->m_Controls.radioAIFImage->isChecked()) { aif.clear(); aifTimeGrid.clear(); mitk::AterialInputFunctionGenerator::Pointer aifGenerator = mitk::AterialInputFunctionGenerator::New(); //Hematocrit level aifGenerator->SetHCL(this->m_Controls.HCLSpinBox->value()); //mask settings this->m_selectedAIFMaskNode = m_Controls.comboAIFMask->GetSelectedNode(); this->m_selectedAIFMask = dynamic_cast(this->m_selectedAIFMaskNode->GetData()); if (this->m_selectedAIFMask->GetTimeSteps() > 1) { MITK_INFO << "Selected AIF mask has multiple timesteps. Only use first timestep to mask model fit. AIF Mask name: " << m_selectedAIFMaskNode->GetName() ; mitk::ImageTimeSelector::Pointer maskedImageTimeSelector = mitk::ImageTimeSelector::New(); maskedImageTimeSelector->SetInput(this->m_selectedAIFMask); maskedImageTimeSelector->SetTimeNr(0); maskedImageTimeSelector->UpdateLargestPossibleRegion(); this->m_selectedAIFMask = maskedImageTimeSelector->GetOutput(); } if (this->m_selectedAIFMask.IsNotNull()) { aifGenerator->SetMask(this->m_selectedAIFMask); } //image settings if (this->m_Controls.checkDedicatedAIFImage->isChecked()) { this->m_selectedAIFImageNode = m_Controls.comboAIFImage->GetSelectedNode(); this->m_selectedAIFImage = dynamic_cast(this->m_selectedAIFImageNode->GetData()); } else { this->m_selectedAIFImageNode = m_selectedNode; this->m_selectedAIFImage = m_selectedImage; } this->PrepareAIFConcentrationImage(); aifGenerator->SetDynamicImage(this->m_inputAIFImage); aif = aifGenerator->GetAterialInputFunction(); aifTimeGrid = aifGenerator->GetAterialInputFunctionTimeGrid(); } else { mitkThrow() << "Cannot generate AIF. View is in a invalide state. No AIF mode selected."; } } void MRPerfusionView::LoadAIFfromFile() { QFileDialog dialog; dialog.setNameFilter(tr("Images (*.csv")); QString fileName = dialog.getOpenFileName(); m_Controls.aifFilePath->setText(fileName); std::string m_aifFilePath = fileName.toStdString(); //Read Input typedef boost::tokenizer< boost::escaped_list_separator > Tokenizer; ///////////////////////////////////////////////////////////////////////////////////////////////// //AIF Data std::ifstream in1(m_aifFilePath.c_str()); if (!in1.is_open()) { this->m_Controls.infoBox->append(QString("Could not open AIF File!")); } std::vector< std::string > vec1; std::string line1; while (getline(in1, line1)) { Tokenizer tok(line1); vec1.assign(tok.begin(), tok.end()); this->AIFinputGrid.push_back(convertToDouble(vec1[0])); this->AIFinputFunction.push_back(convertToDouble(vec1[1])); } } void MRPerfusionView::PrepareConcentrationImage() { mitk::Image::Pointer concentrationImage = this->m_selectedImage; mitk::DataNode::Pointer concentrationNode = this->m_selectedNode; m_HasGeneratedNewInput = false; if (!this->m_Controls.radioButtonNoConversion->isChecked()) { concentrationImage = this->ConvertConcentrationImage(false); concentrationNode = GenerateConcentrationNode(concentrationImage, "Concentration"); m_HasGeneratedNewInput = true; } m_inputImage = concentrationImage; m_inputNode = concentrationNode; - - mitk::EnsureModelFitUID(concentrationNode); } void MRPerfusionView::PrepareAIFConcentrationImage() { mitk::Image::Pointer concentrationImage = this->m_selectedImage; mitk::DataNode::Pointer concentrationNode = this->m_selectedNode; m_HasGeneratedNewInputAIF = false; if (this->m_Controls.checkDedicatedAIFImage->isChecked()) { concentrationImage = this->m_selectedAIFImage; concentrationNode = this->m_selectedAIFImageNode; } if (!this->m_Controls.radioButtonNoConversion->isChecked()) { if (!IsTurboFlashSequenceFlag() && !this->m_Controls.checkDedicatedAIFImage->isChecked()) { if (m_inputImage.IsNull()) { mitkThrow() << "Cannot get AIF concentration image. Invalid view state. Input image is not defined yet, but should be."; } //we can directly use the concentration input image/node (generated by GetConcentrationImage) also for the AIF concentrationImage = this->m_inputImage; concentrationNode = this->m_inputNode; } else { concentrationImage = this->ConvertConcentrationImage(true); concentrationNode = GenerateConcentrationNode(concentrationImage, "AIF Concentration"); m_HasGeneratedNewInputAIF = true; } } m_inputAIFImage = concentrationImage; m_inputAIFNode = concentrationNode; - - mitk::EnsureModelFitUID(concentrationNode); } mitk::ModelFitFunctorBase::Pointer MRPerfusionView::CreateDefaultFitFunctor( const mitk::ModelParameterizerBase* parameterizer) const { mitk::LevenbergMarquardtModelFitFunctor::Pointer fitFunctor = mitk::LevenbergMarquardtModelFitFunctor::New(); mitk::NormalizedSumOfSquaredDifferencesFitCostFunction::Pointer chi2 = mitk::NormalizedSumOfSquaredDifferencesFitCostFunction::New(); fitFunctor->RegisterEvaluationParameter("Chi^2", chi2); if (m_Controls.checkBox_Constraints->isChecked()) { fitFunctor->SetConstraintChecker(m_modelConstraints); } mitk::ModelBase::Pointer refModel = parameterizer->GenerateParameterizedModel(); ::itk::LevenbergMarquardtOptimizer::ScalesType scales; scales.SetSize(refModel->GetNumberOfParameters()); scales.Fill(1.0); fitFunctor->SetScales(scales); fitFunctor->SetDebugParameterMaps(m_Controls.checkDebug->isChecked()); return fitFunctor.GetPointer(); } diff --git a/Plugins/org.mitk.gui.qt.pharmacokinetics.pet/src/internal/PETDynamicView.cpp b/Plugins/org.mitk.gui.qt.pharmacokinetics.pet/src/internal/PETDynamicView.cpp index ed2966912d..dc4a82d910 100644 --- a/Plugins/org.mitk.gui.qt.pharmacokinetics.pet/src/internal/PETDynamicView.cpp +++ b/Plugins/org.mitk.gui.qt.pharmacokinetics.pet/src/internal/PETDynamicView.cpp @@ -1,942 +1,946 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "PETDynamicView.h" #include "mitkWorkbenchUtil.h" #include "mitkAterialInputFunctionGenerator.h" #include "mitkOneTissueCompartmentModelFactory.h" #include "mitkOneTissueCompartmentModelParameterizer.h" #include "mitkExtendedOneTissueCompartmentModelFactory.h" #include "mitkExtendedOneTissueCompartmentModelParameterizer.h" #include "mitkTwoTissueCompartmentFDGModelFactory.h" #include "mitkTwoTissueCompartmentFDGModelParameterizer.h" #include "mitkTwoTissueCompartmentModelFactory.h" #include "mitkTwoTissueCompartmentModelParameterizer.h" #include "mitkNumericTwoTissueCompartmentModelFactory.h" #include "mitkNumericTwoTissueCompartmentModelParameterizer.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Includes for image casting between ITK and MITK #include #include "mitkImageCast.h" #include "mitkITKImageImport.h" #include #include #include const std::string PETDynamicView::VIEW_ID = "org.mitk.gui.qt.pharmacokinetics.pet"; inline double convertToDouble(const std::string& data) { std::istringstream stepStream(data); double value = 0.0; stepStream >> value; return value; } void PETDynamicView::SetFocus() { m_Controls.btnModelling->setFocus(); } void PETDynamicView::CreateQtPartControl(QWidget* parent) { m_Controls.setupUi(parent); m_Controls.btnModelling->setEnabled(false); m_Controls.errorMessageLabel->hide(); this->InitModelComboBox(); connect(m_Controls.btnModelling, SIGNAL(clicked()), this, SLOT(OnModellingButtonClicked())); connect(m_Controls.comboModel, SIGNAL(currentIndexChanged(int)), this, SLOT(OnModellSet(int))); connect(m_Controls.radioPixelBased, SIGNAL(toggled(bool)), this, SLOT(UpdateGUIControls())); //AIF setting m_Controls.groupAIF->hide(); m_Controls.btnAIFFile->setEnabled(false); m_Controls.btnAIFFile->setEnabled(false); m_Controls.radioAIFImage->setChecked(true); m_Controls.comboAIFMask->SetDataStorage(this->GetDataStorage()); m_Controls.comboAIFMask->SetPredicate(m_IsMaskPredicate); m_Controls.comboAIFMask->setVisible(true); m_Controls.comboAIFMask->setEnabled(true); m_Controls.comboAIFImage->SetDataStorage(this->GetDataStorage()); m_Controls.comboAIFImage->SetPredicate(m_IsNoMaskImagePredicate); m_Controls.comboAIFImage->setEnabled(false); m_Controls.checkDedicatedAIFImage->setEnabled(true); m_Controls.HCLSpinBox->setValue(0.0); connect(m_Controls.radioAIFImage, SIGNAL(toggled(bool)), m_Controls.comboAIFMask, SLOT(setVisible(bool))); connect(m_Controls.radioAIFImage, SIGNAL(toggled(bool)), m_Controls.labelAIFMask, SLOT(setVisible(bool))); connect(m_Controls.radioAIFImage, SIGNAL(toggled(bool)), m_Controls.checkDedicatedAIFImage, SLOT(setVisible(bool))); connect(m_Controls.radioAIFImage, SIGNAL(toggled(bool)), m_Controls.comboAIFMask, SLOT(setEnabled(bool))); connect(m_Controls.radioAIFImage, SIGNAL(toggled(bool)), m_Controls.checkDedicatedAIFImage, SLOT(setEnabled(bool))); connect(m_Controls.radioAIFImage, SIGNAL(toggled(bool)), m_Controls.checkDedicatedAIFImage, SLOT(setVisible(bool))); connect(m_Controls.radioAIFImage, SIGNAL(toggled(bool)), m_Controls.comboAIFImage, SLOT(setVisible(bool))); connect(m_Controls.checkDedicatedAIFImage, SIGNAL(toggled(bool)), m_Controls.comboAIFImage, SLOT(setEnabled(bool))); connect(m_Controls.radioAIFImage, SIGNAL(toggled(bool)), this, SLOT(UpdateGUIControls())); connect(m_Controls.radioAIFFile, SIGNAL(toggled(bool)), m_Controls.btnAIFFile, SLOT(setEnabled(bool))); connect(m_Controls.radioAIFFile, SIGNAL(toggled(bool)), m_Controls.aifFilePath, SLOT(setEnabled(bool))); connect(m_Controls.radioAIFFile, SIGNAL(toggled(bool)), this, SLOT(UpdateGUIControls())); connect(m_Controls.btnAIFFile, SIGNAL(clicked()), this, SLOT(LoadAIFfromFile())); //Model fit configuration m_Controls.groupBox_FitConfiguration->hide(); m_Controls.checkBox_Constraints->setEnabled(false); m_Controls.constraintManager->setEnabled(false); m_Controls.initialValuesManager->setEnabled(false); m_Controls.initialValuesManager->setDataStorage(this->GetDataStorage()); connect(m_Controls.radioButton_StartParameters, SIGNAL(toggled(bool)), this, SLOT(UpdateGUIControls())); connect(m_Controls.checkBox_Constraints, SIGNAL(toggled(bool)), this, SLOT(UpdateGUIControls())); connect(m_Controls.initialValuesManager, SIGNAL(initialValuesChanged(void)), this, SLOT(UpdateGUIControls())); connect(m_Controls.radioButton_StartParameters, SIGNAL(toggled(bool)), m_Controls.initialValuesManager, SLOT(setEnabled(bool))); connect(m_Controls.checkBox_Constraints, SIGNAL(toggled(bool)), m_Controls.constraintManager, SLOT(setEnabled(bool))); connect(m_Controls.checkBox_Constraints, SIGNAL(toggled(bool)), m_Controls.constraintManager, SLOT(setVisible(bool))); UpdateGUIControls(); } void PETDynamicView::UpdateGUIControls() { m_Controls.lineFitName->setPlaceholderText(QString::fromStdString(this->GetDefaultFitName())); m_Controls.lineFitName->setEnabled(!m_FittingInProgress); m_Controls.checkBox_Constraints->setEnabled(m_modelConstraints.IsNotNull()); bool is1TCMFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool isExt1TCMFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool isFDGCMFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool is2TCMFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr || dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; m_Controls.groupAIF->setVisible(is1TCMFactory || isExt1TCMFactory || isFDGCMFactory || is2TCMFactory); m_Controls.groupBox_FitConfiguration->setVisible(m_selectedModelFactory); m_Controls.groupBox->setEnabled(!m_FittingInProgress); m_Controls.comboModel->setEnabled(!m_FittingInProgress); m_Controls.groupAIF->setEnabled(!m_FittingInProgress); m_Controls.groupBox_FitConfiguration->setEnabled(!m_FittingInProgress); m_Controls.radioROIbased->setEnabled(m_selectedMask.IsNotNull()); m_Controls.btnModelling->setEnabled(m_selectedImage.IsNotNull() && m_selectedModelFactory.IsNotNull() && !m_FittingInProgress && CheckModelSettings()); } //void PETDynamicView::OnModelSettingChanged() //{ // bool ok = m_selectedImage.IsNotNull() && m_selectedModelFactory.IsNotNull() && !m_FittingInProgress && CheckModelSettings(); // m_Controls.btnModelling->setEnabled(ok); //} void PETDynamicView::OnModellSet(int index) { m_selectedModelFactory = nullptr; if (index > 0) { if (static_cast(index) <= m_FactoryStack.size() ) { m_selectedModelFactory = m_FactoryStack[index - 1]; } else { MITK_WARN << "Invalid model index. Index outside of the factory stack. Factory stack size: "<< m_FactoryStack.size() << "; invalid index: "<< index; } } if (m_selectedModelFactory) { this->m_modelConstraints = dynamic_cast (m_selectedModelFactory->CreateDefaultConstraints().GetPointer()); m_Controls.initialValuesManager->setInitialValues(m_selectedModelFactory->GetParameterNames(), m_selectedModelFactory->GetDefaultInitialParameterization()); if (this->m_modelConstraints.IsNull()) { this->m_modelConstraints = mitk::SimpleBarrierConstraintChecker::New(); } m_Controls.constraintManager->setChecker(this->m_modelConstraints, this->m_selectedModelFactory->GetParameterNames()); } m_Controls.checkBox_Constraints->setEnabled(m_modelConstraints.IsNotNull()); UpdateGUIControls(); } std::string PETDynamicView::GetFitName() const { std::string fitName = m_Controls.lineFitName->text().toStdString(); if (fitName.empty()) { fitName = m_Controls.lineFitName->placeholderText().toStdString(); } return fitName; } std::string PETDynamicView::GetDefaultFitName() const { std::string defaultName = "undefined model"; if (this->m_selectedModelFactory.IsNotNull()) { defaultName = this->m_selectedModelFactory->GetClassID(); } if (this->m_Controls.radioPixelBased->isChecked()) { defaultName += "_pixel"; } else { defaultName += "_roi"; } return defaultName; } void PETDynamicView::OnModellingButtonClicked() { //check if all static parameters set if (m_selectedModelFactory.IsNotNull() && CheckModelSettings()) { mitk::ParameterFitImageGeneratorBase::Pointer generator = nullptr; mitk::modelFit::ModelFitInfo::Pointer fitSession = nullptr; bool isOTCFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool isextOTCFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool isFDGFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool isTTCFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool isNumTTCFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; if (isOTCFactory) { if (this->m_Controls.radioPixelBased->isChecked()) { GenerateModelFit_PixelBased(fitSession, generator); } else { GenerateModelFit_ROIBased(fitSession, generator); } } else if (isextOTCFactory) { if (this->m_Controls.radioPixelBased->isChecked()) { GenerateModelFit_PixelBased(fitSession, generator); } else { GenerateModelFit_ROIBased(fitSession, generator); } } else if (isFDGFactory) { if (this->m_Controls.radioPixelBased->isChecked()) { GenerateModelFit_PixelBased(fitSession, generator); } else { GenerateModelFit_ROIBased(fitSession, generator); } } else if (isTTCFactory) { if (this->m_Controls.radioPixelBased->isChecked()) { GenerateModelFit_PixelBased(fitSession, generator); } else { GenerateModelFit_ROIBased(fitSession, generator); } } else if (isNumTTCFactory) { if (this->m_Controls.radioPixelBased->isChecked()) { GenerateModelFit_PixelBased(fitSession, generator); } else { GenerateModelFit_ROIBased(fitSession, generator); } } //add other models with else if if (generator.IsNotNull() && fitSession.IsNotNull()) { m_FittingInProgress = true; DoFit(fitSession, generator); } else { QMessageBox box; box.setText("Fitting error!"); box.setInformativeText("Could not establish fitting job. Error when setting ab generator, model parameterizer or session info."); box.setStandardButtons(QMessageBox::Ok); box.setDefaultButton(QMessageBox::Ok); box.setIcon(QMessageBox::Warning); box.exec(); } } else { QMessageBox box; box.setText("Static parameters for model are not set!"); box.setInformativeText("Some static parameters, that are needed for calculation are not set and equal to zero. Modeling not possible"); box.setStandardButtons(QMessageBox::Ok); box.setDefaultButton(QMessageBox::Ok); box.setIcon(QMessageBox::Warning); box.exec(); } } void PETDynamicView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*source*/, const QList& selectedNodes) { m_selectedMaskNode = nullptr; m_selectedMask = nullptr; m_Controls.errorMessageLabel->setText(""); m_Controls.masklabel->setText("No (valid) mask selected."); m_Controls.timeserieslabel->setText("No (valid) series selected."); QList nodes = selectedNodes; if (nodes.size() > 0 && this->m_IsNoMaskImagePredicate->CheckNode(nodes.front())) { this->m_selectedNode = nodes.front(); auto selectedImage = dynamic_cast(this->m_selectedNode->GetData()); m_Controls.timeserieslabel->setText((this->m_selectedNode->GetName()).c_str()); if (selectedImage != this->m_selectedImage) { if (selectedImage) { this->m_Controls.initialValuesManager->setReferenceImageGeometry(selectedImage->GetGeometry()); } else { this->m_Controls.initialValuesManager->setReferenceImageGeometry(nullptr); } } this->m_selectedImage = selectedImage; nodes.pop_front(); } else { this->m_selectedNode = nullptr; this->m_selectedImage = nullptr; this->m_Controls.initialValuesManager->setReferenceImageGeometry(nullptr); } if (nodes.size() > 0 && this->m_IsMaskPredicate->CheckNode(nodes.front())) { this->m_selectedMaskNode = nodes.front(); this->m_selectedMask = dynamic_cast(this->m_selectedMaskNode->GetData()); if (this->m_selectedMask->GetTimeSteps() > 1) { MITK_INFO << "Selected mask has multiple timesteps. Only use first timestep to mask model fit. Mask name: " << m_selectedMaskNode->GetName(); mitk::ImageTimeSelector::Pointer maskedImageTimeSelector = mitk::ImageTimeSelector::New(); maskedImageTimeSelector->SetInput(this->m_selectedMask); maskedImageTimeSelector->SetTimeNr(0); maskedImageTimeSelector->UpdateLargestPossibleRegion(); this->m_selectedMask = maskedImageTimeSelector->GetOutput(); } m_Controls.masklabel->setText((this->m_selectedMaskNode->GetName()).c_str()); } if (m_selectedMask.IsNull()) { this->m_Controls.radioPixelBased->setChecked(true); } m_Controls.errorMessageLabel->show(); UpdateGUIControls(); } bool PETDynamicView::CheckModelSettings() const { bool ok = true; //check wether any model is set at all. Otherwise exit with false if (m_selectedModelFactory.IsNotNull()) { bool isOTCFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool isextOTCFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool isFDGFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool isTTCFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool isNumTTCFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; if (isOTCFactory || isextOTCFactory || isFDGFactory || isTTCFactory || isNumTTCFactory) { if (this->m_Controls.radioAIFImage->isChecked()) { ok = ok && m_Controls.comboAIFMask->GetSelectedNode().IsNotNull(); if (this->m_Controls.checkDedicatedAIFImage->isChecked()) { ok = ok && m_Controls.comboAIFImage->GetSelectedNode().IsNotNull(); } } else if (this->m_Controls.radioAIFFile->isChecked()) { ok = ok && (this->AIFinputGrid.size() != 0) && (this->AIFinputFunction.size() != 0); } else { ok = false; } } //add other models as else if and check wether all needed static parameters are set else { ok = false; } if (this->m_Controls.radioButton_StartParameters->isChecked() && !this->m_Controls.initialValuesManager->hasValidInitialValues()) { std::string warning = "Warning. Invalid start parameters. At least one parameter as an invalid image setting as source."; MITK_ERROR << warning; m_Controls.infoBox->append(QString("") + QString::fromStdString(warning) + QString("")); ok = false; }; } else { ok = false; } return ok; } void PETDynamicView::ConfigureInitialParametersOfParameterizer(mitk::ModelParameterizerBase* parameterizer) const { if (m_Controls.radioButton_StartParameters->isChecked()) { //use user defined initial parameters mitk::InitialParameterizationDelegateBase::Pointer paramDelegate = m_Controls.initialValuesManager->getInitialParametrizationDelegate(); parameterizer->SetInitialParameterizationDelegate(paramDelegate); } } template void PETDynamicView::GenerateModelFit_PixelBased( mitk::modelFit::ModelFitInfo::Pointer& modelFitInfo, mitk::ParameterFitImageGeneratorBase::Pointer& generator) { mitk::PixelBasedParameterFitImageGenerator::Pointer fitGenerator = mitk::PixelBasedParameterFitImageGenerator::New(); typename TParameterizer::Pointer modelParameterizer = TParameterizer::New(); mitk::AIFBasedModelBase::AterialInputFunctionType aif; mitk::AIFBasedModelBase::TimeGridType aifTimeGrid; GetAIF(aif, aifTimeGrid); //Model configuration (static parameters) can be done now modelParameterizer->SetAIF(aif); modelParameterizer->SetAIFTimeGrid(aifTimeGrid); this->ConfigureInitialParametersOfParameterizer(modelParameterizer); //Specify fitting strategy and criterion parameters mitk::ModelFitFunctorBase::Pointer fitFunctor = CreateDefaultFitFunctor(modelParameterizer); //Parametrize fit generator fitGenerator->SetModelParameterizer(modelParameterizer); std::string roiUID = ""; if (m_selectedMask.IsNotNull()) { fitGenerator->SetMask(m_selectedMask); - roiUID = mitk::EnsureModelFitUID(this->m_selectedMaskNode); + roiUID = m_selectedMask->GetUID(); } fitGenerator->SetDynamicImage(this->m_selectedImage); fitGenerator->SetFitFunctor(fitFunctor); generator = fitGenerator.GetPointer(); //Create model info modelFitInfo = mitk::modelFit::CreateFitInfoFromModelParameterizer(modelParameterizer, m_selectedNode->GetData(), mitk::ModelFitConstants::FIT_TYPE_VALUE_PIXELBASED(), this->GetFitName(), roiUID); mitk::ScalarListLookupTable::ValueType infoSignal; for (mitk::AIFBasedModelBase::AterialInputFunctionType::const_iterator pos = aif.begin(); pos != aif.end(); ++pos) { infoSignal.push_back(*pos); } modelFitInfo->inputData.SetTableValue("AIF", infoSignal); } template void PETDynamicView::GenerateModelFit_ROIBased( mitk::modelFit::ModelFitInfo::Pointer& modelFitInfo, mitk::ParameterFitImageGeneratorBase::Pointer& generator) { mitk::ROIBasedParameterFitImageGenerator::Pointer fitGenerator = mitk::ROIBasedParameterFitImageGenerator::New(); typename TParameterizer::Pointer modelParameterizer = TParameterizer::New(); //Compute AIF mitk::AterialInputFunctionGenerator::Pointer aifGenerator = mitk::AterialInputFunctionGenerator::New(); aifGenerator->SetDynamicImage(this->m_selectedImage); aifGenerator->SetMask(this->m_selectedAIFMask); mitk::AIFBasedModelBase::AterialInputFunctionType aif = aifGenerator->GetAterialInputFunction(); mitk::AIFBasedModelBase::TimeGridType aifTimeGrid = aifGenerator->GetAterialInputFunctionTimeGrid(); //Model configuration (static parameters) can be done now modelParameterizer->SetAIF(aif); modelParameterizer->SetAIFTimeGrid(aifTimeGrid); this->ConfigureInitialParametersOfParameterizer(modelParameterizer); //Compute ROI signal mitk::MaskedDynamicImageStatisticsGenerator::Pointer signalGenerator = mitk::MaskedDynamicImageStatisticsGenerator::New(); signalGenerator->SetMask(m_selectedMask); signalGenerator->SetDynamicImage(m_selectedImage); signalGenerator->Generate(); mitk::MaskedDynamicImageStatisticsGenerator::ResultType roiSignal = signalGenerator->GetMean(); //Specify fitting strategy and criterion parameters mitk::ModelFitFunctorBase::Pointer fitFunctor = CreateDefaultFitFunctor(modelParameterizer); //Parametrize fit generator fitGenerator->SetModelParameterizer(modelParameterizer); fitGenerator->SetMask(m_selectedMask); fitGenerator->SetFitFunctor(fitFunctor); fitGenerator->SetSignal(roiSignal); fitGenerator->SetTimeGrid(mitk::ExtractTimeGrid(m_selectedImage)); generator = fitGenerator.GetPointer(); - std::string roiUID = mitk::EnsureModelFitUID(this->m_selectedMaskNode); + std::string roiUID = ""; + if (m_selectedMask.IsNotNull()) + { + roiUID = m_selectedMask->GetUID(); + } //Create model info modelFitInfo = mitk::modelFit::CreateFitInfoFromModelParameterizer(modelParameterizer, m_selectedNode->GetData(), mitk::ModelFitConstants::FIT_TYPE_VALUE_ROIBASED(), this->GetFitName(), roiUID); mitk::ScalarListLookupTable::ValueType infoSignal; for (mitk::MaskedDynamicImageStatisticsGenerator::ResultType::const_iterator pos = roiSignal.begin(); pos != roiSignal.end(); ++pos) { infoSignal.push_back(*pos); } modelFitInfo->inputData.SetTableValue("ROI", infoSignal); infoSignal.clear(); for (mitk::AIFBasedModelBase::AterialInputFunctionType::const_iterator pos = aif.begin(); pos != aif.end(); ++pos) { infoSignal.push_back(*pos); } modelFitInfo->inputData.SetTableValue("AIF", infoSignal); } void PETDynamicView::DoFit(const mitk::modelFit::ModelFitInfo* fitSession, mitk::ParameterFitImageGeneratorBase* generator) { std::stringstream message; message << "" << "Fitting Data Set . . ." << ""; m_Controls.errorMessageLabel->setText(message.str().c_str()); m_Controls.errorMessageLabel->show(); ///////////////////////// //create job and put it into the thread pool ParameterFitBackgroundJob* pJob = new ParameterFitBackgroundJob(generator, fitSession, this->m_selectedNode); pJob->setAutoDelete(true); connect(pJob, SIGNAL(Error(QString)), this, SLOT(OnJobError(QString))); connect(pJob, SIGNAL(Finished()), this, SLOT(OnJobFinished())); connect(pJob, SIGNAL(ResultsAreAvailable(mitk::modelFit::ModelFitResultNodeVectorType, const ParameterFitBackgroundJob*)), this, SLOT(OnJobResultsAreAvailable(mitk::modelFit::ModelFitResultNodeVectorType, const ParameterFitBackgroundJob*)), Qt::BlockingQueuedConnection); connect(pJob, SIGNAL(JobProgress(double)), this, SLOT(OnJobProgress(double))); connect(pJob, SIGNAL(JobStatusChanged(QString)), this, SLOT(OnJobStatusChanged(QString))); QThreadPool* threadPool = QThreadPool::globalInstance(); threadPool->start(pJob); } PETDynamicView::PETDynamicView() : m_FittingInProgress(false) { m_selectedImage = nullptr; m_selectedMask = nullptr; mitk::ModelFactoryBase::Pointer factory = mitk::OneTissueCompartmentModelFactory::New().GetPointer(); m_FactoryStack.push_back(factory); factory = mitk::ExtendedOneTissueCompartmentModelFactory::New().GetPointer(); m_FactoryStack.push_back(factory); factory = mitk::TwoTissueCompartmentModelFactory::New().GetPointer(); m_FactoryStack.push_back(factory); factory = mitk::TwoTissueCompartmentFDGModelFactory::New().GetPointer(); m_FactoryStack.push_back(factory); factory = mitk::NumericTwoTissueCompartmentModelFactory::New().GetPointer(); m_FactoryStack.push_back(factory); mitk::NodePredicateDataType::Pointer isLabelSet = mitk::NodePredicateDataType::New("LabelSetImage"); mitk::NodePredicateDataType::Pointer isImage = mitk::NodePredicateDataType::New("Image"); mitk::NodePredicateProperty::Pointer isBinary = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); mitk::NodePredicateAnd::Pointer isLegacyMask = mitk::NodePredicateAnd::New(isImage, isBinary); mitk::NodePredicateOr::Pointer isMask = mitk::NodePredicateOr::New(isLegacyMask, isLabelSet); mitk::NodePredicateAnd::Pointer isNoMask = mitk::NodePredicateAnd::New(isImage, mitk::NodePredicateNot::New(isMask)); this->m_IsMaskPredicate = mitk::NodePredicateAnd::New(isMask, mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object"))).GetPointer(); this->m_IsNoMaskImagePredicate = mitk::NodePredicateAnd::New(isNoMask, mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object"))).GetPointer(); } void PETDynamicView::OnJobFinished() { this->m_Controls.infoBox->append(QString("Fitting finished")); this->m_FittingInProgress = false; }; void PETDynamicView::OnJobError(QString err) { MITK_ERROR << err.toStdString().c_str(); m_Controls.infoBox->append(QString("") + err + QString("")); }; void PETDynamicView::OnJobResultsAreAvailable(mitk::modelFit::ModelFitResultNodeVectorType results, const ParameterFitBackgroundJob* pJob) { //Store the resulting parameter fit image via convenience helper function in data storage //(handles the correct generation of the nodes and their properties) mitk::modelFit::StoreResultsInDataStorage(this->GetDataStorage(), results, pJob->GetParentNode()); m_Controls.errorMessageLabel->setText(""); m_Controls.errorMessageLabel->hide(); }; void PETDynamicView::OnJobProgress(double progress) { QString report = QString("Progress. ") + QString::number(progress); this->m_Controls.infoBox->append(report); }; void PETDynamicView::OnJobStatusChanged(QString info) { this->m_Controls.infoBox->append(info); } void PETDynamicView::InitModelComboBox() const { this->m_Controls.comboModel->clear(); this->m_Controls.comboModel->addItem(tr("No model selected")); for (ModelFactoryStackType::const_iterator pos = m_FactoryStack.begin(); pos != m_FactoryStack.end(); ++pos) { this->m_Controls.comboModel->addItem(QString::fromStdString((*pos)->GetClassID())); } this->m_Controls.comboModel->setCurrentIndex(0); }; mitk::ModelFitFunctorBase::Pointer PETDynamicView::CreateDefaultFitFunctor( const mitk::ModelParameterizerBase* parameterizer) const { mitk::LevenbergMarquardtModelFitFunctor::Pointer fitFunctor = mitk::LevenbergMarquardtModelFitFunctor::New(); mitk::SumOfSquaredDifferencesFitCostFunction::Pointer evaluation = mitk::SumOfSquaredDifferencesFitCostFunction::New(); fitFunctor->RegisterEvaluationParameter("sum_diff^2", evaluation); mitk::ChiSquareFitCostFunction::Pointer chi2 = mitk::ChiSquareFitCostFunction::New(); fitFunctor->RegisterEvaluationParameter("Chi^2", chi2); mitk::ReducedChiSquareFitCostFunction::Pointer redchi2 = mitk::ReducedChiSquareFitCostFunction::New(); fitFunctor->RegisterEvaluationParameter("redChi^2", redchi2); if (m_Controls.checkBox_Constraints->isChecked()) { fitFunctor->SetConstraintChecker(m_modelConstraints); } mitk::ModelBase::Pointer refModel = parameterizer->GenerateParameterizedModel(); ::itk::LevenbergMarquardtOptimizer::ScalesType scales; scales.SetSize(refModel->GetNumberOfParameters()); scales.Fill(1.0); fitFunctor->SetScales(scales); return fitFunctor.GetPointer(); } void PETDynamicView::GetAIF(mitk::AIFBasedModelBase::AterialInputFunctionType& aif, mitk::AIFBasedModelBase::AterialInputFunctionType& aifTimeGrid) { if (this->m_Controls.radioAIFFile->isChecked()) { aif.clear(); aifTimeGrid.clear(); aif.SetSize(AIFinputFunction.size()); aifTimeGrid.SetSize(AIFinputGrid.size()); aif.fill(0.0); aifTimeGrid.fill(0.0); itk::Array::iterator aifPos = aif.begin(); for (std::vector::const_iterator pos = AIFinputFunction.begin(); pos != AIFinputFunction.end(); ++pos, ++aifPos) { *aifPos = *pos; } itk::Array::iterator gridPos = aifTimeGrid.begin(); for (std::vector::const_iterator pos = AIFinputGrid.begin(); pos != AIFinputGrid.end(); ++pos, ++gridPos) { *gridPos = *pos; } } else if (this->m_Controls.radioAIFImage->isChecked()) { aif.clear(); aifTimeGrid.clear(); mitk::AterialInputFunctionGenerator::Pointer aifGenerator = mitk::AterialInputFunctionGenerator::New(); //Hematocrit level aifGenerator->SetHCL(this->m_Controls.HCLSpinBox->value()); //mask settings this->m_selectedAIFMaskNode = m_Controls.comboAIFMask->GetSelectedNode(); this->m_selectedAIFMask = dynamic_cast(this->m_selectedAIFMaskNode->GetData()); if (this->m_selectedAIFMask->GetTimeSteps() > 1) { MITK_INFO << "Selected AIF mask has multiple timesteps. Only use first timestep to mask model fit. AIF Mask name: " << m_selectedAIFMaskNode->GetName() ; mitk::ImageTimeSelector::Pointer maskedImageTimeSelector = mitk::ImageTimeSelector::New(); maskedImageTimeSelector->SetInput(this->m_selectedAIFMask); maskedImageTimeSelector->SetTimeNr(0); maskedImageTimeSelector->UpdateLargestPossibleRegion(); this->m_selectedAIFMask = maskedImageTimeSelector->GetOutput(); } if (this->m_selectedAIFMask.IsNotNull()) { aifGenerator->SetMask(this->m_selectedAIFMask); } //image settings if (this->m_Controls.checkDedicatedAIFImage->isChecked()) { this->m_selectedAIFImageNode = m_Controls.comboAIFImage->GetSelectedNode(); this->m_selectedAIFImage = dynamic_cast(this->m_selectedAIFImageNode->GetData()); } else { this->m_selectedAIFImageNode = m_selectedNode; this->m_selectedAIFImage = m_selectedImage; } aifGenerator->SetDynamicImage(this->m_selectedAIFImage); aif = aifGenerator->GetAterialInputFunction(); aifTimeGrid = aifGenerator->GetAterialInputFunctionTimeGrid(); } else { mitkThrow() << "Cannot generate AIF. View is in a invalide state. No AIF mode selected."; } } void PETDynamicView::LoadAIFfromFile() { QFileDialog dialog; dialog.setNameFilter(tr("Images (*.csv")); QString fileName = dialog.getOpenFileName(); m_Controls.aifFilePath->setText(fileName); std::string m_aifFilePath = fileName.toStdString(); //Read Input typedef boost::tokenizer< boost::escaped_list_separator > Tokenizer; ///////////////////////////////////////////////////////////////////////////////////////////////// //AIF Data std::ifstream in1(m_aifFilePath.c_str()); if (!in1.is_open()) { m_Controls.errorMessageLabel->setText("Could not open AIF File!"); } std::vector< std::string > vec1; std::string line1; while (getline(in1, line1)) { Tokenizer tok(line1); vec1.assign(tok.begin(), tok.end()); // if (vec1.size() < 3) continue; this->AIFinputGrid.push_back(convertToDouble(vec1[0])); this->AIFinputFunction.push_back(convertToDouble(vec1[1])); } }