diff --git a/Modules/Core/include/mitkSurfaceToImageFilter.h b/Modules/Core/include/mitkSurfaceToImageFilter.h index d4adb5e05c..8dc6922b9c 100644 --- a/Modules/Core/include/mitkSurfaceToImageFilter.h +++ b/Modules/Core/include/mitkSurfaceToImageFilter.h @@ -1,97 +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. ===================================================================*/ #ifndef _mitkSurfaceToImageFilter_h__ #define _mitkSurfaceToImageFilter_h__ #include "MitkCoreExports.h" #include "mitkCommon.h" #include "mitkImageSource.h" #include "mitkSurface.h" class vtkPolyData; namespace mitk { /** * * @brief Converts surface data to pixel data. Requires a surface and an * image, which header information defines the output image. * * The resulting image has the same dimension, size, and Geometry3D * as the input image. The image is cut using a vtkStencil. * The user can decide if he wants to keep the original values or create a * binary image by setting MakeBinaryOutputOn (default is \a false). If * set to \a true all voxels inside the surface are set to one and all * outside voxel are set to zero. * * NOTE: Since the reference input image is passed to the vtkStencil in * any case, the image needs to be initialized with pixel values greater than * the numerical minimum of the used pixel type (e.g. at least -127 for * unsigned char images, etc.) to produce a correct binary image * representation of the surface in MakeOutputBinary mode. * * @ingroup SurfaceFilters * @ingroup Process */ class MITKCORE_EXPORT SurfaceToImageFilter : public ImageSource { public: mitkClassMacro(SurfaceToImageFilter, ImageSource); itkFactorylessNewMacro(Self) itkCloneMacro(Self) itkSetMacro(MakeOutputBinary, bool); itkGetMacro(MakeOutputBinary, bool); itkBooleanMacro(MakeOutputBinary); itkSetMacro(UShortBinaryPixelType, bool); itkGetMacro(UShortBinaryPixelType, bool); itkBooleanMacro(UShortBinaryPixelType); itkGetConstMacro(BackgroundValue, float); itkSetMacro(BackgroundValue, float); + itkGetConstMacro(Tolerance, double); + itkSetMacro(Tolerance, double); + virtual void GenerateInputRequestedRegion() override; virtual void GenerateOutputInformation() override; virtual void GenerateData() override; const mitk::Surface *GetInput(void); using itk::ProcessObject::SetInput; virtual void SetInput(const mitk::Surface *surface); void SetImage(const mitk::Image *source); const mitk::Image *GetImage(void); protected: SurfaceToImageFilter(); virtual ~SurfaceToImageFilter(); void Stencil3DImage(int time = 0); bool m_MakeOutputBinary; bool m_UShortBinaryPixelType; float m_BackgroundValue; + double m_Tolerance; }; } // namespace mitk #endif /* MITKCOONSPATCHFILTER_H_HEADER_INCLUDED_C10B22CD */ diff --git a/Modules/Core/src/Algorithms/mitkSurfaceToImageFilter.cpp b/Modules/Core/src/Algorithms/mitkSurfaceToImageFilter.cpp index 3edc5db73f..639edbd568 100644 --- a/Modules/Core/src/Algorithms/mitkSurfaceToImageFilter.cpp +++ b/Modules/Core/src/Algorithms/mitkSurfaceToImageFilter.cpp @@ -1,238 +1,238 @@ /*=================================================================== 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 "mitkSurfaceToImageFilter.h" #include "mitkImageWriteAccessor.h" #include "mitkTimeHelper.h" #include #include #include #include #include #include #include #include #include #include mitk::SurfaceToImageFilter::SurfaceToImageFilter() - : m_MakeOutputBinary(false), m_UShortBinaryPixelType(false), m_BackgroundValue(-10000) + : m_MakeOutputBinary(false), m_UShortBinaryPixelType(false), m_BackgroundValue(-10000), m_Tolerance(0.0) { } mitk::SurfaceToImageFilter::~SurfaceToImageFilter() { } void mitk::SurfaceToImageFilter::GenerateInputRequestedRegion() { mitk::Image *output = this->GetOutput(); if ((output->IsInitialized() == false)) return; GenerateTimeInInputRegion(output, const_cast(this->GetImage())); } void mitk::SurfaceToImageFilter::GenerateOutputInformation() { mitk::Image *inputImage = (mitk::Image *)this->GetImage(); mitk::Image::Pointer output = this->GetOutput(); itkDebugMacro(<< "GenerateOutputInformation()"); if ((inputImage == nullptr) || (inputImage->IsInitialized() == false) || (inputImage->GetTimeGeometry() == nullptr)) return; if (m_MakeOutputBinary) { if (m_UShortBinaryPixelType) { output->Initialize(mitk::MakeScalarPixelType(), *inputImage->GetTimeGeometry()); } else { output->Initialize(mitk::MakeScalarPixelType(), *inputImage->GetTimeGeometry()); } } else { output->Initialize(inputImage->GetPixelType(), *inputImage->GetTimeGeometry()); } output->SetPropertyList(inputImage->GetPropertyList()->Clone()); } void mitk::SurfaceToImageFilter::GenerateData() { mitk::Image::ConstPointer inputImage = this->GetImage(); mitk::Image::Pointer output = this->GetOutput(); if (inputImage.IsNull()) return; if (output->IsInitialized() == false) return; mitk::Image::RegionType outputRegion = output->GetRequestedRegion(); int tstart = outputRegion.GetIndex(3); int tmax = tstart + outputRegion.GetSize(3); if (tmax > 0) { int t; for (t = tstart; t < tmax; ++t) { Stencil3DImage(t); } } else { Stencil3DImage(0); } } void mitk::SurfaceToImageFilter::Stencil3DImage(int time) { mitk::Image::Pointer output = this->GetOutput(); mitk::Image::Pointer binaryImage = mitk::Image::New(); unsigned int size = sizeof(unsigned char); if (m_MakeOutputBinary) { if (m_UShortBinaryPixelType) { binaryImage->Initialize(mitk::MakeScalarPixelType(), *this->GetImage()->GetTimeGeometry(), 1, 1); size = sizeof(unsigned short); } else { binaryImage->Initialize(mitk::MakeScalarPixelType(), *this->GetImage()->GetTimeGeometry(), 1, 1); } } else { binaryImage->Initialize(this->GetImage()->GetPixelType(), *this->GetImage()->GetTimeGeometry(), 1, 1); size = this->GetImage()->GetPixelType().GetSize(); } for (unsigned int i = 0; i < binaryImage->GetDimension(); ++i) { size *= binaryImage->GetDimension(i); } mitk::ImageWriteAccessor accessor(binaryImage); memset(accessor.GetData(), 1, size); const mitk::TimeGeometry *surfaceTimeGeometry = GetInput()->GetTimeGeometry(); const mitk::TimeGeometry *imageTimeGeometry = GetImage()->GetTimeGeometry(); // Convert time step from image time-frame to surface time-frame mitk::TimePointType matchingTimePoint = imageTimeGeometry->TimeStepToTimePoint(time); mitk::TimeStepType surfaceTimeStep = surfaceTimeGeometry->TimePointToTimeStep(matchingTimePoint); vtkPolyData *polydata = ((mitk::Surface *)GetInput())->GetVtkPolyData(surfaceTimeStep); if (polydata) { vtkSmartPointer move = vtkSmartPointer::New(); move->SetInputData(polydata); move->ReleaseDataFlagOn(); vtkSmartPointer transform = vtkSmartPointer::New(); BaseGeometry *geometry = surfaceTimeGeometry->GetGeometryForTimeStep(surfaceTimeStep); if (!geometry) { geometry = GetInput()->GetGeometry(); } transform->PostMultiply(); transform->Concatenate(geometry->GetVtkTransform()->GetMatrix()); // take image geometry into account. vtk-Image information will be changed to unit spacing and zero origin below. BaseGeometry *imageGeometry = imageTimeGeometry->GetGeometryForTimeStep(time); transform->Concatenate(imageGeometry->GetVtkTransform()->GetLinearInverse()); move->SetTransform(transform); vtkSmartPointer normalsFilter = vtkSmartPointer::New(); normalsFilter->SetFeatureAngle(50); normalsFilter->SetConsistency(1); normalsFilter->SetSplitting(1); normalsFilter->SetFlipNormals(0); normalsFilter->ReleaseDataFlagOn(); normalsFilter->SetInputConnection(move->GetOutputPort()); vtkSmartPointer surfaceConverter = vtkSmartPointer::New(); - surfaceConverter->SetTolerance(0.0); + surfaceConverter->SetTolerance(m_Tolerance); surfaceConverter->ReleaseDataFlagOn(); surfaceConverter->SetInputConnection(normalsFilter->GetOutputPort()); vtkImageData *image = m_MakeOutputBinary ? binaryImage->GetVtkImageData() : const_cast(this->GetImage())->GetVtkImageData(time); // fill the image with foreground voxels: unsigned char inval = 1; vtkIdType count = image->GetNumberOfPoints(); for (vtkIdType i = 0; i < count; ++i) { image->GetPointData()->GetScalars()->SetTuple1(i, inval); } // Create stencil and use numerical minimum of pixel type as background value vtkSmartPointer stencil = vtkSmartPointer::New(); stencil->SetInputData(image); stencil->ReverseStencilOff(); stencil->ReleaseDataFlagOn(); stencil->SetStencilConnection(surfaceConverter->GetOutputPort()); stencil->SetBackgroundValue(m_MakeOutputBinary ? 0 : m_BackgroundValue); stencil->Update(); output->SetVolume(stencil->GetOutput()->GetScalarPointer(), time); MITK_INFO << "stencil ref count: " << stencil->GetReferenceCount() << std::endl; } else { memset(accessor.GetData(), 0, size); output->SetVolume(accessor.GetData(), time); } } const mitk::Surface *mitk::SurfaceToImageFilter::GetInput(void) { if (this->GetNumberOfInputs() < 1) { return nullptr; } return static_cast(this->ProcessObject::GetInput(0)); } void mitk::SurfaceToImageFilter::SetInput(const mitk::Surface *input) { // Process object is not const-correct so the const_cast is required here this->ProcessObject::SetNthInput(0, const_cast(input)); } void mitk::SurfaceToImageFilter::SetImage(const mitk::Image *source) { this->ProcessObject::SetNthInput(1, const_cast(source)); } const mitk::Image *mitk::SurfaceToImageFilter::GetImage(void) { return static_cast(this->ProcessObject::GetInput(1)); }