Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
mitkPartialVolumeAnalysisHistogramCalculator.cpp
Go to the documentation of this file.
1 /*===================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center,
6 Division of Medical and Biological Informatics.
7 All rights reserved.
8 
9 This software is distributed WITHOUT ANY WARRANTY; without
10 even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 A PARTICULAR PURPOSE.
12 
13 See LICENSE.txt or http://www.mitk.org for details.
14 
15 ===================================================================*/
16 
17 
19 #include "mitkImageAccessByItk.h"
20 #include "mitkExtractImageFilter.h"
21 
22 #include <itkScalarImageToHistogramGenerator.h>
23 
24 #include <itkStatisticsImageFilter.h>
25 #include <itkLabelStatisticsImageFilter.h>
26 #include <itkBSplineUpsampleImageFilter.h>
27 #include <itkBSplineResampleImageFilterBase.h>
28 #include "itkResampleImageFilter.h"
30 
31 #include <itkCastImageFilter.h>
32 #include <itkImageFileWriter.h>
33 #include <itkVTKImageImport.h>
34 #include <itkVTKImageExport.h>
35 
36 
37 #include <vtkPoints.h>
38 #include <vtkCellArray.h>
39 #include <vtkPolyData.h>
40 #include <vtkLinearExtrusionFilter.h>
41 #include <vtkPolyDataToImageStencil.h>
42 #include <vtkImageStencil.h>
43 #include <vtkImageImport.h>
44 #include <vtkImageExport.h>
45 #include <vtkImageData.h>
46 
47 #include <vtkMetaImageWriter.h>
48 
49 #include <exception>
50 
52 #include "itkBSplineInterpolateImageFunction.h"
53 #include "itkNearestNeighborInterpolateImageFunction.h"
54 
55 #include "itkImageMaskSpatialObject.h"
56 #include "itkRegionOfInterestImageFilter.h"
57 #include "itkListSample.h"
58 
60 
61 #include <iostream>
62 #include <sstream>
63 #include <type_traits>
64 
65 namespace mitk
66 {
67 
69  : m_MaskingMode( MASKING_MODE_NONE ),
70  m_MaskingModeChanged( false ),
71  m_NumberOfBins(256),
72  m_UpsamplingFactor(1),
73  m_GaussianSigma(0),
74  m_ForceUpdate(false),
75  m_PlanarFigureThickness(0)
76  {
78  m_EmptyHistogram->SetMeasurementVectorSize(1);
79  HistogramType::SizeType histogramSize(1);
80  histogramSize.Fill( 256 );
81  m_EmptyHistogram->Initialize( histogramSize );
82 
84  }
85 
86 
88  {
89  }
90 
91 
93  {
94  if ( m_Image != image )
95  {
96  m_Image = image;
97  this->Modified();
98 
99  m_ImageStatisticsTimeStamp.Modified();
101  }
102  }
103 
105  {
106  m_AdditionalResamplingImages.push_back(image);
107  this->Modified();
108  m_ImageStatisticsTimeStamp.Modified();
110  }
111 
113  {
114  this->Modified();
115  m_ImageStatisticsTimeStamp.Modified();
121  }
122 
124  {
125  if ( m_Image.IsNull() )
126  {
127  itkExceptionMacro( << "Image needs to be set first!" );
128  }
129 
130  if ( m_Image->GetTimeSteps() != imageMask->GetTimeSteps() )
131  {
132  itkExceptionMacro( << "Image and image mask need to have equal number of time steps!" );
133  }
134 
135  if ( m_ImageMask != imageMask )
136  {
137  m_ImageMask = imageMask;
138  this->Modified();
139 
142  }
143  }
144 
145 
147  {
148  if ( m_Image.IsNull() )
149  {
150  itkExceptionMacro( << "Image needs to be set first!" );
151  }
152 
153  if ( m_PlanarFigure != planarFigure )
154  {
155  m_PlanarFigure = planarFigure;
156  this->Modified();
157 
160  }
161  }
162 
163 
165  {
166  if ( m_MaskingMode != mode )
167  {
168  m_MaskingMode = mode;
169  m_MaskingModeChanged = true;
170  this->Modified();
171  }
172  }
173 
174 
176  {
178  {
180  m_MaskingModeChanged = true;
181  this->Modified();
182  }
183  }
184 
185 
187  {
189  {
191  m_MaskingModeChanged = true;
192  this->Modified();
193  }
194  }
195 
196 
198  {
200  {
202  m_MaskingModeChanged = true;
203  this->Modified();
204  }
205  }
206 
207 
208 
210  {
211 
212  MITK_DEBUG << "ComputeStatistics() start";
213 
214  if ( m_Image.IsNull() )
215  {
216  itkExceptionMacro( << "Image not set!" );
217  }
218 
219  if ( m_Image->GetReferenceCount() == 1 )
220  {
221  MITK_DEBUG << "No Stats calculated; no one else holds a reference on it";
222  return false;
223  }
224 
225  // If a mask was set but we are the only ones to still hold a reference on
226  // it, delete it.
227  if ( m_ImageMask.IsNotNull() && (m_ImageMask->GetReferenceCount() == 1) )
228  {
229  m_ImageMask = nullptr;
230  }
231 
232 
233  // Check if statistics is already up-to-date
234  unsigned long imageMTime = m_ImageStatisticsTimeStamp.GetMTime();
235  unsigned long maskedImageMTime = m_MaskedImageStatisticsTimeStamp.GetMTime();
236  unsigned long planarFigureMTime = m_PlanarFigureStatisticsTimeStamp.GetMTime();
237 
238  bool imageStatisticsCalculationTrigger = m_ImageStatisticsCalculationTriggerBool;
239  bool maskedImageStatisticsCalculationTrigger = m_MaskedImageStatisticsCalculationTriggerBool;
240  bool planarFigureStatisticsCalculationTrigger = m_PlanarFigureStatisticsCalculationTriggerBool;
241 
242  if ( /*prevent calculation without mask*/!m_ForceUpdate &&( m_MaskingMode == MASKING_MODE_NONE || (
243  ((m_MaskingMode != MASKING_MODE_NONE) || (imageMTime > m_Image->GetMTime() && !imageStatisticsCalculationTrigger))
244  && ((m_MaskingMode != MASKING_MODE_IMAGE) || (m_ImageMask.IsNotNull() && maskedImageMTime > m_ImageMask->GetMTime() && !maskedImageStatisticsCalculationTrigger))
245  && ((m_MaskingMode != MASKING_MODE_PLANARFIGURE) || (m_PlanarFigure.IsNotNull() && planarFigureMTime > m_PlanarFigure->GetMTime() && !planarFigureStatisticsCalculationTrigger)) ) ) )
246  {
247  MITK_DEBUG << "Returning, statistics already up to date!";
248  if ( m_MaskingModeChanged )
249  {
250  m_MaskingModeChanged = false;
251  return true;
252  }
253  else
254  {
255  return false;
256  }
257  }
258 
259  // Reset state changed flag
260  m_MaskingModeChanged = false;
261 
262 
263  // Depending on masking mode, extract and/or generate the required image
264  // and mask data from the user input
265  this->ExtractImageAndMask( );
266 
267 
268  Statistics *statistics;
269  HistogramType::ConstPointer *histogram;
270  switch ( m_MaskingMode )
271  {
272  case MASKING_MODE_NONE:
273  default:
274  statistics = &m_ImageStatistics;
275  histogram = &m_ImageHistogram;
276 
277  m_ImageStatisticsTimeStamp.Modified();
279  break;
280 
281  case MASKING_MODE_IMAGE:
282  statistics = &m_MaskedImageStatistics;
283  histogram = &m_MaskedImageHistogram;
284 
287  break;
288 
290  statistics = &m_PlanarFigureStatistics;
291  histogram = &m_PlanarFigureHistogram;
292 
295  break;
296  }
297 
298  // Calculate statistics and histogram(s)
299  if ( m_InternalImage->GetDimension() == 3 )
300  {
302  {
303  // Reset state changed flag
307  3,
308  *statistics,
309  histogram );
310  }
311  else
312  {
316  3,
317  m_InternalImageMask3D.GetPointer(),
318  *statistics,
319  histogram );
320  }
321  }
322  else if ( m_InternalImage->GetDimension() == 2 )
323  {
325  {
329  2,
330  *statistics,
331  histogram );
332  }
333  else
334  {
338  2,
339  m_InternalImageMask2D.GetPointer(),
340  *statistics,
341  histogram );
342  }
343  }
344  else
345  {
346  MITK_ERROR << "ImageStatistics: Image dimension not supported!";
347  }
348 
349  // Release unused image smart pointers to free memory
350  // m_InternalImage = mitk::Image::Pointer();
353  return true;
354  }
355 
356 
359  {
360  if ( m_Image.IsNull() )
361  {
362  return nullptr;
363  }
364 
365  switch ( m_MaskingMode )
366  {
367  case MASKING_MODE_NONE:
368  default:
369  return m_ImageHistogram;
370 
371  case MASKING_MODE_IMAGE:
372  return m_MaskedImageHistogram;
373 
376  }
377  }
378 
379 
382  {
383  if ( m_Image.IsNull() )
384  {
385  return m_EmptyStatistics;
386  }
387 
388  switch ( m_MaskingMode )
389  {
390  case MASKING_MODE_NONE:
391  default:
392  return m_ImageStatistics;
393 
394  case MASKING_MODE_IMAGE:
396 
399  }
400  }
401 
402 
404  {
405 
406  MITK_DEBUG << "ExtractImageAndMask( ) start";
407 
408  if ( m_Image.IsNull() )
409  {
410  throw std::runtime_error( "Error: image empty!" );
411  }
412 
413  mitk::Image *timeSliceImage = const_cast<mitk::Image*>(m_Image.GetPointer());//imageTimeSelector->GetOutput();
414 
415  switch ( m_MaskingMode )
416  {
417  case MASKING_MODE_NONE:
418  {
419  m_InternalImage = timeSliceImage;
420  int s = m_AdditionalResamplingImages.size();
422  for(int i=0; i<s; i++)
423  {
425  }
426  m_InternalImageMask2D = nullptr;
427  m_InternalImageMask3D = nullptr;
428  break;
429  }
430 
431  case MASKING_MODE_IMAGE:
432  {
433  if ( m_ImageMask.IsNotNull() && (m_ImageMask->GetReferenceCount() > 1) )
434  {
435  ImageTimeSelector::Pointer maskedImageTimeSelector = ImageTimeSelector::New();
436  maskedImageTimeSelector->SetInput( m_ImageMask );
437  maskedImageTimeSelector->SetTimeNr( 0 );
438  maskedImageTimeSelector->UpdateLargestPossibleRegion();
439  mitk::Image *timeSliceMaskedImage = maskedImageTimeSelector->GetOutput();
440 
441  InternalMaskImage(timeSliceMaskedImage);
442 
443  if(m_UpsamplingFactor != 1)
444  {
446  }
447 
449  timeSliceImage,
451 
452  int s = m_AdditionalResamplingImages.size();
454  for(int i=0; i<s; i++)
455  {
459  }
460 
461  }
462  else
463  {
464  throw std::runtime_error( "Error: image mask empty!" );
465  }
466  break;
467  }
468 
470  {
471  m_InternalImageMask2D = nullptr;
472 
473  if ( m_PlanarFigure.IsNull() )
474  {
475  throw std::runtime_error( "Error: planar figure empty!" );
476  }
477  if ( !m_PlanarFigure->IsClosed() )
478  {
479  throw std::runtime_error( "Masking not possible for non-closed figures" );
480  }
481 
482  const BaseGeometry *imageGeometry = timeSliceImage->GetUpdatedGeometry();
483  if ( imageGeometry == nullptr )
484  {
485  throw std::runtime_error( "Image geometry invalid!" );
486  }
487 
488  const PlaneGeometry *planarFigureGeometry2D = m_PlanarFigure->GetPlaneGeometry();
489  if ( planarFigureGeometry2D == nullptr )
490  {
491  throw std::runtime_error( "Planar-Figure not yet initialized!" );
492  }
493 
494  const PlaneGeometry *planarFigureGeometry =
495  dynamic_cast< const PlaneGeometry * >( planarFigureGeometry2D );
496  const AbstractTransformGeometry *abstrTransfGeometry =
497  dynamic_cast< const AbstractTransformGeometry * >( planarFigureGeometry2D );
498 
499  if ( !planarFigureGeometry || abstrTransfGeometry )
500  {
501  throw std::runtime_error( "Only PlaneGeometry supported." );
502  }
503 
504 
505 // unsigned int axis = 2;
506 // unsigned int slice = 0;
507 
509  timeSliceImage,
511  timeSliceImage->GetGeometry(),
512  m_PlanarFigure->GetGeometry(), -1 );
513 
517  3, 2 );
518 
519  int s = m_AdditionalResamplingImages.size();
520  for(int i=0; i<s; i++)
521  {
525  timeSliceImage->GetGeometry(),
526  m_PlanarFigure->GetGeometry(), i );
527 
531  }
532  }
533  }
534 
535  }
536 
537 
539  const Geometry3D *geometry, Vector3D vector,
540  unsigned int &axis )
541  {
542  vector.Normalize();
543  for ( unsigned int i = 0; i < 3; ++i )
544  {
545  Vector3D axisVector = geometry->GetAxisVector( i );
546  axisVector.Normalize();
547 
548  if ( fabs( fabs( axisVector * vector ) - 1.0) < mitk::eps )
549  {
550  axis = i;
551  return true;
552  }
553  }
554 
555  return false;
556  }
557 
559  mitk::Image *image )
560  {
561 
562  typedef itk::ImageMaskSpatialObject<3> ImageMaskSpatialObject;
563  typedef itk::Image< unsigned char, 3 > ImageType;
564 
565  typedef mitk::ImageToItk<ImageType> CastType;
566  CastType::Pointer caster = CastType::New();
567  caster->SetInput(image);
568  caster->Update();
569 
571  maskSO->SetImage ( caster->GetOutput() );
573  maskSO->GetAxisAlignedBoundingBoxRegion();
574 
575  // check if bounding box is empty, if so set it to 1,1,1
576  // to prevent empty mask image
577  if (m_InternalMask3D.GetSize()[0] == 0 )
578  {
579  m_InternalMask3D.SetSize(0,1);
580  m_InternalMask3D.SetSize(1,1);
581  m_InternalMask3D.SetSize(2,1);
582  }
583  MITK_DEBUG << "Bounding Box Region: " << m_InternalMask3D;
584 
585  // crop the mask image to the BoundingBoxRegion extracted via the spatial masking object
586  typedef itk::RegionOfInterestImageFilter< ImageType, MaskImage3DType > ROIFilterType;
588  roi->SetRegionOfInterest(m_InternalMask3D);
589  roi->SetInput(caster->GetOutput());
590  roi->Update();
591 
592  m_InternalImageMask3D = roi->GetOutput();
593 
594  MITK_DEBUG << "Created m_InternalImageMask3D";
595 
596  }
597 
598 
599  template < typename TPixel, unsigned int VImageDimension >
601  const itk::Image< TPixel, VImageDimension > *image,
602  mitk::BaseGeometry* , mitk::BaseGeometry* planegeo3D, int additionalIndex )
603  {
604 
605  MITK_DEBUG << "InternalReorientImagePlane() start";
606 
607  typedef itk::Image< TPixel, VImageDimension > ImageType;
608  typedef itk::Image< float, VImageDimension > FloatImageType;
609 
610  typedef itk::ResampleImageFilter<ImageType, FloatImageType, double> ResamplerType;
611  typename ResamplerType::Pointer resampler = ResamplerType::New();
612 
613  mitk::PlaneGeometry* planegeo = dynamic_cast<mitk::PlaneGeometry*>(planegeo3D);
614  if ( !planegeo )
615  {
616  throw std::runtime_error( "Unexpected null pointer returned for pointer to PlaneGeometry." );
617  }
618  else
619  {
620  mitk::AbstractTransformGeometry* abstrGeo = dynamic_cast<mitk::AbstractTransformGeometry*>(planegeo3D);
621  if ( abstrGeo )
622  {
623  throw std::runtime_error( "Unexpected pointer to AbstractTransformGeometry returned." );
624  }
625  }
626 
627  float upsamp = m_UpsamplingFactor;
628  float gausssigma = m_GaussianSigma;
629 
630  // Spacing
631  typename ResamplerType::SpacingType spacing = planegeo->GetSpacing();
632  spacing[0] = image->GetSpacing()[0] / upsamp;
633  spacing[1] = image->GetSpacing()[1] / upsamp;
634  spacing[2] = image->GetSpacing()[2];
636  {
637  spacing[2] = image->GetSpacing()[2] / upsamp;
638  }
639  resampler->SetOutputSpacing( spacing );
640 
641  // Size
642  typename ResamplerType::SizeType size;
643  size[0] = planegeo->GetExtentInMM(0) / spacing[0];
644  size[1] = planegeo->GetExtentInMM(1) / spacing[1];
645  size[2] = 1+2*m_PlanarFigureThickness; // klaus add +2*m_PlanarFigureThickness
646  MITK_DEBUG << "setting size2:="<<size[2] << " (before " << 1 << ")";
647  resampler->SetSize( size );
648 
649  // Origin
650  typename mitk::Point3D orig = planegeo->GetOrigin();
651  typename mitk::Point3D corrorig;
652  planegeo3D->WorldToIndex(orig,corrorig);
653  corrorig[0] += 0.5/upsamp;
654  corrorig[1] += 0.5/upsamp;
656  {
657  float thickyyy = m_PlanarFigureThickness;
658  thickyyy/=upsamp;
659  corrorig[2] -= thickyyy; // klaus add -= (float)m_PlanarFigureThickness/upsamp statt += 0
660  }
661  planegeo3D->IndexToWorld(corrorig,corrorig);
662  resampler->SetOutputOrigin(corrorig );
663 
664  // Direction
665  typename ResamplerType::DirectionType direction;
666  typename mitk::AffineTransform3D::MatrixType matrix = planegeo->GetIndexToWorldTransform()->GetMatrix();
667  for(unsigned int c = 0; c < matrix.ColumnDimensions; ++c)
668  {
669  double sum = 0;
670  for(unsigned int r = 0 ; r<matrix.RowDimensions; r++)
671  {
672  sum += matrix(r,c)*matrix(r,c);
673  }
674  for(unsigned int r = 0 ; r<matrix.RowDimensions; ++r)
675  {
676  direction(r,c) = matrix(r,c)/sqrt(sum);
677  }
678  }
679  resampler->SetOutputDirection( direction );
680 
681  // Gaussian interpolation
682  if(gausssigma != 0)
683  {
684  double sigma[3];
685  for( unsigned int d = 0; d < 3; d++ )
686  {
687  sigma[d] = gausssigma * image->GetSpacing()[d];
688  }
689  double alpha = 2.0;
690 
692  GaussianInterpolatorType;
693 
694  typename GaussianInterpolatorType::Pointer interpolator
696 
697  interpolator->SetInputImage( image );
698  interpolator->SetParameters( sigma, alpha );
699 
700  resampler->SetInterpolator( interpolator );
701  }
702  else
703  {
704  // typedef typename itk::BSplineInterpolateImageFunction<ImageType, double>
705  // InterpolatorType;
706  typedef typename itk::LinearInterpolateImageFunction<ImageType, double> InterpolatorType;
707 
708  typename InterpolatorType::Pointer interpolator
710 
711  interpolator->SetInputImage( image );
712 
713  resampler->SetInterpolator( interpolator );
714 
715  }
716 
717  // Other resampling options
718  resampler->SetInput( image );
719  resampler->SetDefaultPixelValue(0);
720 
721  MITK_DEBUG << "Resampling requested image plane ... ";
722  resampler->Update();
723  MITK_DEBUG << " ... done";
724 
725  if(additionalIndex < 0)
726  {
728  this->m_InternalImage->InitializeByItk( resampler->GetOutput() );
729  this->m_InternalImage->SetVolume( resampler->GetOutput()->GetBufferPointer() );
730  }
731  else
732  {
733  unsigned int myIndex = additionalIndex;
735  this->m_InternalAdditionalResamplingImages[myIndex]->InitializeByItk( resampler->GetOutput() );
736  this->m_InternalAdditionalResamplingImages[myIndex]->SetVolume( resampler->GetOutput()->GetBufferPointer() );
737  }
738 
739  }
740 
741  template < typename TPixel, unsigned int VImageDimension >
743  const itk::Image< TPixel, VImageDimension > *image, int additionalIndex )
744  {
745  typedef itk::Image< TPixel, VImageDimension > ImageType;
746 
747  typename ImageType::Pointer outImage = ImageType::New();
748  outImage->SetSpacing( m_InternalImageMask3D->GetSpacing() ); // Set the image spacing
749  outImage->SetOrigin( m_InternalImageMask3D->GetOrigin() ); // Set the image origin
750  outImage->SetDirection( m_InternalImageMask3D->GetDirection() ); // Set the image direction
751  outImage->SetRegions( m_InternalImageMask3D->GetLargestPossibleRegion() );
752  outImage->Allocate();
753  outImage->FillBuffer(0);
754 
755  typedef itk::InterpolateImageFunction<ImageType, double>
756  BaseInterpType;
758  GaussianInterpolatorType;
759  typedef itk::LinearInterpolateImageFunction<ImageType, double>
760  LinearInterpolatorType;
761 
762  typename BaseInterpType::Pointer interpolator;
763 
764  if(m_GaussianSigma != 0)
765  {
766  double sigma[3];
767  for( unsigned int d = 0; d < 3; d++ )
768  {
769  sigma[d] = m_GaussianSigma * image->GetSpacing()[d];
770  }
771  double alpha = 2.0;
772 
773  interpolator = GaussianInterpolatorType::New();
774  dynamic_cast<GaussianInterpolatorType*>(interpolator.GetPointer())->SetParameters( sigma, alpha );
775 
776  }
777  else
778  {
779  interpolator = LinearInterpolatorType::New();
780  }
781 
782  interpolator->SetInputImage( image );
783 
784  itk::ImageRegionConstIterator<MaskImage3DType>
785  itmask(m_InternalImageMask3D, m_InternalImageMask3D->GetLargestPossibleRegion());
786  itk::ImageRegionIterator<ImageType>
787  itimage(outImage, outImage->GetLargestPossibleRegion());
788 
789  itmask.GoToBegin();
790  itimage.GoToBegin();
791 
792  itk::Point< double, 3 > point;
793  itk::ContinuousIndex< double, 3 > index;
794  while( !itmask.IsAtEnd() )
795  {
796  if(itmask.Get() != 0)
797  {
798  outImage->TransformIndexToPhysicalPoint (itimage.GetIndex(), point);
799  image->TransformPhysicalPointToContinuousIndex(point, index);
800  itimage.Set(interpolator->EvaluateAtContinuousIndex(index));
801  }
802 
803  ++itmask;
804  ++itimage;
805  }
806 
807  if(additionalIndex < 0)
808  {
810  this->m_InternalImage->InitializeByItk( outImage.GetPointer() );
811  this->m_InternalImage->SetVolume( outImage->GetBufferPointer() );
812  }
813  else
814  {
815  this->m_InternalAdditionalResamplingImages[additionalIndex] = mitk::Image::New();
816  this->m_InternalAdditionalResamplingImages[additionalIndex]->InitializeByItk( outImage.GetPointer() );
817  this->m_InternalAdditionalResamplingImages[additionalIndex]->SetVolume( outImage->GetBufferPointer() );
818  }
819 
820  }
821 
823  const MaskImage3DType *image )
824  {
825  typedef itk::ResampleImageFilter<MaskImage3DType, MaskImage3DType, double> ResamplerType;
827 
828  // Size
829  ResamplerType::SizeType size;
830  size[0] = m_UpsamplingFactor * image->GetLargestPossibleRegion().GetSize()[0];
831  size[1] = m_UpsamplingFactor * image->GetLargestPossibleRegion().GetSize()[1];
832  size[2] = m_UpsamplingFactor * image->GetLargestPossibleRegion().GetSize()[2];;
833  resampler->SetSize( size );
834 
835  // Origin
836  mitk::Point3D orig = image->GetOrigin();
837  resampler->SetOutputOrigin(orig );
838 
839  // Spacing
840  ResamplerType::SpacingType spacing;
841  spacing[0] = image->GetSpacing()[0] / m_UpsamplingFactor;
842  spacing[1] = image->GetSpacing()[1] / m_UpsamplingFactor;
843  spacing[2] = image->GetSpacing()[2] / m_UpsamplingFactor;
844  resampler->SetOutputSpacing( spacing );
845 
846  resampler->SetOutputDirection( image->GetDirection() );
847 
848  typedef itk::NearestNeighborInterpolateImageFunction<MaskImage3DType, double>
849  InterpolatorType;
850 
851  InterpolatorType::Pointer interpolator
853 
854  interpolator->SetInputImage( image );
855 
856  resampler->SetInterpolator( interpolator );
857 
858  // Other resampling options
859  resampler->SetInput( image );
860  resampler->SetDefaultPixelValue(0);
861  resampler->Update();
862 
863  m_InternalImageMask3D = resampler->GetOutput();
864 
865  }
866 
867 
868 
869  template < typename TPixel, unsigned int VImageDimension >
871  const itk::Image< TPixel, VImageDimension > *image,
872  Statistics &statistics,
873  typename HistogramType::ConstPointer *histogram )
874  {
875  MITK_DEBUG << "InternalCalculateStatisticsUnmasked()";
876 
877  typedef itk::Image< TPixel, VImageDimension > ImageType;
878 
879  // Progress listening...
880  typedef itk::SimpleMemberCommand< PartialVolumeAnalysisHistogramCalculator > ITKCommandType;
881  ITKCommandType::Pointer progressListener;
882  progressListener = ITKCommandType::New();
883  progressListener->SetCallbackFunction( this,
885 
886  // Issue 100 artificial progress events since ScalarIMageToHistogramGenerator
887  // does not (yet?) support progress reporting
888  this->InvokeEvent( itk::StartEvent() );
889  for ( unsigned int i = 0; i < 100; ++i )
890  {
892  }
893 
894  // Calculate statistics (separate filter)
895  typedef itk::StatisticsImageFilter< ImageType > StatisticsFilterType;
896  typename StatisticsFilterType::Pointer statisticsFilter = StatisticsFilterType::New();
897  statisticsFilter->SetInput( image );
898  unsigned long observerTag = statisticsFilter->AddObserver(
899  itk::ProgressEvent(), progressListener );
900 
901  statisticsFilter->Update();
902 
903  statisticsFilter->RemoveObserver( observerTag );
904 
905 
906  this->InvokeEvent( itk::EndEvent() );
907 
908  statistics.N = image->GetBufferedRegion().GetNumberOfPixels();
909  statistics.Min = statisticsFilter->GetMinimum();
910  statistics.Max = statisticsFilter->GetMaximum();
911  statistics.Mean = statisticsFilter->GetMean();
912  statistics.Median = 0.0;
913  statistics.Sigma = statisticsFilter->GetSigma();
914  statistics.RMS = sqrt( statistics.Mean * statistics.Mean
915  + statistics.Sigma * statistics.Sigma );
916 
917  typename ImageType::Pointer inImage = const_cast<ImageType*>(image);
918 
919  // Calculate histogram
920  typedef itk::Statistics::ScalarImageToHistogramGenerator< ImageType >
921  HistogramGeneratorType;
922  typename HistogramGeneratorType::Pointer histogramGenerator = HistogramGeneratorType::New();
923  histogramGenerator->SetInput( inImage );
924  histogramGenerator->SetMarginalScale( 10 ); // Defines y-margin width of histogram
925  histogramGenerator->SetNumberOfBins( m_NumberOfBins ); // CT range [-1024, +2048] --> bin size 4 values
926  histogramGenerator->SetHistogramMin( statistics.Min );
927  histogramGenerator->SetHistogramMax( statistics.Max );
928  histogramGenerator->Compute();
929  *histogram = histogramGenerator->GetOutput();
930  }
931 
932 
933  template < typename TPixel, unsigned int VImageDimension >
935  const itk::Image< TPixel, VImageDimension > *image,
936  itk::Image< unsigned char, VImageDimension > *maskImage,
937  Statistics &,
938  typename HistogramType::ConstPointer *histogram )
939  {
940  MITK_DEBUG << "InternalCalculateStatisticsMasked() start";
941 
942  typedef itk::Image< TPixel, VImageDimension > ImageType;
943  typedef itk::Image< unsigned char, VImageDimension > MaskImageType;
944 
945  // generate a list sample of angles at positions
946  // where the fiber-prob is higher than .2*maxprob
947  typedef TPixel MeasurementType;
948  const unsigned int MeasurementVectorLength = 1;
949  typedef itk::Vector< MeasurementType , MeasurementVectorLength >
950  MeasurementVectorType;
951  typedef itk::Statistics::ListSample< MeasurementVectorType > ListSampleType;
952  typename ListSampleType::Pointer listSample = ListSampleType::New();
953  listSample->SetMeasurementVectorSize( MeasurementVectorLength );
954 
955  itk::ImageRegionConstIterator<MaskImageType>
956  itmask(maskImage, maskImage->GetLargestPossibleRegion());
957  itk::ImageRegionConstIterator<ImageType>
958  itimage(image, image->GetLargestPossibleRegion());
959 
960  itmask.GoToBegin();
961  itimage.GoToBegin();
962 
963  while( !itmask.IsAtEnd() )
964  {
965  if(itmask.Get() != 0)
966  {
967  // apend to list
968  MeasurementVectorType mv;
969  mv[0] = ( MeasurementType ) itimage.Get();
970  listSample->PushBack(mv);
971  }
972  ++itmask;
973  ++itimage;
974  }
975 
976  // generate a histogram from the list sample
977  typedef double HistogramMeasurementType;
978  typedef itk::Statistics::Histogram< HistogramMeasurementType, itk::Statistics::DenseFrequencyContainer2 > HistogramType;
979  typedef itk::Statistics::SampleToHistogramFilter< ListSampleType, HistogramType > GeneratorType;
980  typename GeneratorType::Pointer generator = GeneratorType::New();
981  typename GeneratorType::HistogramType::SizeType size(MeasurementVectorLength);
982  size.Fill(m_NumberOfBins);
983  generator->SetHistogramSize( size );
984  generator->SetInput( listSample );
985  generator->SetMarginalScale( 10.0 );
986  generator->Update();
987  *histogram = generator->GetOutput();
988 
989  }
990 
991 
992  template < typename TPixel, unsigned int VImageDimension >
994  itk::Image< TPixel, VImageDimension > *image, int additionalIndex )
995  {
996  typedef itk::Image< TPixel, VImageDimension > ImageType;
997  typedef itk::RegionOfInterestImageFilter< ImageType, ImageType > ROIFilterType;
999  roi->SetRegionOfInterest(m_CropRegion);
1000  roi->SetInput(image);
1001  roi->Update();
1002 
1004  m_InternalAdditionalResamplingImages[additionalIndex]->InitializeByItk(roi->GetOutput());
1005  m_InternalAdditionalResamplingImages[additionalIndex]->SetVolume(roi->GetOutput()->GetBufferPointer());
1006  }
1007 
1008  template < typename TPixel, unsigned int VImageDimension >
1010  itk::Image< TPixel, VImageDimension > *image, unsigned int axis )
1011  {
1012 
1013  MITK_DEBUG << "InternalCalculateMaskFromPlanarFigure() start";
1014 
1015  typedef itk::Image< TPixel, VImageDimension > ImageType;
1016 
1017  // Generate mask image as new image with same header as input image and
1018  // initialize with "1".
1020  newMaskImage->SetSpacing( image->GetSpacing() ); // Set the image spacing
1021  newMaskImage->SetOrigin( image->GetOrigin() ); // Set the image origin
1022  newMaskImage->SetDirection( image->GetDirection() ); // Set the image direction
1023  newMaskImage->SetRegions( image->GetLargestPossibleRegion() );
1024  newMaskImage->Allocate();
1025  newMaskImage->FillBuffer( 1 );
1026 
1027  // Generate VTK polygon from (closed) PlanarFigure polyline
1028  // (The polyline points are shifted by -0.5 in z-direction to make sure
1029  // that the extrusion filter, which afterwards elevates all points by +0.5
1030  // in z-direction, creates a 3D object which is cut by the the plane z=0)
1031  const mitk::PlaneGeometry *planarFigureGeometry2D = m_PlanarFigure->GetPlaneGeometry();
1032  const typename PlanarFigure::PolyLineType planarFigurePolyline = m_PlanarFigure->GetPolyLine( 0 );
1033  const mitk::BaseGeometry *imageGeometry3D = m_InternalImage->GetGeometry( 0 );
1034 
1035  vtkPolyData *polyline = vtkPolyData::New();
1036  polyline->Allocate( 1, 1 );
1037 
1038  // Determine x- and y-dimensions depending on principal axis
1039  int i0, i1;
1040  switch ( axis )
1041  {
1042  case 0:
1043  i0 = 1;
1044  i1 = 2;
1045  break;
1046 
1047  case 1:
1048  i0 = 0;
1049  i1 = 2;
1050  break;
1051 
1052  case 2:
1053  default:
1054  i0 = 0;
1055  i1 = 1;
1056  break;
1057  }
1058 
1059  // Create VTK polydata object of polyline contour
1060  bool outOfBounds = false;
1061  vtkPoints *points = vtkPoints::New();
1062  typename PlanarFigure::PolyLineType::const_iterator it;
1063  for ( it = planarFigurePolyline.begin();
1064  it != planarFigurePolyline.end();
1065  ++it )
1066  {
1067  Point3D point3D;
1068 
1069  // Convert 2D point back to the local index coordinates of the selected
1070  // image
1071  mitk::Point2D point2D = *it;
1072  planarFigureGeometry2D->WorldToIndex(point2D, point2D);
1073  point2D[0] -= 0.5/m_UpsamplingFactor;
1074  point2D[1] -= 0.5/m_UpsamplingFactor;
1075  planarFigureGeometry2D->IndexToWorld(point2D, point2D);
1076  planarFigureGeometry2D->Map( point2D, point3D );
1077 
1078  // Polygons (partially) outside of the image bounds can not be processed
1079  // further due to a bug in vtkPolyDataToImageStencil
1080  if ( !imageGeometry3D->IsInside( point3D ) )
1081  {
1082  outOfBounds = true;
1083  }
1084 
1085  imageGeometry3D->WorldToIndex( point3D, point3D );
1086  point3D[i0] += 0.5;
1087  point3D[i1] += 0.5;
1088 
1089  // Add point to polyline array
1090  points->InsertNextPoint( point3D[i0], point3D[i1], -0.5 );
1091  }
1092  polyline->SetPoints( points );
1093  points->Delete();
1094 
1095  if ( outOfBounds )
1096  {
1097  polyline->Delete();
1098  throw std::runtime_error( "Figure at least partially outside of image bounds!" );
1099  }
1100 
1101  std::size_t numberOfPoints = planarFigurePolyline.size();
1102  auto ptIds = new vtkIdType[numberOfPoints];
1103  for ( std::size_t i = 0; i < numberOfPoints; ++i )
1104  {
1105  ptIds[i] = i;
1106  }
1107  polyline->InsertNextCell( VTK_POLY_LINE, numberOfPoints, ptIds );
1108 
1109 
1110  // Extrude the generated contour polygon
1111  vtkLinearExtrusionFilter *extrudeFilter = vtkLinearExtrusionFilter::New();
1112  extrudeFilter->SetInputData( polyline );
1113  extrudeFilter->SetScaleFactor( 1 );
1114  extrudeFilter->SetExtrusionTypeToNormalExtrusion();
1115  extrudeFilter->SetVector( 0.0, 0.0, 1.0 );
1116 
1117  // Make a stencil from the extruded polygon
1118  vtkPolyDataToImageStencil *polyDataToImageStencil = vtkPolyDataToImageStencil::New();
1119  polyDataToImageStencil->SetInputConnection( extrudeFilter->GetOutputPort() );
1120 
1121 
1122 
1123  // Export from ITK to VTK (to use a VTK filter)
1124  typedef itk::VTKImageImport< MaskImage3DType > ImageImportType;
1125  typedef itk::VTKImageExport< MaskImage3DType > ImageExportType;
1126 
1127  typename ImageExportType::Pointer itkExporter = ImageExportType::New();
1128  itkExporter->SetInput( newMaskImage );
1129 
1130  vtkImageImport *vtkImporter = vtkImageImport::New();
1131  this->ConnectPipelines( itkExporter, vtkImporter );
1132  vtkImporter->Update();
1133 
1134 
1135  // Apply the generated image stencil to the input image
1136  vtkImageStencil *imageStencilFilter = vtkImageStencil::New();
1137  imageStencilFilter->SetInputData( vtkImporter->GetOutput() );
1138  imageStencilFilter->SetStencilConnection(polyDataToImageStencil->GetOutputPort() );
1139  imageStencilFilter->ReverseStencilOff();
1140  imageStencilFilter->SetBackgroundValue( 0 );
1141  imageStencilFilter->Update();
1142 
1143 
1144  // Export from VTK back to ITK
1145  vtkImageExport *vtkExporter = vtkImageExport::New();
1146  vtkExporter->SetInputData( imageStencilFilter->GetOutput() );
1147  vtkExporter->Update();
1148 
1149  typename ImageImportType::Pointer itkImporter = ImageImportType::New();
1150  this->ConnectPipelines( vtkExporter, itkImporter );
1151  itkImporter->Update();
1152 
1153  // calculate cropping bounding box
1154  m_InternalImageMask3D = itkImporter->GetOutput();
1155  m_InternalImageMask3D->SetDirection(image->GetDirection());
1156 
1157  itk::ImageRegionIterator<MaskImage3DType>
1158  itmask(m_InternalImageMask3D, m_InternalImageMask3D->GetLargestPossibleRegion());
1159  itmask.GoToBegin();
1160  while( !itmask.IsAtEnd() )
1161  {
1162  if(itmask.Get() != 0)
1163  {
1164  typename ImageType::IndexType index = itmask.GetIndex();
1165  for(unsigned int thick=0; thick<2*m_PlanarFigureThickness+1; thick++)
1166  {
1167  index[axis] = thick;
1168  m_InternalImageMask3D->SetPixel(index, itmask.Get());
1169  }
1170  }
1171  ++itmask;
1172  }
1173 
1174  itmask.GoToBegin();
1175  itk::ImageRegionIterator<ImageType>
1176  itimage(image, image->GetLargestPossibleRegion());
1177  itimage.GoToBegin();
1178 
1179  typename ImageType::SizeType lowersize;
1181  typename ImageType::SizeType uppersize;
1183  while( !itmask.IsAtEnd() )
1184  {
1185  if(itmask.Get() == 0)
1186  {
1187  itimage.Set(0);
1188  }
1189  else
1190  {
1191  typename ImageType::IndexType index = itimage.GetIndex();
1192  typename ImageType::SizeType signedindex;
1193  signedindex[0] = index[0];
1194  signedindex[1] = index[1];
1195  signedindex[2] = index[2];
1196 
1197  lowersize[0] = signedindex[0] < lowersize[0] ? signedindex[0] : lowersize[0];
1198  lowersize[1] = signedindex[1] < lowersize[1] ? signedindex[1] : lowersize[1];
1199  lowersize[2] = signedindex[2] < lowersize[2] ? signedindex[2] : lowersize[2];
1200 
1201  uppersize[0] = signedindex[0] > uppersize[0] ? signedindex[0] : uppersize[0];
1202  uppersize[1] = signedindex[1] > uppersize[1] ? signedindex[1] : uppersize[1];
1203  uppersize[2] = signedindex[2] > uppersize[2] ? signedindex[2] : uppersize[2];
1204  }
1205 
1206  ++itmask;
1207  ++itimage;
1208  }
1209 
1210  typename ImageType::IndexType index;
1211  index[0] = lowersize[0];
1212  index[1] = lowersize[1];
1213  index[2] = lowersize[2];
1214 
1215  typename ImageType::SizeType size;
1216  size[0] = uppersize[0] - lowersize[0] + 1;
1217  size[1] = uppersize[1] - lowersize[1] + 1;
1218  size[2] = uppersize[2] - lowersize[2] + 1;
1219 
1220  m_CropRegion = itk::ImageRegion<3>(index, size);
1221 
1222  // crop internal image
1223  typedef itk::RegionOfInterestImageFilter< ImageType, ImageType > ROIFilterType;
1224  typename ROIFilterType::Pointer roi = ROIFilterType::New();
1225  roi->SetRegionOfInterest(m_CropRegion);
1226  roi->SetInput(image);
1227  roi->Update();
1228 
1230  m_InternalImage->InitializeByItk(roi->GetOutput());
1231  m_InternalImage->SetVolume(roi->GetOutput()->GetBufferPointer());
1232 
1233  // crop internal mask
1234  typedef itk::RegionOfInterestImageFilter< MaskImage3DType, MaskImage3DType > ROIMaskFilterType;
1236  roi2->SetRegionOfInterest(m_CropRegion);
1237  roi2->SetInput(m_InternalImageMask3D);
1238  roi2->Update();
1239  m_InternalImageMask3D = roi2->GetOutput();
1240 
1241  // Clean up VTK objects
1242  polyline->Delete();
1243  extrudeFilter->Delete();
1244  polyDataToImageStencil->Delete();
1245  vtkImporter->Delete();
1246  imageStencilFilter->Delete();
1247  //vtkExporter->Delete(); // TODO: crashes when outcommented; memory leak??
1248  delete[] ptIds;
1249 
1250  }
1251 
1252 
1254  {
1255  // Need to throw away every second progress event to reach a final count of
1256  // 100 since two consecutive filters are used in this case
1257  static int updateCounter = 0;
1258  if ( updateCounter++ % 2 == 0 )
1259  {
1260  this->InvokeEvent( itk::ProgressEvent() );
1261  }
1262  }
1263 
1264 
1266  {
1267  this->InvokeEvent( itk::ProgressEvent() );
1268  }
1269 
1270 
1271 }
const Point3D GetOrigin() const
Get the origin, e.g. the upper-left corner of the plane.
bool GetPrincipalAxis(const Geometry3D *geometry, Vector3D vector, unsigned int &axis)
If the passed vector matches any of the three principal axes of the passed geometry, the ínteger value corresponding to the axis is set and true is returned.
itk::SmartPointer< Self > Pointer
Standard implementation of BaseGeometry.
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...
#define MITK_ERROR
Definition: mitkLogMacros.h:24
void SetMaskingMode(unsigned int mode)
Set/Get operation mode for masking.
Evaluates the Gaussian interpolation of an image.
#define MITK_DEBUG
Definition: mitkLogMacros.h:26
DataCollection - Class to facilitate loading/accessing structured data.
void ConnectPipelines(ITK_Exporter exporter, VTK_Importer *importer)
itk::Image< double, 3 > FloatImageType
Definition: CLBrainMask.cpp:35
const mitk::Vector3D GetSpacing() const
Get the spacing (size of a pixel).
unsigned int GetTimeSteps() const
Get the number of time steps from the TimeGeometry As the base data has not a data vector given by it...
Definition: mitkBaseData.h:346
void InternalCalculateStatisticsMasked(const itk::Image< TPixel, VImageDimension > *image, itk::Image< unsigned char, VImageDimension > *maskImage, Statistics &statistics, typename HistogramType::ConstPointer *histogram)
virtual void WorldToIndex(const Point2D &pt_mm, Point2D &pt_units) const
virtual void IndexToWorld(const Point2D &pt_units, Point2D &pt_mm) const
#define AccessFixedDimensionByItk_3(mitkImage, itkImageTypeFunction, dimension, arg1, arg2, arg3)
itk::SmartPointer< const Self > ConstPointer
map::core::discrete::Elements< 3 >::InternalImageType ImageType
Vector3D GetAxisVector(unsigned int direction) const
Get vector along bounding-box in the specified direction in mm.
#define AccessFixedDimensionByItk_2(mitkImage, itkImageTypeFunction, dimension, arg1, arg2)
Image class for storing images.
Definition: mitkImage.h:76
const Statistics & GetStatistics() const
Retrieve statistics depending on the current masking mode.
itk::Image< unsigned char, 3 > MaskImageType
Definition: CLBrainMask.cpp:36
virtual bool ComputeStatistics()
Compute statistics (together with histogram) for the current masking mode.
Describes a geometry defined by an vtkAbstractTransform and a plane.
void AddAdditionalResamplingImage(const mitk::Image *image)
Set image for which the same resampling will be applied. and available via GetAdditionalResampledImag...
void InternalCropAdditionalImage(itk::Image< TPixel, VImageDimension > *image, int additionalIndex)
static T max(T x, T y)
Definition: svm.cpp:70
static Pointer New()
void ExtractImageAndMask()
Depending on the masking mode, the image and mask from which to calculate statistics is extracted fro...
const mitk::BaseGeometry * GetUpdatedGeometry(int t=0)
Return the BaseGeometry of the data at time t.
static T min(T x, T y)
Definition: svm.cpp:67
void InternalCalculateMaskFromPlanarFigure(itk::Image< TPixel, VImageDimension > *image, unsigned int axis)
#define AccessFixedDimensionByItk_1(mitkImage, itkImageTypeFunction, dimension, arg1)
Base-class for geometric planar (2D) figures, such as lines, circles, rectangles, polygons...
void IndexToWorld(const mitk::Vector3D &vec_units, mitk::Vector3D &vec_mm) const
Convert (continuous or discrete) index coordinates of a vector vec_units to world coordinates (in mm)...
void InternalResampleImageFromMask(const itk::Image< TPixel, VImageDimension > *image, int additionalIndex)
const HistogramType * GetHistogram() const
Retrieve the histogram depending on the current masking mode.
void SetPlanarFigure(const mitk::PlanarFigure *planarFigure)
Set planar figure for masking.
MITKCORE_EXPORT const ScalarType eps
std::vector< PolyLineElement > PolyLineType
void InternalReorientImagePlane(const itk::Image< TPixel, VImageDimension > *image, mitk::BaseGeometry *imggeo, mitk::BaseGeometry *planegeo3D, int additionalIndex)
Describes a two-dimensional, rectangular plane.
bool IsInside(const mitk::Point3D &p) const
Test whether the point p (world coordinates in mm) is inside the bounding box.
void SetImageMask(const mitk::Image *imageMask)
Set binary image for masking.
mitk::BaseGeometry * GetGeometry(int t=0) const
Return the geometry, which is a TimeGeometry, of the data as non-const pointer.
Definition: mitkBaseData.h:129
ScalarType GetExtentInMM(int direction) const
Get the extent of the bounding-box in the specified direction in mm.
void InternalCalculateStatisticsUnmasked(const itk::Image< TPixel, VImageDimension > *image, Statistics &statistics, typename HistogramType::ConstPointer *histogram)
void SetImage(const mitk::Image *image)
Set image from which to compute statistics.
BaseGeometry Describes the geometry of a data object.
static Pointer New()
mitk::AffineTransform3D * GetIndexToWorldTransform()
Get the transformation used to convert from index to world coordinates.
void WorldToIndex(const mitk::Point3D &pt_mm, mitk::Point3D &pt_units) const
Convert world coordinates (in mm) of a point to (continuous!) index coordinates.
static itkEventMacro(BoundingShapeInteractionEvent, itk::AnyEvent) class MITKBOUNDINGSHAPE_EXPORT BoundingShapeInteractor Pointer New()
Basic interaction methods for mitk::GeometryData.