diff --git a/Modules/ContourModel/Algorithms/mitkContourModelToSurfaceFilter.cpp b/Modules/ContourModel/Algorithms/mitkContourModelToSurfaceFilter.cpp index 9cd9347f9f..a46fbefe00 100644 --- a/Modules/ContourModel/Algorithms/mitkContourModelToSurfaceFilter.cpp +++ b/Modules/ContourModel/Algorithms/mitkContourModelToSurfaceFilter.cpp @@ -1,150 +1,159 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) 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 A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include #include #include #include mitk::ContourModelToSurfaceFilter::ContourModelToSurfaceFilter() { this->SetNthOutput(0,mitk::Surface::New().GetPointer()); } mitk::ContourModelToSurfaceFilter::~ContourModelToSurfaceFilter() { } void mitk::ContourModelToSurfaceFilter::GenerateOutputInformation() { } void mitk::ContourModelToSurfaceFilter::SetInput ( const mitk::ContourModelToSurfaceFilter::InputType* input ) { this->SetInput( 0, input ); } void mitk::ContourModelToSurfaceFilter::SetInput ( unsigned int idx, const mitk::ContourModelToSurfaceFilter::InputType* input ) { if ( idx + 1 > this->GetNumberOfInputs() ) { this->SetNumberOfRequiredInputs(idx + 1); } if ( input != static_cast ( this->ProcessObject::GetInput ( idx ) ) ) { this->ProcessObject::SetNthInput ( idx, const_cast ( input ) ); this->Modified(); } } const mitk::ContourModelToSurfaceFilter::InputType* mitk::ContourModelToSurfaceFilter::GetInput( void ) { if (this->GetNumberOfInputs() < 1) return NULL; return static_cast(this->ProcessObject::GetInput(0)); } const mitk::ContourModelToSurfaceFilter::InputType* mitk::ContourModelToSurfaceFilter::GetInput( unsigned int idx ) { if (this->GetNumberOfInputs() < 1) return NULL; return static_cast(this->ProcessObject::GetInput(idx)); } void mitk::ContourModelToSurfaceFilter::GenerateData() { mitk::Surface* surface = this->GetOutput(); mitk::ContourModel* inputContour = (mitk::ContourModel*)GetInput(); unsigned int numberOfTimeSteps = inputContour->GetTimeSteps(); surface->Expand(numberOfTimeSteps); for(unsigned int currentTimeStep = 0; currentTimeStep < numberOfTimeSteps; currentTimeStep++) { /* First of all convert the control points of the contourModel to vtk points * and add lines in between them */ vtkSmartPointer points = vtkSmartPointer::New(); //the points to draw vtkSmartPointer polygons = vtkSmartPointer::New(); vtkSmartPointer lines = vtkSmartPointer::New(); //the lines to connect the points + // if the contour has less than 3 points, set empty PolyData for current timestep + // polygon needs at least 3 points + if( inputContour->GetNumberOfVertices() <= 2) + { + vtkSmartPointer emptyPolyData = vtkSmartPointer::New(); + surface->SetVtkPolyData(emptyPolyData, currentTimeStep); + continue; + } + //iterate over all control points mitk::ContourModel::VertexIterator current = inputContour->IteratorBegin(currentTimeStep); mitk::ContourModel::VertexIterator end = inputContour->IteratorEnd(currentTimeStep); vtkSmartPointer polygon = vtkSmartPointer::New(); polygon->GetPointIds()->SetNumberOfIds(inputContour->GetNumberOfVertices(currentTimeStep)); int j(0); while(current != end) { mitk::ContourModel::VertexType* currentPoint = *current; vtkIdType id = points->InsertNextPoint(currentPoint->Coordinates[0], currentPoint->Coordinates[1], currentPoint->Coordinates[2]); polygon->GetPointIds()->SetId(j,id); //create connections between the points //no previous point for first point available (ingnore id=0) if(id>0) { lines->InsertNextCell(2); lines->InsertCellPoint(id - 1); lines->InsertCellPoint(id); } current++; j++; } /* * If the contour is closed an additional line has to be created between the first point * and the last point */ if(inputContour->IsClosed(currentTimeStep)) { lines->InsertNextCell(2); lines->InsertCellPoint(0); lines->InsertCellPoint( (inputContour->GetNumberOfVertices(currentTimeStep) - 1) ); } polygons->InsertNextCell(polygon); // Create a polydata to store everything in vtkSmartPointer polyData = vtkSmartPointer::New(); // Add the points to the dataset polyData->SetPoints(points); polyData->SetPolys(polygons); polyData->SetLines(lines); polyData->BuildLinks(); surface->SetVtkPolyData(polyData, currentTimeStep); } } diff --git a/Modules/ContourModel/Algorithms/mitkContourModelUtils.cpp b/Modules/ContourModel/Algorithms/mitkContourModelUtils.cpp index ee9986dbeb..362fea39e9 100755 --- a/Modules/ContourModel/Algorithms/mitkContourModelUtils.cpp +++ b/Modules/ContourModel/Algorithms/mitkContourModelUtils.cpp @@ -1,204 +1,210 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) 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 A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkContourModelUtils.h" #include "mitkImageCast.h" #include "mitkImageAccessByItk.h" #include "mitkContourModel.h" #include "itkCastImageFilter.h" #include "mitkImage.h" #include "mitkSurface.h" #include "vtkPolyData.h" #include "mitkContourModelToSurfaceFilter.h" #include "vtkPolyDataToImageStencil.h" #include "vtkImageStencil.h" #include "mitkImageVtkAccessor.h" #include "vtkSmartPointer.h" #include "vtkImageData.h" #include "vtkImageLogic.h" #include "vtkPointData.h" mitk::ContourModelUtils::ContourModelUtils() { } mitk::ContourModelUtils::~ContourModelUtils() { } mitk::ContourModel::Pointer mitk::ContourModelUtils::ProjectContourTo2DSlice(Image* slice, ContourModel* contourIn3D, bool itkNotUsed( correctionForIpSegmentation ), bool constrainToInside) { if ( !slice || !contourIn3D ) return NULL; ContourModel::Pointer projectedContour = ContourModel::New(); projectedContour->Initialize(*contourIn3D); const Geometry3D* sliceGeometry = slice->GetGeometry(); int numberOfTimesteps = contourIn3D->GetTimeGeometry()->CountTimeSteps(); for(int currentTimestep = 0; currentTimestep < numberOfTimesteps; currentTimestep++) { ContourModel::VertexIterator iter = contourIn3D->Begin(currentTimestep); ContourModel::VertexIterator end = contourIn3D->End(currentTimestep); while( iter != end) { Point3D currentPointIn3D = (*iter)->Coordinates; Point3D projectedPointIn2D; projectedPointIn2D.Fill(0.0); sliceGeometry->WorldToIndex( currentPointIn3D, projectedPointIn2D ); // MITK_INFO << "world point " << currentPointIn3D << " in index is " << projectedPointIn2D; if ( !sliceGeometry->IsIndexInside( projectedPointIn2D ) && constrainToInside ) { MITK_INFO << "**" << currentPointIn3D << " is " << projectedPointIn2D << " --> correct it (TODO)" << std::endl; } projectedContour->AddVertex( projectedPointIn2D, currentTimestep ); iter++; } } return projectedContour; } mitk::ContourModel::Pointer mitk::ContourModelUtils::BackProjectContourFrom2DSlice(const Geometry3D* sliceGeometry, ContourModel* contourIn2D, bool itkNotUsed( correctionForIpSegmentation ) ) { if ( !sliceGeometry || !contourIn2D ) return NULL; ContourModel::Pointer worldContour = ContourModel::New(); worldContour->Initialize(*contourIn2D); int numberOfTimesteps = contourIn2D->GetTimeGeometry()->CountTimeSteps(); for(int currentTimestep = 0; currentTimestep < numberOfTimesteps; currentTimestep++) { ContourModel::VertexIterator iter = contourIn2D->Begin(currentTimestep); ContourModel::VertexIterator end = contourIn2D->End(currentTimestep); while( iter != end) { Point3D currentPointIn2D = (*iter)->Coordinates; Point3D worldPointIn3D; worldPointIn3D.Fill(0.0); sliceGeometry->IndexToWorld( currentPointIn2D, worldPointIn3D ); //MITK_INFO << "index " << currentPointIn2D << " world " << worldPointIn3D << std::endl; worldContour->AddVertex( worldPointIn3D, currentTimestep ); iter++; } } return worldContour; } void mitk::ContourModelUtils::FillContourInSlice( ContourModel* projectedContour, Image* sliceImage, int paintingPixelValue ) { mitk::ContourModelUtils::FillContourInSlice(projectedContour, 0, sliceImage, paintingPixelValue); } void mitk::ContourModelUtils::FillContourInSlice( ContourModel* projectedContour, unsigned int timeStep, Image* sliceImage, int paintingPixelValue ) { //create a surface of the input ContourModel mitk::Surface::Pointer surface = mitk::Surface::New(); mitk::ContourModelToSurfaceFilter::Pointer contourModelFilter = mitk::ContourModelToSurfaceFilter::New(); contourModelFilter->SetInput(projectedContour); contourModelFilter->Update(); surface = contourModelFilter->GetOutput(); // that's our vtkPolyData-Surface vtkSmartPointer surface2D = vtkSmartPointer::New(); - + if (surface->GetVtkPolyData(timeStep) == NULL) + { + MITK_WARN << "No surface has been created from contour model. Add more points to fill contour in slice."; + return; + } surface2D->SetPoints(surface->GetVtkPolyData(timeStep)->GetPoints()); surface2D->SetLines(surface->GetVtkPolyData(timeStep)->GetLines()); surface2D->Modified(); //surface2D->Update(); + + // prepare the binary image's voxel grid vtkSmartPointer whiteImage = vtkSmartPointer::New(); whiteImage->DeepCopy(sliceImage->GetVtkImageData()); // fill the image with foreground voxels: unsigned char inval = 255; unsigned char outval = 0; vtkIdType count = whiteImage->GetNumberOfPoints(); for (vtkIdType i = 0; i < count; ++i) { whiteImage->GetPointData()->GetScalars()->SetTuple1(i, inval); } // polygonal data --> image stencil: vtkSmartPointer pol2stenc = vtkSmartPointer::New(); pol2stenc->SetTolerance(0); pol2stenc->SetInputData(surface2D); pol2stenc->Update(); // cut the corresponding white image and set the background: vtkSmartPointer imgstenc = vtkSmartPointer::New(); imgstenc->SetInputData(whiteImage); imgstenc->SetStencilConnection(pol2stenc->GetOutputPort()); imgstenc->ReverseStencilOff(); imgstenc->SetBackgroundValue(outval); imgstenc->Update(); //Fill according to painting value vtkSmartPointer booleanOperation = vtkSmartPointer::New(); booleanOperation->SetInput2Data(sliceImage->GetVtkImageData()); booleanOperation->SetOperationToOr(); booleanOperation->SetOutputTrueValue(1.0); if(paintingPixelValue == 1) { //COMBINE //slice or stencil booleanOperation->SetInputConnection(imgstenc->GetOutputPort()); booleanOperation->SetOperationToOr(); } else { //CUT //slice and not(stencil) vtkSmartPointer booleanOperationNOT = vtkSmartPointer::New(); booleanOperationNOT->SetInputConnection(imgstenc->GetOutputPort()); booleanOperationNOT->SetOperationToNot(); booleanOperationNOT->Update(); booleanOperation->SetInputConnection(booleanOperationNOT->GetOutputPort()); booleanOperation->SetOperationToAnd(); } booleanOperation->Update(); //copy scalars to output image slice sliceImage->SetVolume(booleanOperation->GetOutput()->GetScalarPointer()); }