diff --git a/Modules/BasicImageProcessing/include/mitkTransformationOperation.h b/Modules/BasicImageProcessing/include/mitkTransformationOperation.h index ffdf369bde..da75c42d7c 100644 --- a/Modules/BasicImageProcessing/include/mitkTransformationOperation.h +++ b/Modules/BasicImageProcessing/include/mitkTransformationOperation.h @@ -1,67 +1,79 @@ /*=================================================================== 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 mitkArithmeticOperation_h #define mitkArithmeticOperation_h #include #include #include namespace mitk { enum BorderCondition { Constant, Periodic, ZeroFluxNeumann }; enum WaveletType { Held, Vow, Simoncelli, Shannon }; enum GridInterpolationPositionType { SameSize, OriginAligned, CenterAligned }; /** \brief Executes a transformation operations on one or two images * * All parameters of the arithmetic operations must be specified during construction. * The actual operation is executed when calling GetResult(). */ class MITKBASICIMAGEPROCESSING_EXPORT TransformationOperation { public: static std::vector MultiResolution(Image::Pointer & image, unsigned int numberOfLevels, bool outputAsDouble = false); static Image::Pointer LaplacianOfGaussian(Image::Pointer & image, double sigma, bool outputAsDouble = false); - static std::vector WaveletForward(Image::Pointer & image, unsigned int numberOfLevels, unsigned int numberOfBands, BorderCondition condition, WaveletType waveletType); + static std::vector WaveletForward(Image::Pointer image, unsigned int numberOfLevels, unsigned int numberOfBands, BorderCondition condition, WaveletType waveletType); static Image::Pointer ResampleImage(Image::Pointer &image, mitk::Vector3D spacing, mitk::ImageMappingInterpolator::Type interpolator, GridInterpolationPositionType position, bool returnAsDouble, bool roundOutput); static Image::Pointer ResampleMask(Image::Pointer &image, mitk::Vector3D spacing, mitk::ImageMappingInterpolator::Type interpolator, GridInterpolationPositionType position); + static Image::Pointer CastToUnsignedChar(Image::Pointer image, int &error); + static Image::Pointer CastToSignedChar(Image::Pointer image, int &error); + static Image::Pointer CastToChar(Image::Pointer image, int &error); + static Image::Pointer CastToUnsignedShort(Image::Pointer image, int &error); + static Image::Pointer CastToShort(Image::Pointer image, int &error); + static Image::Pointer CastToUnsignedInt(Image::Pointer image, int &error); + static Image::Pointer CastToInt(Image::Pointer image, int &error); + static Image::Pointer CastToUnsignedLong(Image::Pointer image, int &error); + static Image::Pointer CastToLong(Image::Pointer image, int &error); + static Image::Pointer CastToFloat(Image::Pointer image, int &error); + static Image::Pointer CastToDouble(Image::Pointer image, int &error); + }; } #endif // mitkArithmeticOperation_h \ No newline at end of file diff --git a/Modules/BasicImageProcessing/src/mitkTransformationOperation.cpp b/Modules/BasicImageProcessing/src/mitkTransformationOperation.cpp index 0f0c302634..00aeebf9c5 100644 --- a/Modules/BasicImageProcessing/src/mitkTransformationOperation.cpp +++ b/Modules/BasicImageProcessing/src/mitkTransformationOperation.cpp @@ -1,504 +1,756 @@ /*=================================================================== 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 "mitkTransformationOperation.h" - +#include +#include #include #include #include #include #include #include // Wavelet #include #include #include #include #include #include #include #include #include #include "itkZeroFluxNeumannBoundaryCondition.h" #include "itkPeriodicBoundaryCondition.h" #include "itkConstantBoundaryCondition.h" //#include #include "itkCastImageFilter.h" #include "itkUnaryFunctorImageFilter.h" #include #include #include namespace mitk { namespace Functor { template< class TInput> class ThresholdValue { public: ThresholdValue() {}; ~ThresholdValue() {}; bool operator!=(const ThresholdValue &) const { return false; } bool operator==(const ThresholdValue & other) const { return !(*this != other); } inline unsigned short operator()(const TInput & A) const { if (A < value) return 0; else return 1; } double value = 0.0; }; template< class TInput, class TOutput> class RoundValue { public: RoundValue() {}; ~RoundValue() {}; bool operator!=(const RoundValue &) const { return false; } bool operator==(const RoundValue & other) const { return !(*this != other); } inline TOutput operator()(const TInput & A) const { return std::round(A); } }; } } + + +// Error Codes: 0: Successfull +// 1: General Error (Not Specific) +// 2: Error when duplicating images +// 3: Error when casting image +template +static void ExecuteConvertToDataType(itk::Image* image, mitk::Image::Pointer &resultImage, int & isSuccessful) +{ + typedef itk::Image InputImageType; + typedef itk::Image OutputImageType; + + isSuccessful = 1; + + if (std::is_same::value) // If input has already the "right" data type, only clone it. + { + try + { + typedef itk::ImageDuplicator DuplicateFilterType; + typename DuplicateFilterType::Pointer duplicateFilter = DuplicateFilterType::New(); + + duplicateFilter->SetInputImage(image); + duplicateFilter->Update(); + CastToMitkImage(duplicateFilter->GetOutput(), resultImage); + } + catch (...) + { + resultImage = nullptr; + isSuccessful = 2; + return; + } + + } + else // Convert the image data type if it has the "wrong" datatype. + { + try + { + typedef itk::CastImageFilter CastFilterType; + typename CastFilterType::Pointer castFilter = CastFilterType::New(); + + castFilter->SetInput(image); + castFilter->Update(); + CastToMitkImage(castFilter->GetOutput(), resultImage); + } + catch (...) + { + resultImage = nullptr; + isSuccessful = 3; + return; + } + } + + isSuccessful = 0; + return; +} + +// Error Codes: 0: Successfull +// 1: General Error (Not Specific) +// 2: Error when duplicating images +// 3: Error when casting image +// 4: General Error (really early) +// 5: Unsupported image type +// +// Commented types are not +template +static void ExecuteConvertToGivenType(itk::Image* image, std::type_index &type, mitk::Image::Pointer &resultImage, int & isSuccessful) +{ + isSuccessful = 4; + + if (type == typeid(unsigned char)) + { + ExecuteConvertToDataType(image, resultImage, isSuccessful); + } + else if (type == typeid(signed char)) + { + ExecuteConvertToDataType(image, resultImage, isSuccessful); + } + else if (type == typeid(char)) + { + ExecuteConvertToDataType(image, resultImage, isSuccessful); + } + //else if (type == typeid(wchar_t)) + //{ + // ExecuteConvertToDataType(image, resultImage, isSuccessful); + //} + //else if (type == typeid(char16_t)) + //{ + // ExecuteConvertToDataType(image, resultImage, isSuccessful); + //} + //else if (type == typeid(char32_t)) + //{ + // ExecuteConvertToDataType(image, resultImage, isSuccessful); + //} + //else if (type == typeid(bool)) + //{ + // ExecuteConvertToDataType(image, resultImage, isSuccessful); + //} + else if (type == typeid(unsigned short int)) + { + ExecuteConvertToDataType(image, resultImage, isSuccessful); + } + else if (type == typeid(short int)) + { + ExecuteConvertToDataType(image, resultImage, isSuccessful); + } + else if (type == typeid(unsigned int)) + { + ExecuteConvertToDataType(image, resultImage, isSuccessful); + } else if (type == typeid(int)) + { + ExecuteConvertToDataType(image, resultImage, isSuccessful); + } + else if (type == typeid(unsigned long int)) + { + ExecuteConvertToDataType(image, resultImage, isSuccessful); + } + else if (type == typeid(long int)) + { + ExecuteConvertToDataType(image, resultImage, isSuccessful); + } + //else if (type == typeid(unsigned long long int)) + //{ + // ExecuteConvertToDataType(image, resultImage, isSuccessful); + //} + //else if (type == typeid(long long int)) + //{ + // ExecuteConvertToDataType(image, resultImage, isSuccessful); + //} + else if (type == typeid(float)) + { + ExecuteConvertToDataType(image, resultImage, isSuccessful); + } + else if (type == typeid(double)) + { + ExecuteConvertToDataType(image, resultImage, isSuccessful); + } + //else if (type == typeid(long double)) + //{ + // ExecuteConvertToDataType(image, resultImage, isSuccessful); + //} + else + { + resultImage = NULL; + isSuccessful = 5; + } +} + + template static void ExecuteMultiResolution(itk::Image* image, unsigned int numberOfLevels, bool outputAsDouble, std::vector &resultImages) { typedef itk::Image ImageType; typedef itk::Image DoubleOutputType; typedef itk::RecursiveMultiResolutionPyramidImageFilter ImageTypeFilterType; typedef itk::RecursiveMultiResolutionPyramidImageFilter DoubleTypeFilterType; if (outputAsDouble) { typename DoubleTypeFilterType::Pointer recursiveMultiResolutionPyramidImageFilter = DoubleTypeFilterType::New(); recursiveMultiResolutionPyramidImageFilter->SetInput(image); recursiveMultiResolutionPyramidImageFilter->SetNumberOfLevels(numberOfLevels); recursiveMultiResolutionPyramidImageFilter->Update(); // This outputs the levels (0 is the lowest resolution) for (unsigned int i = 0; i < numberOfLevels; ++i) { mitk::Image::Pointer outputImage = mitk::Image::New(); CastToMitkImage(recursiveMultiResolutionPyramidImageFilter->GetOutput(i), outputImage); resultImages.push_back(outputImage); } } else { typename ImageTypeFilterType::Pointer recursiveMultiResolutionPyramidImageFilter = ImageTypeFilterType::New(); recursiveMultiResolutionPyramidImageFilter->SetInput(image); recursiveMultiResolutionPyramidImageFilter->SetNumberOfLevels(numberOfLevels); recursiveMultiResolutionPyramidImageFilter->Update(); // This outputs the levels (0 is the lowest resolution) for (unsigned int i = 0; i < numberOfLevels; ++i) { mitk::Image::Pointer outputImage = mitk::Image::New(); CastToMitkImage(recursiveMultiResolutionPyramidImageFilter->GetOutput(i), outputImage); resultImages.push_back(outputImage); } } } std::vector mitk::TransformationOperation::MultiResolution(Image::Pointer & image, unsigned int numberOfLevels, bool outputAsDouble) { std::vector resultImages; AccessByItk_n(image, ExecuteMultiResolution, (numberOfLevels, outputAsDouble, resultImages)); return resultImages; } template static void ExecuteLaplacianOfGaussian(itk::Image* image, double sigma, bool outputAsDouble, mitk::Image::Pointer &resultImage) { typedef itk::Image ImageType; typedef itk::Image DoubleOutputType; typedef itk::LaplacianRecursiveGaussianImageFilter ImageTypeFilterType; typedef itk::LaplacianRecursiveGaussianImageFilter DoubleTypeFilterType; if (outputAsDouble) { typename DoubleTypeFilterType::Pointer filter = DoubleTypeFilterType::New(); filter->SetInput(image); filter->SetSigma(sigma); filter->Update(); CastToMitkImage(filter->GetOutput(), resultImage); } else { typename ImageTypeFilterType::Pointer filter = ImageTypeFilterType::New(); filter->SetInput(image); filter->SetSigma(sigma); filter->Update(); CastToMitkImage(filter->GetOutput(), resultImage); } } mitk::Image::Pointer mitk::TransformationOperation::LaplacianOfGaussian(Image::Pointer & image, double sigma, bool outputAsDouble) { Image::Pointer resultImage; AccessByItk_n(image, ExecuteLaplacianOfGaussian, (sigma, outputAsDouble, resultImage)); return resultImage; } template static void ExecuteSpecificWaveletTransformation(itk::Image* image, unsigned int numberOfLevels, unsigned int numberOfBands, mitk::BorderCondition condition, std::vector &resultImages) { const unsigned int Dimension = VImageDimension; typedef TInputPixel PixelType; typedef TOutputPixel OutputPixelType; typedef itk::Image< PixelType, Dimension > ImageType; typedef itk::Image< double, Dimension > DoubleImageType; typedef itk::Image< OutputPixelType, Dimension > OutputImageType; typedef itk::CastImageFilter< ImageType, DoubleImageType > CastFilterType; typedef itk::FFTPadPositiveIndexImageFilter< DoubleImageType > FFTPadType; typedef itk::ForwardFFTImageFilter< DoubleImageType, itk::Image< std::complex, Dimension> > FFTFilterType; typedef typename FFTFilterType::OutputImageType ComplexImageType; typedef TWaveletFunction WaveletFunctionType; typedef itk::WaveletFrequencyFilterBankGenerator< ComplexImageType, WaveletFunctionType > WaveletFilterBankType; typedef itk::WaveletFrequencyForward< ComplexImageType, ComplexImageType, WaveletFilterBankType > ForwardWaveletType; typedef itk::InverseFFTImageFilter< ComplexImageType, OutputImageType > InverseFFTFilterType; // Convert input parameter unsigned int highSubBands = numberOfBands; //inputBands; unsigned int levels = numberOfLevels; + auto oldDirection = image->GetDirection(); + typename ImageType::DirectionType oldDir = image->GetDirection(); + typename ImageType::DirectionType newDir; + + for (int i = 0; i < VImageDimension; ++i) + { + for (int j = 0; j < VImageDimension; ++j) + { + newDir[i][j] = ((i == j) ? itk::SpacePrecisionType(1.0) : itk::SpacePrecisionType(0)); + } + } + image->SetDirection(newDir); // Perform FFT on input image typename CastFilterType::Pointer castFilter = CastFilterType::New(); castFilter->SetInput(image); // Pad Image so it fits the expect typename FFTPadType::Pointer fftpad = FFTPadType::New(); fftpad->SetSizeGreatestPrimeFactor(4); itk::ConstantBoundaryCondition< DoubleImageType > constantBoundaryCondition; itk::PeriodicBoundaryCondition< DoubleImageType > periodicBoundaryCondition; itk::ZeroFluxNeumannBoundaryCondition< DoubleImageType > zeroFluxNeumannBoundaryCondition; switch (condition) { case mitk::BorderCondition::Constant: fftpad->SetBoundaryCondition(&constantBoundaryCondition); break; case mitk::BorderCondition::Periodic: fftpad->SetBoundaryCondition(&periodicBoundaryCondition); break; case mitk::BorderCondition::ZeroFluxNeumann: fftpad->SetBoundaryCondition(&zeroFluxNeumannBoundaryCondition); break; default: break; } fftpad->SetInput(castFilter->GetOutput()); typename FFTFilterType::Pointer fftFilter = FFTFilterType::New(); fftFilter->SetInput(fftpad->GetOutput()); // Calculate forward transformation typename ForwardWaveletType::Pointer forwardWavelet = ForwardWaveletType::New(); forwardWavelet->SetHighPassSubBands(highSubBands); forwardWavelet->SetLevels(levels); forwardWavelet->SetInput(fftFilter->GetOutput()); forwardWavelet->Update(); - // Obtain target spacing, size and origin typename ComplexImageType::SpacingType inputSpacing; for (unsigned int i = 0; i < Dimension; ++i) { - inputSpacing[i] = image->GetLargestPossibleRegion().GetSize()[i]; + inputSpacing[i] = image->GetSpacing()[i]; } typename ComplexImageType::SpacingType expectedSpacing = inputSpacing; typename ComplexImageType::PointType inputOrigin = image->GetOrigin(); typename ComplexImageType::PointType expectedOrigin = inputOrigin; typename ComplexImageType::SizeType inputSize = fftFilter->GetOutput()->GetLargestPossibleRegion().GetSize(); typename ComplexImageType::SizeType expectedSize = inputSize; // Inverse FFT to obtain filtered images typename InverseFFTFilterType::Pointer inverseFFT = InverseFFTFilterType::New(); for (unsigned int level = 0; level < numberOfLevels + 1; ++level) { double scaleFactorPerLevel = std::pow(static_cast< double >(forwardWavelet->GetScaleFactor()),static_cast< double >(level)); for (unsigned int i = 0; i < Dimension; ++i) { - expectedSize[i] = inputSize[i] / scaleFactorPerLevel; expectedOrigin[i] = inputOrigin[i]; expectedSpacing[i] = inputSpacing[i] * scaleFactorPerLevel; } for (unsigned int band = 0; band < highSubBands; ++band) { unsigned int nOutput = level * forwardWavelet->GetHighPassSubBands() + band; // Do not compute bands in low-pass level. if (level == numberOfLevels && band == 0) { nOutput = forwardWavelet->GetTotalOutputs() - 1; } else if (level == numberOfLevels && band != 0) { break; } inverseFFT->SetInput(forwardWavelet->GetOutput(nOutput)); inverseFFT->Update(); auto itkOutputImage = inverseFFT->GetOutput(); + itkOutputImage->SetOrigin(inputOrigin); itkOutputImage->SetSpacing(expectedSpacing); + itkOutputImage->SetDirection(oldDir); mitk::Image::Pointer outputImage = mitk::Image::New(); CastToMitkImage(itkOutputImage, outputImage); resultImages.push_back(outputImage); } } } template static void ExecuteWaveletTransformation(itk::Image* image, unsigned int numberOfLevels, unsigned int numberOfBands, mitk::BorderCondition condition, mitk::WaveletType waveletType, std::vector &resultImages) { typedef itk::Point< double, VImageDimension > PointType; typedef itk::HeldIsotropicWavelet< double, VImageDimension, PointType > HeldIsotropicWaveletType; typedef itk::VowIsotropicWavelet< double, VImageDimension, PointType > VowIsotropicWaveletType; typedef itk::SimoncelliIsotropicWavelet< double, VImageDimension, PointType > SimoncelliIsotropicWaveletType; typedef itk::ShannonIsotropicWavelet< double, VImageDimension, PointType > ShannonIsotropicWaveletType; switch (waveletType) { case mitk::WaveletType::Held: ExecuteSpecificWaveletTransformation(image, numberOfLevels, numberOfBands, condition, resultImages); break; case mitk::WaveletType::Shannon: ExecuteSpecificWaveletTransformation(image, numberOfLevels, numberOfBands, condition, resultImages); break; case mitk::WaveletType::Simoncelli: ExecuteSpecificWaveletTransformation(image, numberOfLevels, numberOfBands, condition, resultImages); break; case mitk::WaveletType::Vow: ExecuteSpecificWaveletTransformation(image, numberOfLevels, numberOfBands, condition, resultImages); break; default: ExecuteSpecificWaveletTransformation(image, numberOfLevels, numberOfBands, condition, resultImages); break; } } -std::vector mitk::TransformationOperation::WaveletForward(Image::Pointer & image, unsigned int numberOfLevels, unsigned int numberOfBands, mitk::BorderCondition condition, mitk::WaveletType waveletType) +std::vector mitk::TransformationOperation::WaveletForward(Image::Pointer image, unsigned int numberOfLevels, unsigned int numberOfBands, mitk::BorderCondition condition, mitk::WaveletType waveletType) { std::vector resultImages; AccessByItk_n(image, ExecuteWaveletTransformation, (numberOfLevels, numberOfBands, condition, waveletType, resultImages)); return resultImages; } template static void ExecuteImageTypeToDouble(itk::Image* image, mitk::Image::Pointer &outputImage) { typedef itk::Image< TPixel, VImageDimension > ImageType; typedef itk::Image< double, VImageDimension > DoubleImageType; typedef itk::CastImageFilter< ImageType, DoubleImageType > CastFilterType; typedef itk::ImageDuplicator< DoubleImageType > DuplicatorType; // Perform FFT on input image typename CastFilterType::Pointer castFilter = CastFilterType::New(); castFilter->SetInput(image); castFilter->Update(); typename DuplicatorType::Pointer duplicator = DuplicatorType::New(); duplicator->SetInputImage(castFilter->GetOutput()); duplicator->Update(); CastToMitkImage(duplicator->GetOutput(), outputImage); } template static void ExecuteRoundImage(itk::Image* /*image*/, mitk::Image::Pointer resampledImage, mitk::Image::Pointer &outputImage) { typedef itk::Image< TPixel, VImageDimension > ImageType; typedef itk::Image< double, VImageDimension > DoubleImageType; typedef itk::UnaryFunctorImageFilter< DoubleImageType, ImageType, mitk::Functor::RoundValue > DefaultFilterType; typename DoubleImageType::Pointer itkImage = DoubleImageType::New(); mitk::CastToItkImage(resampledImage, itkImage); typename DefaultFilterType::Pointer filter = DefaultFilterType::New(); filter->SetInput(itkImage); filter->Update(); CastToMitkImage(filter->GetOutput(), outputImage); } mitk::Image::Pointer mitk::TransformationOperation::ResampleImage(Image::Pointer &image, mitk::Vector3D spacingVector, mitk::ImageMappingInterpolator::Type interpolator, GridInterpolationPositionType position, bool returnAsDouble, bool roundOutput) { // Convert image to double if required mitk::Image::Pointer tmpImage = image; if (returnAsDouble) { AccessByItk_n(image, ExecuteImageTypeToDouble, (tmpImage)); } auto newGeometry = image->GetGeometry()->Clone(); mitk::Vector3D spacing; mitk::BaseGeometry::BoundsArrayType bounds = newGeometry->GetBounds(); for (int i = 0; i < 3; ++i) { spacing[i] = newGeometry->GetSpacing()[i]; //bounds[i*2+1] = newGeometry->GetBounds()[i * 2 + 1]; if (spacingVector[i] > 0) { spacing[i] = spacingVector[i]; if (position == mitk::GridInterpolationPositionType::SameSize) { unsigned int samples = image->GetDimensions()[i]; double currentSpacing = newGeometry->GetSpacing()[i]; double newFactor = std::floor(samples*currentSpacing / spacingVector[i]); spacing[i] = samples * currentSpacing / newFactor; } } bounds[i * 2] = 0; bounds[i*2+1] = std::ceil(bounds[i*2+1] * newGeometry->GetSpacing()[i] *1.0 / spacing[i]); } mitk::Point3D origin = newGeometry->GetOrigin(); if (position == mitk::GridInterpolationPositionType::CenterAligned) { for (int i = 0; i < 3; ++i) { double oldLength = newGeometry->GetSpacing()[i] * newGeometry->GetBounds()[i*2+1]; double newLength = spacing[i] * bounds[i*2+1]; origin[i] = origin[i] - (newLength - oldLength) / 2; } } newGeometry->SetSpacing(spacing); newGeometry->SetOrigin(origin); newGeometry->SetBounds(bounds); mitk::Image::Pointer tmpResult = ImageMappingHelper::map( tmpImage, mitk::GenerateIdentityRegistration3D().GetPointer(), false, 0.0, //Padding Value newGeometry.GetPointer(), false, 0, //Error Value interpolator ); mitk::Image::Pointer result = mitk::Image::New(); if (roundOutput) { AccessByItk_n(tmpImage, ExecuteRoundImage, (tmpResult, result)); } else { result = tmpResult; } return result; } template static void ExecuteImageThresholding(itk::Image* image, mitk::Image::Pointer &resultImage) { typedef itk::Image ImageType; typedef itk::Image MaskType; typedef itk::UnaryFunctorImageFilter< ImageType, MaskType, mitk::Functor::ThresholdValue > DefaultFilterType; typename DefaultFilterType::Pointer filter = DefaultFilterType::New(); filter->SetInput(image); filter->GetFunctor().value = 0.5; filter->Update(); CastToMitkImage(filter->GetOutput(), resultImage); } mitk::Image::Pointer mitk::TransformationOperation::ResampleMask(Image::Pointer &image, mitk::Vector3D spacingVector, mitk::ImageMappingInterpolator::Type interpolator, GridInterpolationPositionType position) { mitk::Image::Pointer result; if (interpolator == mitk::ImageMappingInterpolator::NearestNeighbor) { result = TransformationOperation::ResampleImage(image, spacingVector, interpolator, position, false, false); } else { auto tmpResult = TransformationOperation::ResampleImage(image, spacingVector, interpolator, position, true, false); AccessByItk_n(tmpResult, ExecuteImageThresholding, (result)); } return result; } +mitk::Image::Pointer mitk::TransformationOperation::CastToUnsignedChar(Image::Pointer image, int &error) +{ + mitk::Image::Pointer result; + std::type_index type = typeid(unsigned char); + AccessByItk_n(image, ExecuteConvertToGivenType, (type, result, error)); + return result; +} + +mitk::Image::Pointer mitk::TransformationOperation::CastToSignedChar(Image::Pointer image, int &error) +{ + mitk::Image::Pointer result; + std::type_index type = typeid(signed char); + AccessByItk_n(image, ExecuteConvertToGivenType, (type, result, error)); + return result; +} + +mitk::Image::Pointer mitk::TransformationOperation::CastToChar(Image::Pointer image, int &error) +{ + mitk::Image::Pointer result; + std::type_index type = typeid(char); + AccessByItk_n(image, ExecuteConvertToGivenType, (type, result, error)); + return result; +} + +mitk::Image::Pointer mitk::TransformationOperation::CastToUnsignedShort(Image::Pointer image, int &error) +{ + mitk::Image::Pointer result; + std::type_index type = typeid(unsigned short int); + AccessByItk_n(image, ExecuteConvertToGivenType, (type, result, error)); + return result; +} + +mitk::Image::Pointer mitk::TransformationOperation::CastToShort(Image::Pointer image, int &error) +{ + mitk::Image::Pointer result; + std::type_index type = typeid(short int); + AccessByItk_n(image, ExecuteConvertToGivenType, (type, result, error)); + return result; +} + +mitk::Image::Pointer mitk::TransformationOperation::CastToUnsignedInt(Image::Pointer image, int &error) +{ + mitk::Image::Pointer result; + std::type_index type = typeid(unsigned int); + AccessByItk_n(image, ExecuteConvertToGivenType, (type, result, error)); + return result; +} + +mitk::Image::Pointer mitk::TransformationOperation::CastToInt(Image::Pointer image, int &error) +{ + mitk::Image::Pointer result; + std::type_index type = typeid(int); + AccessByItk_n(image, ExecuteConvertToGivenType, (type, result, error)); + return result; +} + +mitk::Image::Pointer mitk::TransformationOperation::CastToUnsignedLong(Image::Pointer image, int &error) +{ + mitk::Image::Pointer result; + std::type_index type = typeid(unsigned long int); + AccessByItk_n(image, ExecuteConvertToGivenType, (type, result, error)); + return result; +} + +mitk::Image::Pointer mitk::TransformationOperation::CastToLong(Image::Pointer image, int &error) +{ + mitk::Image::Pointer result; + std::type_index type = typeid(long int); + AccessByItk_n(image, ExecuteConvertToGivenType, (type, result, error)); + return result; +} + +mitk::Image::Pointer mitk::TransformationOperation::CastToFloat(Image::Pointer image, int &error) +{ + mitk::Image::Pointer result; + std::type_index type = typeid(float); + AccessByItk_n(image, ExecuteConvertToGivenType, (type, result, error)); + return result; +} + +mitk::Image::Pointer mitk::TransformationOperation::CastToDouble(Image::Pointer image, int &error) +{ + mitk::Image::Pointer result; + std::type_index type = typeid(double); + AccessByItk_n(image, ExecuteConvertToGivenType, (type, result, error)); + return result; +} + + + + namespace itk { namespace utils { IndexPairType IndexToLevelBandSteerablePyramid(unsigned int linearIndex, unsigned int levels, unsigned int bands) { unsigned int totalOutputs = 1 + levels * bands; if (linearIndex > totalOutputs - 1) { itkGenericExceptionMacro(<< "Failed converting linearIndex " << linearIndex << " with levels: " << levels << " bands: " << bands << " to Level,Band pair : out of bounds"); } // Low pass (band = 0). if (linearIndex == totalOutputs - 1) { return std::make_pair(levels - 1, 0); } unsigned int band = (linearIndex) % bands + 1; // note integer division ahead. unsigned int level = (linearIndex) / bands; itkAssertInDebugAndIgnoreInReleaseMacro(level < levels); return std::make_pair(level, band); } // Instantiation template unsigned int ComputeMaxNumberOfLevels<3>(const Size< 3 >& inputSize, const unsigned int & scaleFactor); template unsigned int ComputeMaxNumberOfLevels<2>(const Size< 2 >& inputSize, const unsigned int & scaleFactor); } // end namespace utils } // end namespace itk diff --git a/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomicsTransformationView.cpp b/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomicsTransformationView.cpp index 88ad07f15f..4bca11d9cd 100644 --- a/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomicsTransformationView.cpp +++ b/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomicsTransformationView.cpp @@ -1,379 +1,499 @@ /*=================================================================== 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 "QmitkRadiomicsTransformationView.h" // QT includes (GUI) #include #include #include #include #include #include #include +#include +#include +#include // Berry includes (selection service) #include #include // MITK includes (GUI) #include #include "QmitkDataNodeSelectionProvider.h" #include "mitkDataNodeObject.h" // MITK includes (general #include #include #include #include #include // Specific GUI Includes #include "QmitkGIFConfigurationPanel.h" QmitkRadiomicsTransformation::QmitkRadiomicsTransformation() : QmitkAbstractView(), m_Controls(nullptr) { } QmitkRadiomicsTransformation::~QmitkRadiomicsTransformation() { //berry::ISelectionService* s = GetSite()->GetWorkbenchWindow()->GetSelectionService(); //if(s) // s->RemoveSelectionListener(m_SelectionListener); } void QmitkRadiomicsTransformation::CreateQtPartControl(QWidget *parent) { if (m_Controls == nullptr) { m_Controls = new Ui::QmitkRadiomicsTransformationViewControls; m_Controls->setupUi(parent); QLabel * label1 = new QLabel("Image: "); QmitkDataStorageComboBox * cb_inputimage = new QmitkDataStorageComboBox(this->GetDataStorage(), mitk::TNodePredicateDataType::New()); m_Controls->m_InputImageGroup->layout()->addWidget(label1); m_Controls->m_InputImageGroup->layout()->addWidget(cb_inputimage); this->CreateConnections(); } } void QmitkRadiomicsTransformation::CreateConnections() { if ( m_Controls ) { connect( (QObject*)(m_Controls->buttonExecuteMultiresolution), SIGNAL(clicked() ), this, SLOT(executeButtonMultiResolutionPressed() ) ); connect((QObject*)(m_Controls->m_WaveletExecuteButton), SIGNAL(clicked()), this, SLOT(executeButtonWaveletPressed())); connect((QObject*)(m_Controls->m_ExecuteLOG), SIGNAL(clicked()), this, SLOT(executeButtonLoGPressed())); connect((QObject*)(m_Controls->buttonResampleImage), SIGNAL(clicked()), this, SLOT(executeButtonResamplingPressed())); + connect(m_Controls->buttonConvertToUChar, &QCommandLinkButton::clicked, this, [this] { executeConvertToButton(0); }); + //connect(m_Controls->buttonConvertToSChar, &QCommandLinkButton::clicked, this, [this] { executeConvertToButton(1); }); + connect(m_Controls->buttonConvertToChar, &QCommandLinkButton::clicked, this, [this] { executeConvertToButton(2); }); + connect(m_Controls->buttonConvertToUShort, &QCommandLinkButton::clicked, this, [this] { executeConvertToButton(3); }); + connect(m_Controls->buttonConvertToShort, &QCommandLinkButton::clicked, this, [this] { executeConvertToButton(4); }); + connect(m_Controls->buttonConvertToUInt, &QCommandLinkButton::clicked, this, [this] { executeConvertToButton(5); }); + connect(m_Controls->buttonConvertToInt, &QCommandLinkButton::clicked, this, [this] { executeConvertToButton(6); }); + //connect(m_Controls->buttonConvertToULong, &QCommandLinkButton::clicked, this, [this] { executeConvertToButton(7); }); + //connect(m_Controls->buttonConvertToLong, &QCommandLinkButton::clicked, this, [this] { executeConvertToButton(8); }); + connect(m_Controls->buttonConvertToFloat, &QCommandLinkButton::clicked, this, [this] { executeConvertToButton(9); }); + connect(m_Controls->buttonConvertToDouble, &QCommandLinkButton::clicked, this, [this] { executeConvertToButton(10); }); } } void QmitkRadiomicsTransformation::executeButtonMultiResolutionPressed() { QmitkDataStorageComboBox * cb_image = dynamic_cast(m_Controls->m_InputImageGroup->layout()->itemAt(1)->widget()); mitk::BaseData* baseDataRawImage = NULL; mitk::Image::Pointer raw_image; std::string nodeName; if ((cb_image->GetSelectedNode().IsNotNull() ) ) { baseDataRawImage = (cb_image->GetSelectedNode()->GetData()); nodeName = cb_image->GetSelectedNode()->GetName(); } if ((baseDataRawImage != NULL)) { raw_image = dynamic_cast(baseDataRawImage); } else { QMessageBox msgBox; msgBox.setText("Please specify the images that shlould be used."); msgBox.exec(); return; } if (raw_image.IsNull()) { QMessageBox msgBox; msgBox.setText("Error during processing the specified images."); msgBox.exec(); return; } unsigned int numberOfLevels = m_Controls->m_NumberOfLevels->value(); bool resultAsDouble = m_Controls->m_resultAsDouble->isChecked(); auto results = mitk::TransformationOperation::MultiResolution(raw_image, numberOfLevels, resultAsDouble); unsigned int level = 1; for (auto image : results) { mitk::DataNode::Pointer result = mitk::DataNode::New(); result->SetProperty("name", mitk::StringProperty::New(nodeName+"::MultiRes::Level-"+us::Any(numberOfLevels-level).ToString())); result->SetData(image); GetDataStorage()->Add(result, cb_image->GetSelectedNode()); ++level; } } void QmitkRadiomicsTransformation::executeButtonWaveletPressed() { QmitkDataStorageComboBox * cb_image = dynamic_cast(m_Controls->m_InputImageGroup->layout()->itemAt(1)->widget()); mitk::BaseData* baseDataRawImage = NULL; mitk::Image::Pointer raw_image; std::string nodeName; if ((cb_image->GetSelectedNode().IsNotNull())) { baseDataRawImage = (cb_image->GetSelectedNode()->GetData()); nodeName = cb_image->GetSelectedNode()->GetName(); } if ((baseDataRawImage != NULL)) { raw_image = dynamic_cast(baseDataRawImage); } else { QMessageBox msgBox; msgBox.setText("Please specify the images that shlould be used."); msgBox.exec(); return; } if (raw_image.IsNull()) { QMessageBox msgBox; msgBox.setText("Error during processing the specified images."); msgBox.exec(); return; } unsigned int numberOfLevels = m_Controls->m_WaveletNumberOfLevels->value(); unsigned int numberOfBands = m_Controls->m_WaveletNumberOfBands->value(); mitk::BorderCondition condition = mitk::BorderCondition::Constant; mitk::WaveletType waveletType = mitk::WaveletType::Held; std::string waveletStr = m_Controls->m_WaveletWavelet->currentText().toStdString(); if (waveletStr == "Shannon") { waveletType = mitk::WaveletType::Shannon; } if (waveletStr == "Simoncelli") { waveletType = mitk::WaveletType::Simoncelli; } if (waveletStr == "Vow") { waveletType = mitk::WaveletType::Vow; } if (waveletStr == "Held") { waveletType = mitk::WaveletType::Held; } std::string conditionStr = m_Controls->m_WaveletBorderCondition->currentText().toStdString(); if (conditionStr == "Constant") { condition = mitk::BorderCondition::Constant; } if (conditionStr == "Periodic") { condition = mitk::BorderCondition::Periodic; } if (conditionStr == "Zero Flux Neumann") { condition = mitk::BorderCondition::ZeroFluxNeumann; } auto results = mitk::TransformationOperation::WaveletForward(raw_image, numberOfLevels, numberOfBands, condition, waveletType); unsigned int level = 0; for (auto image : results) { mitk::DataNode::Pointer result = mitk::DataNode::New(); result->SetProperty("name", mitk::StringProperty::New(nodeName + "::Wavelet::"+waveletStr+"-"+conditionStr+"::Level-" + us::Any(level).ToString())); result->SetData(image); GetDataStorage()->Add(result, cb_image->GetSelectedNode()); ++level; } } void QmitkRadiomicsTransformation::executeButtonLoGPressed() { QmitkDataStorageComboBox * cb_image = dynamic_cast(m_Controls->m_InputImageGroup->layout()->itemAt(1)->widget()); mitk::BaseData* baseDataRawImage = NULL; mitk::Image::Pointer raw_image; std::string nodeName; if ((cb_image->GetSelectedNode().IsNotNull())) { baseDataRawImage = (cb_image->GetSelectedNode()->GetData()); nodeName = cb_image->GetSelectedNode()->GetName(); } if ((baseDataRawImage != NULL)) { raw_image = dynamic_cast(baseDataRawImage); } else { QMessageBox msgBox; msgBox.setText("Please specify the images that shlould be used."); msgBox.exec(); return; } if (raw_image.IsNull()) { QMessageBox msgBox; msgBox.setText("Error during processing the specified images."); msgBox.exec(); return; } double sigma = m_Controls->m_LoGSigma->value(); bool resultAsDouble = m_Controls->m_LogResultAsDouble->isChecked(); auto results = mitk::TransformationOperation::LaplacianOfGaussian(raw_image, sigma, resultAsDouble); mitk::DataNode::Pointer result = mitk::DataNode::New(); result->SetProperty("name", mitk::StringProperty::New(nodeName + "::LoG::Sigma-" + us::Any(sigma).ToString())); result->SetData(results); GetDataStorage()->Add(result, cb_image->GetSelectedNode()); } void QmitkRadiomicsTransformation::executeButtonResamplingPressed() { QmitkDataStorageComboBox * cb_image = dynamic_cast(m_Controls->m_InputImageGroup->layout()->itemAt(1)->widget()); mitk::BaseData* baseDataRawImage = NULL; mitk::Image::Pointer raw_image; std::string nodeName; if ((cb_image->GetSelectedNode().IsNotNull())) { baseDataRawImage = (cb_image->GetSelectedNode()->GetData()); nodeName = cb_image->GetSelectedNode()->GetName(); } if ((baseDataRawImage != NULL)) { raw_image = dynamic_cast(baseDataRawImage); } else { QMessageBox msgBox; msgBox.setText("Please specify the images that shlould be used."); msgBox.exec(); return; } if (raw_image.IsNull()) { QMessageBox msgBox; msgBox.setText("Error during processing the specified images."); msgBox.exec(); return; } mitk::ImageMappingInterpolator::Type interpolatorType; switch (m_Controls->comboInterpolationMode->currentIndex()) { case 0: interpolatorType = mitk::ImageMappingInterpolator::Linear; break; case 1: interpolatorType = mitk::ImageMappingInterpolator::BSpline_3; break; case 2: interpolatorType = mitk::ImageMappingInterpolator::NearestNeighbor; break; case 3: interpolatorType = mitk::ImageMappingInterpolator::WSinc_Hamming; break; case 4: interpolatorType = mitk::ImageMappingInterpolator::WSinc_Welch; break; default: interpolatorType = mitk::ImageMappingInterpolator::Linear; } mitk::GridInterpolationPositionType gridPosition; switch (m_Controls->comboAxisAlignment->currentIndex()) { case 0: gridPosition = mitk::GridInterpolationPositionType::OriginAligned; break; case 1: gridPosition = mitk::GridInterpolationPositionType::CenterAligned; break; case 2: gridPosition = mitk::GridInterpolationPositionType::SameSize; break; default: gridPosition = mitk::GridInterpolationPositionType::OriginAligned; } bool resultAsDouble = m_Controls->checkResamplingOutputAsDouble->isChecked(); bool roundResult = m_Controls->checkResamplingRoundOutput->isChecked(); mitk::Vector3D spacing; spacing.Fill(-1); if (m_Controls->checkResampleX->isChecked()) { spacing[0] = m_Controls->doubleSpinDimensionX->value(); } if (m_Controls->checkResampleY->isChecked()) { spacing[1] = m_Controls->doubleSpinDimensionY->value(); } if (m_Controls->checkResampleZ->isChecked()) { spacing[2] = m_Controls->doubleSpinDimensionZ->value(); } mitk::Image::Pointer results; if (m_Controls->checkResampleAsMask->isChecked()) { results = mitk::TransformationOperation::ResampleMask(raw_image, spacing, interpolatorType, gridPosition); mitk::LabelSetImage::Pointer oldLabelImage = dynamic_cast (raw_image.GetPointer()); if (oldLabelImage.IsNotNull()) { mitk::LabelSetImage::Pointer labelResult = mitk::LabelSetImage::New(); labelResult->InitializeByLabeledImage(results); labelResult->AddLabelSetToLayer(labelResult->GetActiveLayer(), oldLabelImage->GetLabelSet()); results = dynamic_cast(labelResult.GetPointer()); } } else { results = mitk::TransformationOperation::ResampleImage(raw_image, spacing, interpolatorType, gridPosition, resultAsDouble, roundResult); } mitk::DataNode::Pointer result = mitk::DataNode::New(); result->SetProperty("name", mitk::StringProperty::New(nodeName + "::Resampled" )); result->SetData(results); GetDataStorage()->Add(result, cb_image->GetSelectedNode()); } + +void QmitkRadiomicsTransformation::executeConvertToButton(int button) +{ + QmitkDataStorageComboBox * cb_image = dynamic_cast(m_Controls->m_InputImageGroup->layout()->itemAt(1)->widget()); + mitk::BaseData* baseDataRawImage = NULL; + + mitk::Image::Pointer raw_image; + std::string nodeName; + if ((cb_image->GetSelectedNode().IsNotNull())) + { + baseDataRawImage = (cb_image->GetSelectedNode()->GetData()); + nodeName = cb_image->GetSelectedNode()->GetName(); + } + if ((baseDataRawImage != NULL)) + { + raw_image = dynamic_cast(baseDataRawImage); + } + else { + QMessageBox msgBox; + msgBox.setText("Please specify the images that shlould be used."); + msgBox.exec(); + return; + } + if (raw_image.IsNull()) + { + QMessageBox msgBox; + msgBox.setText("Error during processing the specified images."); + msgBox.exec(); + return; + } + + mitk::Image::Pointer result; + std::string typeString = ""; + int successful = 1; + + switch (button) + { + case 0: + result = mitk::TransformationOperation::CastToUnsignedChar(raw_image, successful); + typeString = "uchar"; + break; + case 1: + result = mitk::TransformationOperation::CastToSignedChar(raw_image, successful); + typeString = "schar"; + break; + case 2: + result = mitk::TransformationOperation::CastToChar(raw_image, successful); + typeString = "char"; + break; + case 3: + result = mitk::TransformationOperation::CastToUnsignedShort(raw_image, successful); + typeString = "ushort"; + break; + case 4: + result = mitk::TransformationOperation::CastToShort(raw_image, successful); + typeString = "short"; + break; + case 5: + result = mitk::TransformationOperation::CastToUnsignedInt(raw_image, successful); + typeString = "uint"; + break; + case 6: + result = mitk::TransformationOperation::CastToInt(raw_image, successful); + typeString = "int"; + break; + case 7: + result = mitk::TransformationOperation::CastToUnsignedLong(raw_image, successful); + typeString = "ulong"; + break; + case 8: + result = mitk::TransformationOperation::CastToLong(raw_image, successful); + typeString = "long"; + break; + case 9: + result = mitk::TransformationOperation::CastToFloat(raw_image, successful); + typeString = "float"; + break; + case 10: + result = mitk::TransformationOperation::CastToDouble(raw_image, successful); + typeString = "double"; + break; + } + + if (successful == 0) + { + mitk::DataNode::Pointer resultNode = mitk::DataNode::New(); + resultNode->SetProperty("name", mitk::StringProperty::New(nodeName + "::Type-" + typeString)); + resultNode->SetData(result); + GetDataStorage()->Add(resultNode, cb_image->GetSelectedNode()); + } + else if (successful == 5) + { + QMessageBox msgBox; + msgBox.setText("Original Image has an unsupported image type."); + msgBox.exec(); + return; + } + else { + QMessageBox msgBox; + msgBox.setText("An unknown error occured. This could be caused by unsuported data types."); + msgBox.exec(); + MITK_INFO << "Unknown error. Return value is " << successful; + return; + } +} + void QmitkRadiomicsTransformation::SetFocus() { } //datamanager selection changed void QmitkRadiomicsTransformation::OnSelectionChanged(berry::IWorkbenchPart::Pointer, const QList& nodes) { //any nodes there? if (!nodes.empty()) { } } diff --git a/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomicsTransformationView.h b/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomicsTransformationView.h index 68ae5b0e14..2c8fd725b9 100644 --- a/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomicsTransformationView.h +++ b/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomicsTransformationView.h @@ -1,99 +1,101 @@ /*=================================================================== 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. ===================================================================*/ #if !defined(QmitkRadiomicsTransformationView_H__INCLUDED) #define QmitkRadiomicsTransformationView_H__INCLUDED #include #include #include "ui_QmitkRadiomicsTransformationViewControls.h" #include "QmitkStepperAdapter.h" #include #include /*! \brief This module allows to use some basic image processing filters for preprocessing, image enhancement and testing purposes Several basic ITK image processing filters, like denoising, morphological and edge detection are encapsulated in this module and can be selected via a list and an intuitive parameter input. The selected filter will be applied on the image, and a new image showing the output is displayed as result. Also, some image arithmetic operations are available. Images can be 3D or 4D. In the 4D case, the filters work on the 3D image selected via the time slider. The result is also a 3D image. \class QmitkRadiomicsTransformation \author Tobias Schwarz \version 1.0 (3M3) \date 2009-05-10 \ingroup Bundles */ class RADIOMICS_EXPORT QmitkRadiomicsTransformation : public QmitkAbstractView { Q_OBJECT public: /*! \brief default constructor */ QmitkRadiomicsTransformation(); /*! \brief default destructor */ virtual ~QmitkRadiomicsTransformation(); /*! \brief method for creating the widget containing the application controls, like sliders, buttons etc. */ virtual void CreateQtPartControl(QWidget *parent) override; virtual void SetFocus() override; /*! \brief method for creating the connections of main and control widget */ virtual void CreateConnections(); /*! \brief Invoked when the DataManager selection changed */ virtual void OnSelectionChanged(berry::IWorkbenchPart::Pointer part, const QList& nodes) override; protected slots: void executeButtonMultiResolutionPressed(); void executeButtonWaveletPressed(); void executeButtonLoGPressed(); void executeButtonResamplingPressed(); + void executeConvertToButton(int button); + private: /*! * controls containing sliders for scrolling through the slices */ Ui::QmitkRadiomicsTransformationViewControls *m_Controls; }; #endif // !defined(QmitkRadiomicsTransformation_H__INCLUDED) diff --git a/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomicsTransformationViewControls.ui b/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomicsTransformationViewControls.ui index 4dcd715d4f..a910aeec23 100644 --- a/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomicsTransformationViewControls.ui +++ b/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomicsTransformationViewControls.ui @@ -1,506 +1,594 @@ QmitkRadiomicsTransformationViewControls 0 0 448 980 Form QFrame::NoFrame QFrame::Raised - 0 + 4 0 0 430 - 846 + 819 Multi-Resolution Pyramid Number of Levels: 1 Return result as double: true true Execute Multi-Resolution Pyramid Qt::Vertical 20 40 + + + 0 + 0 + 430 + 819 + + Resample Image Dimension X true Dimension Y true Dimension Z true 7 40000000.000000000000000 7 40000000.000000000000000 7 40000000.000000000000000 Interpolation mode Grid alignment method Linear B-Spline Nearest Neighbour WSinc Hamming WSinc Welch Origin aligned Center aligned Same size (adapts final dimension) Output as double Resample as mask Round output Resample Image Qt::Vertical 20 40 0 0 430 - 846 + 819 Wavelet Transformation Number of Levels: 1 20000 Number of Bands: 1 2000 Border Condition: Wavelet: Constant Periodic Zero Flux Neumann Shannon Simoncelli Vow Held Execute Wavelet Transformation Qt::Vertical 20 40 0 0 430 - 846 + 819 Laplacian of Gaussian 4 1.000000000000000 1000000000000.000000000000000 Gaussian Sigma: Return result as double: true Execute Laplacian of Gaussian Qt::Vertical 20 40 + + + Transform Data Type + + + + + + + + Convert to Unsigned Char + + + + + + + Convert to Char + + + + + + + Convert to Unsigned Short + + + + + + + Convert to Short + + + + + + + Convert to Unsigned Int + + + + + + + Convert to Int + + + + + + + Convert to Float + + + + + + + Convert to Double + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + +