diff --git a/Modules/ModelFit/autoload/IO/mitkModelFitIOActivator.cpp b/Modules/ModelFit/autoload/IO/mitkModelFitIOActivator.cpp index 404470f04d..4ad24e9436 100644 --- a/Modules/ModelFit/autoload/IO/mitkModelFitIOActivator.cpp +++ b/Modules/ModelFit/autoload/IO/mitkModelFitIOActivator.cpp @@ -1,99 +1,100 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include #include #include #include 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::CoreServices::GetPropertyDescriptions()->AddDescription(name, description); mitk::PropertyPersistenceInfo::Pointer ppi = mitk::PropertyPersistenceInfo::New(); ppi->SetNameAndKey(name, key); mitk::CoreServices::GetPropertyPersistence()->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::CoreServices::GetPropertyDescriptions()->AddDescription(name, description); mitk::PropertyPersistenceInfo::Pointer ppi = mitk::PropertyPersistenceInfo::New(); ppi->SetNameAndKey(name, key); ppi->SetDeserializationFunction(deFnc); ppi->SetSerializationFunction(serFnc); mitk::CoreServices::GetPropertyPersistence()->AddInfo(ppi, true); } void Load(us::ModuleContext* /*context*/) { //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", "Functions 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", "Value identifies the model type."); registerProperty(mitk::ModelFitConstants::XAXIS_NAME_PROPERTY_NAME(), "modelfit_xaxis_name", "Value identifies the model type."); registerProperty(mitk::ModelFitConstants::XAXIS_UNIT_PROPERTY_NAME(), "modelfit_xaxis_unit", "Value identifies the model type."); registerProperty(mitk::ModelFitConstants::YAXIS_NAME_PROPERTY_NAME(), "modelfit_yaxis_name", "Value identifies the model type."); registerProperty(mitk::ModelFitConstants::YAXIS_UNIT_PROPERTY_NAME(), "modelfit_yaxis_unit", "Value identifies the model type."); registerProperty(mitk::ModelFitConstants::FIT_UID_PROPERTY_NAME(), "modelfit_fit_uid", "Value identifies the model type."); + 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", "Value identifies the model type."); registerProperty(mitk::ModelFitConstants::FIT_INPUT_IMAGEUID_PROPERTY_NAME(), "modelfit_fit_input_imageUID", "Value identifies the model type."); registerProperty(mitk::ModelFitConstants::FIT_INPUT_ROIUID_PROPERTY_NAME(), "modelfit_fit_input_roiUID", "Value identifies the model type."); registerProperty(mitk::ModelFitConstants::FIT_INPUT_DATA_PROPERTY_NAME(), "modelfit_fit_input_data", "Value identifies the model type."); registerProperty(mitk::ModelFitConstants::FIT_STATIC_PARAMETERS_PROPERTY_NAME(), "modelfit_fit_staticParameters", "Value identifies the model type.", PropertyPersistenceDeserialization::deserializeXMLToScalarListLookupTableProperty, PropertyPersistenceSerialization::serializeScalarListLookupTablePropertyToXML); } void Unload(us::ModuleContext* ) { } private: }; } US_EXPORT_MODULE_ACTIVATOR(mitk::ModelFitIOActivator) diff --git a/Modules/ModelFit/include/mitkModelFitConstants.h b/Modules/ModelFit/include/mitkModelFitConstants.h index ccc300e864..be1d6697a5 100644 --- a/Modules/ModelFit/include/mitkModelFitConstants.h +++ b/Modules/ModelFit/include/mitkModelFitConstants.h @@ -1,204 +1,210 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _MITK_MODEL_FIT_CONSTANTS_H_ #define _MITK_MODEL_FIT_CONSTANTS_H_ #include #include "MitkModelFitExports.h" #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4251) #endif 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(); /** * 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(); }; } #ifdef _MSC_VER #pragma warning(pop) #endif #endif diff --git a/Modules/ModelFit/include/mitkModelFitInfo.h b/Modules/ModelFit/include/mitkModelFitInfo.h index ccf8b3bf39..6c83b168ef 100644 --- a/Modules/ModelFit/include/mitkModelFitInfo.h +++ b/Modules/ModelFit/include/mitkModelFitInfo.h @@ -1,200 +1,206 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef 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::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; 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 NodeUIDType roiUID = ""); + const std::string& fitType, const std::string& fitName = "", const NodeUIDType 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 NodeUIDType roiUID = ""); + const std::string& fitType, const ScalarListLookupTable& inputData, const std::string& fitName = "", + const NodeUIDType 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/mitkModelFitResultHelper.h b/Modules/ModelFit/include/mitkModelFitResultHelper.h index f73d9792fb..8e8625fc02 100644 --- a/Modules/ModelFit/include/mitkModelFitResultHelper.h +++ b/Modules/ModelFit/include/mitkModelFitResultHelper.h @@ -1,65 +1,65 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __MITK_MODEL_FIT_RESULT_HELPER_H_ #define __MITK_MODEL_FIT_RESULT_HELPER_H_ #include #include #include "mitkScalarListLookupTableProperty.h" #include "mitkModelBase.h" #include "mitkModelFitParameter.h" #include "mitkModelFitStaticParameterMap.h" #include "MitkModelFitExports.h" namespace mitk { class DataStorage; class ModelTraitsInterface; class ModelBase; namespace modelFit { class ModelFitInfo; typedef std::map ModelFitResultImageMapType; typedef std::vector ModelFitResultNodeVectorType; /**Helper function that sets the properties of the passed base data according to the given model fit info instance and parameter specification. @param data Instance that properties should be configured. @param name Name of the parameter this data instance represents. @param dataType Type of the parameter this data instance represents. @param fitInfo Instance to the fit info that containes the information of the fit that derived the parameter. @pre Data must point to a valid instance. @pre fitInfo must point to an valid instance. */ MITKMODELFIT_EXPORT void SetModelFitDataProperties(mitk::BaseData* data, const ModelBase::ParameterNameType& name, modelFit::Parameter::Type dataType, const modelFit::ModelFitInfo* fitInfo); MITKMODELFIT_EXPORT mitk::ScalarListLookupTableProperty::Pointer ConvertStaticParametersToProperty(const mitk::modelFit::StaticParameterMap& params); - MITKMODELFIT_EXPORT DataNode::Pointer CreateResultNode(const ModelBase::ParameterNameType& name, modelFit::Parameter::Type nodeType, Image* parameterImage, const ModelFitInfo* modelFitInfo, const std::string& sessionName = ""); + MITKMODELFIT_EXPORT DataNode::Pointer CreateResultNode(const ModelBase::ParameterNameType& name, modelFit::Parameter::Type nodeType, Image* parameterImage, const ModelFitInfo* modelFitInfo); - MITKMODELFIT_EXPORT ModelFitResultNodeVectorType CreateResultNodeMap(const ModelFitResultImageMapType& results, const ModelFitResultImageMapType& derivedResults, const ModelFitResultImageMapType& criterionResults, const ModelFitResultImageMapType& evaluationResults, const ModelFitInfo* fitInfo, const std::string& sessionName = ""); + MITKMODELFIT_EXPORT ModelFitResultNodeVectorType CreateResultNodeMap(const ModelFitResultImageMapType& results, const ModelFitResultImageMapType& derivedResults, const ModelFitResultImageMapType& criterionResults, const ModelFitResultImageMapType& evaluationResults, const ModelFitInfo* fitInfo); MITKMODELFIT_EXPORT void StoreResultsInDataStorage(DataStorage* storage, const ModelFitResultNodeVectorType& resultNodes, DataNode* parentNode = NULL); } } #endif diff --git a/Modules/ModelFit/src/Common/mitkModelFitConstants.cpp b/Modules/ModelFit/src/Common/mitkModelFitConstants.cpp index 7f990249fd..b373857280 100644 --- a/Modules/ModelFit/src/Common/mitkModelFitConstants.cpp +++ b/Modules/ModelFit/src/Common/mitkModelFitConstants.cpp @@ -1,50 +1,51 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "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::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_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::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";} \ No newline at end of file diff --git a/Modules/ModelFit/src/Common/mitkModelFitInfo.cpp b/Modules/ModelFit/src/Common/mitkModelFitInfo.cpp index fa7ae9d2a4..64018019af 100644 --- a/Modules/ModelFit/src/Common/mitkModelFitInfo.cpp +++ b/Modules/ModelFit/src/Common/mitkModelFitInfo.cpp @@ -1,431 +1,432 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include "mitkDataNode.h" #include "mitkDataStorage.h" #include "mitkModelFitInfo.h" #include "mitkScalarListLookupTableProperty.h" #include "mitkModelFitException.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 NULL; } 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 NULL; } mitk::DataStorage::SetOfObjects::ConstPointer nodes = GetNodesOfFit(uid, storage); if (nodes.IsNull() || nodes->empty()) { return NULL; } mitk::DataNode::ConstPointer node = nodes->GetElement( 0).GetPointer(); //take one of the nodes as template if (!node->GetData()) { return NULL; } 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 NULL; } // 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 NULL; } } 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 NULL; } if (storage) { mitk::DataNode::Pointer inputNode = GetNodeByModelFitUID(storage, fit->inputUID); if (inputNode.IsNull()) { MITK_ERROR << "Cannot create valid model fit info. input node cannot be found."; return NULL; } mitk::Image::Pointer inputImage = dynamic_cast(inputNode->GetData()); if (inputImage.IsNull()) { MITK_ERROR << "Cannot create valid model fit info. input node does not contain an image."; return NULL; } 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, +mitk::BaseData* inputImage, const std::string& fitType, const std::string& fitName, const NodeUIDType roiUID) { if (!usedParameterizer) { return NULL; } 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 NodeUIDType roiUID) +mitk::BaseData* inputImage, const std::string& fitType, const ScalarListLookupTable& inputData, +const std::string& fitName, const NodeUIDType roiUID) { mitk::modelFit::ModelFitInfo::Pointer info = CreateFitInfoFromModelParameterizer(usedParameterizer, - inputImage, fitType, roiUID); + 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 NULL; } 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/mitkModelFitResultHelper.cpp b/Modules/ModelFit/src/Common/mitkModelFitResultHelper.cpp index ea751791fd..4f5c1cb67d 100644 --- a/Modules/ModelFit/src/Common/mitkModelFitResultHelper.cpp +++ b/Modules/ModelFit/src/Common/mitkModelFitResultHelper.cpp @@ -1,273 +1,274 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkModelFitResultHelper.h" #include #include #include "mitkModelTraitsInterface.h" #include "mitkModelFitConstants.h" #include "mitkModelFitInfo.h" 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()); 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, const std::string& sessionName) + 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 (!sessionName.empty()) + if (!fitInfo->fitName.empty()) { - nodeName = sessionName+"_"+nodeName; + 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, const std::string& sessionName ) +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: "<first, modelFit::Parameter::ParameterType, pos->second, fitInfo, sessionName); + 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, sessionName); + 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, sessionName); + 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, sessionName); + 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); } }; diff --git a/Modules/ModelFit/test/mitkModelFitInfoTest.cpp b/Modules/ModelFit/test/mitkModelFitInfoTest.cpp index 8dd0c2c646..7528aee218 100644 --- a/Modules/ModelFit/test/mitkModelFitInfoTest.cpp +++ b/Modules/ModelFit/test/mitkModelFitInfoTest.cpp @@ -1,266 +1,271 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include "mitkTestingMacros.h" #include "mitkProperties.h" #include "mitkStandaloneDataStorage.h" #include "mitkModelFitInfo.h" #include "mitkModelFitConstants.h" #include "mitkModelFitException.h" 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); testImage->SetProperty(mitk::ModelFitConstants::FIT_UID_PROPERTY_NAME().c_str(), mitk::StringProperty::New("Fit1")); + 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::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[]*/) { 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",NULL).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",NULL).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(NULL,storage); MITK_TEST_CONDITION_REQUIRED(uidSet.size() == 0, "Testing if GetFitUIDsOfNode works correctly with invalid node."); uidSet = mitk::modelFit::GetFitUIDsOfNode(testNode,NULL); MITK_TEST_CONDITION_REQUIRED(uidSet.size() == 0, "Testing if GetFitUIDsOfNode works correctly with invalid storage."); MITK_TEST_END() } diff --git a/Modules/ModelFitUI/Qmitk/QmitkParameterFitBackgroundJob.cpp b/Modules/ModelFitUI/Qmitk/QmitkParameterFitBackgroundJob.cpp index 560c5245ca..5f77a32368 100644 --- a/Modules/ModelFitUI/Qmitk/QmitkParameterFitBackgroundJob.cpp +++ b/Modules/ModelFitUI/Qmitk/QmitkParameterFitBackgroundJob.cpp @@ -1,110 +1,109 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Software Development for Integrated Diagnostic and Therapy. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "QmitkParameterFitBackgroundJob.h" #include "mitkModelFitInfo.h" void ParameterFitBackgroundJob::OnFitEvent(::itk::Object* caller, const itk::EventObject & event) { itk::ProgressEvent progressEvent; itk::InitializeEvent initEvent; itk::StartEvent startEvent; itk::EndEvent endEvent; if (progressEvent.CheckEvent(&event)) { mitk::ParameterFitImageGeneratorBase* castedReporter = dynamic_cast(caller); emit JobProgress(castedReporter->GetProgress()); } else if (initEvent.CheckEvent(&event)) { emit JobStatusChanged(QString("Initializing parameter fit generator")); } else if (startEvent.CheckEvent(&event)) { emit JobStatusChanged(QString("Started fitting process.")); } else if (endEvent.CheckEvent(&event)) { emit JobStatusChanged(QString("Finished fitting process.")); } } ParameterFitBackgroundJob:: -ParameterFitBackgroundJob(mitk::ParameterFitImageGeneratorBase* generator, const mitk::modelFit::ModelFitInfo* fitInfo, const std::string& fitName, mitk::DataNode* parentNode) +ParameterFitBackgroundJob(mitk::ParameterFitImageGeneratorBase* generator, const mitk::modelFit::ModelFitInfo* fitInfo, mitk::DataNode* parentNode) { if (!generator) { mitkThrow() << "Cannot create parameter fit background job. Passed fit generator is NULL."; } if (!fitInfo) { mitkThrow() << "Cannot create parameter fit background job. Passed model traits interface is NULL."; } m_Generator = generator; m_ModelFitInfo = fitInfo; - m_FitName = fitName; m_ParentNode = parentNode; m_spCommand = ::itk::MemberCommand::New(); m_spCommand->SetCallbackFunction(this, &ParameterFitBackgroundJob::OnFitEvent); m_ObserverID = m_Generator->AddObserver(::itk::AnyEvent(), m_spCommand); }; mitk::DataNode* ParameterFitBackgroundJob:: GetParentNode() const { return m_ParentNode; }; ParameterFitBackgroundJob:: ~ParameterFitBackgroundJob() { m_Generator->RemoveObserver(m_ObserverID); }; void ParameterFitBackgroundJob:: run() { try { emit JobStatusChanged(QString("Started fit session.Generate UID: ")+QString::fromStdString(m_ModelFitInfo->uid)); m_Generator->Generate(); emit JobStatusChanged(QString("Generate result nodes.")); - m_Results = mitk::modelFit::CreateResultNodeMap(m_Generator->GetParameterImages(), m_Generator->GetDerivedParameterImages(), m_Generator->GetCriterionImages(), m_Generator->GetEvaluationParameterImages(), m_ModelFitInfo, m_FitName); + m_Results = mitk::modelFit::CreateResultNodeMap(m_Generator->GetParameterImages(), m_Generator->GetDerivedParameterImages(), m_Generator->GetCriterionImages(), m_Generator->GetEvaluationParameterImages(), m_ModelFitInfo); emit ResultsAreAvailable(m_Results, this); } catch (::std::exception& e) { emit Error(QString("Error while fitting data. Details: ")+QString::fromLatin1(e.what())); } catch (...) { emit Error(QString("Unkown error when fitting the data.")); } emit Finished(); }; diff --git a/Modules/ModelFitUI/Qmitk/QmitkParameterFitBackgroundJob.h b/Modules/ModelFitUI/Qmitk/QmitkParameterFitBackgroundJob.h index 5a320840e8..0cb5b505d3 100644 --- a/Modules/ModelFitUI/Qmitk/QmitkParameterFitBackgroundJob.h +++ b/Modules/ModelFitUI/Qmitk/QmitkParameterFitBackgroundJob.h @@ -1,81 +1,78 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Software Development for Integrated Diagnostic and Therapy. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef __QMITK_PARAMETER_FIT_BACKGROUND_JOB_H #define __QMITK_PARAMETER_FIT_BACKGROUND_JOB_H //QT #include #include //MITK #include #include #include #include // ITK #include #include "MitkModelFitUIExports.h" class MITKMODELFITUI_EXPORT ParameterFitBackgroundJob : public QObject, public QRunnable { // 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: - ParameterFitBackgroundJob(mitk::ParameterFitImageGeneratorBase* generator, const mitk::modelFit::ModelFitInfo* fitInfo, const std::string& fitName ="", mitk::DataNode* parentNode = NULL); + ParameterFitBackgroundJob(mitk::ParameterFitImageGeneratorBase* generator, const mitk::modelFit::ModelFitInfo* fitInfo, mitk::DataNode* parentNode = NULL); ~ParameterFitBackgroundJob(); void run(); /**Returns the node (if defined), that is the parent object for the results of the job. May be null.*/ mitk::DataNode* GetParentNode() const; signals: void Finished(); void Error(QString err); void ResultsAreAvailable(mitk::modelFit::ModelFitResultNodeVectorType resultMap, const ParameterFitBackgroundJob* pJob); void JobProgress(double progress); void JobStatusChanged(QString info); protected: //Inputs mitk::ParameterFitImageGeneratorBase::Pointer m_Generator; mitk::modelFit::ModelFitInfo::ConstPointer m_ModelFitInfo; mitk::DataNode::Pointer m_ParentNode; - //job settings - std::string m_FitName; - // Results mitk::modelFit::ModelFitResultNodeVectorType m_Results; ::itk::MemberCommand::Pointer m_spCommand; unsigned long m_ObserverID; void OnFitEvent(::itk::Object *, const itk::EventObject &event); }; #endif diff --git a/Plugins/org.mitk.gui.qt.fit.demo/src/internal/FitGeneratorDemoView.cpp b/Plugins/org.mitk.gui.qt.fit.demo/src/internal/FitGeneratorDemoView.cpp index 5bab2c3967..159f88d044 100644 --- a/Plugins/org.mitk.gui.qt.fit.demo/src/internal/FitGeneratorDemoView.cpp +++ b/Plugins/org.mitk.gui.qt.fit.demo/src/internal/FitGeneratorDemoView.cpp @@ -1,259 +1,258 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "FitGeneratorDemoView.h" #include #include #include #include #include "mitkWorkbenchUtil.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include const std::string FitGeneratorDemoView::VIEW_ID = "org.mitk.gui.qt.fit.demo"; typedef itk::Image FrameITKImageType; typedef itk::Image DynamicITKImageType; void FitGeneratorDemoView::SetFocus() { m_Controls.btnModelling->setFocus(); } void FitGeneratorDemoView::CreateQtPartControl(QWidget* parent) { m_Controls.setupUi(parent); m_Controls.btnModelling->setEnabled(false); connect(m_Controls.btnModelling, SIGNAL(clicked()), this, SLOT(OnModellingButtonClicked())); connect(m_Controls.btnGenerateTestData, SIGNAL(clicked()), this, SLOT(OnGenerateTestDataButtonClicked())); m_Controls.leFitName->setText(tr("demo")); } void FitGeneratorDemoView::OnModellingButtonClicked() { Generate(); } void FitGeneratorDemoView::OnGenerateTestDataButtonClicked() { mitk::Image::Pointer testImage = mitk::GenerateDynamicTestImageMITK(); mitk::DataNode::Pointer testNode = mitk::DataNode::New(); testNode->SetData(testImage); testNode->SetName("LinearModel_4DTestImage"); this->GetDataStorage()->Add(testNode); } void FitGeneratorDemoView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*source*/, const QList& /*nodes*/) { QList dataNodes = this->GetDataManagerSelection(); m_selectedNode = NULL; m_selectedImage = NULL; m_selectedMaskNode = NULL; m_selectedMask = NULL; if (!dataNodes.empty()) { m_selectedNode = dataNodes[0]; mitk::Image* selectedImage = dynamic_cast(m_selectedNode->GetData()); if (selectedImage && selectedImage->GetDimension(3) > 1) { m_selectedImage = selectedImage; } if (dataNodes.size() > 1) { m_selectedMaskNode = dataNodes[1]; mitk::NodePredicateDataType::Pointer isLabelSet = mitk::NodePredicateDataType::New("LabelSetImage"); mitk::NodePredicateDataType::Pointer isImage = mitk::NodePredicateDataType::New("Image"); mitk::NodePredicateProperty::Pointer isBinary = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); mitk::NodePredicateAnd::Pointer isLegacyMask = mitk::NodePredicateAnd::New(isImage, isBinary); mitk::NodePredicateOr::Pointer maskPredicate = mitk::NodePredicateOr::New(isLegacyMask, isLabelSet); mitk::Image* selectedMask = dynamic_cast(this->m_selectedMaskNode->GetData()); if (selectedMask && maskPredicate->CheckNode(m_selectedMaskNode)) { m_selectedMask = selectedMask; if (this->m_selectedMask->GetTimeSteps() > 1) { MITK_INFO << "Selected mask has multiple timesteps. Only use first timestep to mask model fit. Mask name: " << m_selectedMaskNode->GetName() ; mitk::ImageTimeSelector::Pointer maskedImageTimeSelector = mitk::ImageTimeSelector::New(); maskedImageTimeSelector->SetInput(this->m_selectedMask); maskedImageTimeSelector->SetTimeNr(0); maskedImageTimeSelector->UpdateLargestPossibleRegion(); this->m_selectedMask = maskedImageTimeSelector->GetOutput(); } } } } if (m_selectedImage) { m_Controls.lTimeseries->setText((m_selectedNode->GetName()).c_str()); } else { if (m_selectedNode.IsNull()) { m_Controls.lTimeseries->setText("None"); } else { m_Controls.lTimeseries->setText("Error. Selected node #1 is no 4D image!"); } } if (m_selectedMask) { m_Controls.lMask->setText((m_selectedMaskNode->GetName()).c_str()); } else { if (m_selectedMaskNode.IsNull()) { m_Controls.lMask->setText("None"); } else { m_Controls.lMask->setText("Error. Selected node #2 is no mask!"); } } m_Controls.btnModelling->setEnabled(m_selectedImage.IsNotNull()); } void FitGeneratorDemoView::Generate() { mitk::PixelBasedParameterFitImageGenerator::Pointer fitGenerator = mitk::PixelBasedParameterFitImageGenerator::New(); //Model configuration (static parameters) can be done now //Specify fitting strategy and evaluation parameters mitk::LevenbergMarquardtModelFitFunctor::Pointer fitFunctor = mitk::LevenbergMarquardtModelFitFunctor::New(); mitk::SumOfSquaredDifferencesFitCostFunction::Pointer evaluation = mitk::SumOfSquaredDifferencesFitCostFunction::New(); fitFunctor->RegisterEvaluationParameter("sum_diff^2", evaluation); //Parametrize fit generator mitk::LinearModelParameterizer::Pointer parameterizer = mitk::LinearModelParameterizer::New(); fitGenerator->SetModelParameterizer(parameterizer); fitGenerator->SetDynamicImage(m_selectedImage); fitGenerator->SetFitFunctor(fitFunctor); if (m_selectedMask.IsNotNull()) { fitGenerator->SetMask(m_selectedMask); } mitk::modelFit::ModelFitInfo::Pointer fitSession = mitk::modelFit::CreateFitInfoFromModelParameterizer(parameterizer, m_selectedNode->GetData(), - mitk::ModelFitConstants::FIT_TYPE_VALUE_PIXELBASED()); + mitk::ModelFitConstants::FIT_TYPE_VALUE_PIXELBASED(), m_Controls.leFitName->text().toStdString()); ///////////////////////// //create job and put it into the thread pool - ParameterFitBackgroundJob* pJob = new ParameterFitBackgroundJob(fitGenerator, fitSession, - m_Controls.leFitName->text().toStdString(), m_selectedNode); + ParameterFitBackgroundJob* pJob = new ParameterFitBackgroundJob(fitGenerator, fitSession, m_selectedNode); pJob->setAutoDelete(true); connect(pJob, SIGNAL(Error(QString)), this, SLOT(OnJobError(QString))); connect(pJob, SIGNAL(Finished()), this, SLOT(OnJobFinished())); connect(pJob, SIGNAL(ResultsAreAvailable(mitk::modelFit::ModelFitResultNodeVectorType, const ParameterFitBackgroundJob*)), this, SLOT(OnJobResultsAreAvailable(mitk::modelFit::ModelFitResultNodeVectorType, const ParameterFitBackgroundJob*)), Qt::BlockingQueuedConnection); connect(pJob, SIGNAL(JobProgress(double)), this, SLOT(OnJobProgress(double))); connect(pJob, SIGNAL(JobStatusChanged(QString)), this, SLOT(OnJobStatusChanged(QString))); QThreadPool* threadPool = QThreadPool::globalInstance(); threadPool->start(pJob); } FitGeneratorDemoView::FitGeneratorDemoView() { m_selectedImage = NULL; m_selectedNode = NULL; } void FitGeneratorDemoView::OnJobFinished() { this->m_Controls.textEdit->append(QString("Fitting finished")); }; void FitGeneratorDemoView::OnJobError(QString err) { MITK_ERROR << err.toStdString().c_str(); m_Controls.textEdit->append(QString("") + err + QString("")); }; void FitGeneratorDemoView::OnJobResultsAreAvailable( mitk::modelFit::ModelFitResultNodeVectorType results, const ParameterFitBackgroundJob* pJob) { //Store the resulting parameter fit image via convenience helper function in data storage //(handles the correct generation of the nodes and their properties) mitk::modelFit::StoreResultsInDataStorage(this->GetDataStorage(), results, pJob->GetParentNode()); }; void FitGeneratorDemoView::OnJobProgress(double progress) { QString report = QString("Progress. ") + QString::number(progress); this->m_Controls.textEdit->append(report); }; void FitGeneratorDemoView::OnJobStatusChanged(QString info) { this->m_Controls.textEdit->append(info); } diff --git a/Plugins/org.mitk.gui.qt.fit.genericfitting/src/internal/GenericDataFittingView.cpp b/Plugins/org.mitk.gui.qt.fit.genericfitting/src/internal/GenericDataFittingView.cpp index 1f3b5cfe9f..cb3daf252c 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,643 +1,646 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "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()) != NULL; 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 = NULL; 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 = NULL; mitk::modelFit::ModelFitInfo::Pointer fitSession = NULL; bool isLinearFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != NULL; bool isGenericFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != NULL; bool isT2DecayFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != NULL; 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 = NULL; m_selectedImage = NULL; m_selectedMaskNode = NULL; m_selectedMask = NULL; 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()) != NULL; 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); } 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(), + 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); //Create model info modelFitInfo = mitk::modelFit::CreateFitInfoFromModelParameterizer(modelParameterizer, - m_selectedNode->GetData(), mitk::ModelFitConstants::FIT_TYPE_VALUE_ROIBASED(), + 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 - std::string fitName = m_Controls.lineFitName->text().toStdString(); - if (fitName.empty()) - { - fitName = m_Controls.lineFitName->placeholderText().toStdString(); - } - - ParameterFitBackgroundJob* pJob = new ParameterFitBackgroundJob(generator, fitSession, fitName, this->m_selectedNode); + 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 = NULL; m_selectedMask = NULL; 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.genericfitting/src/internal/GenericDataFittingView.h b/Plugins/org.mitk.gui.qt.fit.genericfitting/src/internal/GenericDataFittingView.h index cf8d5884c4..88d5b40577 100644 --- a/Plugins/org.mitk.gui.qt.fit.genericfitting/src/internal/GenericDataFittingView.h +++ b/Plugins/org.mitk.gui.qt.fit.genericfitting/src/internal/GenericDataFittingView.h @@ -1,155 +1,157 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef GenericDataFittingView_h #define GenericDataFittingView_h #include #include "QmitkAbstractView.h" #include "itkCommand.h" #include "ui_GenericDataFittingViewControls.h" #include "mitkModelBase.h" #include "QmitkParameterFitBackgroundJob.h" #include "mitkModelFitResultHelper.h" #include "mitkModelFactoryBase.h" #include "mitkLevenbergMarquardtModelFitFunctor.h" #include "mitkSimpleBarrierConstraintChecker.h" #include /*! * @brief Plugin for generic dynamic image data fitting */ class GenericDataFittingView : public QmitkAbstractView { Q_OBJECT public: /*! @brief The view's unique ID - required by MITK */ static const std::string VIEW_ID; GenericDataFittingView(); protected slots: void OnModellingButtonClicked(); void OnJobFinished(); void OnJobError(QString err); void OnJobResultsAreAvailable(mitk::modelFit::ModelFitResultNodeVectorType results, const ParameterFitBackgroundJob* pJob); void OnJobProgress(double progress); void OnJobStatusChanged(QString info); void OnModellSet(int); void OnNrOfParamsChanged(); /**Sets visibility and enabled state of the GUI depending on the settings and workflow state.*/ void UpdateGUIControls(); protected: typedef QList SelectedDataNodeVectorType; // Overridden base class functions /*! * @brief Sets up the UI controls and connects the slots and signals. Gets * called by the framework to create the GUI at the right time. * @param[in,out] parent The parent QWidget, as this class itself is not a QWidget * subclass. */ void CreateQtPartControl(QWidget* parent); /*! * @brief Sets the focus to the plot curve button. Gets called by the framework to set the * focus on the right widget. */ void SetFocus(); template void GenerateModelFit_ROIBased(mitk::modelFit::ModelFitInfo::Pointer& modelFitInfo, mitk::ParameterFitImageGeneratorBase::Pointer& generator); template void GenerateModelFit_PixelBased(mitk::modelFit::ModelFitInfo::Pointer& modelFitInfo, mitk::ParameterFitImageGeneratorBase::Pointer& generator); /** Helper function that configures the initial parameter strategy of a parameterizer according to the settings of the GUI.*/ void ConfigureInitialParametersOfParameterizer(mitk::ModelParameterizerBase* parameterizer) const; void PrepareFitConfiguration(); bool IsGenericParamFactorySelected() const; /*! Starts the fitting job with the passed generator and session info*/ void DoFit(const mitk::modelFit::ModelFitInfo* fitSession, mitk::ParameterFitImageGeneratorBase* generator); /**Checks if the settings in the GUI are valid for the chosen model.*/ bool CheckModelSettings() const; void InitModelComboBox() const; /*! \brief called by QmitkFunctionality when DataManager's selection has changed */ virtual void OnSelectionChanged(berry::IWorkbenchPart::Pointer source, const QList& selectedNodes); // Variables /*! @brief The view's UI controls */ Ui::GeneralDataFittingViewControls m_Controls; /* Nodes selected by user/ui for the fit */ mitk::DataNode::Pointer m_selectedNode; mitk::DataNode::Pointer m_selectedMaskNode; /* Images selected by user/ui for the fit */ mitk::Image::Pointer m_selectedImage; mitk::Image::Pointer m_selectedMask; mitk::ModelFactoryBase::Pointer m_selectedModelFactory; mitk::SimpleBarrierConstraintChecker::Pointer m_modelConstraints; private: bool m_FittingInProgress; typedef std::vector ModelFactoryStackType; ModelFactoryStackType m_FactoryStack; /**Helper function that generates a default fitting functor * default is a levenberg marquart based optimizer with all scales set to 1.0. * Constraint setter will be set based on the gui setting and a evaluation parameter * "sum of squared differences" will always be set.*/ mitk::ModelFitFunctorBase::Pointer CreateDefaultFitFunctor(const mitk::ModelParameterizerBase* parameterizer) const; /**Returns the default fit name, derived from the current GUI settings.*/ std::string GetDefaultFitName() const; + /**Returns the current set name of the fit (either default name or use defined name).*/ + std::string GetFitName() const; mitk::NodePredicateBase::Pointer m_IsNotABinaryImagePredicate; mitk::NodePredicateBase::Pointer m_IsBinaryImagePredicate; }; #endif 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 dd56a085c6..e197e697c0 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,1396 +1,1400 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "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 #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); 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(mitk::AterialInputFunctionGenerator::DEFAULT_HEMATOCRIT_LEVEL); 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.groupBoxTurboFlash->hide(); m_Controls.radioButtonNoConversion->setChecked(true); m_Controls.factorSpinBox->setEnabled(false); m_Controls.groupBox_viaT1Map->hide(); 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.factorSpinBox, SLOT(setEnabled(bool))); connect(m_Controls.radioButton_relativeEnchancement, SIGNAL(toggled(bool)), m_Controls.factorSpinBox, SLOT(setEnabled(bool))); connect(m_Controls.factorSpinBox, SIGNAL(valueChanged(double)), this, SLOT(UpdateGUIControls())); connect(m_Controls.radioButtonUsingT1, SIGNAL(toggled(bool)), m_Controls.groupBox_viaT1Map, SLOT(setVisible(bool))); connect(m_Controls.radioButtonUsingT1, 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.ComboT1Map->SetDataStorage(this->GetDataStorage()); m_Controls.ComboT1Map->SetPredicate(m_IsNoMaskImagePredicate); m_Controls.ComboT1Map->setEnabled(false); connect(m_Controls.radioButtonUsingT1, SIGNAL(toggled(bool)), m_Controls.ComboT1Map, 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()) != NULL; bool isToftsFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != NULL || dynamic_cast (m_selectedModelFactory.GetPointer()) != NULL; bool is2CXMFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != NULL || dynamic_cast (m_selectedModelFactory.GetPointer()) != NULL; bool isNum2CXMFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != NULL; m_Controls.groupAIF->setVisible(isToftsFactory || is2CXMFactory); m_Controls.groupDescBrix->setVisible(isDescBrixFactory); m_Controls.groupNum2CXM->setVisible(isNum2CXMFactory); m_Controls.groupConcentration->setVisible(isToftsFactory || is2CXMFactory); 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()); } void MRPerfusionView::OnModellSet(int index) { m_selectedModelFactory = NULL; 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()) { mitk::ParameterFitImageGeneratorBase::Pointer generator = NULL; mitk::modelFit::ModelFitInfo::Pointer fitSession = NULL; bool isDescBrixFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != NULL; bool is3LinearFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != NULL; bool isExtToftsFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != NULL; bool isStanToftsFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != NULL; bool is2CXMFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != NULL; bool isNum2CXMFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != NULL; if (isDescBrixFactory) { if (this->m_Controls.radioPixelBased->isChecked()) { GenerateDescriptiveBrixModel_PixelBased(fitSession, generator); } else { GenerateDescriptiveBrixModel_ROIBased(fitSession, generator); } } else if (is3LinearFactory) { if (this->m_Controls.radioPixelBased->isChecked()) { Generate3StepLinearModelFit_PixelBased(fitSession, generator); } else { Generate3StepLinearModelFit_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 = NULL; m_selectedMask = NULL; 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 = NULL; this->m_selectedImage = NULL; 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 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()) != NULL; bool is3LinearFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != NULL; bool isToftsFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != NULL|| dynamic_cast (m_selectedModelFactory.GetPointer()) != NULL; bool is2CXMFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != NULL; bool isNum2CXMFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != NULL; 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) { 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); } else if (this->m_Controls.radioButton_absoluteEnhancement->isChecked() || this->m_Controls.radioButton_relativeEnchancement->isChecked()) { ok = ok && (m_Controls.factorSpinBox->value() > 0); } else if (this->m_Controls.radioButtonUsingT1->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.ComboT1Map->GetSelectedNode().IsNotNull()); } else if (this->m_Controls.radioButtonNoConversion->isChecked()) { ok = ok; } 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); } else if (this->m_Controls.radioButton_absoluteEnhancement->isChecked() || this->m_Controls.radioButton_relativeEnchancement->isChecked()) { ok = ok && (m_Controls.factorSpinBox->value() > 0); } else if (this->m_Controls.radioButtonUsingT1->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.ComboT1Map->GetSelectedNode().IsNotNull()); } else if (this->m_Controls.radioButtonNoConversion->isChecked()) { ok = ok; } 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; } 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); } 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(), roiUID); + 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); //Create model info modelFitInfo = mitk::modelFit::CreateFitInfoFromModelParameterizer(modelParameterizer, - m_selectedNode->GetData(), mitk::ModelFitConstants::FIT_TYPE_VALUE_ROIBASED(), roiUID); + 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 MRPerfusionView::Generate3StepLinearModelFit_PixelBased(mitk::modelFit::ModelFitInfo::Pointer& modelFitInfo, mitk::ParameterFitImageGeneratorBase::Pointer& generator) { mitk::PixelBasedParameterFitImageGenerator::Pointer fitGenerator = mitk::PixelBasedParameterFitImageGenerator::New(); mitk::ThreeStepLinearModelParameterizer::Pointer modelParameterizer = mitk::ThreeStepLinearModelParameterizer::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); } 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(), roiUID); + m_selectedNode->GetData(), mitk::ModelFitConstants::FIT_TYPE_VALUE_PIXELBASED(), this->GetFitName(), roiUID); } void MRPerfusionView::Generate3StepLinearModelFit_ROIBased(mitk::modelFit::ModelFitInfo::Pointer& modelFitInfo, mitk::ParameterFitImageGeneratorBase::Pointer& generator) { if (m_selectedMask.IsNull()) { return; } mitk::ROIBasedParameterFitImageGenerator::Pointer fitGenerator = mitk::ROIBasedParameterFitImageGenerator::New(); mitk::ThreeStepLinearModelParameterizer::Pointer modelParameterizer = mitk::ThreeStepLinearModelParameterizer::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); //Create model info modelFitInfo = mitk::modelFit::CreateFitInfoFromModelParameterizer(modelParameterizer, - m_selectedNode->GetData(), mitk::ModelFitConstants::FIT_TYPE_VALUE_ROIBASED(), roiUID); + 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(); mitk::Image::Pointer concentrationImage; mitk::DataNode::Pointer concentrationNode; GetConcentrationImage(concentrationImage, concentrationNode, false); 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); } fitGenerator->SetDynamicImage(concentrationImage); fitGenerator->SetFitFunctor(fitFunctor); generator = fitGenerator.GetPointer(); //Create model info modelFitInfo = mitk::modelFit::CreateFitInfoFromModelParameterizer(modelParameterizer, - concentrationNode->GetData(), mitk::ModelFitConstants::FIT_TYPE_VALUE_PIXELBASED(), + concentrationNode->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 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(); mitk::Image::Pointer concentrationImage; mitk::DataNode::Pointer concentrationNode; GetConcentrationImage(concentrationImage, concentrationNode, false); 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(concentrationImage); 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(concentrationImage)); generator = fitGenerator.GetPointer(); std::string roiUID = mitk::EnsureModelFitUID(this->m_selectedMaskNode); //Create model info modelFitInfo = mitk::modelFit::CreateFitInfoFromModelParameterizer(modelParameterizer, - concentrationNode->GetData(), mitk::ModelFitConstants::FIT_TYPE_VALUE_ROIBASED(), + concentrationNode->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 MRPerfusionView::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 - std::string fitName = m_Controls.lineFitName->text().toStdString(); - if (fitName.empty()) - { - fitName = m_Controls.lineFitName->placeholderText().toStdString(); - } - - ParameterFitBackgroundJob* pJob = new ParameterFitBackgroundJob(generator, fitSession, fitName, + 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); } MRPerfusionView::MRPerfusionView() : m_FittingInProgress(false) { m_selectedImage = NULL; m_selectedMask = NULL; mitk::ModelFactoryBase::Pointer factory = mitk::DescriptivePharmacokineticBrixModelFactory::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()); m_Controls.errorMessageLabel->setText(""); m_Controls.errorMessageLabel->hide(); }; 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::AddConcentrationImage(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); this->GetDataStorage()->Add(result, m_selectedNode); 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.radioButtonUsingT1->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()); } else if (this->m_Controls.radioButtonUsingT1->isChecked()) { concentrationGen->SetRecoveryTime(m_Controls.TRSpinBox->value()); concentrationGen->SetRelaxivity(m_Controls.RelaxivitySpinBox->value()); concentrationGen->SetT10Image(dynamic_cast(m_Controls.ComboT1Map->GetSelectedNode()->GetData())); //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()); } 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; } mitk::Image::Pointer concentrationImage; mitk::DataNode::Pointer concentrationNode; this->GetConcentrationImage(concentrationImage, concentrationNode, true); aifGenerator->SetDynamicImage(concentrationImage); 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()) { 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])); } } void MRPerfusionView::GetConcentrationImage(mitk::Image::Pointer& concentrationImage, mitk::DataNode::Pointer& concentrationNode, bool AIFMode) { if (this->m_Controls.radioButtonNoConversion->isChecked()) { if (this->m_Controls.checkDedicatedAIFImage->isChecked() && AIFMode) { concentrationImage = this->m_selectedAIFImage; concentrationNode = this->m_selectedAIFImageNode; } else { concentrationImage = this->m_selectedImage; concentrationNode = this->m_selectedNode; } } else { if (AIFMode && !IsTurboFlashSequenceFlag() && !this->m_Controls.checkDedicatedAIFImage->isChecked()) { //we can directly use the input image/node for the AIF if (m_inputImage.IsNull()) { mitkThrow() << "Cannot get AIF concentration image. Invalid view state. Input image is not defined yet, but should be."; } concentrationImage = this->m_inputImage; concentrationNode = this->m_inputNode; } else { concentrationImage = this->ConvertConcentrationImage(AIFMode); if (AIFMode) { concentrationNode = AddConcentrationImage(concentrationImage, "AIF Concentration"); } else { concentrationNode = AddConcentrationImage(concentrationImage, "Concentration"); } } } if (AIFMode) { m_inputAIFImage = concentrationImage; m_inputAIFNode = concentrationNode; } else { m_inputImage = concentrationImage; m_inputNode = 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.mri/src/internal/MRPerfusionView.h b/Plugins/org.mitk.gui.qt.pharmacokinetics.mri/src/internal/MRPerfusionView.h index 2924dbeadb..ad27f0cb52 100644 --- a/Plugins/org.mitk.gui.qt.pharmacokinetics.mri/src/internal/MRPerfusionView.h +++ b/Plugins/org.mitk.gui.qt.pharmacokinetics.mri/src/internal/MRPerfusionView.h @@ -1,203 +1,205 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef MRPerfusionView_h #define MRPerfusionView_h #include #include "QmitkAbstractView.h" #include "itkCommand.h" #include "ui_MRPerfusionViewControls.h" #include "mitkModelBase.h" #include "QmitkParameterFitBackgroundJob.h" #include "mitkModelFitResultHelper.h" #include "mitkModelFactoryBase.h" #include "mitkLevenbergMarquardtModelFitFunctor.h" #include "mitkSimpleBarrierConstraintChecker.h" #include "mitkAIFBasedModelBase.h" /*! * @brief Test Plugin for SUV calculations of PET images */ class MRPerfusionView : public QmitkAbstractView { Q_OBJECT public: /*! @brief The view's unique ID - required by MITK */ static const std::string VIEW_ID; MRPerfusionView(); protected slots: void OnModellingButtonClicked(); void OnJobFinished(); void OnJobError(QString err); void OnJobResultsAreAvailable(mitk::modelFit::ModelFitResultNodeVectorType results, const ParameterFitBackgroundJob* pJob); void OnJobProgress(double progress); void OnJobStatusChanged(QString info); void OnModellSet(int); void LoadAIFfromFile(); /**Sets visibility and enabled state of the GUI depending on the settings and workflow state.*/ void UpdateGUIControls(); protected: typedef QList SelectedDataNodeVectorType; // Overridden base class functions /*! * @brief Sets up the UI controls and connects the slots and signals. Gets * called by the framework to create the GUI at the right time. * @param[in,out] parent The parent QWidget, as this class itself is not a QWidget * subclass. */ void CreateQtPartControl(QWidget* parent); /*! * @brief Sets the focus to the plot curve button. Gets called by the framework to set the * focus on the right widget. */ void SetFocus(); /*! @brief Generates a configured fit generator and the corresponding modelinfo for a descriptive brix model with pixel based strategy. * @remark add GenerateFunction for each model in the Combo box*/ void GenerateDescriptiveBrixModel_PixelBased(mitk::modelFit::ModelFitInfo::Pointer& modelFitInfo, mitk::ParameterFitImageGeneratorBase::Pointer& generator); void GenerateDescriptiveBrixModel_ROIBased(mitk::modelFit::ModelFitInfo::Pointer& modelFitInfo, mitk::ParameterFitImageGeneratorBase::Pointer& generator); void Generate3StepLinearModelFit_PixelBased(mitk::modelFit::ModelFitInfo::Pointer& modelFitInfo, mitk::ParameterFitImageGeneratorBase::Pointer& generator); void Generate3StepLinearModelFit_ROIBased(mitk::modelFit::ModelFitInfo::Pointer& modelFitInfo, mitk::ParameterFitImageGeneratorBase::Pointer& generator); template void GenerateAIFbasedModelFit_ROIBased(mitk::modelFit::ModelFitInfo::Pointer& modelFitInfo, mitk::ParameterFitImageGeneratorBase::Pointer& generator); template void GenerateAIFbasedModelFit_PixelBased(mitk::modelFit::ModelFitInfo::Pointer& modelFitInfo, mitk::ParameterFitImageGeneratorBase::Pointer& generator); /** Helper function that configures the initial parameter strategy of a parameterizer according to the settings of the GUI.*/ void ConfigureInitialParametersOfParameterizer(mitk::ModelParameterizerBase* parameterizer) const; /*! Starts the fitting job with the passed generator and session info*/ void DoFit(const mitk::modelFit::ModelFitInfo* fitSession, mitk::ParameterFitImageGeneratorBase* generator); /**Checks if the settings in the GUI are valid for the chosen model.*/ bool CheckModelSettings() const; void InitModelComboBox() const; /*! Helper method that adds an concentration image as child node to the current m_selectedNode and returns this new child node.*/ mitk::DataNode::Pointer AddConcentrationImage(mitk::Image* image, const std::string& nodeName) const; /*! \brief called by QmitkFunctionality when DataManager's selection has changed */ virtual void OnSelectionChanged(berry::IWorkbenchPart::Pointer source, const QList& selectedNodes); // Variables /*! @brief The view's UI controls */ Ui::MRPerfusionViewControls m_Controls; /* Nodes selected by user/ui for the fit */ mitk::DataNode::Pointer m_selectedNode; mitk::DataNode::Pointer m_selectedMaskNode; mitk::DataNode::Pointer m_selectedAIFMaskNode; mitk::DataNode::Pointer m_selectedAIFImageNode; /* Images selected by user/ui for the fit */ mitk::Image::Pointer m_selectedImage; mitk::Image::Pointer m_selectedMask; mitk::Image::Pointer m_selectedAIFMask; mitk::Image::Pointer m_selectedAIFImage; /* Node used for the fit (my be the selected image or converted ones (depending on the ui settings */ mitk::DataNode::Pointer m_inputNode; mitk::DataNode::Pointer m_inputAIFNode; /* Image used for the fit (my be the selected image or converted ones (depending on the ui settings */ mitk::Image::Pointer m_inputImage; mitk::Image::Pointer m_inputAIFImage; mitk::ModelFactoryBase::Pointer m_selectedModelFactory; mitk::SimpleBarrierConstraintChecker::Pointer m_modelConstraints; private: bool IsTurboFlashSequenceFlag() const; bool m_FittingInProgress; typedef std::vector ModelFactoryStackType; ModelFactoryStackType m_FactoryStack; /**Converts the selected image to a concentration image based on the given gui settings. AIFMode controls if the concentration image for the fit input or the AIF will be converted.*/ mitk::Image::Pointer ConvertConcentrationImage(bool AIFMode); /**Helper function that (depending on the gui settings) directly pass back the selected image/node or the newly generated concentration image/node. The result is always what should be used as input for the fitting. If AIFMode is true the function will generate the data for the AIF.*/ void GetConcentrationImage(mitk::Image::Pointer& concentrationImage, mitk::DataNode::Pointer& concentrationNode, bool AIFMode); /**Helper function that (depending on the gui settings) generates and passes back the AIF and its time grid that should be used for fitting. @remark the parameters aif and aifTimeGrid will be initialized accordingly if the method returns.*/ void GetAIF(mitk::AIFBasedModelBase::AterialInputFunctionType& aif, mitk::AIFBasedModelBase::AterialInputFunctionType& aifTimeGrid); /**Helper function that generates a default fitting functor * default is a levenberg marquart based optimizer with all scales set to 1.0. * Constraint setter will be set based on the gui setting and a evaluation parameter * "sum of squared differences" will always be set.*/ mitk::ModelFitFunctorBase::Pointer CreateDefaultFitFunctor(const mitk::ModelParameterizerBase* parameterizer) const; /**Returns the default fit name, derived from the current GUI settings.*/ std::string GetDefaultFitName() const; + /**Returns the current set name of the fit (either default name or use defined name).*/ + std::string GetFitName() const; std::vector AIFinputGrid; std::vector AIFinputFunction; mitk::NodePredicateBase::Pointer m_IsNoMaskImagePredicate; mitk::NodePredicateBase::Pointer m_IsMaskPredicate; }; #endif 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 63bcebd4dc..37d27c213b 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, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "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()) != NULL; bool isExt1TCMFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != NULL; bool isFDGCMFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != NULL; bool is2TCMFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != NULL || dynamic_cast (m_selectedModelFactory.GetPointer()) != NULL; 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 = NULL; 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 = NULL; mitk::modelFit::ModelFitInfo::Pointer fitSession = NULL; bool isOTCFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != NULL; bool isextOTCFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != NULL; bool isFDGFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != NULL; bool isTTCFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != NULL; bool isNumTTCFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != NULL; 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 = NULL; m_selectedMask = NULL; 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 = NULL; this->m_selectedImage = NULL; 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()) != NULL; bool isextOTCFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != NULL; bool isFDGFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != NULL; bool isTTCFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != NULL; bool isNumTTCFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != NULL; 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); } 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(), roiUID); + 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); //Create model info modelFitInfo = mitk::modelFit::CreateFitInfoFromModelParameterizer(modelParameterizer, - m_selectedNode->GetData(), mitk::ModelFitConstants::FIT_TYPE_VALUE_ROIBASED(), roiUID); + 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 - std::string fitName = m_Controls.lineFitName->text().toStdString(); - if (fitName.empty()) - { - fitName = m_Controls.lineFitName->placeholderText().toStdString(); - } - - ParameterFitBackgroundJob* pJob = new ParameterFitBackgroundJob(generator, fitSession, fitName, + 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 = NULL; m_selectedMask = NULL; mitk::ModelFactoryBase::Pointer factory = mitk::OneTissueCompartmentModelFactory::New().GetPointer(); m_FactoryStack.push_back(factory); factory = mitk::ExtendedOneTissueCompartmentModelFactory::New().GetPointer(); m_FactoryStack.push_back(factory); factory = mitk::TwoTissueCompartmentModelFactory::New().GetPointer(); m_FactoryStack.push_back(factory); factory = mitk::TwoTissueCompartmentFDGModelFactory::New().GetPointer(); m_FactoryStack.push_back(factory); factory = mitk::NumericTwoTissueCompartmentModelFactory::New().GetPointer(); m_FactoryStack.push_back(factory); mitk::NodePredicateDataType::Pointer isLabelSet = mitk::NodePredicateDataType::New("LabelSetImage"); mitk::NodePredicateDataType::Pointer isImage = mitk::NodePredicateDataType::New("Image"); mitk::NodePredicateProperty::Pointer isBinary = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); mitk::NodePredicateAnd::Pointer isLegacyMask = mitk::NodePredicateAnd::New(isImage, isBinary); mitk::NodePredicateOr::Pointer isMask = mitk::NodePredicateOr::New(isLegacyMask, isLabelSet); mitk::NodePredicateAnd::Pointer isNoMask = mitk::NodePredicateAnd::New(isImage, mitk::NodePredicateNot::New(isMask)); this->m_IsMaskPredicate = mitk::NodePredicateAnd::New(isMask, mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object"))).GetPointer(); this->m_IsNoMaskImagePredicate = mitk::NodePredicateAnd::New(isNoMask, mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object"))).GetPointer(); } void PETDynamicView::OnJobFinished() { this->m_Controls.infoBox->append(QString("Fitting finished")); this->m_FittingInProgress = false; }; void PETDynamicView::OnJobError(QString err) { MITK_ERROR << err.toStdString().c_str(); m_Controls.infoBox->append(QString("") + err + QString("")); }; void PETDynamicView::OnJobResultsAreAvailable(mitk::modelFit::ModelFitResultNodeVectorType results, const ParameterFitBackgroundJob* pJob) { //Store the resulting parameter fit image via convenience helper function in data storage //(handles the correct generation of the nodes and their properties) mitk::modelFit::StoreResultsInDataStorage(this->GetDataStorage(), results, pJob->GetParentNode()); m_Controls.errorMessageLabel->setText(""); m_Controls.errorMessageLabel->hide(); }; void PETDynamicView::OnJobProgress(double progress) { QString report = QString("Progress. ") + QString::number(progress); this->m_Controls.infoBox->append(report); }; void PETDynamicView::OnJobStatusChanged(QString info) { this->m_Controls.infoBox->append(info); } void PETDynamicView::InitModelComboBox() const { this->m_Controls.comboModel->clear(); this->m_Controls.comboModel->addItem(tr("No model selected")); for (ModelFactoryStackType::const_iterator pos = m_FactoryStack.begin(); pos != m_FactoryStack.end(); ++pos) { this->m_Controls.comboModel->addItem(QString::fromStdString((*pos)->GetClassID())); } this->m_Controls.comboModel->setCurrentIndex(0); }; mitk::ModelFitFunctorBase::Pointer PETDynamicView::CreateDefaultFitFunctor( const mitk::ModelParameterizerBase* parameterizer) const { mitk::LevenbergMarquardtModelFitFunctor::Pointer fitFunctor = mitk::LevenbergMarquardtModelFitFunctor::New(); mitk::SumOfSquaredDifferencesFitCostFunction::Pointer evaluation = mitk::SumOfSquaredDifferencesFitCostFunction::New(); fitFunctor->RegisterEvaluationParameter("sum_diff^2", evaluation); mitk::ChiSquareFitCostFunction::Pointer chi2 = mitk::ChiSquareFitCostFunction::New(); fitFunctor->RegisterEvaluationParameter("Chi^2", chi2); mitk::ReducedChiSquareFitCostFunction::Pointer redchi2 = mitk::ReducedChiSquareFitCostFunction::New(); fitFunctor->RegisterEvaluationParameter("redChi^2", redchi2); if (m_Controls.checkBox_Constraints->isChecked()) { fitFunctor->SetConstraintChecker(m_modelConstraints); } mitk::ModelBase::Pointer refModel = parameterizer->GenerateParameterizedModel(); ::itk::LevenbergMarquardtOptimizer::ScalesType scales; scales.SetSize(refModel->GetNumberOfParameters()); scales.Fill(1.0); fitFunctor->SetScales(scales); return fitFunctor.GetPointer(); } void PETDynamicView::GetAIF(mitk::AIFBasedModelBase::AterialInputFunctionType& aif, mitk::AIFBasedModelBase::AterialInputFunctionType& aifTimeGrid) { if (this->m_Controls.radioAIFFile->isChecked()) { aif.clear(); aifTimeGrid.clear(); aif.SetSize(AIFinputFunction.size()); aifTimeGrid.SetSize(AIFinputGrid.size()); aif.fill(0.0); aifTimeGrid.fill(0.0); itk::Array::iterator aifPos = aif.begin(); for (std::vector::const_iterator pos = AIFinputFunction.begin(); pos != AIFinputFunction.end(); ++pos, ++aifPos) { *aifPos = *pos; } itk::Array::iterator gridPos = aifTimeGrid.begin(); for (std::vector::const_iterator pos = AIFinputGrid.begin(); pos != AIFinputGrid.end(); ++pos, ++gridPos) { *gridPos = *pos; } } else if (this->m_Controls.radioAIFImage->isChecked()) { aif.clear(); aifTimeGrid.clear(); mitk::AterialInputFunctionGenerator::Pointer aifGenerator = mitk::AterialInputFunctionGenerator::New(); //Hematocrit level aifGenerator->SetHCL(this->m_Controls.HCLSpinBox->value()); //mask settings this->m_selectedAIFMaskNode = m_Controls.comboAIFMask->GetSelectedNode(); this->m_selectedAIFMask = dynamic_cast(this->m_selectedAIFMaskNode->GetData()); if (this->m_selectedAIFMask->GetTimeSteps() > 1) { MITK_INFO << "Selected AIF mask has multiple timesteps. Only use first timestep to mask model fit. AIF Mask name: " << m_selectedAIFMaskNode->GetName() ; mitk::ImageTimeSelector::Pointer maskedImageTimeSelector = mitk::ImageTimeSelector::New(); maskedImageTimeSelector->SetInput(this->m_selectedAIFMask); maskedImageTimeSelector->SetTimeNr(0); maskedImageTimeSelector->UpdateLargestPossibleRegion(); this->m_selectedAIFMask = maskedImageTimeSelector->GetOutput(); } if (this->m_selectedAIFMask.IsNotNull()) { aifGenerator->SetMask(this->m_selectedAIFMask); } //image settings if (this->m_Controls.checkDedicatedAIFImage->isChecked()) { this->m_selectedAIFImageNode = m_Controls.comboAIFImage->GetSelectedNode(); this->m_selectedAIFImage = dynamic_cast(this->m_selectedAIFImageNode->GetData()); } else { this->m_selectedAIFImageNode = m_selectedNode; this->m_selectedAIFImage = m_selectedImage; } aifGenerator->SetDynamicImage(this->m_selectedAIFImage); aif = aifGenerator->GetAterialInputFunction(); aifTimeGrid = aifGenerator->GetAterialInputFunctionTimeGrid(); } else { mitkThrow() << "Cannot generate AIF. View is in a invalide state. No AIF mode selected."; } } void PETDynamicView::LoadAIFfromFile() { QFileDialog dialog; dialog.setNameFilter(tr("Images (*.csv")); QString fileName = dialog.getOpenFileName(); m_Controls.aifFilePath->setText(fileName); std::string m_aifFilePath = fileName.toStdString(); //Read Input typedef boost::tokenizer< boost::escaped_list_separator > Tokenizer; ///////////////////////////////////////////////////////////////////////////////////////////////// //AIF Data std::ifstream in1(m_aifFilePath.c_str()); if (!in1.is_open()) { m_Controls.errorMessageLabel->setText("Could not open AIF File!"); } std::vector< std::string > vec1; std::string line1; while (getline(in1, line1)) { Tokenizer tok(line1); vec1.assign(tok.begin(), tok.end()); // if (vec1.size() < 3) continue; this->AIFinputGrid.push_back(convertToDouble(vec1[0])); this->AIFinputFunction.push_back(convertToDouble(vec1[1])); } } diff --git a/Plugins/org.mitk.gui.qt.pharmacokinetics.pet/src/internal/PETDynamicView.h b/Plugins/org.mitk.gui.qt.pharmacokinetics.pet/src/internal/PETDynamicView.h index 0e6ab0e70e..ababc97ded 100644 --- a/Plugins/org.mitk.gui.qt.pharmacokinetics.pet/src/internal/PETDynamicView.h +++ b/Plugins/org.mitk.gui.qt.pharmacokinetics.pet/src/internal/PETDynamicView.h @@ -1,174 +1,176 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef PETDynamicView_h #define PETDynamicView_h #include #include "QmitkAbstractView.h" #include "itkCommand.h" #include "ui_PETDynamicViewControls.h" #include "mitkModelBase.h" #include "QmitkParameterFitBackgroundJob.h" #include "mitkModelFitResultHelper.h" #include "mitkModelFactoryBase.h" #include "mitkLevenbergMarquardtModelFitFunctor.h" #include "mitkSimpleBarrierConstraintChecker.h" #include "mitkAIFBasedModelBase.h" /*! * @brief Test Plugin for SUV calculations of PET images */ class PETDynamicView : public QmitkAbstractView { Q_OBJECT public: /*! @brief The view's unique ID - required by MITK */ static const std::string VIEW_ID; PETDynamicView(); protected slots: void OnModellingButtonClicked(); void OnJobFinished(); void OnJobError(QString err); void OnJobResultsAreAvailable(mitk::modelFit::ModelFitResultNodeVectorType results, const ParameterFitBackgroundJob* pJob); void OnJobProgress(double progress); void OnJobStatusChanged(QString info); void OnModellSet(int); void LoadAIFfromFile(); // void OnModelSettingChanged(); void UpdateGUIControls(); protected: typedef QList SelectedDataNodeVectorType; // Overridden base class functions /*! * @brief Sets up the UI controls and connects the slots and signals. Gets * called by the framework to create the GUI at the right time. * @param[in,out] parent The parent QWidget, as this class itself is not a QWidget * subclass. */ void CreateQtPartControl(QWidget* parent); /*! * @brief Sets the focus to the plot curve button. Gets called by the framework to set the * focus on the right widget. */ void SetFocus(); /*! @brief Generates a configured fit generator and the corresponding modelinfo for a descriptive brix model with pixel based strategy. * @remark add GenerateFunction for each model in the Combo box*/ template void GenerateModelFit_ROIBased(mitk::modelFit::ModelFitInfo::Pointer& modelFitInfo, mitk::ParameterFitImageGeneratorBase::Pointer& generator); template void GenerateModelFit_PixelBased(mitk::modelFit::ModelFitInfo::Pointer& modelFitInfo, mitk::ParameterFitImageGeneratorBase::Pointer& generator); /** Helper function that configures the initial parameter strategy of a parameterizer according to the settings of the GUI.*/ void ConfigureInitialParametersOfParameterizer(mitk::ModelParameterizerBase* parameterizer) const; /*! Starts the fitting job with the passed generator and session info*/ void DoFit(const mitk::modelFit::ModelFitInfo* fitSession, mitk::ParameterFitImageGeneratorBase* generator); bool CheckModelSettings() const; void InitModelComboBox() const; /*! \brief called by QmitkFunctionality when DataManager's selection has changed */ virtual void OnSelectionChanged(berry::IWorkbenchPart::Pointer source, const QList& selectedNodes); /*! @brief The view's UI controls */ Ui::PETDynamicViewControls m_Controls; mitk::DataNode::Pointer m_selectedNode; mitk::DataNode::Pointer m_selectedMaskNode; mitk::DataNode::Pointer m_selectedAIFMaskNode; mitk::DataNode::Pointer m_selectedAIFImageNode; mitk::Image::Pointer m_selectedImage; mitk::Image::Pointer m_selectedMask; mitk::Image::Pointer m_selectedAIFMask; mitk::Image::Pointer m_selectedAIFImage; /* Node used for the fit (my be the selected image or converted ones (depending on the ui settings */ mitk::DataNode::Pointer m_inputNode; mitk::DataNode::Pointer m_inputAIFNode; /* Image used for the fit (my be the selected image or converted ones (depending on the ui settings */ mitk::Image::Pointer m_inputImage; mitk::Image::Pointer m_inputAIFImage; mitk::ModelFactoryBase::Pointer m_selectedModelFactory; mitk::SimpleBarrierConstraintChecker::Pointer m_modelConstraints; private: bool m_FittingInProgress; typedef std::vector ModelFactoryStackType; ModelFactoryStackType m_FactoryStack; /**Helper function that (depending on the gui settings) generates and passes back the AIF and its time grid that should be used for fitting. @remark the parameters aif and aifTimeGrid will be initialized accordingly if the method returns.*/ void GetAIF(mitk::AIFBasedModelBase::AterialInputFunctionType& aif, mitk::AIFBasedModelBase::AterialInputFunctionType& aifTimeGrid); /**Helper function that generates a default fitting functor * default is a levenberg marquart based optimizer with all scales set to 1.0. * Constraint setter will be set based on the gui setting and a evaluation parameter * "sum of squared differences" will always be set.*/ mitk::ModelFitFunctorBase::Pointer CreateDefaultFitFunctor(const mitk::ModelParameterizerBase* parameterizer) const; /**Returns the default fit name, derived from the current GUI settings.*/ std::string GetDefaultFitName() const; + /**Returns the current set name of the fit (either default name or use defined name).*/ + std::string GetFitName() const; std::vector AIFinputGrid; std::vector AIFinputFunction; mitk::NodePredicateBase::Pointer m_IsNoMaskImagePredicate; mitk::NodePredicateBase::Pointer m_IsMaskPredicate; }; #endif