diff --git a/Modules/MatchPointRegistration/include/mitkImageStitchingHelper.h b/Modules/MatchPointRegistration/include/mitkImageStitchingHelper.h new file mode 100644 index 0000000000..f82f0fdad0 --- /dev/null +++ b/Modules/MatchPointRegistration/include/mitkImageStitchingHelper.h @@ -0,0 +1,59 @@ +/*============================================================================ + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center (DKFZ) +All rights reserved. + +Use of this source code is governed by a 3-clause BSD license that can be +found in the LICENSE file. + +============================================================================*/ + + +#ifndef MITK_IMAGE_STITCHING_HELPER_H +#define MITK_IMAGE_STITCHING_HELPER_H + +#include "mapRegistrationBase.h" +#include "mitkImage.h" +#include "mitkGeometry3D.h" + +#include "mitkMAPRegistrationWrapper.h" +#include "mitkImageMappingHelper.h" + +#include "MitkMatchPointRegistrationExports.h" + +namespace mitk +{ + /**Helper that maps a given input image + * @param input Image that should be mapped. + * @param registration Pointer to the registration instance that should be used for mapping + * @param resultGeometry Pointer to the Geometry object that specifies the grid of the result image. If not defined the geometry of the input image will be used. + * @param paddingValue Indicates the value that should be used if an out of input error occurs (and throwOnOutOfInputAreaError is false). + * @param interpolatorType Indicates the type of interpolation strategy that should be used. + * @pre input must be valid + * @pre registration must be valid + * @pre Dimensionality of the registration must match with the input imageinput must be valid + * @remark Depending in the settings of throwOnOutOfInputAreaError and throwOnMappingError it may also throw + * due to inconsistencies in the mapping process. See parameter description. + * @result Pointer to the resulting mapped image.h*/ + MITKMATCHPOINTREGISTRATION_EXPORT Image::Pointer StitchImages(std::vector inputs, + std::vector<::map::core::RegistrationBase::ConstPointer> registrations, + const BaseGeometry* resultGeometry, + const double& paddingValue = 0, + mitk::ImageMappingInterpolator::Type interpolatorType = mitk::ImageMappingInterpolator::Linear); + + MITKMATCHPOINTREGISTRATION_EXPORT Image::Pointer StitchImages(std::vector inputs, + std::vector registrations, + const BaseGeometry* resultGeometry, + const double& paddingValue = 0, + mitk::ImageMappingInterpolator::Type interpolatorType = mitk::ImageMappingInterpolator::Linear); + + MITKMATCHPOINTREGISTRATION_EXPORT Image::Pointer StitchImages(std::vector inputs, + const BaseGeometry* resultGeometry, + const double& paddingValue = 0, + mitk::ImageMappingInterpolator::Type interpolatorType = mitk::ImageMappingInterpolator::Linear); + +} + +#endif diff --git a/Modules/MatchPointRegistration/src/Helper/mitkImageStitchingHelper.cpp b/Modules/MatchPointRegistration/src/Helper/mitkImageStitchingHelper.cpp new file mode 100644 index 0000000000..eaedfee5e4 --- /dev/null +++ b/Modules/MatchPointRegistration/src/Helper/mitkImageStitchingHelper.cpp @@ -0,0 +1,212 @@ +/*============================================================================ + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center (DKFZ) +All rights reserved. + +Use of this source code is governed by a 3-clause BSD license that can be +found in the LICENSE file. + +============================================================================*/ + +#include "mitkImageStitchingHelper.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "mapRegistration.h" + +#include "mitkRegistrationHelper.h" + +template +typename ::itk::InterpolateImageFunction< TImage >::Pointer generateInterpolator(mitk::ImageMappingInterpolator::Type interpolatorType) +{ + typedef ::itk::InterpolateImageFunction< TImage > BaseInterpolatorType; + typename BaseInterpolatorType::Pointer result; + + switch (interpolatorType) + { + case mitk::ImageMappingInterpolator::NearestNeighbor: + { + result = ::itk::NearestNeighborInterpolateImageFunction::New(); + break; + } + case mitk::ImageMappingInterpolator::BSpline_3: + { + typename ::itk::BSplineInterpolateImageFunction::Pointer spInterpolator = ::itk::BSplineInterpolateImageFunction::New(); + spInterpolator->SetSplineOrder(3); + result = spInterpolator; + break; + } + case mitk::ImageMappingInterpolator::WSinc_Hamming: + { + result = ::itk::WindowedSincInterpolateImageFunction::New(); + break; + } + case mitk::ImageMappingInterpolator::WSinc_Welch: + { + result = ::itk::WindowedSincInterpolateImageFunction >::New(); + break; + } + default: + { + result = ::itk::LinearInterpolateImageFunction::New(); + break; + } + + } + + return result; +}; + +template +void doMITKStitching(const ::itk::Image* input1, + mitk::Image::Pointer& result, + std::vector inputs, + std::vector<::map::core::RegistrationBase::ConstPointer> registrations, + const mitk::BaseGeometry* resultGeometry, + const double& paddingValue, mitk::ImageMappingInterpolator::Type interpolatorType) +{ + using ConcreteRegistrationType = ::map::core::Registration; + using ItkImageType = itk::Image; + + using StitchingFilterType = ::itk::StitchImageFilter; + auto stitcher = StitchingFilterType::New(); + + stitcher->SetDefaultPixelValue(paddingValue); + + stitcher->SetOutputSpacing(resultGeometry->GetSpacing()); + stitcher->SetOutputOrigin(resultGeometry->GetOrigin()); + stitcher->SetOutputDirection(resultGeometry->GetIndexToWorldTransform()->GetMatrix()); + ItkImageType::SizeType size; + size[0] = resultGeometry->GetExtent(0); + size[1] = resultGeometry->GetExtent(1); + size[2] = resultGeometry->GetExtent(2); + stitcher->SetSize(size); + + auto inputIter = inputs.begin(); + auto regIter = registrations.begin(); + unsigned int index = 0; + + while (inputIter != inputs.end()) + { + auto itkInput = mitk::ImageToItkImage(*inputIter); + + auto castedReg = dynamic_cast(regIter->GetPointer()); + + auto kernel = dynamic_cast* >(&(castedReg->getInverseMapping())); + if (nullptr == kernel) + { + mitkThrow() << "Cannot stitch images. At least passed registration object #"<SetInput(index, itkInput, kernel->getTransformModel(), generateInterpolator< ::itk::Image >(interpolatorType)); + } + + stitcher->Update(); + mitk::CastToMitkImage<>(stitcher->GetOutput(),result); +} + +mitk::Image::Pointer +mitk::StitchImages(std::vector inputs, + std::vector<::map::core::RegistrationBase::ConstPointer> registrations, + const BaseGeometry* resultGeometry, + const double& paddingValue, + mitk::ImageMappingInterpolator::Type interpolatorType) +{ + if (inputs.size() != registrations.size()) + { + mitkThrow() << "Cannot stitch images. Passed inputs vector and registrations vector have different sizes."; + } + + if (inputs.empty()) + { + mitkThrow() << "Cannot stitch images. No input images are defined."; + } + + auto inputDim = inputs.front()->GetDimension(); + auto inputPixelType = inputs.front()->GetPixelType(); + + for (const auto& input : inputs) + { + if (input->GetDimension() != inputDim) + { + mitkThrow() << "Cannot stitch images. Images have different dimensions. Dimeonsion of first input: " << inputDim << "; wrong dimension: " << input->GetDimension(); + } + if (input->GetPixelType() != inputPixelType) + { + mitkThrow() << "Cannot stitch images. Input images have different pixeltypes. The current implementation does only support stitching of images with same pixel type. Dimeonsion of first input: " << inputPixelType.GetTypeAsString() << "; wrong dimension: " << input->GetPixelType().GetTypeAsString(); + } + if (input->GetTimeSteps() > 1) + { + mitkThrow() << "Cannot stitch dynamic images. At least one input image has multiple time steps."; + } + } + + for (const auto& reg : registrations) + { + if (reg->getMovingDimensions() != inputDim) + { + mitkThrow() << "Cannot stitch images. At least one registration has a different moving dimension then the inputs. Dimeonsion of inputs: " << inputDim << "; wrong dimension: " << reg->getMovingDimensions(); + } + if (reg->getTargetDimensions() != inputDim) + { + mitkThrow() << "Cannot stitch images. At least one registration has a different target dimension then the inputs. Dimeonsion of inputs: " << inputDim << "; wrong dimension: " << reg->getTargetDimensions(); + } + } + + Image::Pointer result; + + AccessFixedDimensionByItk_n(inputs.front(), doMITKStitching, 3, (result, inputs, registrations, resultGeometry, paddingValue, interpolatorType)); + + return result; +} + +mitk::Image::Pointer +mitk::StitchImages(std::vector inputs, + std::vector registrations, + const BaseGeometry* resultGeometry, + const double& paddingValue, + mitk::ImageMappingInterpolator::Type interpolatorType) +{ + + std::vector<::map::core::RegistrationBase::ConstPointer> unwrappedRegs; + for (const auto& reg : registrations) + { + if (!reg) + { + mitkThrow() << "Cannot stitch images. At least one passed registration wrapper pointer is nullptr."; + } + unwrappedRegs.push_back(reg->GetRegistration()); + } + + Image::Pointer result = StitchImages(inputs, unwrappedRegs, resultGeometry, paddingValue, interpolatorType); + return result; +} + +mitk::Image::Pointer +mitk::StitchImages(std::vector inputs, + const BaseGeometry* resultGeometry, + const double& paddingValue, + mitk::ImageMappingInterpolator::Type interpolatorType) +{ + auto defaultReg = GenerateIdentityRegistration3D(); + std::vector<::map::core::RegistrationBase::ConstPointer> defaultRegs; + defaultRegs.resize(inputs.size()); + std::fill(defaultRegs.begin(), defaultRegs.end(), defaultReg->GetRegistration()); + + Image::Pointer result = StitchImages(inputs, defaultRegs, resultGeometry, paddingValue, interpolatorType); + return result; +} +