diff --git a/Modules/ContourModel/Algorithms/mitkContourModelUtils.cpp b/Modules/ContourModel/Algorithms/mitkContourModelUtils.cpp index 8a00582c96..32c7f81ad1 100755 --- a/Modules/ContourModel/Algorithms/mitkContourModelUtils.cpp +++ b/Modules/ContourModel/Algorithms/mitkContourModelUtils.cpp @@ -1,238 +1,238 @@ /*============================================================================ 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 mitk::ContourModelUtils::ContourModelUtils() { } mitk::ContourModelUtils::~ContourModelUtils() { } mitk::ContourModel::Pointer mitk::ContourModelUtils::ProjectContourTo2DSlice( Image *slice, ContourModel *contourIn3D, bool, bool) { if (nullptr == slice || nullptr == contourIn3D) return nullptr; auto projectedContour = ContourModel::New(); projectedContour->Initialize(*contourIn3D); auto sliceGeometry = slice->GetGeometry(); auto numberOfTimesteps = static_cast(contourIn3D->GetTimeSteps()); for (decltype(numberOfTimesteps) t = 0; t < numberOfTimesteps; ++t) { auto iter = contourIn3D->Begin(t); auto end = contourIn3D->End(t); while (iter != end) { const auto ¤tPointIn3D = (*iter)->Coordinates; Point3D projectedPointIn2D; projectedPointIn2D.Fill(0.0); sliceGeometry->WorldToIndex(currentPointIn3D, projectedPointIn2D); projectedContour->AddVertex(projectedPointIn2D, t); ++iter; } } return projectedContour; } mitk::ContourModel::Pointer mitk::ContourModelUtils::BackProjectContourFrom2DSlice( const BaseGeometry *sliceGeometry, ContourModel *contourIn2D, bool) { if (nullptr == sliceGeometry || nullptr == contourIn2D) return nullptr; auto worldContour = ContourModel::New(); worldContour->Initialize(*contourIn2D); auto numberOfTimesteps = static_cast(contourIn2D->GetTimeSteps()); for (decltype(numberOfTimesteps) t = 0; t < numberOfTimesteps; ++t) { auto iter = contourIn2D->Begin(t); auto end = contourIn2D->End(t); while (iter != end) { const auto ¤tPointIn2D = (*iter)->Coordinates; Point3D worldPointIn3D; worldPointIn3D.Fill(0.0); sliceGeometry->IndexToWorld(currentPointIn2D, worldPointIn3D); worldContour->AddVertex(worldPointIn3D, t); ++iter; } } return worldContour; } void mitk::ContourModelUtils::FillContourInSlice( const ContourModel *projectedContour, Image *sliceImage, const Image* workingImage, int paintingPixelValue) { FillContourInSlice(projectedContour, 0, sliceImage, workingImage, paintingPixelValue); } void mitk::ContourModelUtils::FillContourInSlice( - const ContourModel *projectedContour, unsigned int t, Image *sliceImage, const Image* workingImage, int paintingPixelValue) + const ContourModel *projectedContour, unsigned int contourTimeStep, Image *sliceImage, const Image* workingImage, int paintingPixelValue) { if (nullptr == projectedContour) { mitkThrow() << "Cannot fill contour in slice. Passed contour is invalid"; } if (nullptr == sliceImage) { mitkThrow() << "Cannot fill contour in slice. Passed slice is invalid"; } auto contourModelFilter = mitk::ContourModelToSurfaceFilter::New(); contourModelFilter->SetInput(projectedContour); contourModelFilter->Update(); auto surface = mitk::Surface::New(); surface = contourModelFilter->GetOutput(); - if (nullptr == surface->GetVtkPolyData(t)) + if (nullptr == surface->GetVtkPolyData(contourTimeStep)) { MITK_WARN << "Could not create surface from contour model."; return; } auto surface2D = vtkSmartPointer::New(); - surface2D->SetPoints(surface->GetVtkPolyData(t)->GetPoints()); - surface2D->SetLines(surface->GetVtkPolyData(t)->GetLines()); + surface2D->SetPoints(surface->GetVtkPolyData(contourTimeStep)->GetPoints()); + surface2D->SetLines(surface->GetVtkPolyData(contourTimeStep)->GetLines()); auto image = vtkSmartPointer::New(); image->DeepCopy(sliceImage->GetVtkImageData()); const double FOREGROUND_VALUE = 255.0; const double BACKGROUND_VALUE = 0.0; vtkIdType count = image->GetNumberOfPoints(); for (decltype(count) i = 0; i < count; ++i) image->GetPointData()->GetScalars()->SetTuple1(i, FOREGROUND_VALUE); auto polyDataToImageStencil = vtkSmartPointer::New(); // Set a minimal tolerance, so that clipped pixels will be added to contour as well. polyDataToImageStencil->SetTolerance(mitk::eps); polyDataToImageStencil->SetInputData(surface2D); polyDataToImageStencil->Update(); auto imageStencil = vtkSmartPointer::New(); imageStencil->SetInputData(image); imageStencil->SetStencilConnection(polyDataToImageStencil->GetOutputPort()); imageStencil->ReverseStencilOff(); imageStencil->SetBackgroundValue(BACKGROUND_VALUE); imageStencil->Update(); vtkSmartPointer filledImage = imageStencil->GetOutput(); vtkSmartPointer resultImage = sliceImage->GetVtkImageData(); FillSliceInSlice(filledImage, resultImage, workingImage, paintingPixelValue); sliceImage->SetVolume(resultImage->GetScalarPointer()); } void mitk::ContourModelUtils::FillSliceInSlice( vtkSmartPointer filledImage, vtkSmartPointer resultImage, const Image* image, int paintingPixelValue) { auto labelImage = dynamic_cast(image); auto numberOfPoints = filledImage->GetNumberOfPoints(); if (nullptr == labelImage) { for (decltype(numberOfPoints) i = 0; i < numberOfPoints; ++i) { if (1 < filledImage->GetPointData()->GetScalars()->GetTuple1(i)) resultImage->GetPointData()->GetScalars()->SetTuple1(i, paintingPixelValue); } } else { auto backgroundValue = labelImage->GetExteriorLabel()->GetValue(); if (paintingPixelValue != backgroundValue) { for (decltype(numberOfPoints) i = 0; i < numberOfPoints; ++i) { if (1 < filledImage->GetPointData()->GetScalars()->GetTuple1(i)) { auto existingValue = resultImage->GetPointData()->GetScalars()->GetTuple1(i); if (!labelImage->GetLabel(existingValue, labelImage->GetActiveLayer())->GetLocked()) resultImage->GetPointData()->GetScalars()->SetTuple1(i, paintingPixelValue); } } } else { auto activePixelValue = labelImage->GetActiveLabel(labelImage->GetActiveLayer())->GetValue(); for (decltype(numberOfPoints) i = 0; i < numberOfPoints; ++i) { if (1 < filledImage->GetPointData()->GetScalars()->GetTuple1(i)) { if (resultImage->GetPointData()->GetScalars()->GetTuple1(i) == activePixelValue) resultImage->GetPointData()->GetScalars()->SetTuple1(i, paintingPixelValue); } } } } } mitk::ContourModel::Pointer mitk::ContourModelUtils::MoveZerothContourTimeStep(const ContourModel *contour, unsigned int t) { if (nullptr == contour) return nullptr; auto resultContour = ContourModel::New(); resultContour->Expand(t + 1); std::for_each(contour->Begin(), contour->End(), [&resultContour, t](ContourElement::VertexType *vertex) { resultContour->AddVertex(vertex, t); }); return resultContour; } int mitk::ContourModelUtils::GetActivePixelValue(const Image* workingImage) { auto* labelSetImage = dynamic_cast(workingImage); int activePixelValue = 1; if (nullptr != labelSetImage) { activePixelValue = labelSetImage->GetActiveLabel(labelSetImage->GetActiveLayer())->GetValue(); } return activePixelValue; } diff --git a/Modules/ContourModel/Algorithms/mitkContourModelUtils.h b/Modules/ContourModel/Algorithms/mitkContourModelUtils.h index 1539a771e4..dec716cbc6 100644 --- a/Modules/ContourModel/Algorithms/mitkContourModelUtils.h +++ b/Modules/ContourModel/Algorithms/mitkContourModelUtils.h @@ -1,110 +1,113 @@ /*============================================================================ 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. ============================================================================*/ #ifndef mitkContourModelUtils_h #define mitkContourModelUtils_h #include #include #include #include namespace mitk { /** * \brief Helpful methods for working with contours and images * * */ class MITKCONTOURMODEL_EXPORT ContourModelUtils : public itk::Object { public: mitkClassMacroItkParent(ContourModelUtils, itk::Object); /** \brief Projects a contour onto an image point by point. Converts from world to index coordinates. \param slice \param contourIn3D \param correctionForIpSegmentation adds 0.5 to x and y index coordinates (difference between ipSegmentation and MITK contours) \param constrainToInside */ static ContourModel::Pointer ProjectContourTo2DSlice(Image *slice, ContourModel *contourIn3D, bool correctionForIpSegmentation, bool constrainToInside); /** \brief Projects a slice index coordinates of a contour back into world coordinates. \param sliceGeometry \param contourIn2D \param correctionForIpSegmentation subtracts 0.5 to x and y index coordinates (difference between ipSegmentation and MITK contours) */ static ContourModel::Pointer BackProjectContourFrom2DSlice(const BaseGeometry *sliceGeometry, ContourModel *contourIn2D, bool correctionForIpSegmentation = false); /** - \brief Fill a contour in a 2D slice with a specified pixel value at time step 0. + \brief Fill a contour in a 2D slice with a specified pixel value. + This version always uses the contour of time step 0 and fills the image. \pre sliceImage points to a valid instance \pre projectedContour points to a valid instance */ static void FillContourInSlice(const ContourModel *projectedContour, Image *sliceImage, const Image* workingImage, int paintingPixelValue = 1); /** - \brief Fill a contour in a 2D slice with a specified pixel value at a given time step. + \brief Fill a contour in a 2D slice with a specified pixel value. + This overloaded version uses the contour at the passed contourTimeStep + to file the passed image slice. \pre sliceImage points to a valid instance \pre projectedContour points to a valid instance */ static void FillContourInSlice(const ContourModel *projectedContour, - unsigned int timeStep, + unsigned int contourTimeStep, Image *sliceImage, const Image* workingImage, int paintingPixelValue = 1); /** \brief Fills a image (filledImage) into another image (resultImage) by incorporating the rules of LabelSet-Images */ static void FillSliceInSlice(vtkSmartPointer filledImage, vtkSmartPointer resultImage, const Image* image, int paintingPixelValue); /** \brief Move the contour in time step 0 to to a new contour model at the given time step. */ static ContourModel::Pointer MoveZerothContourTimeStep(const ContourModel *contour, unsigned int timeStep); /** \brief Retrieves the active pixel value of a (labelset) image. If the image is basic image, the pixel value 1 (one) will be returned. If the image is actually a labelset image, the pixel value of the active label of the active layer will be returned. \param workingImage The (labelset) image to retrieve the active pixel value of. */ static int GetActivePixelValue(const Image* workingImage); protected: ContourModelUtils(); ~ContourModelUtils() override; }; } #endif