diff --git a/Modules/Segmentation/Algorithms/mitkImageToContourFilter.cpp b/Modules/Segmentation/Algorithms/mitkImageToContourFilter.cpp index 239428d659..b6661faa7a 100644 --- a/Modules/Segmentation/Algorithms/mitkImageToContourFilter.cpp +++ b/Modules/Segmentation/Algorithms/mitkImageToContourFilter.cpp @@ -1,169 +1,159 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include #include #include #include #include #include #include #include #include #include #include mitk::ImageToContourFilter::ImageToContourFilter() : m_SliceGeometry(nullptr), m_UseProgressBar(false), m_ProgressStepSize(1), m_ContourValue(1.0) { } mitk::ImageToContourFilter::~ImageToContourFilter() { } void mitk::ImageToContourFilter::GenerateData() { mitk::Image::ConstPointer sliceImage = ImageToSurfaceFilter::GetInput(); if (!sliceImage) { MITK_ERROR << "mitk::ImageToContourFilter: No input available. Please set the input!" << std::endl; itkExceptionMacro("mitk::ImageToContourFilter: No input available. Please set the input!"); return; } if (sliceImage->GetDimension() > 2 || sliceImage->GetDimension() < 2) { MITK_ERROR << "mitk::ImageToImageFilter::GenerateData() works only with 2D images. Please assure that your input " "image is 2D!" << std::endl; itkExceptionMacro( "mitk::ImageToImageFilter::GenerateData() works only with 2D images. Please assure that your input image is 2D!"); return; } m_SliceGeometry = sliceImage->GetGeometry(); AccessFixedDimensionByItk(sliceImage, Itk2DContourExtraction, 2); // Setting progressbar if (this->m_UseProgressBar) mitk::ProgressBar::GetInstance()->Progress(this->m_ProgressStepSize); } template void mitk::ImageToContourFilter::Itk2DContourExtraction(const itk::Image *sliceImage) { - typedef itk::Image ImageType; - typedef itk::ContourExtractor2DImageFilter ContourExtractor; + using ImageType = itk::Image; + using BinaryFilter = itk::UnaryGeneratorImageFilter; + using PadFilter = itk::ConstantPadImageFilter; + using ContourExtractorFilter = itk::ContourExtractor2DImageFilter; - typedef itk::ConstantPadImageFilter PadFilterType; - typename PadFilterType::Pointer padFilter = PadFilterType::New(); - typename ImageType::SizeType lowerExtendRegion; - lowerExtendRegion[0] = 1; - lowerExtendRegion[1] = 1; + // Create a binary mask - typename ImageType::SizeType upperExtendRegion; - upperExtendRegion[0] = 1; - upperExtendRegion[1] = 1; + auto binaryFilter = BinaryFilter::New(); - auto filter = itk::UnaryGeneratorImageFilter::New(); + binaryFilter->SetInput(sliceImage); + binaryFilter->SetFunctor([this](TPixel pixVal) { return fabs(pixVal - m_ContourValue) < mitk::eps ? 1.0 : 0.0; }); - auto contourValPicker = [this] (TPixel pixVal) - { - return fabs(pixVal-m_ContourValue) < mitk::eps - ? pixVal - : TPixel(); - }; - - filter->SetInput(sliceImage); - filter->SetFunctor(contourValPicker); - filter->Update(); - - /* - * We need to pad here, since the ITK contour extractor fails if the - * segmentation touches more than one image edge. - * By padding the image for one row at each edge we overcome this issue - */ - padFilter->SetInput(filter->GetOutput()); - padFilter->SetConstant(0); - padFilter->SetPadLowerBound(lowerExtendRegion); - padFilter->SetPadUpperBound(upperExtendRegion); - - typename ContourExtractor::Pointer contourExtractor = ContourExtractor::New(); - contourExtractor->SetInput(padFilter->GetOutput()); - contourExtractor->SetContourValue(m_ContourValue-0.5); - contourExtractor->Update(); - - unsigned int foundPaths = contourExtractor->GetNumberOfOutputs(); - - vtkSmartPointer contourSurface = vtkSmartPointer::New(); - vtkSmartPointer points = vtkSmartPointer::New(); - vtkSmartPointer polygons = vtkSmartPointer::New(); + // Pad the mask since the contour extractor would not close contours along pixels at the border + + typename ImageType::SizeType bound; + bound.Fill(1); + + auto padFilter = PadFilter::New(); + + padFilter->SetInput(binaryFilter->GetOutput()); + padFilter->SetPadLowerBound(bound); + padFilter->SetPadUpperBound(bound); + + // Extract the contour(s) + + auto contourExtractorFilter = ContourExtractorFilter::New(); + + contourExtractorFilter->SetInput(padFilter->GetOutput()); + contourExtractorFilter->SetContourValue(0.5); + contourExtractorFilter->Update(); + + unsigned int foundPaths = contourExtractorFilter->GetNumberOfOutputs(); + + auto contourSurface = vtkSmartPointer::New(); + auto points = vtkSmartPointer::New(); + auto polygons = vtkSmartPointer::New(); unsigned int pointId = 0; for (unsigned int i = 0; i < foundPaths; i++) { - const ContourPath *currentPath = contourExtractor->GetOutput(i)->GetVertexList(); + const auto* currentPath = contourExtractorFilter->GetOutput(i)->GetVertexList(); - vtkSmartPointer polygon = vtkSmartPointer::New(); + auto polygon = vtkSmartPointer::New(); polygon->GetPointIds()->SetNumberOfIds(currentPath->Size()); Point3D currentPoint; Point3D currentWorldPoint; for (unsigned int j = 0; j < currentPath->Size(); j++) { currentPoint[0] = currentPath->ElementAt(j)[0]; currentPoint[1] = currentPath->ElementAt(j)[1]; currentPoint[2] = 0; m_SliceGeometry->IndexToWorld(currentPoint, currentWorldPoint); points->InsertPoint(pointId, currentWorldPoint[0], currentWorldPoint[1], currentWorldPoint[2]); polygon->GetPointIds()->SetId(j, pointId); pointId++; } // for2 polygons->InsertNextCell(polygon); } // for1 contourSurface->SetPoints(points); contourSurface->SetPolys(polygons); contourSurface->BuildLinks(); Surface::Pointer finalSurface = this->GetOutput(); finalSurface->SetVtkPolyData(contourSurface); } void mitk::ImageToContourFilter::GenerateOutputInformation() { Superclass::GenerateOutputInformation(); } void mitk::ImageToContourFilter::SetUseProgressBar(bool status) { this->m_UseProgressBar = status; } void mitk::ImageToContourFilter::SetProgressStepSize(unsigned int stepSize) { this->m_ProgressStepSize = stepSize; } \ No newline at end of file