/*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "mitkOverwriteSliceImageFilter.h" #include "mitkImageCast.h" #include "mitkSegmentationInterpolationController.h" #include "mitkApplyDiffImageOperation.h" #include "mitkOperationEvent.h" #include "mitkInteractionConst.h" #include "mitkUndoController.h" #include "mitkDiffImageApplier.h" #include "mitkImageTimeSelector.h" #include #include mitk::OverwriteSliceImageFilter::OverwriteSliceImageFilter() :m_SliceIndex(0), m_SliceDimension(0), m_TimeStep(0), m_Dimension0(0), m_Dimension1(1), m_CreateUndoInformation(false) { m_bSliceAndImageOriented = true; } mitk::OverwriteSliceImageFilter::~OverwriteSliceImageFilter() { } void mitk::OverwriteSliceImageFilter::GenerateData() { // // this is the place to implement the major part of undo functionality (bug #491) // here we have to create undo/do operations // // WHO is the operation actor? This object may not be destroyed ever (design of undo stack)! // -> some singleton method of this filter? // // neccessary additional objects: // - something that executes the operations // - the operation class (must hold a binary diff or something) // - observer commands to know when the image is deleted (no further action then, perhaps even remove the operations from the undo stack) // Image::ConstPointer input = ImageToImageFilter::GetInput(0); Image::ConstPointer input3D = input; Image::ConstPointer slice = m_SliceImage; if ( input.IsNull() || slice.IsNull() ) return; switch (m_SliceDimension) { default: case 2: m_Dimension0 = 0; m_Dimension1 = 1; break; case 1: m_Dimension0 = 0; m_Dimension1 = 2; break; case 0: m_Dimension0 = 1; m_Dimension1 = 2; break; } if ( slice->GetDimension() != 2 || input->GetDimension() != 3 ) { itkExceptionMacro("Slice and image dimensions differ or slice index is too large. Sorry, cannot work like this."); return; } if ( slice->GetDimension(0) != input->GetDimension(m_Dimension0) || slice->GetDimension(1) != input->GetDimension(m_Dimension1) || m_SliceIndex >= input->GetDimension(m_SliceDimension) ) { m_bSliceAndImageOriented = false; } if ( input->GetDimension() == 4 ) { ImageTimeSelector::Pointer timeSelector = ImageTimeSelector::New(); timeSelector->SetInput( input ); timeSelector->SetTimeNr( m_TimeStep ); timeSelector->UpdateLargestPossibleRegion(); input3D = timeSelector->GetOutput(); } if ( m_SliceDifferenceImage.IsNull() || m_SliceDifferenceImage->GetDimension(0) != m_SliceImage->GetDimension(0) || m_SliceDifferenceImage->GetDimension(1) != m_SliceImage->GetDimension(1) ) { m_SliceDifferenceImage = mitk::Image::New(); mitk::PixelType pixelType( typeid(short signed int) ); m_SliceDifferenceImage->Initialize( pixelType, 2, m_SliceImage->GetDimensions() ); } // this will do a long long if/else to find out both pixel types AccessFixedDimensionByItk( input3D, ItkImageSwitch, 3 ); SegmentationInterpolationController* interpolator = SegmentationInterpolationController::InterpolatorForImage( input ); if (interpolator) { interpolator->BlockModified(true); if ( m_bSliceAndImageOriented ) { interpolator->SetChangedSlice( m_SliceDifferenceImage, m_SliceDimension, m_SliceIndex, m_TimeStep ); } } if ( m_bSliceAndImageOriented && m_CreateUndoInformation ) { // create do/undo operations (we don't execute the doOp here, because it has already been executed during calculation of the diff image ApplyDiffImageOperation* doOp = new ApplyDiffImageOperation( OpTEST, const_cast(input.GetPointer()), m_SliceDifferenceImage, m_TimeStep, m_SliceDimension, m_SliceIndex ); ApplyDiffImageOperation* undoOp = new ApplyDiffImageOperation( OpTEST, const_cast(input.GetPointer()), m_SliceDifferenceImage, m_TimeStep, m_SliceDimension, m_SliceIndex ); undoOp->SetFactor( -1.0 ); OperationEvent* undoStackItem = new OperationEvent( DiffImageApplier::GetInstanceForUndo(), doOp, undoOp, this->EventDescription(m_SliceDimension, m_SliceIndex, m_TimeStep) ); UndoController::GetCurrentUndoModel()->SetOperationEvent( undoStackItem ); } // this image is modified (good to know for the renderer) input->Modified(); if (interpolator) { interpolator->BlockModified(false); } } // basically copied from mitk/Core/Algorithms/mitkImageAccessByItk.h #define myMITKOverwriteSliceImageFilterAccessByItk(mitkImage, itkImageTypeFunction, pixeltype, dimension, itkimage2) \ if ( typeId == typeid(pixeltype) ) \ { \ typedef itk::Image ImageType; \ typedef mitk::ImageToItk ImageToItkType; \ itk::SmartPointer imagetoitk = ImageToItkType::New(); \ imagetoitk->SetInput(mitkImage); \ imagetoitk->Update(); \ itkImageTypeFunction(imagetoitk->GetOutput(), itkimage2); \ } #define myMITKOverwriteSliceImageFilterAccessAllTypesByItk(mitkImage, itkImageTypeFunction, dimension, itkimage2) \ { \ myMITKOverwriteSliceImageFilterAccessByItk(mitkImage, itkImageTypeFunction, double, dimension, itkimage2) else \ myMITKOverwriteSliceImageFilterAccessByItk(mitkImage, itkImageTypeFunction, float, dimension, itkimage2) else \ myMITKOverwriteSliceImageFilterAccessByItk(mitkImage, itkImageTypeFunction, int, dimension, itkimage2) else \ myMITKOverwriteSliceImageFilterAccessByItk(mitkImage, itkImageTypeFunction, unsigned int, dimension, itkimage2) else \ myMITKOverwriteSliceImageFilterAccessByItk(mitkImage, itkImageTypeFunction, short, dimension, itkimage2) else \ myMITKOverwriteSliceImageFilterAccessByItk(mitkImage, itkImageTypeFunction, unsigned short, dimension, itkimage2) else \ myMITKOverwriteSliceImageFilterAccessByItk(mitkImage, itkImageTypeFunction, char, dimension, itkimage2) else \ myMITKOverwriteSliceImageFilterAccessByItk(mitkImage, itkImageTypeFunction, unsigned char, dimension, itkimage2) \ } template void mitk::OverwriteSliceImageFilter::ItkImageSwitch( itk::Image* itkImage ) { const std::type_info& typeId=*(m_SliceImage->GetPixelType().GetTypeId()); myMITKOverwriteSliceImageFilterAccessAllTypesByItk( m_SliceImage, ItkImageProcessing, 2, itkImage ); } template void mitk::OverwriteSliceImageFilter::ItkImageProcessing( itk::Image* inputImage, itk::Image* outputImage ) { typedef itk::Image SliceImageType; typedef itk::Image DiffImageType; typedef itk::Image VolumeImageType; typedef itk::ImageSliceIteratorWithIndex< VolumeImageType > OutputSliceIteratorType; typedef itk::ImageRegionConstIterator< SliceImageType > InputSliceIteratorType; typedef itk::ImageRegionIterator< DiffImageType > DiffSliceIteratorType; InputSliceIteratorType inputIterator( inputImage, inputImage->GetLargestPossibleRegion() ); typename DiffImageType::Pointer diffImage; CastToItkImage( m_SliceDifferenceImage, diffImage ); DiffSliceIteratorType diffIterator( diffImage, diffImage->GetLargestPossibleRegion() ); // iterate over output slice (and over input slice simultaneously) inputIterator.GoToBegin(); diffIterator.GoToBegin(); if ( m_bSliceAndImageOriented ) { std::cout << "Oriented" << std::endl; typename VolumeImageType::RegionType sliceInVolumeRegion; sliceInVolumeRegion = outputImage->GetLargestPossibleRegion(); sliceInVolumeRegion.SetSize( m_SliceDimension, 1 ); // just one slice sliceInVolumeRegion.SetIndex( m_SliceDimension, m_SliceIndex ); // exactly this slice, please // Get an iterator to the output image slice OutputSliceIteratorType outputIterator( outputImage, sliceInVolumeRegion ); outputIterator.SetFirstDirection(m_Dimension0); outputIterator.SetSecondDirection(m_Dimension1); outputIterator.GoToBegin(); while ( !outputIterator.IsAtEnd() ) { while ( !outputIterator.IsAtEndOfSlice() ) { while ( !outputIterator.IsAtEndOfLine() ) { std::cout << outputIterator.GetIndex()[ 0 ] << ", " << outputIterator.GetIndex()[ 1 ] << ", " << outputIterator.GetIndex()[ 2 ] << " = " << int( inputIterator.Get() ) << std::endl; diffIterator.Set( static_cast(inputIterator.Get() - outputIterator.Get()) ); // oh oh, not good for bigger values outputIterator.Set( (TPixel2) inputIterator.Get() ); ++outputIterator; ++inputIterator; ++diffIterator; } outputIterator.NextLine(); } outputIterator.NextSlice(); } } else { std::cout << "NOT Oriented" << std::endl; while ( !inputIterator.IsAtEnd() ) { //itk::Point itkPhysicalPointInput; // inputImage->TransformIndexToPhysicalPoint( inputIterator.GetIndex(), itkPhysicalPointInput ); //mitk::Point3D inputWorldPoint; //itk::Point itkPhysicalPointInput3D; //itkPhysicalPointInput3D[ 0 ] = itkPhysicalPointInput[ 0 ]; //itkPhysicalPointInput3D[ 1 ] = itkPhysicalPointInput[ 1 ]; //itkPhysicalPointInput3D[ 2 ] = 0; //m_SliceGeometry3D->ItkPhysicalPointToWorld( itkPhysicalPointInput3D, inputWorldPoint ); mitk::Point2D Pt_mm2D; mitk::Point3D Pt_mm3D; mitk::Point2D pt_units; pt_units[ 0 ] = inputIterator.GetIndex()[ 0 ]; pt_units[ 1 ] = inputIterator.GetIndex()[ 1 ]; m_PlaneGeometry->IndexToWorld( pt_units, Pt_mm2D ); m_PlaneGeometry->Map( Pt_mm2D, Pt_mm3D ); itk::Image::IndexType outputIndex; m_ImageGeometry3D->WorldToIndex( Pt_mm3D, outputIndex ); bool isInside = outputImage->GetLargestPossibleRegion().IsInside( outputIndex ); // Convert index to MITK world //mitk::Point3D atPt3d_units; //atPt3d_units.Fill(0.0); //atPt3d_units[ 0 ] = inputIterator.GetIndex()[ 0 ]; //atPt3d_units[ 1 ] = inputIterator.GetIndex()[ 1 ]; //atPt3d_units[ 2 ] = 0; //mitk::Point3D pt_mm; //itk::Point itkPhysicalPoint; //m_SliceGeometry3D->IndexToWorld( atPt3d_units, pt_mm ); //itk::Point itkPhysicalPoint; //m_ImageGeometry3D->WorldToItkPhysicalPoint( Pt_mm3D, itkPhysicalPoint ); TPixel2 outputPixel = 0; // Only access ITK image if it's inside if ( isInside ) { outputPixel = outputImage->GetPixel( outputIndex ); outputImage->SetPixel( outputIndex, (TPixel2) inputIterator.Get() ); } if ( inputIterator.Get() != 0 ) { std::cout << inputIterator.GetIndex( )[ 0 ] << ", " << inputIterator.GetIndex( )[ 1 ] << ", " << " ---> " << outputIndex[ 0 ] << ", " << outputIndex[ 1 ] << ", " << outputIndex[ 2 ] << " = " << int( inputIterator.Get() ) << std::endl; } // Set difference image diffIterator.Set( static_cast(inputIterator.Get() - outputPixel ) ); // oh oh, not good for bigger values ++inputIterator; ++diffIterator; } } } std::string mitk::OverwriteSliceImageFilter::EventDescription( unsigned int sliceDimension, unsigned int sliceIndex, unsigned int timeStep ) { std::stringstream s; s << "Changed slice ("; switch (sliceDimension) { default: case 2: s << "T"; break; case 1: s << "C"; break; case 0: s << "S"; break; } s << " " << sliceIndex << " " << timeStep << ")"; return s.str(); } const mitk::Geometry3D* mitk::OverwriteSliceImageFilter::GetSliceGeometry3D() const { return m_SliceGeometry3D; } void mitk::OverwriteSliceImageFilter::SetSliceGeometry3D( const mitk::Geometry3D* val ) { m_SliceGeometry3D = val; } const mitk::PlaneGeometry* mitk::OverwriteSliceImageFilter::GetPlaneGeometry() const { return m_PlaneGeometry; } void mitk::OverwriteSliceImageFilter::SetPlaneGeometry( const mitk::PlaneGeometry* val ) { m_PlaneGeometry = val; } const mitk::Geometry3D* mitk::OverwriteSliceImageFilter::GetImageGeometry3D() const { return m_ImageGeometry3D; } void mitk::OverwriteSliceImageFilter::SetImageGeometry3D( const mitk::Geometry3D* val ) { m_ImageGeometry3D = val; }