22 #include <itkCastImageFilter.h> 23 #include <itkVTKImageExport.h> 24 #include <itkVTKImageImport.h> 25 #include <itkImageDuplicator.h> 26 #include <itkExceptionObject.h> 27 #include <itkLineIterator.h> 29 #include <vtkPoints.h> 30 #include <vtkImageStencil.h> 31 #include <vtkImageImport.h> 32 #include <vtkImageExport.h> 33 #include <vtkLassoStencilSource.h> 34 #include <vtkSmartPointer.h> 43 if ( planarFigure.IsNull() )
45 throw std::runtime_error(
"Error: planar figure empty!" );
48 const PlaneGeometry *planarFigurePlaneGeometry = planarFigure->GetPlaneGeometry();
49 if ( planarFigurePlaneGeometry ==
nullptr )
51 throw std::runtime_error(
"Planar-Figure not yet initialized!" );
54 const auto *planarFigureGeometry =
55 dynamic_cast< const PlaneGeometry *
>( planarFigurePlaneGeometry );
56 if ( planarFigureGeometry ==
nullptr )
58 throw std::runtime_error(
"Non-planar planar figures not supported!" );
61 if (planarFigure != m_PlanarFigure)
64 m_PlanarFigure = planarFigure;
71 if (IsUpdateRequired())
73 this->CalculateMask();
75 return m_ReferenceImage;
78 template <
typename TPixel,
unsigned int VImageDimension >
79 void PlanarFigureMaskGenerator::InternalCalculateMaskFromPlanarFigure(
80 const itk::Image< TPixel, VImageDimension > *
image,
unsigned int axis )
82 typedef itk::Image< unsigned short, 2 > MaskImage2DType;
84 typename MaskImage2DType::Pointer maskImage = MaskImage2DType::New();
85 maskImage->SetOrigin(image->GetOrigin());
86 maskImage->SetSpacing(image->GetSpacing());
87 maskImage->SetLargestPossibleRegion(image->GetLargestPossibleRegion());
88 maskImage->SetBufferedRegion(image->GetBufferedRegion());
89 maskImage->SetDirection(image->GetDirection());
90 maskImage->SetNumberOfComponentsPerPixel(image->GetNumberOfComponentsPerPixel());
91 maskImage->Allocate();
92 maskImage->FillBuffer(1);
103 if (m_PlanarFigure->GetPolyLinesSize() == 2)
104 planarFigureHolePolyline = m_PlanarFigure->GetPolyLine(1);
130 bool outOfBounds =
false;
131 vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
132 typename PlanarFigure::PolyLineType::const_iterator it;
133 for ( it = planarFigurePolyline.begin();
134 it != planarFigurePolyline.end();
144 planarFigurePlaneGeometry->
Map( *it, point3D );
148 if ( !imageGeometry3D->
IsInside( point3D ) )
155 points->InsertNextPoint( point3D[i0], point3D[i1], 0 );
158 vtkSmartPointer<vtkPoints> holePoints =
nullptr;
160 if (!planarFigureHolePolyline.empty())
162 holePoints = vtkSmartPointer<vtkPoints>::New();
165 PlanarFigure::PolyLineType::const_iterator end = planarFigureHolePolyline.end();
167 for (it = planarFigureHolePolyline.begin(); it != end; ++it)
170 planarFigurePlaneGeometry->
Map(*it, point3D);
172 holePoints->InsertNextPoint(point3D[i0], point3D[i1], 0);
178 double bounds[6] = {0, 0, 0, 0, 0, 0};
179 points->GetBounds( bounds );
180 bool extent_x = (fabs(bounds[0] - bounds[1])) <
mitk::eps;
181 bool extent_y = (fabs(bounds[2] - bounds[3])) <
mitk::eps;
182 bool extent_z = (fabs(bounds[4] - bounds[5])) <
mitk::eps;
185 if ( m_PlanarFigure->IsClosed() &&
186 ((extent_x && extent_y) || (extent_x && extent_z) || (extent_y && extent_z)))
188 mitkThrow() <<
"Figure has a zero area and cannot be used for masking.";
193 throw std::runtime_error(
"Figure at least partially outside of image bounds!" );
197 vtkSmartPointer<vtkLassoStencilSource> lassoStencil = vtkSmartPointer<vtkLassoStencilSource>::New();
198 lassoStencil->SetShapeToPolygon();
199 lassoStencil->SetPoints( points );
201 vtkSmartPointer<vtkLassoStencilSource> holeLassoStencil =
nullptr;
203 if (holePoints.GetPointer() !=
nullptr)
205 holeLassoStencil = vtkSmartPointer<vtkLassoStencilSource>::New();
206 holeLassoStencil->SetShapeToPolygon();
207 holeLassoStencil->SetPoints(holePoints);
211 typedef itk::VTKImageImport< MaskImage2DType > ImageImportType;
212 typedef itk::VTKImageExport< MaskImage2DType > ImageExportType;
214 typename ImageExportType::Pointer itkExporter = ImageExportType::New();
215 itkExporter->SetInput( maskImage );
218 vtkSmartPointer<vtkImageImport> vtkImporter = vtkSmartPointer<vtkImageImport>::New();
219 this->ConnectPipelines( itkExporter, vtkImporter );
222 vtkSmartPointer<vtkImageStencil> imageStencilFilter = vtkSmartPointer<vtkImageStencil>::New();
223 imageStencilFilter->SetInputConnection( vtkImporter->GetOutputPort() );
224 imageStencilFilter->SetStencilConnection(lassoStencil->GetOutputPort());
225 imageStencilFilter->ReverseStencilOff();
226 imageStencilFilter->SetBackgroundValue( 0 );
227 imageStencilFilter->Update();
229 vtkSmartPointer<vtkImageStencil> holeStencilFilter =
nullptr;
231 if (holeLassoStencil.GetPointer() !=
nullptr)
233 holeStencilFilter = vtkSmartPointer<vtkImageStencil>::New();
234 holeStencilFilter->SetInputConnection(imageStencilFilter->GetOutputPort());
235 holeStencilFilter->SetStencilConnection(holeLassoStencil->GetOutputPort());
236 holeStencilFilter->ReverseStencilOn();
237 holeStencilFilter->SetBackgroundValue(0);
238 holeStencilFilter->Update();
242 vtkSmartPointer<vtkImageExport> vtkExporter = vtkSmartPointer<vtkImageExport>::New();
243 vtkExporter->SetInputConnection( holeStencilFilter.GetPointer() ==
nullptr 244 ? imageStencilFilter->GetOutputPort()
245 : holeStencilFilter->GetOutputPort());
246 vtkExporter->Update();
248 typename ImageImportType::Pointer itkImporter = ImageImportType::New();
249 this->ConnectPipelines( vtkExporter, itkImporter );
250 itkImporter->Update();
252 typedef itk::ImageDuplicator< ImageImportType::OutputImageType > DuplicatorType;
253 DuplicatorType::Pointer duplicator = DuplicatorType::New();
254 duplicator->SetInputImage( itkImporter->GetOutput() );
255 duplicator->Update();
258 m_InternalITKImageMask2D = duplicator->GetOutput();
261 template <
typename TPixel,
unsigned int VImageDimension >
262 void PlanarFigureMaskGenerator::InternalCalculateMaskFromOpenPlanarFigure(
263 const itk::Image< TPixel, VImageDimension > *image,
unsigned int axis )
265 typedef itk::Image< unsigned short, 2 > MaskImage2DType;
266 typedef itk::LineIterator< MaskImage2DType > LineIteratorType;
267 typedef MaskImage2DType::IndexType IndexType2D;
268 typedef std::vector< IndexType2D > IndexVecType;
270 typename MaskImage2DType::Pointer maskImage = MaskImage2DType::New();
271 maskImage->SetOrigin(image->GetOrigin());
272 maskImage->SetSpacing(image->GetSpacing());
273 maskImage->SetLargestPossibleRegion(image->GetLargestPossibleRegion());
274 maskImage->SetBufferedRegion(image->GetBufferedRegion());
275 maskImage->SetDirection(image->GetDirection());
276 maskImage->SetNumberOfComponentsPerPixel(image->GetNumberOfComponentsPerPixel());
277 maskImage->Allocate();
278 maskImage->FillBuffer(0);
307 int numPolyLines = m_PlanarFigure->GetPolyLinesSize();
308 for (
int lineId = 0; lineId < numPolyLines; ++lineId )
311 bool outOfBounds =
false;
312 IndexVecType pointIndices;
313 typename PlanarFigure::PolyLineType::const_iterator it;
314 for ( it = planarFigurePolyline.begin();
315 it != planarFigurePolyline.end();
320 planarFigurePlaneGeometry->
Map( *it, point3D );
322 if ( !imageGeometry3D->
IsInside( point3D ) )
330 index2D[0] = point3D[i0];
331 index2D[1] = point3D[i1];
333 pointIndices.push_back( index2D );
338 throw std::runtime_error(
"Figure at least partially outside of image bounds!" );
341 for ( IndexVecType::const_iterator it = pointIndices.begin(); it != pointIndices.end()-1; ++it )
343 IndexType2D ind1 = *it;
344 IndexType2D ind2 = *(it+1);
346 LineIteratorType lineIt( maskImage, ind1, ind2 );
347 while ( !lineIt.IsAtEnd() )
356 m_InternalITKImageMask2D = maskImage;
361 if (!planarGeometry)
return false;
362 if (!geometry)
return false;
365 return GetPrincipalAxis(geometry,planarGeometry->
GetNormal(), axis);
368 bool PlanarFigureMaskGenerator::GetPrincipalAxis(
373 for (
unsigned int i = 0; i < 3; ++i )
376 axisVector.Normalize();
382 const double epsilon = 5e-5;
383 if ( fabs( fabs( axisVector * vector ) - 1.0) < epsilon)
393 void PlanarFigureMaskGenerator::CalculateMask()
400 if (m_PlanarFigure.IsNull())
407 MITK_WARN <<
"Multiple TimeSteps are not supported in PlanarFigureMaskGenerator (yet).";
411 if ( imageGeometry ==
nullptr )
413 throw std::runtime_error(
"Image geometry invalid!" );
421 imgTimeSel->UpdateLargestPossibleRegion();
422 m_InternalTimeSliceImage = imgTimeSel->GetOutput();
429 m_InternalITKImageMask2D =
nullptr;
430 const PlaneGeometry *planarFigurePlaneGeometry = m_PlanarFigure->GetPlaneGeometry();
431 const auto *planarFigureGeometry =
dynamic_cast< const PlaneGeometry *
>( planarFigurePlaneGeometry );
436 if ( !this->GetPrincipalAxis( imageGeometry,
437 planarFigureGeometry->GetNormal(), axis ) )
439 throw std::runtime_error(
"Non-aligned planar figures not supported!" );
441 m_PlanarFigureAxis = axis;
444 itk::Image< unsigned short, 3 >::IndexType index;
445 imageGeometry->
WorldToIndex( planarFigureGeometry->GetOrigin(), index );
447 unsigned int slice = index[axis];
448 m_PlanarFigureSlice = slice;
455 if ( !m_PlanarFigure->IsClosed() )
458 InternalCalculateMaskFromOpenPlanarFigure,
464 InternalCalculateMaskFromPlanarFigure,
478 m_ReferenceImage = inputImageSlice;
493 if (IsUpdateRequired())
495 this->CalculateMask();
499 m_InternalMaskUpdateTime = this->GetMTime();
506 unsigned int dimension = m_InternalTimeSliceImage->GetDimension();
511 imageExtractor->SetInput( m_InternalTimeSliceImage );
512 imageExtractor->SetSliceDimension( axis );
513 imageExtractor->SetSliceIndex( slice );
514 imageExtractor->Update();
515 return imageExtractor->GetOutput();
517 else if(dimension == 2)
519 return m_InternalTimeSliceImage;
523 MITK_ERROR <<
"Unsupported image dimension. Dimension is: " << dimension <<
". Only 2D and 3D images are supported.";
528 bool PlanarFigureMaskGenerator::IsUpdateRequired()
const 530 unsigned long thisClassTimeStamp = this->GetMTime();
532 unsigned long planarFigureTimeStamp = m_PlanarFigure->GetMTime();
533 unsigned long inputImageTimeStamp =
m_inputImage->GetMTime();
535 if (thisClassTimeStamp > m_InternalMaskUpdateTime)
540 if (m_InternalMaskUpdateTime < planarFigureTimeStamp || m_InternalMaskUpdateTime < inputImageTimeStamp)
545 if (internalMaskTimeStamp > m_InternalMaskUpdateTime)
mitk::Image::ConstPointer m_inputImage
Vector3D GetAxisVector(unsigned int direction) const
Get vector along bounding-box in the specified direction in mm.
bool IsInside(const mitk::Point3D &p) const
Test whether the point p (world coordinates in mm) is inside the bounding box.
DataCollection - Class to facilitate loading/accessing structured data.
virtual bool Map(const mitk::Point3D &pt3d_mm, mitk::Point2D &pt2d_mm) const
Project a 3D point given in mm (pt3d_mm) onto the 2D geometry. The result is a 2D point in mm (pt2d_m...
Image::Pointer GrabItkImageMemory(itk::SmartPointer< ItkOutputImageType > &itkimage, mitk::Image *mitkImage=nullptr, const BaseGeometry *geometry=nullptr, bool update=true)
Grabs the memory of an itk::Image (with a specific type) and puts it into an mitk::Image.The memory is managed by the mitk::Image after calling this function. The itk::Image remains valid until the mitk::Image decides to free the memory.
mitk::Image::Pointer m_InternalMask
mitk::Image::Pointer image
void WorldToIndex(const mitk::Point3D &pt_mm, mitk::Point3D &pt_units) const
Convert world coordinates (in mm) of a point to (continuous!) index coordinates.
Vector3D GetNormal() const
Normal of the plane.
#define AccessFixedDimensionByItk_1(mitkImage, itkImageTypeFunction, dimension, arg1)
MITKCORE_EXPORT const ScalarType eps
Describes a two-dimensional, rectangular plane.
BaseGeometry Describes the geometry of a data object.