diff --git a/Modules/PlanarFigureSegmentation/mitkPlanarFigureSegmentationController.cpp b/Modules/PlanarFigureSegmentation/mitkPlanarFigureSegmentationController.cpp index f7830aaf49..e7cbdc1573 100644 --- a/Modules/PlanarFigureSegmentation/mitkPlanarFigureSegmentationController.cpp +++ b/Modules/PlanarFigureSegmentation/mitkPlanarFigureSegmentationController.cpp @@ -1,281 +1,312 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) -Copyright (c) German Cancer Research Center, +Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. -This software is distributed WITHOUT ANY WARRANTY; without -even the implied warranty of MERCHANTABILITY or FITNESS FOR +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkPlanarFigureSegmentationController.h" #include "mitkSurfaceToImageFilter.h" #include #include #include #include #include #include #include +#include "mitkImageWriter.h" +#include "mitkSurfaceVtkWriter.h" +#include "mitkImageToSurfaceFilter.h" #include "itkTimeProbe.h" #include "itkResampleImageFilter.h" #include "itkInvertIntensityImageFilter.h" #include "itkBinaryThresholdImageFilter.h" #include "mitkImageAccessByItk.h" +#include "mitkImageCast.h" + + mitk::PlanarFigureSegmentationController::PlanarFigureSegmentationController() : itk::Object() , m_ReduceFilter( NULL ) , m_NormalsFilter( NULL ) , m_DistanceImageCreator( NULL ) , m_ReferenceImage( NULL ) , m_SegmentationAsImage( NULL ) { InitializeFilters(); } mitk::PlanarFigureSegmentationController::~PlanarFigureSegmentationController() { } void mitk::PlanarFigureSegmentationController::SetReferenceImage( mitk::Image::Pointer referenceImage ) { m_ReferenceImage = referenceImage; } void mitk::PlanarFigureSegmentationController::AddPlanarFigure( mitk::PlanarFigure::Pointer planarFigure ) { if ( planarFigure.IsNull() ) return; bool newFigure = true; int indexOfFigure = -1; for( int i=0; iCreateSurfaceFromPlanarFigure( planarFigure ); m_SurfaceList.push_back( figureAsSurface ); indexOfFigure = m_PlanarFigureList.size() -1 ; } else { figureAsSurface = this->CreateSurfaceFromPlanarFigure( planarFigure ); m_SurfaceList.at(indexOfFigure) = figureAsSurface; } m_ReduceFilter->SetInput( indexOfFigure, figureAsSurface ); m_NormalsFilter->SetInput( indexOfFigure, m_ReduceFilter->GetOutput( indexOfFigure ) ); m_DistanceImageCreator->SetInput( indexOfFigure, m_NormalsFilter->GetOutput( indexOfFigure ) ); } void mitk::PlanarFigureSegmentationController::RemovePlanarFigure( mitk::PlanarFigure::Pointer planarFigure ) { if ( planarFigure.IsNull() ) return; bool figureFound = false; int indexOfFigure = -1; for( int i=0; iRemoveInputs( m_NormalsFilter->GetOutput( indexOfFigure ) ); m_NormalsFilter->RemoveInputs( m_ReduceFilter->GetOutput( indexOfFigure ) ); m_ReduceFilter->RemoveInputs( const_cast(m_ReduceFilter->GetInput(indexOfFigure)) ); // PlanarFigureListType::iterator whereIter = m_PlanarFigureList.begin(); // whereIter += indexOfFigure; // m_PlanarFigureList.erase( whereIter ); -// +// // SurfaceListType::iterator surfaceIter = m_SurfaceList.begin(); // surfaceIter += indexOfFigure; // m_SurfaceList.erase( surfaceIter ); } else { // this is not very nice! If the figure that has been removed is NOT the last - // one in the list we have to create new filters and add all remaining + // one in the list we have to create new filters and add all remaining // inputs again. - // - // Has to be done as the filters do not work when removing an input + // + // Has to be done as the filters do not work when removing an input // other than the last one. - + // create new filters InitializeFilters(); // and add all existing surfaces SurfaceListType::iterator surfaceIter = m_SurfaceList.begin(); for ( surfaceIter = m_SurfaceList.begin(); surfaceIter!=m_SurfaceList.end(); surfaceIter++ ) { m_ReduceFilter->SetInput( indexOfFigure, (*surfaceIter) ); m_NormalsFilter->SetInput( indexOfFigure, m_ReduceFilter->GetOutput( indexOfFigure ) ); m_DistanceImageCreator->SetInput( indexOfFigure, m_NormalsFilter->GetOutput( indexOfFigure ) ); } } PlanarFigureListType::iterator whereIter = m_PlanarFigureList.begin(); whereIter += indexOfFigure; m_PlanarFigureList.erase( whereIter ); SurfaceListType::iterator surfaceIter = m_SurfaceList.begin(); surfaceIter += indexOfFigure; m_SurfaceList.erase( surfaceIter ); } mitk::Image::Pointer mitk::PlanarFigureSegmentationController::GetInterpolationResult() { m_SegmentationAsImage = NULL; if ( m_PlanarFigureList.size() == 0 ) { m_SegmentationAsImage = mitk::Image::New(); //m_SegmentationAsImage->Initialize(m_ReferenceImage); m_SegmentationAsImage->Initialize(mitk::MakeScalarPixelType() , *m_ReferenceImage->GetTimeSlicedGeometry()); return m_SegmentationAsImage; } + itk::Image::Pointer itkImage; + CastToItkImage( m_ReferenceImage, itkImage ); + m_DistanceImageCreator->SetReferenceImage( itkImage ); + m_ReduceFilter->Update(); m_NormalsFilter->Update(); m_DistanceImageCreator->Update(); mitk::Image::Pointer distanceImage = m_DistanceImageCreator->GetOutput(); - vtkSmartPointer marchingCubes = vtkMarchingCubes::New(); - marchingCubes->SetInput( distanceImage->GetVtkImageData() ); - marchingCubes->SetValue(0,0); - marchingCubes->Update(); + // If this bool flag is true, the distanceImage will be written to the + // filesystem as nrrd-image and as surface-representation. + bool debugOutput(false); + if ( debugOutput ) + { + mitk::ImageWriter::Pointer imageWriter = mitk::ImageWriter::New(); + imageWriter->SetInput( distanceImage ); + imageWriter->SetExtension( ".nrrd" ); + imageWriter->SetFileName( "v:/DistanceImage" ); + imageWriter->Update(); + } + + mitk::ImageToSurfaceFilter::Pointer imageToSurfaceFilter = mitk::ImageToSurfaceFilter::New(); + imageToSurfaceFilter->SetInput( distanceImage ); + imageToSurfaceFilter->SetThreshold( 0 ); + imageToSurfaceFilter->Update(); + + mitk::Surface::Pointer segmentationAsSurface = imageToSurfaceFilter->GetOutput(); + + if ( debugOutput ) + { + mitk::SurfaceVtkWriter::Pointer surfaceWriter = mitk::SurfaceVtkWriter::New(); + surfaceWriter->SetInput( segmentationAsSurface ); + surfaceWriter->SetExtension( ".vtk" ); + surfaceWriter->SetFileName( "v:/DistanceImageAsSurface.vtk" ); + surfaceWriter->Update(); + } - mitk::Surface::Pointer segmentationAsSurface = mitk::Surface::New(); - segmentationAsSurface->SetVtkPolyData(marchingCubes->GetOutput()); - segmentationAsSurface->GetGeometry()->SetOrigin( distanceImage->GetGeometry()->GetOrigin() ); mitk::SurfaceToImageFilter::Pointer surfaceToImageFilter = mitk::SurfaceToImageFilter::New(); surfaceToImageFilter->SetInput( segmentationAsSurface ); surfaceToImageFilter->SetImage( m_ReferenceImage ); surfaceToImageFilter->SetMakeOutputBinary(true); surfaceToImageFilter->Update(); m_SegmentationAsImage = surfaceToImageFilter->GetOutput(); return m_SegmentationAsImage; } mitk::Surface::Pointer mitk::PlanarFigureSegmentationController::CreateSurfaceFromPlanarFigure( mitk::PlanarFigure::Pointer figure ) { if ( figure.IsNull() ) { MITK_ERROR << "Given PlanarFigure is NULL. Please provide valid PlanarFigure."; return NULL; } mitk::Surface::Pointer newSurface = mitk::Surface::New(); vtkSmartPointer points = vtkPoints::New(); vtkSmartPointer polygon = vtkSmartPointer::New(); vtkSmartPointer cells = vtkCellArray::New(); vtkSmartPointer polyData = vtkPolyData::New(); const mitk::Geometry2D* figureGeometry = figure->GetGeometry2D(); // Get the polyline mitk::PlanarFigure::PolyLineType planarPolyLine = figure->GetPolyLine(0); mitk::PlanarFigure::PolyLineType::iterator iter; // iterate over the polyline, ... int pointCounter = 0; for( iter = planarPolyLine.begin(); iter != planarPolyLine.end(); iter++ ) { // ... determine the world-coordinates mitk::Point2D polyLinePoint = iter->Point; mitk::Point3D pointInWorldCoordiantes; figureGeometry->Map( polyLinePoint, pointInWorldCoordiantes ); // and add them as new points to the vtkPoints points->InsertNextPoint( pointInWorldCoordiantes[0], pointInWorldCoordiantes[1], pointInWorldCoordiantes[2] ); ++pointCounter; } // for( int i=0; iGetNumberOfControlPoints(); i++ ) // { // // ... determine the world-coordinates // mitk::Point2D polyLinePoint = figure->GetControlPoint(i); // mitk::Point3D pointInWorldCoordiantes; // figureGeometry->Map( polyLinePoint, pointInWorldCoordiantes ); -// +// // // and add them as new points to the vtkPoints // points->InsertNextPoint( pointInWorldCoordiantes[0], pointInWorldCoordiantes[1], pointInWorldCoordiantes[2] ); // ++pointCounter; // } // create a polygon with the points of the polyline polygon->GetPointIds()->SetNumberOfIds( pointCounter ); for(unsigned int i = 0; i < pointCounter; i++) { polygon->GetPointIds()->SetId(i,i); } // initialize the vtkCellArray and vtkPolyData cells->InsertNextCell(polygon); polyData->SetPoints(points); polyData->SetPolys( cells ); // set the polydata to the surface newSurface->SetVtkPolyData( polyData ); return newSurface; } mitk::PlanarFigureSegmentationController::PlanarFigureListType mitk::PlanarFigureSegmentationController::GetAllPlanarFigures() { return m_PlanarFigureList; } void mitk::PlanarFigureSegmentationController::InitializeFilters() { m_ReduceFilter = mitk::ReduceContourSetFilter::New(); m_ReduceFilter->SetReductionType(ReduceContourSetFilter::NTH_POINT); m_ReduceFilter->SetStepSize( 10 ); m_NormalsFilter = mitk::ComputeContourSetNormalsFilter::New(); m_DistanceImageCreator = mitk::CreateDistanceImageFromSurfaceFilter::New(); } + diff --git a/Modules/PlanarFigureSegmentation/mitkPlanarFigureSegmentationController.h b/Modules/PlanarFigureSegmentation/mitkPlanarFigureSegmentationController.h index 7e94d0e70c..e83016826d 100644 --- a/Modules/PlanarFigureSegmentation/mitkPlanarFigureSegmentationController.h +++ b/Modules/PlanarFigureSegmentation/mitkPlanarFigureSegmentationController.h @@ -1,152 +1,156 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) -Copyright (c) German Cancer Research Center, +Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. -This software is distributed WITHOUT ANY WARRANTY; without -even the implied warranty of MERCHANTABILITY or FITNESS FOR +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef mitkPlanarFigureSegmentationController_h_Included #define mitkPlanarFigureSegmentationController_h_Included #include "mitkCommon.h" #include "PlanarFigureSegmentationExports.h" #include "mitkImage.h" #include "mitkPlanarFigure.h" #include #include "mitkReduceContourSetFilter.h" #include #include namespace mitk { /** -* \brief This class creates a binary image from a set of PlanarFigures. -* -* The class offers a convenient way to create a binary image from a +* \brief This class creates a binary image from a set of PlanarFigures. +* +* The class offers a convenient way to create a binary image from a * variable number of contours that are represented by PlanarFigures. -* -* The first step is to create a mitkSurface for each PlanarFigure. -* +* +* The first step is to create a mitkSurface for each PlanarFigure. +* * The actual segmentation is done by interpolating these surfaces -* by means of the mitkCreateDistanceImageFromSurfaceFilter. -* -* Using the vtkMarchingCubes a surface is created from the resulting -* distance-image. This surface is then turned into a binary image using the +* by means of the mitkCreateDistanceImageFromSurfaceFilter. +* +* Using the vtkMarchingCubes a surface is created from the resulting +* distance-image. This surface is then turned into a binary image using the * mitkSurfaceToImageFilter. */ class PlanarFigureSegmentation_EXPORT PlanarFigureSegmentationController : public itk::Object { public: mitkClassMacro(PlanarFigureSegmentationController, itk::Object); itkNewMacro(PlanarFigureSegmentationController); /// specify the segmentation image that should be interpolated virtual ~PlanarFigureSegmentationController(); typedef std::vector PlanarFigureListType; typedef std::vector SurfaceListType; /** * \brief Setter for the reference image. - * - * The reference image is the image on which the segmentation is + * + * The reference image is the image on which the segmentation is * performed. It's needed to set the correct geometry information * on the segmentation result (pixel-spacing, slice-thickness, etc.). */ void SetReferenceImage( Image::Pointer referenceImage ); /** * \brief Adds a new PlanarFigure to be considered in the interpolation. - * + * * This method can be used to add a new contour, represented by a * PlanarFigure, to be considered in the interpolation. - * + * * It is not possible to add the same PlanarFigure twice. - * + * * \warn The method does NOT check if there are two PlanarFigures on * the same slice. Doing this will lead to wrong segmentation results. */ void AddPlanarFigure( PlanarFigure::Pointer planarFigure ); void RemovePlanarFigure( mitk::PlanarFigure::Pointer planarFigure ); /** * \brief Performs the interpolation and returns the result * as binary image. - * + * * This method updates the CreateDistanceImageFromSurfaceFilter * and creates a binary image from the resulting distance-image. - * - * This is done by creating an intermediate mitk::Surface that - * represents the interpolated 3D contour using the vtkMarchingCubes. - * - * The binary image is then extracted from the surface by means of + * + * This is done by creating an intermediate mitk::Surface that + * represents the interpolated 3D contour using the vtkMarchingCubes. + * + * The binary image is then extracted from the surface by means of * the mitkSurfaceToImageFilter. */ Image::Pointer GetInterpolationResult(); /** * \brief Method to create a surface from a PlanarFigure - * - * This method takes any kind of PlanarFigure and creates a - * surface-representation. + * + * This method takes any kind of PlanarFigure and creates a + * surface-representation. * The resulting surface contains of only ONE vtkPolygon that contains * all points of the PlanarFigure's polyline. */ static Surface::Pointer CreateSurfaceFromPlanarFigure( PlanarFigure::Pointer figure ); PlanarFigureListType GetAllPlanarFigures(); - + + void SetReferenceDirectionVector( mitk::Vector3D vector ); + protected: PlanarFigureSegmentationController(); void InitializeFilters(); PlanarFigureListType m_PlanarFigureList; SurfaceListType m_SurfaceList; /** * \brief Filter to reduce the number of control points. */ ReduceContourSetFilter::Pointer m_ReduceFilter; /** * \brief Filter to compute the normals for the created surface */ ComputeContourSetNormalsFilter::Pointer m_NormalsFilter; - + /** * \brief Filter to create "distance-image" from contours. */ CreateDistanceImageFromSurfaceFilter::Pointer m_DistanceImageCreator; - + Image::Pointer m_ReferenceImage; Image::Pointer m_SegmentationAsImage; + mitk::Vector3D m_ReferenceDirectionVector; + }; } // namespace #endif