diff --git a/Modules/Core/include/mitkExtractSliceFilter2.h b/Modules/Core/include/mitkExtractSliceFilter2.h index 6864ad7cd5..90ab58cbb5 100644 --- a/Modules/Core/include/mitkExtractSliceFilter2.h +++ b/Modules/Core/include/mitkExtractSliceFilter2.h @@ -1,57 +1,62 @@ /*=================================================================== 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 mitkExtractSliceFilter2_h #define mitkExtractSliceFilter2_h #include #include #include namespace mitk { class MITKCORE_EXPORT ExtractSliceFilter2 final : public ImageToImageFilter { public: enum Interpolator { NearestNeighbor, Linear, Cubic }; mitkClassMacro(ExtractSliceFilter2, ImageToImageFilter) itkFactorylessNewMacro(Self) + void SetInput(const InputImageType* image) override; + void SetInput(unsigned int index, const InputImageType* image) override; + const PlaneGeometry* GetOutputGeometry() const; void SetOutputGeometry(PlaneGeometry::Pointer outputGeometry); Interpolator GetInterpolator() const; void SetInterpolator(Interpolator interpolator); private: ExtractSliceFilter2(); ~ExtractSliceFilter2() override; - void GenerateData() override; + void AllocateOutputs() override; + void BeforeThreadedGenerateData() override; + void ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, itk::ThreadIdType threadId) override; void VerifyInputInformation() override; struct Impl; Impl* m_Impl; }; } #endif diff --git a/Modules/Core/src/Algorithms/mitkExtractSliceFilter2.cpp b/Modules/Core/src/Algorithms/mitkExtractSliceFilter2.cpp index d5c055c80e..282d6a0a46 100644 --- a/Modules/Core/src/Algorithms/mitkExtractSliceFilter2.cpp +++ b/Modules/Core/src/Algorithms/mitkExtractSliceFilter2.cpp @@ -1,244 +1,290 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include -#include -#include #include #include #include -#include -#include #include namespace { +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable: 4996) +#endif + + char* GetData(mitk::Image* image) + { + return static_cast(image->GetData()); + } + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + template - typename itk::InterpolateImageFunction::Pointer CreateInterpolator(mitk::ExtractSliceFilter2::Interpolator interpolator) + void CreateInterpolateImageFunction(const TInputImage* inputImage, mitk::ExtractSliceFilter2::Impl* impl) { - switch (interpolator) + itk::InterpolateImageFunction::Pointer interpolateImageFunction; + + switch (impl->Interpolator) { - case mitk::ExtractSliceFilter2::NearestNeighbor: - return itk::NearestNeighborInterpolateImageFunction::New().GetPointer(); + case mitk::ExtractSliceFilter2::NearestNeighbor: + interpolateImageFunction = itk::NearestNeighborInterpolateImageFunction::New().GetPointer(); + break; - case mitk::ExtractSliceFilter2::Linear: - return itk::LinearInterpolateImageFunction::New().GetPointer(); + case mitk::ExtractSliceFilter2::Linear: + interpolateImageFunction = itk::LinearInterpolateImageFunction::New().GetPointer(); + break; - case mitk::ExtractSliceFilter2::Cubic: - { - auto interpolateImageFunction = itk::BSplineInterpolateImageFunction::New(); - interpolateImageFunction->SetSplineOrder(2); - return interpolateImageFunction.GetPointer(); - } + case mitk::ExtractSliceFilter2::Cubic: + { + auto bSplineInterpolateImageFunction = itk::BSplineInterpolateImageFunction::New(); + bSplineInterpolateImageFunction->SetSplineOrder(2); + interpolateImageFunction = bSplineInterpolateImageFunction.GetPointer(); + break; + } - default: - mitkThrow() << "Interplator is unknown."; + default: + mitkThrow() << "Interplator is unknown."; } + + interpolateImageFunction->SetInputImage(inputImage); + + impl->InterpolateImageFunction = interpolateImageFunction.GetPointer(); } template - void GenerateData(itk::Image* inputImage, mitk::Image* outputImage, mitk::PlaneGeometry* outputGeometry, mitk::ExtractSliceFilter2::Interpolator interpolator) + void GenerateData(const itk::Image* inputImage, const mitk::ExtractSliceFilter2::Impl* impl, const mitk::ExtractSliceFilter2::OutputImageRegionType& outputRegion) { - typedef typename itk::ImportImageFilter ImportImageFilter; - typedef typename ImportImageFilter::IndexType Index; - typedef typename ImportImageFilter::SizeType Size; - typedef typename ImportImageFilter::RegionType Region; - typedef typename Size::SizeValueType SizeValue; - - Index index; - index.Fill(0); + typedef itk::Image TInputImage; + typedef itk::InterpolateImageFunction TInterpolateImageFunction; - Size size; - size[0] = outputGeometry->GetExtent(0); - size[1] = outputGeometry->GetExtent(1); - size[2] = 1; + auto outputImage = impl->OutputImage; + auto outputGeometry = impl->OutputGeometry; + auto interpolateImageFunction = static_cast(impl->InterpolateImageFunction.GetPointer()); - Region region; - region.SetIndex(index); - region.SetSize(size); + auto origin = outputGeometry->GetOrigin(); + auto spacing = outputGeometry->GetSpacing(); + auto xDirection = outputGeometry->GetAxisVector(0); + auto yDirection = outputGeometry->GetAxisVector(1); - auto interpolateImageFunction = CreateInterpolator>(interpolator); - interpolateImageFunction->SetInputImage(inputImage); + xDirection.Normalize(); + yDirection.Normalize(); - const SizeValue NUMBER_OF_PIXELS = size[0] * size[1] * size[2]; - TPixel* buffer = new TPixel[NUMBER_OF_PIXELS]; + auto spacingAlongXDirection = xDirection * spacing[0]; + auto spacingAlongYDirection = yDirection * spacing[1]; - std::array direction = - { - outputGeometry->GetAxisVector(0), - outputGeometry->GetAxisVector(1), - outputGeometry->GetNormal() - }; + origin -= spacingAlongXDirection * 0.5; + origin -= spacingAlongYDirection * 0.5; - direction[0].Normalize(); - direction[1].Normalize(); - direction[2].Normalize(); + const std::size_t pixelSize = outputImage->GetPixelType().GetSize(); + const std::size_t height = outputGeometry->GetExtent(1); + const std::size_t xBegin = outputRegion.GetIndex(0); + const std::size_t yBegin = outputRegion.GetIndex(1); + const std::size_t xEnd = xBegin + outputRegion.GetSize(0); + const std::size_t yEnd = yBegin + outputRegion.GetSize(1); - mitk::Matrix3D directionMatrix; - - for (int j = 0; j < 3; ++j) - { - for (int i = 0; i < 3; ++i) - { - directionMatrix(i, j) = direction[j][i]; - } - } - - auto spacing = outputGeometry->GetSpacing(); - - std::array spacingAlongDirection = - { - direction[0] * spacing[0], - direction[1] * spacing[1] - }; + auto data = GetData(outputImage); - auto origin = outputGeometry->GetOrigin(); - origin -= spacingAlongDirection[0] * 0.5; - origin -= spacingAlongDirection[1] * 0.5; + const TPixel backgroundPixel = std::numeric_limits::lowest(); + TPixel pixel; + itk::ContinuousIndex index; + mitk::Point3D yPoint; mitk::Point3D point; - mitk::Point3D yComponent; - itk::ContinuousIndex continuousIndex; - for (SizeValue y = 0; y < size[1]; ++y) + for (std::size_t y = yBegin; y < yEnd; ++y) { - yComponent = origin + spacingAlongDirection[1] * y; + yPoint = origin + spacingAlongYDirection * y; - for (SizeValue x = 0; x < size[0]; ++x) + for (std::size_t x = xBegin; x < xEnd; ++x) { - point = yComponent + spacingAlongDirection[0] * x; - - buffer[size[1] * y + x] = inputImage->TransformPhysicalPointToContinuousIndex(point, continuousIndex) - ? interpolateImageFunction->EvaluateAtContinuousIndex(continuousIndex) - : std::numeric_limits::lowest(); + point = yPoint + spacingAlongXDirection * x; + + if (inputImage->TransformPhysicalPointToContinuousIndex(point, index)) + { + pixel = interpolateImageFunction->EvaluateAtContinuousIndex(index); + memcpy(static_cast(data + pixelSize * (height * y + x)), static_cast(&pixel), pixelSize); + } + else + { + memcpy(static_cast(data + pixelSize * (height * y + x)), static_cast(&backgroundPixel), pixelSize); + } } } - - auto importImageFilter = ImportImageFilter::New(); - importImageFilter->SetRegion(region); - importImageFilter->SetOrigin(outputGeometry->GetOrigin()); - importImageFilter->SetSpacing(outputGeometry->GetSpacing()); - importImageFilter->SetDirection(directionMatrix); - importImageFilter->SetImportPointer(buffer, NUMBER_OF_PIXELS, true); - importImageFilter->Update(); - - mitk::GrabItkImageMemory(importImageFilter->GetOutput(), outputImage); } void VerifyInputImage(const mitk::Image* inputImage) { auto dimension = inputImage->GetDimension(); if (3 != dimension) mitkThrow() << "Input images with " << dimension << " dimensions are not supported."; if (!inputImage->IsInitialized()) mitkThrow() << "Input image is not initialized."; if (!inputImage->IsVolumeSet()) mitkThrow() << "Input image volume is not set."; auto geometry = inputImage->GetGeometry(); if (nullptr == geometry || !geometry->IsValid()) mitkThrow() << "Input image has invalid geometry."; if (!geometry->GetImageGeometry()) mitkThrow() << "Geometry of input image is not an image geometry."; } void VerifyOutputGeometry(const mitk::PlaneGeometry* outputGeometry) { if (nullptr == outputGeometry) mitkThrow() << "Output geometry is not set."; if (!outputGeometry->GetImageGeometry()) mitkThrow() << "Output geometry is not an image geometry."; } } struct mitk::ExtractSliceFilter2::Impl { Impl(); ~Impl(); + mitk::Image* OutputImage; PlaneGeometry::Pointer OutputGeometry; Interpolator Interpolator; + itk::Object::Pointer InterpolateImageFunction; }; mitk::ExtractSliceFilter2::Impl::Impl() - : Interpolator(NearestNeighbor) + : OutputImage(nullptr), + Interpolator(NearestNeighbor) { } mitk::ExtractSliceFilter2::Impl::~Impl() { } mitk::ExtractSliceFilter2::ExtractSliceFilter2() : m_Impl(new Impl) { } mitk::ExtractSliceFilter2::~ExtractSliceFilter2() { delete m_Impl; } -void mitk::ExtractSliceFilter2::GenerateData() +void mitk::ExtractSliceFilter2::AllocateOutputs() +{ + const auto* inputImage = this->GetInput(); + const auto* outputGeometry = this->GetOutputGeometry(); + auto outputImage = this->GetOutput(); + auto pixelType = inputImage->GetPixelType(); + + outputImage->Initialize(pixelType, 1, *outputGeometry); + + auto data = new char[pixelType.GetSize() * outputGeometry->GetExtent(0) * outputGeometry->GetExtent(1)]; + + try + { + if (!outputImage->SetImportVolume(data, 0, 0, mitk::Image::ReferenceMemory)) + throw; + } + catch (...) + { + delete[] data; + } +} + +void mitk::ExtractSliceFilter2::BeforeThreadedGenerateData() { - AccessFixedDimensionByItk_n(this->GetInput(), ::GenerateData, 3, (this->GetOutput(), m_Impl->OutputGeometry, m_Impl->Interpolator)); + if (nullptr != m_Impl->InterpolateImageFunction) + return; + + const auto* inputImage = this->GetInput(); + AccessFixedDimensionByItk_1(inputImage, CreateInterpolateImageFunction, 3, m_Impl); +} + +void mitk::ExtractSliceFilter2::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, itk::ThreadIdType threadId) +{ + m_Impl->OutputImage = this->GetOutput(); + + const auto* inputImage = this->GetInput(); + AccessFixedDimensionByItk_2(inputImage, ::GenerateData, 3, m_Impl, outputRegionForThread); +} + +void mitk::ExtractSliceFilter2::SetInput(const InputImageType* image) +{ + if (this->GetInput() == image) + return; + + Superclass::SetInput(image); + m_Impl->InterpolateImageFunction = nullptr; +} + +void mitk::ExtractSliceFilter2::SetInput(unsigned int index, const InputImageType* image) +{ + if (0 != index) + mitkThrow() << "Input index " << index << " is invalid."; + + this->SetInput(image); } const mitk::PlaneGeometry* mitk::ExtractSliceFilter2::GetOutputGeometry() const { return m_Impl->OutputGeometry; } void mitk::ExtractSliceFilter2::SetOutputGeometry(PlaneGeometry::Pointer outputGeometry) { if (m_Impl->OutputGeometry != outputGeometry) { m_Impl->OutputGeometry = outputGeometry; this->Modified(); } } mitk::ExtractSliceFilter2::Interpolator mitk::ExtractSliceFilter2::GetInterpolator() const { return m_Impl->Interpolator; } void mitk::ExtractSliceFilter2::SetInterpolator(Interpolator interpolator) { if (m_Impl->Interpolator != interpolator) { m_Impl->Interpolator = interpolator; + m_Impl->InterpolateImageFunction = nullptr; this->Modified(); } } void mitk::ExtractSliceFilter2::VerifyInputInformation() { Superclass::VerifyInputInformation(); VerifyInputImage(this->GetInput()); VerifyOutputGeometry(m_Impl->OutputGeometry.GetPointer()); }