diff --git a/Modules/Core/include/mitkImageAccessByItk.h b/Modules/Core/include/mitkImageAccessByItk.h index 4010d4e634..95bdee91d1 100644 --- a/Modules/Core/include/mitkImageAccessByItk.h +++ b/Modules/Core/include/mitkImageAccessByItk.h @@ -1,787 +1,785 @@ /*=================================================================== 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 MITKIMAGEACCESSBYITK_H_HEADER_INCLUDED #define MITKIMAGEACCESSBYITK_H_HEADER_INCLUDED #include #include #include #include #include #include #include #include #include #include namespace mitk { /** * \brief Exception class thrown in #AccessByItk macros. * * This exception can be thrown by the invocation of the #AccessByItk macros, * if the MITK image is of non-expected dimension or pixel type. * * \ingroup Adaptor */ class AccessByItkException : public virtual std::runtime_error { public: AccessByItkException(const std::string &msg) : std::runtime_error(msg) {} ~AccessByItkException() throw() override {} }; } // namespace mitk #ifndef DOXYGEN_SKIP #define _accessByItkPixelTypeException(pixelType, pixelTypeSeq) \ { \ std::string msg("Pixel type "); \ msg.append(pixelType.GetPixelTypeAsString()); \ msg.append(" is not in " BOOST_PP_STRINGIZE(pixelTypeSeq)); \ throw mitk::AccessByItkException(msg); \ } #define _accessByItkDimensionException(dim, validDims) \ { \ std::stringstream msg; \ msg << "Dimension " << (dim) << " is not in " << validDims; \ throw mitk::AccessByItkException(msg.str()); \ } #define _checkSpecificDimensionIter(r, mitkImage, dim) \ if (mitkImage->GetDimension() == dim) \ ; \ else #define _checkSpecificDimension(mitkImage, dimSeq) \ BOOST_PP_SEQ_FOR_EACH(_checkSpecificDimensionIter, mitkImage, dimSeq) \ _accessByItkDimensionException(mitkImage->GetDimension(), BOOST_PP_STRINGIZE(dimSeq)) #define _msvc_expand_bug(macro, arg) BOOST_PP_EXPAND(macro arg) //-------------------------------- 0-Arg Versions -------------------------------------- #define _accessByItk(itkImageTypeFunctionAndImageSeq, pixeltype, dimension) \ if (pixelType == mitk::MakePixelType(pixelType.GetNumberOfComponents()) && \ BOOST_PP_SEQ_TAIL(itkImageTypeFunctionAndImageSeq)->GetDimension() == dimension) \ { \ BOOST_PP_SEQ_HEAD(itkImageTypeFunctionAndImageSeq) \ (mitk::ImageToItkImage(BOOST_PP_SEQ_TAIL(itkImageTypeFunctionAndImageSeq)).GetPointer()); \ } \ else #define _accessByItkArgs(itkImageTypeFunction, type) (itkImageTypeFunction, BOOST_PP_TUPLE_REM(2) type) // product will be of the form ((itkImageTypeFunction)(mitkImage))(short)(2) for pixel type short and dimension 2 #ifdef _MSC_VER #define _accessByItkProductIter(r, product) \ _msvc_expand_bug(_accessByItk, \ _msvc_expand_bug(_accessByItkArgs, \ (BOOST_PP_SEQ_HEAD(product), BOOST_PP_SEQ_TO_TUPLE(BOOST_PP_SEQ_TAIL(product))))) #else #define _accessByItkProductIter(r, product) \ BOOST_PP_EXPAND( \ _accessByItk _accessByItkArgs(BOOST_PP_SEQ_HEAD(product), BOOST_PP_SEQ_TO_TUPLE(BOOST_PP_SEQ_TAIL(product)))) #endif #define _accessFixedTypeByItk(itkImageTypeFunction, mitkImage, pixelTypeSeq, dimSeq) \ BOOST_PP_SEQ_FOR_EACH_PRODUCT(_accessByItkProductIter, (((itkImageTypeFunction)(mitkImage)))(pixelTypeSeq)(dimSeq)) //-------------------------------- n-Arg Versions -------------------------------------- #define _accessByItk_n(itkImageTypeFunctionAndImageSeq, pixeltype, dimension, args) \ if (pixelType == mitk::MakePixelType(pixelType.GetNumberOfComponents()) && \ BOOST_PP_SEQ_TAIL(itkImageTypeFunctionAndImageSeq)->GetDimension() == dimension) \ { \ BOOST_PP_SEQ_HEAD(itkImageTypeFunctionAndImageSeq) \ (mitk::ImageToItkImage(BOOST_PP_SEQ_TAIL(itkImageTypeFunctionAndImageSeq)).GetPointer(), \ BOOST_PP_TUPLE_REM(BOOST_PP_SEQ_HEAD(args)) BOOST_PP_SEQ_TAIL(args)); \ } \ else #define _accessByItkArgs_n(itkImageTypeFunction, type, args) (itkImageTypeFunction, BOOST_PP_TUPLE_REM(2) type, args) // product will be of the form (((itkImageTypeFunction)(mitkImage))(3)(a,b,c))(short)(2) // for the variable argument list a,b,c and for pixel type short and dimension 2 #ifdef _MSC_VER #define _accessByItkProductIter_n(r, product) \ _msvc_expand_bug(_accessByItk_n, \ _msvc_expand_bug(_accessByItkArgs_n, \ (BOOST_PP_SEQ_HEAD(BOOST_PP_SEQ_HEAD(product)), \ BOOST_PP_SEQ_TO_TUPLE(BOOST_PP_SEQ_TAIL(product)), \ BOOST_PP_SEQ_TAIL(BOOST_PP_SEQ_HEAD(product))))) #else #define _accessByItkProductIter_n(r, product) \ BOOST_PP_EXPAND(_accessByItk_n _accessByItkArgs_n(BOOST_PP_SEQ_HEAD(BOOST_PP_SEQ_HEAD(product)), \ BOOST_PP_SEQ_TO_TUPLE(BOOST_PP_SEQ_TAIL(product)), \ BOOST_PP_SEQ_TAIL(BOOST_PP_SEQ_HEAD(product)))) #endif #define _accessFixedTypeByItk_n(itkImageTypeFunction, mitkImage, pixelTypeSeq, dimSeq, va_tuple) \ BOOST_PP_SEQ_FOR_EACH_PRODUCT( \ _accessByItkProductIter_n, \ ((((itkImageTypeFunction)(mitkImage))(MITK_PP_ARG_COUNT va_tuple)va_tuple))(pixelTypeSeq)(dimSeq)) #endif // DOXYGEN_SKIP /** * \brief Access a MITK image by an ITK image * * Define a templated function or method (\a itkImageTypeFunction) * within which the mitk-image (\a mitkImage) is accessed: * \code * template < typename TPixel, unsigned int VImageDimension > * void ExampleFunction( itk::Image* itkImage ); * \endcode * * The itk::Image passed to the function/method has the same * data-pointer as the mitk-image. Depending on the const-ness of the * \c mitkImage, your templated access function needs to take a const or * non-const itk::Image pointer and you will get read-only or full read/write * access to the data vector of the mitk-image using the itk-image. * * Example code using the access function above: * \code * mitk::Image* inputMitkImage = ... * try * { * AccessByItk(inputMitkImage, ExampleFunction); * } * catch (const mitk::AccessByItkException& e) * { * // mitk::Image is of wrong pixel type or dimension, * // insert error handling here * } * \endcode * * \param mitkImage The MITK input image. * \param itkImageTypeFunction The templated access-function to be called. * * \throws mitk::AccessByItkException If mitkImage is of unsupported pixel type or dimension. * * \note If your inputMitkImage is an mitk::Image::Pointer, use * inputMitkImage.GetPointer() * \note If you need to pass additional parameters to your * access-function (\a itkImageTypeFunction), use #AccessByItk_n. * \note If you know the dimension of your input mitk-image, * it is better to use AccessFixedDimensionByItk (less code * is generated). * \sa AccessFixedDimensionByItk * \sa AccessFixedTypeByItk * \sa AccessFixedPixelTypeByItk * \sa AccessByItk_n * * \ingroup Adaptor */ #define AccessByItk(mitkImage, itkImageTypeFunction) \ AccessFixedTypeByItk( \ mitkImage, itkImageTypeFunction, MITK_ACCESSBYITK_PIXEL_TYPES_SEQ, MITK_ACCESSBYITK_DIMENSIONS_SEQ) /** * \brief Access a mitk-image with known pixeltype (but unknown dimension) by an itk-image. * * For usage, see #AccessByItk. * * \param pixelTypeSeq A sequence of pixel types, like (short)(char)(int) * \param mitkImage The MITK input image. * \param itkImageTypeFunction The templated access-function to be called. * * \throws mitk::AccessByItkException If mitkImage is of unsupported pixel type or dimension. * * If the image has a different pixel type, a mitk::AccessByItkException exception is * thrown. If you do not know the pixel type for sure, use #AccessByItk. * * \sa AccessByItk * \sa AccessFixedDimensionByItk * \sa AccessFixedTypeByItk * \sa AccessFixedPixelTypeByItk_n * * \ingroup Adaptor */ #define AccessFixedPixelTypeByItk(mitkImage, itkImageTypeFunction, pixelTypeSeq) \ AccessFixedTypeByItk(mitkImage, itkImageTypeFunction, pixelTypeSeq, MITK_ACCESSBYITK_DIMENSIONS_SEQ) /** * \brief Access a mitk-image with an integral pixel type by an itk-image * * See #AccessByItk for details. * * \param mitkImage The MITK input image. * \param itkImageTypeFunction The templated access-function to be called. * * \throws mitk::AccessByItkException If mitkImage is of unsupported pixel type or dimension. * * \sa AccessFixedPixelTypeByItk * \sa AccessByItk * \sa AccessIntegralPixelTypeByItk_n */ #define AccessIntegralPixelTypeByItk(mitkImage, itkImageTypeFunction) \ AccessFixedTypeByItk( \ mitkImage, itkImageTypeFunction, MITK_ACCESSBYITK_INTEGRAL_PIXEL_TYPES_SEQ, MITK_ACCESSBYITK_DIMENSIONS_SEQ) /** * \brief Access a mitk-image with a floating point pixel type by an ITK image * * See #AccessByItk for details. * * \param mitkImage The MITK input image. * \param itkImageTypeFunction The templated access-function to be called. * * \throws mitk::AccessByItkException If mitkImage is of unsupported pixel type or dimension. * * \sa AccessFixedPixelTypeByItk * \sa AccessByItk * \sa AccessFloatingPixelTypeByItk_n */ #define AccessFloatingPixelTypeByItk(mitkImage, itkImageTypeFunction) \ AccessFixedTypeByItk( \ mitkImage, itkImageTypeFunction, MITK_ACCESSBYITK_FLOATING_PIXEL_TYPES_SEQ, MITK_ACCESSBYITK_DIMENSIONS_SEQ) #define AccessVectorPixelTypeByItk(mitkImage, itkImageTypeFunction) \ AccessFixedTypeByItk( \ mitkImage, itkImageTypeFunction, MITK_ACCESSBYITK_VECTOR_PIXEL_TYPES_SEQ, MITK_ACCESSBYITK_DIMENSIONS_SEQ) /** * \brief Access a mitk-image with known dimension by an itk-image * * For usage, see #AccessByItk. * * \param dimension Dimension of the mitk-image. If the image has a different dimension, * a mitk::AccessByItkException exception is thrown. * \param mitkImage The MITK input image. * \param itkImageTypeFunction The templated access-function to be called. * * \throws mitk::AccessByItkException If mitkImage is of unsupported pixel type or dimension. * * \note If you do not know the dimension for sure, use #AccessByItk. * * \sa AccessByItk * \sa AccessFixedDimensionByItk_n * \sa AccessFixedTypeByItk * \sa AccessFixedPixelTypeByItk * * \ingroup Adaptor */ #define AccessFixedDimensionByItk(mitkImage, itkImageTypeFunction, dimension) \ AccessFixedTypeByItk(mitkImage, itkImageTypeFunction, MITK_ACCESSBYITK_PIXEL_TYPES_SEQ, (dimension)) #define AccessVectorFixedDimensionByItk(mitkImage, itkImageTypeFunction, dimension) \ AccessFixedTypeByItk(mitkImage, itkImageTypeFunction, MITK_ACCESSBYITK_VECTOR_PIXEL_TYPES_SEQ, (dimension)) /** * \brief Access a mitk-image with known type (pixel type and dimension) by an itk-image. * * The provided mitk-image must be in the set of types created by taking the * cartesian product of the pixel type sequence and the dimension sequence. * For example, a call to * \code * AccessFixedTypeByItk(myMitkImage, MyAccessFunction, (short)(int), (2)(3)) * \endcode * asserts that the type of myMitkImage (pixeltype,dim) is in the set {(short,2),(short,3),(int,2),(int,3)}. * For more information, see #AccessByItk. * * \param pixelTypeSeq A sequence of pixel types, like (short)(char)(int). * \param dimSeq A sequence of dimensions, like (2)(3). * \param mitkImage The MITK input image. * \param itkImageTypeFunction The templated access-function to be called. * * \throws mitk::AccessByItkException If mitkImage is of unsupported pixel type or dimension. * * If the image has a different dimension or pixel type, * a mitk::AccessByItkException exception is thrown. * * \note If you do not know the dimension for sure, use #AccessByItk. * * \sa AccessByItk * \sa AccessFixedDimensionByItk * \sa AccessFixedTypeByItk_n * \sa AccessFixedPixelTypeByItk * * \ingroup Adaptor */ #define AccessFixedTypeByItk(mitkImage, itkImageTypeFunction, pixelTypeSeq, dimSeq) \ \ { \ const mitk::PixelType &pixelType = mitkImage->GetPixelType(); \ _checkSpecificDimension(mitkImage, dimSeq); \ _accessFixedTypeByItk(itkImageTypeFunction, mitkImage, pixelTypeSeq, dimSeq) \ _accessByItkPixelTypeException(mitkImage->GetPixelType(), pixelTypeSeq) \ } //------------------------------ n-Arg Access Macros ----------------------------------- /** * \brief Access a MITK image by an ITK image with one or more parameters. * * Define a templated function or method (\a itkImageTypeFunction) with one ore more * additional parameters, within which the mitk-image (\a mitkImage) is accessed: * \code * template < typename TPixel, unsigned int VImageDimension > * void ExampleFunction( itk::Image* itkImage, SomeType param); * \endcode * * The itk::Image passed to the function/method has the same * data-pointer as the mitk-image. So you have full read- and write- * access to the data vector of the mitk-image using the itk-image. * Call by: * \code * SomeType param = ... * mitk::Image* inputMitkImage = ... * try * { * AccessByItk_n(inputMitkImage, ExampleFunction, (param)); * } * catch (const mitk::AccessByItkException& e) * { * // mitk::Image is of wrong pixel type or dimension, * // insert error handling here * } * \endcode * * \param va_tuple A variable length tuple containing the arguments to be passed * to the access function itkImageTypeFunction, e.g. ("first", 2, THIRD). * \param mitkImage The MITK input image. * \param itkImageTypeFunction The templated access-function to be called. * * \throws mitk::AccessByItkException If mitkImage is of unsupported pixel type or dimension. * * \note If your inputMitkImage is an mitk::Image::Pointer, use * inputMitkImage.GetPointer() * \note If you know the dimension of your input mitk-image, * it is better to use AccessFixedDimensionByItk_n (less code * is generated). * \sa AccessFixedDimensionByItk_n * \sa AccessFixedTypeByItk_n * \sa AccessFixedPixelTypeByItk_n * \sa AccessByItk * * \ingroup Adaptor */ #define AccessByItk_n(mitkImage, itkImageTypeFunction, va_tuple) \ AccessFixedTypeByItk_n( \ mitkImage, itkImageTypeFunction, MITK_ACCESSBYITK_PIXEL_TYPES_SEQ, MITK_ACCESSBYITK_DIMENSIONS_SEQ, va_tuple) /** * \brief Access a mitk-image with known pixeltype (but unknown dimension) by an itk-image * with one or more parameters. * * For usage, see #AccessByItk_n. * * \param va_tuple A variable length tuple containing the arguments to be passed * to the access function itkImageTypeFunction, e.g. ("first", 2, THIRD). * \param pixelTypeSeq A sequence of pixel types, like (short)(char)(int). * \param mitkImage The MITK input image. * \param itkImageTypeFunction The templated access-function to be called. * * \throws mitk::AccessByItkException If mitkImage is of unsupported pixel type or dimension. * * If the image has a different pixel type, a mitk::AccessByItkException exception is * thrown. If you do not know the pixel type for sure, use #AccessByItk_n. * * \sa AccessByItk_n * \sa AccessFixedDimensionByItk_n * \sa AccessFixedTypeByItk_n * \sa AccessFixedPixelTypeByItk * * \ingroup Adaptor */ #define AccessFixedPixelTypeByItk_n(mitkImage, itkImageTypeFunction, pixelTypeSeq, va_tuple) \ AccessFixedTypeByItk_n(mitkImage, itkImageTypeFunction, pixelTypeSeq, MITK_ACCESSBYITK_DIMENSIONS_SEQ, va_tuple) /** * \brief Access an mitk::Image with an integral pixel type by an ITK image with * one or more parameters. * * See #AccessByItk_n for details. * * \param va_tuple A variable length tuple containing the arguments to be passed * to the access function itkImageTypeFunction, e.g. ("first", 2, THIRD). * \param mitkImage The MITK input image. * \param itkImageTypeFunction The templated access-function to be called. * * \throws mitk::AccessByItkException If mitkImage is of unsupported pixel type or dimension. * * \sa AccessFixedPixelTypeByItk_n * \sa AccessByItk_n * \sa AccessIntegralPixelTypeByItk */ #define AccessIntegralPixelTypeByItk_n(mitkImage, itkImageTypeFunction, va_tuple) \ AccessFixedTypeByItk_n(mitkImage, \ itkImageTypeFunction, \ MITK_ACCESSBYITK_INTEGRAL_PIXEL_TYPES_SEQ, \ MITK_ACCESSBYITK_DIMENSIONS_SEQ, \ va_tuple) /** * \brief Access an mitk::Image with a floating point pixel type by an ITK image * with one or more parameters. * * See #AccessByItk_n for details. * * \param va_tuple A variable length tuple containing the arguments to be passed * to the access function itkImageTypeFunction, e.g. ("first", 2, THIRD). * \param mitkImage The MITK input image. * \param itkImageTypeFunction The templated access-function to be called. * * \throws mitk::AccessByItkException If mitkImage is of unsupported pixel type or dimension. * * \sa AccessFixedPixelTypeByItk_n * \sa AccessByItk_n * \sa AccessFloatingPixelTypeByItk */ #define AccessFloatingPixelTypeByItk_n(mitkImage, itkImageTypeFunction, va_tuple) \ AccessFixedTypeByItk_n(mitkImage, \ itkImageTypeFunction, \ MITK_ACCESSBYITK_FLOATING_PIXEL_TYPES_SEQ, \ MITK_ACCESSBYITK_DIMENSIONS_SEQ, \ va_tuple) /** * \brief Access a vector mitk::Image by an ITK vector image with one or more parameters. * * See #AccessByItk_n for details. * * \param va_tuple A variable length tuple containing the arguments to be passed * to the access function itkImageTypeFunction, e.g. ("first", 2, THIRD). * \param mitkImage The MITK input image. * \param itkImageTypeFunction The templated access-function to be called. * * \throws mitk::AccessByItkException If mitkImage is of unsupported pixel type or dimension. * * \sa AccessFixedPixelTypeByItk_n * \sa AccessByItk_n */ #define AccessVectorPixelTypeByItk_n(mitkImage, itkImageTypeFunction, va_tuple) \ AccessFixedTypeByItk_n(mitkImage, \ itkImageTypeFunction, \ MITK_ACCESSBYITK_VECTOR_PIXEL_TYPES_SEQ, \ MITK_ACCESSBYITK_DIMENSIONS_SEQ, \ va_tuple) /** * \brief Access a mitk-image with known dimension by an itk-image with * one or more parameters. * * For usage, see #AccessByItk_n. * * \param dimension Dimension of the mitk-image. If the image has a different dimension, * a mitk::AccessByItkException exception is thrown. * \param va_tuple A variable length tuple containing the arguments to be passed * to the access function itkImageTypeFunction, e.g. ("first", 2, THIRD). * \param mitkImage The MITK input image. * \param itkImageTypeFunction The templated access-function to be called. * * \throws mitk::AccessByItkException If mitkImage is of unsupported pixel type or dimension. * * \note If you do not know the dimension for sure, use #AccessByItk_n. * * \sa AccessByItk_n * \sa AccessFixedDimensionByItk * \sa AccessFixedTypeByItk_n * \sa AccessFixedPixelTypeByItk_n * * \ingroup Adaptor */ #define AccessFixedDimensionByItk_n(mitkImage, itkImageTypeFunction, dimension, va_tuple) \ AccessFixedTypeByItk_n(mitkImage, itkImageTypeFunction, MITK_ACCESSBYITK_PIXEL_TYPES_SEQ, (dimension), va_tuple) /** * \brief Access a vector mitk-image with known dimension by a ITK vector image with * one or more parameters. * * For usage, see #AccessByItk_n. * * \param dimension Dimension of the mitk-image. If the image has a different dimension, * a mitk::AccessByItkException exception is thrown. * \param va_tuple A variable length tuple containing the arguments to be passed * to the access function itkImageTypeFunction, e.g. ("first", 2, THIRD). * \param mitkImage The MITK input image. * \param itkImageTypeFunction The templated access-function to be called. * * \throws mitk::AccessByItkException If mitkImage is of unsupported pixel type or dimension. * * \note If you do not know the dimension for sure, use #AccessVectorPixelTypeByItk_n. * * \sa AccessByItk_n * \sa AccessVectorPixelTypeByItk_n * \sa AccessFixedTypeByItk_n * * \ingroup Adaptor */ #define AccessVectorFixedDimensionByItk_n(mitkImage, itkImageTypeFunction, dimension, va_tuple) \ AccessFixedTypeByItk_n( \ mitkImage, itkImageTypeFunction, MITK_ACCESSBYITK_VECTOR_PIXEL_TYPES_SEQ, (dimension), va_tuple) /** * \brief Access a mitk-image with known type (pixel type and dimension) by an itk-image * with one or more parameters. * * For usage, see AccessFixedTypeByItk. * * \param pixelTypeSeq A sequence of pixel types, like (short)(char)(int). * \param dimSeq A sequence of dimensions, like (2)(3). * \param va_tuple A variable length tuple containing the arguments to be passed * to the access function itkImageTypeFunction, e.g. ("first", 2, THIRD). * \param mitkImage The MITK input image. * \param itkImageTypeFunction The templated access-function to be called. * * \throws mitk::AccessByItkException If mitkImage is of unsupported pixel type or dimension. * * If the image has a different dimension or pixel type, * a mitk::AccessByItkException exception is thrown. * * \note If you do not know the dimension for sure, use #AccessByItk_n. * * \sa AccessByItk_n * \sa AccessFixedDimensionByItk_n * \sa AccessFixedTypeByItk * \sa AccessFixedPixelTypeByItk_n * * \ingroup Adaptor */ #define AccessFixedTypeByItk_n(mitkImage, itkImageTypeFunction, pixelTypeSeq, dimSeq, va_tuple) \ \ { \ const mitk::PixelType &pixelType = mitkImage->GetPixelType(); \ _checkSpecificDimension(mitkImage, dimSeq); \ _accessFixedTypeByItk_n(itkImageTypeFunction, mitkImage, pixelTypeSeq, dimSeq, va_tuple) \ _accessByItkPixelTypeException(mitkImage->GetPixelType(), pixelTypeSeq) \ } //------------------------- For back-wards compatibility ------------------------------- #define AccessByItk_1(mitkImage, itkImageTypeFunction, arg1) AccessByItk_n(mitkImage, itkImageTypeFunction, (arg1)) #define AccessFixedPixelTypeByItk_1(mitkImage, itkImageTypeFunction, pixelTypeSeq, arg1) \ AccessFixedPixelTypeByItk_n(mitkImage, itkImageTypeFunction, pixelTypeSeq, (arg1)) #define AccessFixedDimensionByItk_1(mitkImage, itkImageTypeFunction, dimension, arg1) \ AccessFixedDimensionByItk_n(mitkImage, itkImageTypeFunction, dimension, (arg1)) #define AccessFixedTypeByItk_1(mitkImage, itkImageTypeFunction, pixelTypeSeq, dimSeq, arg1) \ AccessFixedTypeByItk_n(mitkImage, itkImageTypeFunction, pixelTypeSeq, dimSeq, (arg1)) #define AccessByItk_2(mitkImage, itkImageTypeFunction, arg1, arg2) \ AccessByItk_n(mitkImage, itkImageTypeFunction, (arg1, arg2)) #define AccessFixedPixelTypeByItk_2(mitkImage, itkImageTypeFunction, pixelTypeSeq, arg1, arg2) \ AccessFixedPixelTypeByItk_n(mitkImage, itkImageTypeFunction, pixelTypeSeq, (arg1, arg2)) #define AccessFixedDimensionByItk_2(mitkImage, itkImageTypeFunction, dimension, arg1, arg2) \ AccessFixedDimensionByItk_n(mitkImage, itkImageTypeFunction, dimension, (arg1, arg2)) #define AccessFixedTypeByItk_2(mitkImage, itkImageTypeFunction, pixelTypeSeq, dimSeq, arg1, arg2) \ AccessFixedTypeByItk_n(mitkImage, itkImageTypeFunction, pixelTypeSeq, dimSeq, (arg1, arg2)) #define AccessByItk_3(mitkImage, itkImageTypeFunction, arg1, arg2, arg3) \ AccessByItk_n(mitkImage, itkImageTypeFunction, (arg1, arg2, arg3)) #define AccessFixedPixelTypeByItk_3(mitkImage, itkImageTypeFunction, pixelTypeSeq, arg1, arg2, arg3) \ AccessFixedPixelTypeByItk_n(mitkImage, itkImageTypeFunction, pixelTypeSeq, (arg1, arg2, arg3)) #define AccessFixedDimensionByItk_3(mitkImage, itkImageTypeFunction, dimension, arg1, arg2, arg3) \ AccessFixedDimensionByItk_n(mitkImage, itkImageTypeFunction, dimension, (arg1, arg2, arg3)) #define AccessFixedTypeByItk_3(mitkImage, itkImageTypeFunction, pixelTypeSeq, dimSeq, arg1, arg2, arg3) \ AccessFixedTypeByItk_n(mitkImage, itkImageTypeFunction, pixelTypeSeq, dimSeq, (arg1, arg2, arg3)) //----------------------------- Access two MITK Images --------------------------------- #ifndef DOXYGEN_SKIP #define _accessTwoImagesByItk(itkImageTypeFunction, pixeltype1, dim1, pixeltype2, dim2) \ if (pixelType1 == mitk::MakePixelType>() && \ pixelType2 == mitk::MakePixelType>() && constImage1->GetDimension() == dim1 && \ constImage2->GetDimension() == dim2) \ { \ typedef itk::Image ImageType1; \ typedef itk::Image ImageType2; \ typedef mitk::ImageToItk ImageToItkType1; \ typedef mitk::ImageToItk ImageToItkType2; \ itk::SmartPointer imagetoitk1 = ImageToItkType1::New(); \ imagetoitk1->SetInput(nonConstImage1); \ imagetoitk1->Update(); \ itk::SmartPointer imagetoitk2 = ImageToItkType2::New(); \ imagetoitk2->SetInput(nonConstImage2); \ imagetoitk2->Update(); \ itkImageTypeFunction(imagetoitk1->GetOutput(), imagetoitk2->GetOutput()); \ } \ else #define _accessTwoImagesByItk_n(itkImageTypeFunction, args, pixeltype1, dim1, pixeltype2, dim2) \ if (pixelType1 == mitk::MakePixelType>() && \ pixelType2 == mitk::MakePixelType>() && constImage1->GetDimension() == dim1 && \ constImage2->GetDimension() == dim2) \ { \ typedef itk::Image ImageType1; \ typedef itk::Image ImageType2; \ typedef mitk::ImageToItk ImageToItkType1; \ typedef mitk::ImageToItk ImageToItkType2; \ itk::SmartPointer imagetoitk1 = ImageToItkType1::New(); \ imagetoitk1->SetInput(nonConstImage1); \ imagetoitk1->Update(); \ itk::SmartPointer imagetoitk2 = ImageToItkType2::New(); \ imagetoitk2->SetInput(nonConstImage2); \ imagetoitk2->Update(); \ itkImageTypeFunction( \ imagetoitk1->GetOutput(), imagetoitk2->GetOutput(), BOOST_PP_TUPLE_REM(MITK_PP_ARG_COUNT args) args); \ } \ else //itkImageTypeFunction(imagetoitk1->GetOutput(), imagetoitk2->GetOutput(), args); \ //BOOST_PP_TUPLE_REM(MITK_PP_ARG_COUNT args) args, #define _accessTwoImagesByItkArgs2(itkImageTypeFunction, type1, type2) \ (itkImageTypeFunction, BOOST_PP_TUPLE_REM(2) type1, BOOST_PP_TUPLE_REM(2) type2) #define _accessTwoImagesByItkArgs2_n(itkImageTypeFunction, args, type1, type2) \ (itkImageTypeFunction, BOOST_PP_TUPLE_REM(1) args, BOOST_PP_TUPLE_REM(2) type1, BOOST_PP_TUPLE_REM(2) type2) #define _accessTwoImagesByItkArgs(product) \ BOOST_PP_EXPAND(_accessTwoImagesByItkArgs2 BOOST_PP_EXPAND( \ (BOOST_PP_SEQ_HEAD(product), BOOST_PP_TUPLE_REM(2) BOOST_PP_SEQ_TO_TUPLE(BOOST_PP_SEQ_TAIL(product))))) #define _accessTwoImagesByItkArgs_n(product) \ BOOST_PP_EXPAND(_accessTwoImagesByItkArgs2_n BOOST_PP_EXPAND((BOOST_PP_SEQ_HEAD(BOOST_PP_SEQ_HEAD(product)), \ BOOST_PP_SEQ_TAIL(BOOST_PP_SEQ_HEAD(product)), \ BOOST_PP_TUPLE_REM(2) \ BOOST_PP_SEQ_TO_TUPLE(BOOST_PP_SEQ_TAIL(product))))) // product is of the form (itkImageTypeFunction)((short,2))((char,2)) #ifdef _MSC_VER #define _accessTwoImagesByItkIter(r, product) \ BOOST_PP_EXPAND(_accessTwoImagesByItk _msvc_expand_bug( \ _accessTwoImagesByItkArgs2, \ (BOOST_PP_SEQ_HEAD(product), \ _msvc_expand_bug(BOOST_PP_TUPLE_REM(2), BOOST_PP_EXPAND(BOOST_PP_SEQ_TO_TUPLE(BOOST_PP_SEQ_TAIL(product))))))) #else #define _accessTwoImagesByItkIter(r, product) BOOST_PP_EXPAND(_accessTwoImagesByItk _accessTwoImagesByItkArgs(product)) #endif // product is of the form (((itkImageTypeFunction)(1)))((short,2))((char,2)) #ifdef _MSC_VER #define _accessTwoImagesByItkIter_n(r, product) \ BOOST_PP_EXPAND(_accessTwoImagesByItk_n _msvc_expand_bug( \ _accessTwoImagesByItkArgs2_n, \ (BOOST_PP_SEQ_HEAD(BOOST_PP_SEQ_HEAD(product)), \ BOOST_PP_SEQ_TAIL(BOOST_PP_SEQ_HEAD(product)), \ _msvc_expand_bug(BOOST_PP_TUPLE_REM(2), BOOST_PP_EXPAND(BOOST_PP_SEQ_TO_TUPLE(BOOST_PP_SEQ_TAIL(product))))))) \ #else #define _accessTwoImagesByItkIter_n(r, product) \ BOOST_PP_EXPAND(_accessTwoImagesByItk_n _accessTwoImagesByItkArgs_n(product)) #endif #define _accessTwoImagesByItkForEach(itkImageTypeFunction, tseq1, tseq2) \ BOOST_PP_SEQ_FOR_EACH_PRODUCT(_accessTwoImagesByItkIter, ((itkImageTypeFunction))(tseq1)(tseq2)) #define _accessTwoImagesByItkForEach_n(itkImageTypeFunction, tseq1, tseq2, va_tuple) \ BOOST_PP_SEQ_FOR_EACH_PRODUCT(_accessTwoImagesByItkIter_n, (((itkImageTypeFunction) (va_tuple)))(tseq1)(tseq2)) #endif // DOXYGEN_SKIP /** * \brief Access two mitk-images with known dimension by itk-images * * Define a templated function or method (\a itkImageTypeFunction) * within which the mitk-images (\a mitkImage1 and \a mitkImage2) are accessed: * \code * template * void ExampleFunctionTwoImages(itk::Image* itkImage1, itk::Image* itkImage2); * \endcode * * The itk::Image passed to the function/method has the same * data-pointer as the mitk-image. So you have full read- and write- * access to the data vector of the mitk-image using the itk-image. * Call by: * \code * mitk::Image* inputMitkImage1 = ... * mitk::Image* inputMitkImage2 = ... * try * { * AccessTwoImagesFixedDimensionByItk(inputMitkImage1, inputMitkImage2, ExampleFunctionTwoImages, 3); * } * catch (const mitk::AccessByItkException& e) * { * // mitk::Image arguments are of wrong pixel type or dimension, * // insert error handling here * } * \endcode * * \note If your inputMitkImage1 or inputMitkImage2 is a mitk::Image::Pointer, use * inputMitkImage1.GetPointer(). * * \param mitkImage1 The first MITK input image. * \param mitkImage1 The second MITK input image. * \param itkImageTypeFunction The name of the template access-function to be called. * \param dimension Dimension of the two mitk-images. * * \throws mitk::AccessByItkException If mitkImage1 and mitkImage2 have different dimensions or * one of the images is of unsupported pixel type or dimension. * * \sa #AccessByItk * * \ingroup Adaptor */ #define AccessTwoImagesFixedDimensionByItk(mitkImage1, mitkImage2, itkImageTypeFunction, dimension) \ \ { \ const mitk::PixelType &pixelType1 = mitkImage1->GetPixelType(); \ const mitk::PixelType &pixelType2 = mitkImage2->GetPixelType(); \ const mitk::Image *constImage1 = mitkImage1; \ const mitk::Image *constImage2 = mitkImage2; \ mitk::Image *nonConstImage1 = const_cast(constImage1); \ mitk::Image *nonConstImage2 = const_cast(constImage2); \ nonConstImage1->Update(); \ nonConstImage2->Update(); \ _checkSpecificDimension(mitkImage1, (dimension)); \ _checkSpecificDimension(mitkImage2, (dimension)); \ _accessTwoImagesByItkForEach( \ itkImageTypeFunction, MITK_ACCESSBYITK_TYPES_DIMN_SEQ(dimension), MITK_ACCESSBYITK_TYPES_DIMN_SEQ(dimension)) \ { \ std::string msg("Pixel type "); \ msg.append(pixelType1.GetComponentTypeAsString()); \ msg.append(" or pixel type "); \ msg.append(pixelType2.GetComponentTypeAsString()); \ msg.append(" is not in " BOOST_PP_STRINGIZE(MITK_ACCESSBYITK_TYPES_DIMN_SEQ(dimension))); \ throw mitk::AccessByItkException(msg); \ } \ } #define AccessTwoImagesFixedDimensionByItk_n(mitkImage1, mitkImage2, itkImageTypeFunction, dimension, va_tuple) \ \ { \ const mitk::PixelType &pixelType1 = mitkImage1->GetPixelType(); \ const mitk::PixelType &pixelType2 = mitkImage2->GetPixelType(); \ const mitk::Image *constImage1 = mitkImage1; \ const mitk::Image *constImage2 = mitkImage2; \ mitk::Image *nonConstImage1 = const_cast(constImage1); \ mitk::Image *nonConstImage2 = const_cast(constImage2); \ - MITK_INFO << "va_tuple elem 0: " << BOOST_PP_TUPLE_ELEM(0, va_tuple); \ - MITK_INFO << "va_tuple elem 1: " << BOOST_PP_TUPLE_ELEM(1, va_tuple); \ nonConstImage1->Update(); \ nonConstImage2->Update(); \ _checkSpecificDimension(mitkImage1, (dimension)); \ _checkSpecificDimension(mitkImage2, (dimension)); \ _accessTwoImagesByItkForEach_n(itkImageTypeFunction, \ MITK_ACCESSBYITK_TYPES_DIMN_SEQ(dimension), \ MITK_ACCESSBYITK_TYPES_DIMN_SEQ(dimension), \ va_tuple) \ { \ std::string msg("Pixel type "); \ msg.append(pixelType1.GetComponentTypeAsString()); \ msg.append(" or pixel type "); \ msg.append(pixelType2.GetComponentTypeAsString()); \ msg.append(" is not in " BOOST_PP_STRINGIZE(MITK_ACCESSBYITK_TYPES_DIMN_SEQ(dimension))); \ throw mitk::AccessByItkException(msg); \ - } \ + } \ } #endif // of MITKIMAGEACCESSBYITK_H_HEADER_INCLUDED 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 0cfbfc8f56..b0a8f2af00 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,1400 +1,1399 @@ /*=================================================================== 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/math/constants/constants.hpp" #include "boost/tokenizer.hpp" #include #include "mitkWorkbenchUtil.h" #include "mitkAterialInputFunctionGenerator.h" #include "mitkConcentrationCurveGenerator.h" #include "mitkNumericTwoCompartmentExchangeModelFactory.h" #include "mitkNumericTwoCompartmentExchangeModelParameterizer.h" #include "mitkThreeStepLinearModelFactory.h" #include "mitkThreeStepLinearModelParameterizer.h" #include "mitkTwoCompartmentExchangeModelFactory.h" #include "mitkTwoCompartmentExchangeModelParameterizer.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 #include #include // Includes for image casting between ITK and MITK #include "mitkITKImageImport.h" #include "mitkImageCast.h" #include #include #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(), 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(), 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(), 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(), 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(), 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(), 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 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> 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 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(); }