diff --git a/Modules/Core/include/mitkExtractSliceFilter2.h b/Modules/Core/include/mitkExtractSliceFilter2.h index 54b2fa14d4..161e8459e5 100644 --- a/Modules/Core/include/mitkExtractSliceFilter2.h +++ b/Modules/Core/include/mitkExtractSliceFilter2.h @@ -1,58 +1,82 @@ /*=================================================================== 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 { + /** \brief Extract an arbitrarily oriented 2-d image from a 3-d image. + * + * Use ExtractSliceFilter2::SetOutputGeometry to specify the orientation of + * the 2-d output image. + * + * If a pixel of the 2-d output image isn't located within the bounds of the + * 3-d input image, it is set to the lowest possible pixel value. + * + * Cubic interpolation is considerably slow on the first update for a newly + * set input image. Subsequent filter updates with cubic interpolation are + * faster by several orders of magnitude as long as the input image was + * neither changed nor modified. + * + * This filter is completely based on ITK compared to the VTK-based + * mitk::ExtractSliceFilter. It is more robust, easy to use, and produces + * an mitk::Image with valid geometry. Generally it is not as fast as + * mitk::ExtractSliceFilter, though. + */ class MITKCORE_EXPORT ExtractSliceFilter2 final : public ImageToImageFilter { public: - enum class Interpolator + enum Interpolator { NearestNeighbor, Linear, - WindowedSinc_Lanczos_3 + 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: + using Superclass::SetInput; + ExtractSliceFilter2(); ~ExtractSliceFilter2() override; - void GenerateData() override; - void GenerateInputRequestedRegion() 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/include/mitkImageToItk.txx b/Modules/Core/include/mitkImageToItk.txx index c99f9dc6a0..3b2b49d897 100644 --- a/Modules/Core/include/mitkImageToItk.txx +++ b/Modules/Core/include/mitkImageToItk.txx @@ -1,294 +1,294 @@ /*=================================================================== 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 IMAGETOITK_TXX_INCLUDED_C1C2FCD2 #define IMAGETOITK_TXX_INCLUDED_C1C2FCD2 #include "itkImportMitkImageContainer.h" #include "mitkBaseProcess.h" #include "mitkException.h" #include "mitkImageReadAccessor.h" #include "mitkImageToItk.h" #include "mitkImageWriteAccessor.h" +#include + template struct SetLengthHelper { SetLengthHelper(TImageType *in) { m_Image = in; } private: TImageType *m_Image; }; template struct SetLengthHelper> { typedef itk::Image TImageType; SetLengthHelper(TImageType *in) { m_Image = in; } void SetVectorLength(size_t) {} private: TImageType *m_Image; }; template struct SetLengthHelper> { typedef itk::VectorImage TImageType; SetLengthHelper(TImageType *in) { m_Image = in; } void SetVectorLength(size_t len) { m_Image->SetVectorLength(len); } private: TImageType *m_Image; }; template void mitk::ImageToItk::SetInput(mitk::Image *input) { this->SetInput(static_cast(input)); m_ConstInput = false; } template void mitk::ImageToItk::SetInput(const mitk::Image *input) { this->CheckInput(input); // Process object is not const-correct so the const_cast is required here itk::ProcessObject::PushFrontInput(input); m_ConstInput = true; } template mitk::Image *mitk::ImageToItk::GetInput(void) { if (this->GetNumberOfInputs() < 1) { return nullptr; } return static_cast(itk::ProcessObject::GetInput(0)); } template const mitk::Image *mitk::ImageToItk::GetInput() const { if (this->GetNumberOfInputs() < 1) { return nullptr; } return static_cast(itk::ProcessObject::GetInput(0)); } template void mitk::ImageToItk::GenerateData() { // Allocate output mitk::Image::Pointer input = this->GetInput(); typename Superclass::OutputImageType::Pointer output = this->GetOutput(); unsigned long noBytes = input->GetDimension(0); for (unsigned int i = 1; i < TOutputImage::GetImageDimension(); ++i) { noBytes = noBytes * input->GetDimension(i); } const mitk::PixelType pixelType = input->GetPixelType(); if (pixelType.GetPixelType() == itk::ImageIOBase::VECTOR) { noBytes *= pixelType.GetNumberOfComponents(); SetLengthHelper helper(output.GetPointer()); helper.SetVectorLength(pixelType.GetNumberOfComponents()); } - mitk::ImageAccessorBase *imageAccess; + std::unique_ptr imageAccess; if (m_ConstInput) { - imageAccess = new mitk::ImageReadAccessor(input, static_cast(nullptr), m_Options); + imageAccess.reset(new mitk::ImageReadAccessor(input, nullptr, m_Options)); } else { - imageAccess = new mitk::ImageWriteAccessor(input, static_cast(nullptr), m_Options); + imageAccess.reset(new mitk::ImageWriteAccessor(input, nullptr, m_Options)); } // hier wird momentan wohl nur der erste Channel verwendet??!! if (imageAccess->GetData() == nullptr) { itkWarningMacro(<< "no image data to import in ITK image"); RegionType bufferedRegion; output->SetBufferedRegion(bufferedRegion); return; } if (m_CopyMemFlag) { itkDebugMacro("copyMem ..."); output->Allocate(); memcpy(output->GetBufferPointer(), imageAccess->GetData(), sizeof(InternalPixelType) * noBytes); - - delete imageAccess; } else { itkDebugMacro("do not copyMem ..."); typedef itk::ImportMitkImageContainer ImportContainerType; typename ImportContainerType::Pointer import; import = ImportContainerType::New(); import->Initialize(); itkDebugMacro(<< "size of container = " << import->Size()); // import->SetImageDataItem(m_ImageDataItem); - import->SetImageAccessor(imageAccess, sizeof(InternalPixelType) * noBytes); + import->SetImageAccessor(imageAccess.release(), sizeof(InternalPixelType) * noBytes); output->SetPixelContainer(import); itkDebugMacro(<< "size of container = " << import->Size()); } } template void mitk::ImageToItk::UpdateOutputInformation() { mitk::Image::Pointer input = this->GetInput(); if (input.IsNotNull() && (input->GetSource().IsNotNull()) && input->GetSource()->Updating()) { typename Superclass::OutputImageType::Pointer output = this->GetOutput(); unsigned long t1 = input->GetUpdateMTime() + 1; if (t1 > this->m_OutputInformationMTime.GetMTime()) { output->SetPipelineMTime(t1); this->GenerateOutputInformation(); this->m_OutputInformationMTime.Modified(); } return; } Superclass::UpdateOutputInformation(); } template void mitk::ImageToItk::GenerateOutputInformation() { mitk::Image::ConstPointer input = this->GetInput(); typename Superclass::OutputImageType::Pointer output = this->GetOutput(); // allocate size, origin, spacing, direction in types of output image SizeType size; const unsigned int itkDimMin3 = (TOutputImage::ImageDimension > 3 ? TOutputImage::ImageDimension : 3); const unsigned int itkDimMax3 = (TOutputImage::ImageDimension < 3 ? TOutputImage::ImageDimension : 3); typename Superclass::OutputImageType::PointType::ValueType origin[itkDimMin3]; typename Superclass::OutputImageType::SpacingType::ComponentType spacing[itkDimMin3]; typename Superclass::OutputImageType::DirectionType direction; // copy as much information as possible into size and spacing unsigned int i; for (i = 0; i < itkDimMax3; ++i) { size[i] = input->GetDimension(i); spacing[i] = input->GetGeometry()->GetSpacing()[i]; } for (; i < TOutputImage::ImageDimension; ++i) { origin[i] = 0.0; size[i] = input->GetDimension(i); spacing[i] = 1.0; } // build region from size IndexType start; start.Fill(0); RegionType region; region.SetIndex(start); region.SetSize(size); // copy as much information as possible into origin const mitk::Point3D &mitkorigin = input->GetGeometry()->GetOrigin(); itk2vtk(mitkorigin, origin); // copy as much information as possible into direction direction.SetIdentity(); unsigned int j; const AffineTransform3D::MatrixType &matrix = input->GetGeometry()->GetIndexToWorldTransform()->GetMatrix(); /// \warning 2D MITK images could have a 3D rotation, since they have a 3x3 geometry matrix. /// If it is only a rotation around the axial plane normal, it can be express with a 2x2 matrix. /// In this case, the ITK image conservs this information and is identical to the MITK image! /// If the MITK image contains any other rotation, the ITK image will have no rotation at all. /// Spacing is of course conserved in both cases. // the following loop devides by spacing now to normalize columns. // counterpart of InitializeByItk in mitkImage.h line 372 of revision 15092. // Check if information is lost if (TOutputImage::ImageDimension <= 2) { if ((TOutputImage::ImageDimension == 2) && ((matrix[0][2] != 0) || (matrix[1][2] != 0) || (matrix[2][0] != 0) || (matrix[2][1] != 0) || ((matrix[2][2] != 1) && (matrix[2][2] != -1)))) { // The 2D MITK image contains 3D rotation information. // This cannot be expressed in a 2D ITK image, so the ITK image will have no rotation } else { // The 2D MITK image can be converted to an 2D ITK image without information loss! for (i = 0; i < itkDimMax3; ++i) for (j = 0; j < itkDimMax3; ++j) direction[i][j] = matrix[i][j] / spacing[j]; } } else { // Normal 3D image. Conversion possible without problem! for (i = 0; i < itkDimMax3; ++i) for (j = 0; j < itkDimMax3; ++j) direction[i][j] = matrix[i][j] / spacing[j]; } // set information into output image output->SetRegions(region); output->SetOrigin(origin); output->SetSpacing(spacing); output->SetDirection(direction); } template void mitk::ImageToItk::CheckInput(const mitk::Image *input) const { if (input == nullptr) { itkExceptionMacro(<< "image is null"); } if (input->GetDimension() != TOutputImage::GetImageDimension()) { itkExceptionMacro(<< "image has dimension " << input->GetDimension() << " instead of " << TOutputImage::GetImageDimension()); } if (!(input->GetPixelType() == mitk::MakePixelType(input->GetPixelType().GetNumberOfComponents()))) { itkExceptionMacro(<< "image has wrong pixel type "); } } template void mitk::ImageToItk::PrintSelf(std::ostream &os, itk::Indent indent) const { Superclass::PrintSelf(os, indent); } #endif // IMAGETOITK_TXX_INCLUDED_C1C2FCD2 diff --git a/Modules/Core/src/Algorithms/mitkExtractSliceFilter2.cpp b/Modules/Core/src/Algorithms/mitkExtractSliceFilter2.cpp index d33ae99dc8..261c5d5e61 100644 --- a/Modules/Core/src/Algorithms/mitkExtractSliceFilter2.cpp +++ b/Modules/Core/src/Algorithms/mitkExtractSliceFilter2.cpp @@ -1,240 +1,278 @@ /*=================================================================== 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 #include +struct mitk::ExtractSliceFilter2::Impl +{ + Impl(); + ~Impl(); + + mitk::Image* OutputImage; + PlaneGeometry::Pointer OutputGeometry; + mitk::ExtractSliceFilter2::Interpolator Interpolator; + itk::Object::Pointer InterpolateImageFunction; +}; + +mitk::ExtractSliceFilter2::Impl::Impl() + : OutputImage(nullptr), + Interpolator(NearestNeighbor) +{ +} + +mitk::ExtractSliceFilter2::Impl::~Impl() +{ +} + namespace { template - typename itk::InterpolateImageFunction::Pointer CreateInterpolator(mitk::ExtractSliceFilter2::Interpolator interpolator) + void CreateInterpolateImageFunction(const TInputImage* inputImage, mitk::ExtractSliceFilter2::Impl* impl) { - switch (interpolator) + typename itk::InterpolateImageFunction::Pointer interpolateImageFunction; + + switch (impl->Interpolator) { - case mitk::ExtractSliceFilter2::Interpolator::NearestNeighbor: - return itk::NearestNeighborInterpolateImageFunction::New().GetPointer(); + case mitk::ExtractSliceFilter2::NearestNeighbor: + interpolateImageFunction = itk::NearestNeighborInterpolateImageFunction::New().GetPointer(); + break; - case mitk::ExtractSliceFilter2::Interpolator::Linear: - return itk::LinearInterpolateImageFunction::New().GetPointer(); + case mitk::ExtractSliceFilter2::Linear: + interpolateImageFunction = itk::LinearInterpolateImageFunction::New().GetPointer(); + break; - case mitk::ExtractSliceFilter2::Interpolator::WindowedSinc_Lanczos_3: - return itk::WindowedSincInterpolateImageFunction>::New().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); - - Size size; - size[0] = outputGeometry->GetExtent(0); - size[1] = outputGeometry->GetExtent(1); - size[2] = 1; - - Region region; - region.SetIndex(index); - region.SetSize(size); - - auto interpolateImageFunction = CreateInterpolator>(interpolator); - interpolateImageFunction->SetInputImage(inputImage); + typedef itk::Image TInputImage; + typedef itk::InterpolateImageFunction TInterpolateImageFunction; - const SizeValue NUMBER_OF_PIXELS = size[0] * size[1] * size[2]; - TPixel* buffer = new TPixel[NUMBER_OF_PIXELS]; + auto outputImage = impl->OutputImage; + auto outputGeometry = impl->OutputGeometry; + auto interpolateImageFunction = static_cast(impl->InterpolateImageFunction.GetPointer()); auto origin = outputGeometry->GetOrigin(); + auto spacing = outputGeometry->GetSpacing(); + auto xDirection = outputGeometry->GetAxisVector(0); + auto yDirection = outputGeometry->GetAxisVector(1); - std::array direction = - { - outputGeometry->GetAxisVector(0), - outputGeometry->GetAxisVector(1), - outputGeometry->GetNormal() - }; + xDirection.Normalize(); + yDirection.Normalize(); - direction[0].Normalize(); - direction[1].Normalize(); - direction[2].Normalize(); + auto spacingAlongXDirection = xDirection * spacing[0]; + auto spacingAlongYDirection = yDirection * spacing[1]; - mitk::Matrix3D directionMatrix; + origin -= spacingAlongXDirection * 0.5; + origin -= spacingAlongYDirection * 0.5; - for (int j = 0; j < 3; ++j) - { - for (int i = 0; i < 3; ++i) - { - directionMatrix(i, j) = direction[j][i]; - } - } - - auto spacing = outputGeometry->GetSpacing(); + 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); - std::array spacingAlongDirection = - { - direction[0] * spacing[0], - direction[1] * spacing[1] - }; + mitk::ImageWriteAccessor writeAccess(outputImage, nullptr, mitk::ImageAccessorBase::IgnoreLock); + auto data = static_cast(writeAccess.GetData());; - std::array halfSpacingAlongDirection = - { - spacingAlongDirection[0] * 0.5, - 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 - halfSpacingAlongDirection[1]; + 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 - halfSpacingAlongDirection[0]; - - 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 +mitk::ExtractSliceFilter2::ExtractSliceFilter2() + : m_Impl(new Impl) { - Impl(); - ~Impl(); - - PlaneGeometry::Pointer OutputGeometry; - Interpolator Interpolator; -}; +} -mitk::ExtractSliceFilter2::Impl::Impl() - : Interpolator(Interpolator::NearestNeighbor) +mitk::ExtractSliceFilter2::~ExtractSliceFilter2() { + delete m_Impl; } -mitk::ExtractSliceFilter2::Impl::~Impl() +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[static_cast(pixelType.GetSize() * outputGeometry->GetExtent(0) * outputGeometry->GetExtent(1))]; + + try + { + if (!outputImage->SetImportVolume(data, 0, 0, mitk::Image::ReferenceMemory)) + throw; + } + catch (...) + { + delete[] data; + } } -mitk::ExtractSliceFilter2::ExtractSliceFilter2() - : m_Impl(new Impl) +void mitk::ExtractSliceFilter2::BeforeThreadedGenerateData() { + if (nullptr != m_Impl->InterpolateImageFunction && this->GetInput()->GetMTime() < this->GetMTime()) + return; + + const auto* inputImage = this->GetInput(); + AccessFixedDimensionByItk_1(inputImage, CreateInterpolateImageFunction, 3, m_Impl); } -mitk::ExtractSliceFilter2::~ExtractSliceFilter2() +void mitk::ExtractSliceFilter2::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, itk::ThreadIdType) { - delete m_Impl; + m_Impl->OutputImage = this->GetOutput(); + + const auto* inputImage = this->GetInput(); + AccessFixedDimensionByItk_2(inputImage, ::GenerateData, 3, m_Impl, outputRegionForThread); } -void mitk::ExtractSliceFilter2::GenerateData() +void mitk::ExtractSliceFilter2::SetInput(const InputImageType* image) { - AccessFixedDimensionByItk_n(this->GetInput(), ::GenerateData, 3, (this->GetOutput(), m_Impl->OutputGeometry, m_Impl->Interpolator)); + if (this->GetInput() == image) + return; + + Superclass::SetInput(image); + m_Impl->InterpolateImageFunction = nullptr; } -void mitk::ExtractSliceFilter2::GenerateInputRequestedRegion() +void mitk::ExtractSliceFilter2::SetInput(unsigned int index, const InputImageType* image) { - itk::ProcessObject::GenerateInputRequestedRegion(); + 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) { - m_Impl->OutputGeometry = 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) { - m_Impl->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()); } diff --git a/Modules/Core/src/DataManagement/mitkImageWriteAccessor.cpp b/Modules/Core/src/DataManagement/mitkImageWriteAccessor.cpp index dcd2908507..ffc9a0215d 100644 --- a/Modules/Core/src/DataManagement/mitkImageWriteAccessor.cpp +++ b/Modules/Core/src/DataManagement/mitkImageWriteAccessor.cpp @@ -1,151 +1,151 @@ /*=================================================================== 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 "mitkImageWriteAccessor.h" mitk::ImageWriteAccessor::ImageWriteAccessor(ImagePointer image, const mitk::ImageDataItem *iDI, int OptionFlags) : ImageAccessorBase(image.GetPointer(), iDI, OptionFlags), m_Image(image) { OrganizeWriteAccess(); } mitk::ImageWriteAccessor::~ImageWriteAccessor() { // In case of non-coherent memory, copied area needs to be written back // TODO m_Image->m_ReadWriteLock.Lock(); // delete self from list of ImageReadAccessors in Image auto it = std::find(m_Image->m_Writers.begin(), m_Image->m_Writers.end(), this); m_Image->m_Writers.erase(it); // delete lock, if there are no waiting ImageAccessors if (m_WaitLock->m_WaiterCount <= 0) { m_WaitLock->m_Mutex.Unlock(); delete m_WaitLock; } else { m_WaitLock->m_Mutex.Unlock(); } m_Image->m_ReadWriteLock.Unlock(); } const mitk::Image *mitk::ImageWriteAccessor::GetImage() const { return m_Image.GetPointer(); } void mitk::ImageWriteAccessor::OrganizeWriteAccess() { m_Image->m_ReadWriteLock.Lock(); bool readOverlap = false; bool writeOverlap = false; ImageAccessorWaitLock *overlapLock = nullptr; // Check, if there is any Read-Access going on if (m_Image->m_Readers.size() > 0) { // Check for every ReadAccessor, if the Region of this ImageAccessors overlaps // make sure this iterator is not used, when m_ReadWriteLock is Unlocked! auto it = m_Image->m_Readers.begin(); for (; it != m_Image->m_Readers.end(); ++it) { ImageAccessorBase *r = *it; if ((r->m_Options & IgnoreLock) == 0 && Overlap(r)) { // An Overlap was detected. PreventRecursiveMutexLock(r); readOverlap = true; overlapLock = r->m_WaitLock; break; } // if } // for } // if // Check, if there is any Write-Access going on if (m_Image->m_Writers.size() > 0) { // Check for every WriteAccessor, if the Region of this ImageAccessors overlaps // make sure this iterator is not used, when m_ReadWriteLock is Unlocked! auto it = m_Image->m_Writers.begin(); for (; it != m_Image->m_Writers.end(); ++it) { ImageAccessorBase *w = *it; - if (Overlap(w)) + if ((w->m_Options & IgnoreLock) == 0 && Overlap(w)) { // An Overlap was detected. PreventRecursiveMutexLock(w); // save overlapping Waitlock writeOverlap = true; overlapLock = w->m_WaitLock; break; } // if } // for } // if if (readOverlap || writeOverlap) { // Throw an exception or wait for the WriteAccessor w until it is released and start again with the request // afterwards. if (!(m_Options & ExceptionIfLocked)) { // WAIT overlapLock->m_WaiterCount += 1; m_Image->m_ReadWriteLock.Unlock(); ImageAccessorBase::WaitForReleaseOf(overlapLock); // after waiting for the ImageAccessor, start this method again OrganizeWriteAccess(); return; } else { // THROW EXCEPTION m_Image->m_ReadWriteLock.Unlock(); mitkThrowException(mitk::MemoryIsLockedException) << "The image part being ordered by the ImageAccessor is already in use and locked"; // MITK_ERROR("Speicherbereich belegt"); return; } } // Now, we know, that there is no conflict with a Read- or Write-Access // Lock the Mutex in ImageAccessorBase, to make sure that every other ImageAccessor has to wait m_WaitLock->m_Mutex.Lock(); // insert self into Writers list in Image m_Image->m_Writers.push_back(this); // printf("WriteAccess %d %d\n",(int) m_Image->m_Readers.size(),(int) m_Image->m_Writers.size()); // fflush(0); m_Image->m_ReadWriteLock.Unlock(); }