Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
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.