diff --git a/CMakeExternals/MITKData.cmake b/CMakeExternals/MITKData.cmake index 548389cdab..5c10814529 100644 --- a/CMakeExternals/MITKData.cmake +++ b/CMakeExternals/MITKData.cmake @@ -1,35 +1,35 @@ #----------------------------------------------------------------------------- # MITK Data #----------------------------------------------------------------------------- # Sanity checks if(DEFINED MITK_DATA_DIR AND NOT EXISTS ${MITK_DATA_DIR}) message(FATAL_ERROR "MITK_DATA_DIR variable is defined but corresponds to non-existing directory") endif() set(proj MITK-Data) set(proj_DEPENDENCIES) set(MITK-Data_DEPENDS ${proj}) if(BUILD_TESTING) - set(revision_tag df83b68b) -# ^^^^^^^^ these are just to check correct length of hash part + set(revision_tag f31f5df7) +# ^^^^^^^^ these are just to check correct length of hash part ExternalProject_Add(${proj} URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/MITK-Data_${revision_tag}.tar.gz UPDATE_COMMAND "" CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "" DEPENDS ${proj_DEPENDENCIES} ) set(MITK_DATA_DIR ${ep_source_dir}/${proj}) else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif(BUILD_TESTING) diff --git a/Modules/Segmentation/Testing/files.cmake b/Modules/Segmentation/Testing/files.cmake index 3665976cf5..987a673809 100644 --- a/Modules/Segmentation/Testing/files.cmake +++ b/Modules/Segmentation/Testing/files.cmake @@ -1,43 +1,44 @@ set(MODULE_TESTS mitkContourMapper2DTest.cpp mitkContourTest.cpp mitkDataNodeSegmentationTest.cpp + mitkImageToContourFilterTest.cpp # mitkSegmentationInterpolationTest.cpp mitkOverwriteSliceFilterTest.cpp mitkOverwriteSliceFilterObliquePlaneTest.cpp # mitkToolManagerTest.cpp mitkToolManagerProviderTest.cpp ) if(MITK_ENABLE_RENDERING_TESTING) #since mitkInteractionTestHelper is currently creating a vtkRenderWindow set(MODULE_TESTS ${MODULE_TESTS} mitkToolInteractionTest.cpp ) endif() set(MODULE_IMAGE_TESTS mitkManualSegmentationToSurfaceFilterTest.cpp #only runs on images mitkOverwriteSliceImageFilterTest.cpp #only runs on images ) set(MODULE_CUSTOM_TESTS ) set(MODULE_TESTIMAGES US4DCyl.nrrd Pic3D.nrrd Pic2DplusT.nrrd BallBinary30x30x30.nrrd Png2D-bw.png ) # Create an artificial module initializing class for # usServices set(testdriver_init_file ) usFunctionGenerateModuleInit(testdriver_init_file NAME SegmentationTestDriver DEPENDS "Segmentation" VERSION "0.1.0" ) set(TEST_CPP_FILES ${testdriver_init_file}) diff --git a/Modules/Segmentation/Testing/mitkImageToContourFilterTest.cpp b/Modules/Segmentation/Testing/mitkImageToContourFilterTest.cpp new file mode 100644 index 0000000000..91102af916 --- /dev/null +++ b/Modules/Segmentation/Testing/mitkImageToContourFilterTest.cpp @@ -0,0 +1,109 @@ +/*=================================================================== + +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 + +class mitkImageToContourFilterTestSuite : public mitk::TestFixture +{ + CPPUNIT_TEST_SUITE(mitkImageToContourFilterTestSuite); + MITK_TEST(TestExtractContoursFromAnEmptySlice); + MITK_TEST(TestExtractASingleContourFromASlice); + MITK_TEST(TestExtractTwoContoursFromASingleSlice); + CPPUNIT_TEST_SUITE_END(); + +private: + + mitk::Image::Pointer m_EmptySlice; + mitk::Image::Pointer m_SliceWithSingleContour; + mitk::Image::Pointer m_SliceWithTwoContours; + mitk::ImageToContourFilter::Pointer m_ContourExtractor; + +public: + + void setUp() + { + //Load the image + //TODO Move/create segmentation subfolder + m_EmptySlice = mitk::IOUtil::LoadImage(GetTestDataFilePath("SurfaceInterpolation/ImageToContour/EmptySlice.nrrd")); + CPPUNIT_ASSERT_MESSAGE("Failed to load image for test: [EmptySlice.nrrd]", m_EmptySlice.IsNotNull()); + + m_SliceWithSingleContour = mitk::IOUtil::LoadImage(GetTestDataFilePath("SurfaceInterpolation/ImageToContour/SliceWithSingleContour.nrrd")); + CPPUNIT_ASSERT_MESSAGE("Failed to load image for test: [SliceWithSingleContour.nrrd]", m_SliceWithSingleContour.IsNotNull()); + + m_SliceWithTwoContours = mitk::IOUtil::LoadImage(GetTestDataFilePath("SurfaceInterpolation/ImageToContour/SliceWithTwoContours.nrrd")); + CPPUNIT_ASSERT_MESSAGE("Failed to load image for test: [SliceWithTwoContours.nrrd]", m_SliceWithTwoContours.IsNotNull()); + + m_ContourExtractor = mitk::ImageToContourFilter::New(); + CPPUNIT_ASSERT_MESSAGE("Failed to initialize ImageToContourFilter", m_ContourExtractor.IsNotNull()); + } + + // Extract contours from an empty slice + void TestExtractContoursFromAnEmptySlice() + { + m_ContourExtractor->SetInput(m_EmptySlice); + m_ContourExtractor->Update(); + mitk::Surface::Pointer emptyContour = m_ContourExtractor->GetOutput(); + + CPPUNIT_ASSERT_MESSAGE("Extracted contour is not empty", emptyContour->GetVtkPolyData()->GetNumberOfPoints() == 0); + } + + // Extract a single contour from a slice + void TestExtractASingleContourFromASlice() + { + m_ContourExtractor->SetInput(m_SliceWithSingleContour); + m_ContourExtractor->Update(); + + CPPUNIT_ASSERT_MESSAGE("ImageToContourFilter has wrong number of outputs!", m_ContourExtractor->GetNumberOfOutputs() == 1); + + mitk::Surface::Pointer contour = m_ContourExtractor->GetOutput(); + + mitk::Surface::Pointer referenceContour = mitk::IOUtil::LoadSurface(GetTestDataFilePath("SurfaceInterpolation/Reference/SingleContour.vtk")); + + CPPUNIT_ASSERT_MESSAGE("Extracted contour has wrong number of points!", contour->GetVtkPolyData()->GetNumberOfPoints() == + referenceContour->GetVtkPolyData()->GetNumberOfPoints()); + + CPPUNIT_ASSERT_MESSAGE("Unequal contours", mitk::Equal(contour->GetVtkPolyData(), referenceContour->GetVtkPolyData(), 0.000001, true)); + } + + // Extract multiple contours from a single slice + void TestExtractTwoContoursFromASingleSlice() + { + m_ContourExtractor->SetInput(m_SliceWithTwoContours); + m_ContourExtractor->Update(); + + CPPUNIT_ASSERT_MESSAGE("ImageToContourFilter has wrong number of outputs!", m_ContourExtractor->GetNumberOfOutputs() == 1); + + mitk::Surface::Pointer contour = m_ContourExtractor->GetOutput(0); + + mitk::Surface::Pointer referenceContour = mitk::IOUtil::LoadSurface(GetTestDataFilePath("SurfaceInterpolation/Reference/TwoContours.vtk")); + + CPPUNIT_ASSERT_MESSAGE("Extracted contour1 has wrong number of points!", contour->GetVtkPolyData()->GetNumberOfPoints() == + referenceContour->GetVtkPolyData()->GetNumberOfPoints()); + + CPPUNIT_ASSERT_MESSAGE("Extracted contour1 has wrong number of points!", contour->GetVtkPolyData()->GetNumberOfPolys() == + referenceContour->GetVtkPolyData()->GetNumberOfPolys()); + + CPPUNIT_ASSERT_MESSAGE("Unequal contours", mitk::Equal(contour->GetVtkPolyData(), referenceContour->GetVtkPolyData(), 0.000001, true)); + + } +}; + +MITK_TEST_SUITE_REGISTRATION(mitkImageToContourFilter) diff --git a/Modules/SurfaceInterpolation/CMakeLists.txt b/Modules/SurfaceInterpolation/CMakeLists.txt index 5eedf67a05..047662be67 100644 --- a/Modules/SurfaceInterpolation/CMakeLists.txt +++ b/Modules/SurfaceInterpolation/CMakeLists.txt @@ -1,4 +1,6 @@ MITK_CREATE_MODULE( DEPENDS MitkImageExtraction WARNINGS_AS_ERRORS ) + +add_subdirectory(Testing) diff --git a/Modules/SurfaceInterpolation/Testing/CMakeLists.txt b/Modules/SurfaceInterpolation/Testing/CMakeLists.txt new file mode 100644 index 0000000000..153cd81e2e --- /dev/null +++ b/Modules/SurfaceInterpolation/Testing/CMakeLists.txt @@ -0,0 +1 @@ +MITK_CREATE_MODULE_TESTS() diff --git a/Modules/SurfaceInterpolation/Testing/files.cmake b/Modules/SurfaceInterpolation/Testing/files.cmake new file mode 100644 index 0000000000..f1effd0152 --- /dev/null +++ b/Modules/SurfaceInterpolation/Testing/files.cmake @@ -0,0 +1,5 @@ +set(MODULE_TESTS + mitkComputeContourSetNormalsFilterTest.cpp + mitkCreateDistanceImageFromSurfaceFilterTest.cpp + mitkReduceContourSetFilterTest.cpp +) diff --git a/Modules/SurfaceInterpolation/Testing/mitkComputeContourSetNormalsFilterTest.cpp b/Modules/SurfaceInterpolation/Testing/mitkComputeContourSetNormalsFilterTest.cpp new file mode 100644 index 0000000000..b146bb1b38 --- /dev/null +++ b/Modules/SurfaceInterpolation/Testing/mitkComputeContourSetNormalsFilterTest.cpp @@ -0,0 +1,88 @@ +/*=================================================================== + +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 +#include + +class mitkComputeContourSetNormalsFilterTestSuite : public mitk::TestFixture +{ + CPPUNIT_TEST_SUITE(mitkComputeContourSetNormalsFilterTestSuite); + MITK_TEST(TestComputeNormals); + MITK_TEST(TestComputeNormalsWithHole); + CPPUNIT_TEST_SUITE_END(); + +private: + + mitk::ComputeContourSetNormalsFilter::Pointer m_ContourNormalsFilter; + +public: + + void setUp() + { + m_ContourNormalsFilter = mitk::ComputeContourSetNormalsFilter::New(); + CPPUNIT_ASSERT_MESSAGE("Failed to initialize ReduceContourSetFilter", m_ContourNormalsFilter.IsNotNull()); + } + + // Compute the normals for a regular contour + void TestComputeNormals() + { + mitk::Surface::Pointer contour = mitk::IOUtil::LoadSurface(GetTestDataFilePath("SurfaceInterpolation/Reference/SingleContour.vtk")); + m_ContourNormalsFilter->SetInput(contour); + m_ContourNormalsFilter->Update(); + // Get the computed normals (basically lines) + mitk::Surface::Pointer normals = m_ContourNormalsFilter->GetNormalsAsSurface(); + // Get the actual surface object which has the contours stored as normals internally + mitk::Surface::Pointer contourWithNormals = m_ContourNormalsFilter->GetOutput(); + + mitk::Surface::Pointer referenceContour = mitk::IOUtil::LoadSurface(GetTestDataFilePath("SurfaceInterpolation/Reference/ContourWithNormals.vtk")); + mitk::Surface::Pointer referenceNormals = mitk::IOUtil::LoadSurface(GetTestDataFilePath("SurfaceInterpolation/Reference/ContourNormals.vtk")); + + CPPUNIT_ASSERT_MESSAGE("Unequal contours", mitk::Equal(contourWithNormals->GetVtkPolyData(), referenceContour->GetVtkPolyData(), 0.000001, true)); + CPPUNIT_ASSERT_MESSAGE("Unequal contours", mitk::Equal(normals->GetVtkPolyData(), referenceNormals->GetVtkPolyData(), 0.000001, true)); + } + + + + // Reduce contours with Douglas Peucker + void TestComputeNormalsWithHole() + { + mitk::Image::Pointer segmentationImage = mitk::IOUtil::LoadImage(GetTestDataFilePath("SurfaceInterpolation/Reference/LiverSegmentation.nrrd")); + + mitk::Surface::Pointer contour = mitk::IOUtil::LoadSurface(GetTestDataFilePath("SurfaceInterpolation/ComputeNormals/ContourWithHoles.vtk")); + m_ContourNormalsFilter->SetInput(contour); + m_ContourNormalsFilter->SetSegmentationBinaryImage(segmentationImage); + m_ContourNormalsFilter->Update(); + mitk::Surface::Pointer contourWithNormals = m_ContourNormalsFilter->GetOutput(); + mitk::Surface::Pointer normals = m_ContourNormalsFilter->GetNormalsAsSurface(); + + mitk::Surface::Pointer contourReference = mitk::IOUtil::LoadSurface(GetTestDataFilePath("SurfaceInterpolation/Reference/ContourWithHolesWithNormals.vtk")); + mitk::Surface::Pointer normalsReference = mitk::IOUtil::LoadSurface(GetTestDataFilePath("SurfaceInterpolation/Reference/NormalsWithHoles.vtk")); + + CPPUNIT_ASSERT_MESSAGE("Error computing normals", mitk::Equal(normals->GetVtkPolyData(), normalsReference->GetVtkPolyData(), 0.000001, true)); + CPPUNIT_ASSERT_MESSAGE("Error computing normals", + contourWithNormals->GetVtkPolyData()->GetCellData()->GetNormals()->GetNumberOfTuples() == contourReference->GetVtkPolyData()->GetNumberOfPoints()); + } + +}; + +MITK_TEST_SUITE_REGISTRATION(mitkComputeContourSetNormalsFilter) diff --git a/Modules/SurfaceInterpolation/Testing/mitkCreateDistanceImageFromSurfaceFilterTest.cpp b/Modules/SurfaceInterpolation/Testing/mitkCreateDistanceImageFromSurfaceFilterTest.cpp new file mode 100644 index 0000000000..ea429d4a4a --- /dev/null +++ b/Modules/SurfaceInterpolation/Testing/mitkCreateDistanceImageFromSurfaceFilterTest.cpp @@ -0,0 +1,134 @@ +/*=================================================================== + +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 + +class mitkCreateDistanceImageFromSurfaceFilterTestSuite : public mitk::TestFixture +{ + CPPUNIT_TEST_SUITE(mitkCreateDistanceImageFromSurfaceFilterTestSuite); + MITK_TEST(TestCreateDistanceImageForLiver); + MITK_TEST(TestCreateDistanceImageForTube); + CPPUNIT_TEST_SUITE_END(); + +private: + + std::vector contourList; + +public: + + void setUp() + { + + } + + template + void GetImageBase(itk::Image* input, itk::ImageBase<3>::Pointer& result) + { + result->Graft(input); + } + + // Interpolate the shape of a liver + void TestCreateDistanceImageForLiver() + { + // That's the number of available liver contours in MITK-Data + unsigned int NUMBER_OF_LIVER_CONTOURS = 18; + + for (unsigned int i = 0; i <= NUMBER_OF_LIVER_CONTOURS; ++i) + { + std::stringstream s; + s << "SurfaceInterpolation/InterpolateLiver/LiverContourWithNormals_"; + s << i; + s << ".vtk"; + mitk::Surface::Pointer contour = mitk::IOUtil::LoadSurface(GetTestDataFilePath(s.str())); + contourList.push_back(contour); + } + + mitk::Image::Pointer segmentationImage = mitk::IOUtil::LoadImage(GetTestDataFilePath("SurfaceInterpolation/Reference/LiverSegmentation.nrrd")); + + mitk::ComputeContourSetNormalsFilter::Pointer m_NormalsFilter = mitk::ComputeContourSetNormalsFilter::New(); + mitk::CreateDistanceImageFromSurfaceFilter::Pointer m_InterpolateSurfaceFilter = mitk::CreateDistanceImageFromSurfaceFilter::New(); + + itk::ImageBase<3>::Pointer itkImage = itk::ImageBase<3>::New(); + AccessFixedDimensionByItk_1( segmentationImage, GetImageBase, 3, itkImage ); + m_InterpolateSurfaceFilter->SetReferenceImage( itkImage.GetPointer() ); + + for (unsigned int j = 0; j < contourList.size(); j++) + { + m_NormalsFilter->SetInput(j, contourList.at(j)); + m_InterpolateSurfaceFilter->SetInput(j, m_NormalsFilter->GetOutput(j)); + } + + m_InterpolateSurfaceFilter->Update(); + + mitk::Image::Pointer liverDistanceImage = m_InterpolateSurfaceFilter->GetOutput(); + + CPPUNIT_ASSERT(liverDistanceImage.IsNotNull()); + mitk::Image::Pointer liverDistanceImageReference = mitk::IOUtil::LoadImage(GetTestDataFilePath("SurfaceInterpolation/Reference/LiverDistanceImage.nrrd")); + + MITK_ASSERT_EQUAL(liverDistanceImageReference, liverDistanceImage, "LiverDistanceImages are not equal!"); + } + + + + void TestCreateDistanceImageForTube() + { + // That's the number of available contours with holes in MITK-Data + unsigned int NUMBER_OF_TUBE_CONTOURS = 5; + + for (unsigned int i = 0; i < NUMBER_OF_TUBE_CONTOURS; ++i) + { + std::stringstream s; + s << "SurfaceInterpolation/InterpolateWithHoles/ContourWithHoles_"; + s << i; + s << ".vtk"; + mitk::Surface::Pointer contour = mitk::IOUtil::LoadSurface(GetTestDataFilePath(s.str())); + contourList.push_back(contour); + } + + mitk::Image::Pointer segmentationImage = mitk::IOUtil::LoadImage(GetTestDataFilePath("SurfaceInterpolation/Reference/SegmentationWithHoles.nrrd")); + + mitk::ComputeContourSetNormalsFilter::Pointer m_NormalsFilter = mitk::ComputeContourSetNormalsFilter::New(); + mitk::CreateDistanceImageFromSurfaceFilter::Pointer m_InterpolateSurfaceFilter = mitk::CreateDistanceImageFromSurfaceFilter::New(); + + m_NormalsFilter->SetSegmentationBinaryImage(segmentationImage); + itk::ImageBase<3>::Pointer itkImage = itk::ImageBase<3>::New(); + AccessFixedDimensionByItk_1( segmentationImage, GetImageBase, 3, itkImage ); + m_InterpolateSurfaceFilter->SetReferenceImage( itkImage.GetPointer() ); + + for (unsigned int j = 0; j < contourList.size(); j++) + { + m_NormalsFilter->SetInput(j, contourList.at(j)); + m_InterpolateSurfaceFilter->SetInput(j, m_NormalsFilter->GetOutput(j)); + } + + m_InterpolateSurfaceFilter->Update(); + + mitk::Image::Pointer holeDistanceImage = m_InterpolateSurfaceFilter->GetOutput(); + + CPPUNIT_ASSERT(holeDistanceImage.IsNotNull()); + mitk::Image::Pointer holesDistanceImageReference = mitk::IOUtil::LoadImage(GetTestDataFilePath("SurfaceInterpolation/Reference/HolesDistanceImage.nrrd")); + + MITK_ASSERT_EQUAL(holesDistanceImageReference, holeDistanceImage, "HolesDistanceImages are not equal!"); + } + +}; + +MITK_TEST_SUITE_REGISTRATION(mitkCreateDistanceImageFromSurfaceFilter) diff --git a/Modules/SurfaceInterpolation/Testing/mitkReduceContourSetFilterTest.cpp b/Modules/SurfaceInterpolation/Testing/mitkReduceContourSetFilterTest.cpp new file mode 100644 index 0000000000..6ead064e22 --- /dev/null +++ b/Modules/SurfaceInterpolation/Testing/mitkReduceContourSetFilterTest.cpp @@ -0,0 +1,74 @@ +/*=================================================================== + +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 + +class mitkReduceContourSetFilterTestSuite : public mitk::TestFixture +{ + CPPUNIT_TEST_SUITE(mitkReduceContourSetFilterTestSuite); + MITK_TEST(TestReduceContourWithNthPoint); + MITK_TEST(TestReduceContourWithDouglasPeuker); + CPPUNIT_TEST_SUITE_END(); + +private: + + mitk::ReduceContourSetFilter::Pointer m_ContourReducer; + +public: + + void setUp() + { + m_ContourReducer = mitk::ReduceContourSetFilter::New(); + CPPUNIT_ASSERT_MESSAGE("Failed to initialize ReduceContourSetFilter", m_ContourReducer.IsNotNull()); + } + + // Reduce contours with nth point + void TestReduceContourWithNthPoint() + { + mitk::Surface::Pointer contour = mitk::IOUtil::LoadSurface(GetTestDataFilePath("SurfaceInterpolation/Reference/SingleContour.vtk")); + m_ContourReducer->SetInput(contour); + m_ContourReducer->SetReductionType(mitk::ReduceContourSetFilter::NTH_POINT); + m_ContourReducer->SetStepSize(20); + m_ContourReducer->Update(); + mitk::Surface::Pointer reducedContour = m_ContourReducer->GetOutput(); + + mitk::Surface::Pointer reference = mitk::IOUtil::LoadSurface(GetTestDataFilePath("SurfaceInterpolation/Reference/ReducedContourNthPoint_20.vtk")); + + CPPUNIT_ASSERT_MESSAGE("Unequal contours", mitk::Equal(reducedContour->GetVtkPolyData(), reference->GetVtkPolyData(), 0.000001, true)); + } + + // Reduce contours with Douglas Peucker + void TestReduceContourWithDouglasPeuker() + { + mitk::Surface::Pointer contour = mitk::IOUtil::LoadSurface(GetTestDataFilePath("SurfaceInterpolation/Reference/TwoContours.vtk")); + m_ContourReducer->SetInput(contour); + m_ContourReducer->SetReductionType(mitk::ReduceContourSetFilter::DOUGLAS_PEUCKER); + m_ContourReducer->Update(); + mitk::Surface::Pointer reducedContour = m_ContourReducer->GetOutput(); + + mitk::Surface::Pointer reference = mitk::IOUtil::LoadSurface(GetTestDataFilePath("SurfaceInterpolation/Reference/ReducedContourDouglasPeucker.vtk")); + + CPPUNIT_ASSERT_MESSAGE("Unequal contours", mitk::Equal(reducedContour->GetVtkPolyData(), reference->GetVtkPolyData(), 0.000001, true)); + } + +}; + +MITK_TEST_SUITE_REGISTRATION(mitkReduceContourSetFilter) diff --git a/Modules/SurfaceInterpolation/mitkComputeContourSetNormalsFilter.cpp b/Modules/SurfaceInterpolation/mitkComputeContourSetNormalsFilter.cpp index 7589adbeae..9c6ab2bdbd 100644 --- a/Modules/SurfaceInterpolation/mitkComputeContourSetNormalsFilter.cpp +++ b/Modules/SurfaceInterpolation/mitkComputeContourSetNormalsFilter.cpp @@ -1,319 +1,321 @@ /*=================================================================== 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 "mitkComputeContourSetNormalsFilter.h" #include "mitkImagePixelReadAccessor.h" mitk::ComputeContourSetNormalsFilter::ComputeContourSetNormalsFilter() { m_MaxSpacing = 5; this->m_UseProgressBar = false; this->m_ProgressStepSize = 1; mitk::Surface::Pointer output = mitk::Surface::New(); this->SetNthOutput(0, output.GetPointer()); } mitk::ComputeContourSetNormalsFilter::~ComputeContourSetNormalsFilter() { } void mitk::ComputeContourSetNormalsFilter::GenerateData() { unsigned int numberOfInputs = this->GetNumberOfIndexedInputs(); this->CreateOutputsForAllInputs(numberOfInputs); //Iterating over each input for(unsigned int i = 0; i < numberOfInputs; i++) { //Getting the inputs polydata and polygons Surface* currentSurface = const_cast( this->GetInput(i) ); vtkPolyData* polyData = currentSurface->GetVtkPolyData(); vtkSmartPointer existingPolys = polyData->GetPolys(); vtkSmartPointer existingPoints = polyData->GetPoints(); existingPolys->InitTraversal(); vtkIdType* cell (NULL); vtkIdType cellSize (0); //The array that contains all the vertex normals of the current polygon vtkSmartPointer normals = vtkSmartPointer::New(); normals->SetNumberOfComponents(3); normals->SetNumberOfTuples(polyData->GetNumberOfPoints()); //If the current contour is an inner contour then the direction is -1 //A contour lies inside another one if the pixel values in the direction of the normal is 1 m_NegativeNormalCounter = 0; m_PositiveNormalCounter = 0; + vtkIdType offSet (0); //Iterating over each polygon for( existingPolys->InitTraversal(); existingPolys->GetNextCell(cellSize, cell);) { if(cellSize < 3)continue; //First we calculate the current polygon's normal double polygonNormal[3] = {0.0}; double p1[3]; double p2[3]; double v1[3]; double v2[3]; existingPoints->GetPoint(cell[0], p1); unsigned int index = cellSize*0.5; existingPoints->GetPoint(cell[index], p2); v1[0] = p2[0]-p1[0]; v1[1] = p2[1]-p1[1]; v1[2] = p2[2]-p1[2]; for (unsigned int k = 2; k < cellSize; k++) { index = cellSize*0.25; existingPoints->GetPoint(cell[index], p1); index = cellSize*0.75; existingPoints->GetPoint(cell[index], p2); v2[0] = p2[0]-p1[0]; v2[1] = p2[1]-p1[1]; v2[2] = p2[2]-p1[2]; vtkMath::Cross(v1,v2,polygonNormal); if (vtkMath::Norm(polygonNormal) != 0) break; } vtkMath::Normalize(polygonNormal); //Now we start computing the normal for each vertex double vertexNormalTemp[3]; existingPoints->GetPoint(cell[0], p1); existingPoints->GetPoint(cell[1], p2); v1[0] = p2[0]-p1[0]; v1[1] = p2[1]-p1[1]; v1[2] = p2[2]-p1[2]; vtkMath::Cross(v1,polygonNormal,vertexNormalTemp); vtkMath::Normalize(vertexNormalTemp); double vertexNormal[3]; for (unsigned j = 0; j < cellSize-2; j++) { existingPoints->GetPoint(cell[j+1], p1); existingPoints->GetPoint(cell[j+2], p2); v1[0] = p2[0]-p1[0]; v1[1] = p2[1]-p1[1]; v1[2] = p2[2]-p1[2]; vtkMath::Cross(v1,polygonNormal,vertexNormal); vtkMath::Normalize(vertexNormal); double finalNormal[3]; finalNormal[0] = (vertexNormal[0] + vertexNormalTemp[0])*0.5; finalNormal[1] = (vertexNormal[1] + vertexNormalTemp[1])*0.5; finalNormal[2] = (vertexNormal[2] + vertexNormalTemp[2])*0.5; //Here we determine the direction of the normal - if (j == 0 && m_SegmentationBinaryImage) + if (m_SegmentationBinaryImage) { Point3D worldCoord; worldCoord[0] = p1[0]+finalNormal[0]*m_MaxSpacing; worldCoord[1] = p1[1]+finalNormal[1]*m_MaxSpacing; worldCoord[2] = p1[2]+finalNormal[2]*m_MaxSpacing; double val = 0.0; mitk::ImagePixelReadAccessor readAccess(m_SegmentationBinaryImage); mitk::Index3D idx; m_SegmentationBinaryImage->GetGeometry()->WorldToIndex(worldCoord, idx); val = readAccess.GetPixelByIndexSafe(idx); - if (val == 1.0) + if (val == 0.0) { ++m_PositiveNormalCounter; } else { ++m_NegativeNormalCounter; } } vertexNormalTemp[0] = vertexNormal[0]; vertexNormalTemp[1] = vertexNormal[1]; vertexNormalTemp[2] = vertexNormal[2]; vtkIdType id = cell[j+1]; normals->SetTuple(id,finalNormal); } existingPoints->GetPoint(cell[0], p1); existingPoints->GetPoint(cell[1], p2); v1[0] = p2[0]-p1[0]; v1[1] = p2[1]-p1[1]; v1[2] = p2[2]-p1[2]; vtkMath::Cross(v1,polygonNormal,vertexNormal); vtkMath::Normalize(vertexNormal); vertexNormal[0] = (vertexNormal[0] + vertexNormalTemp[0])*0.5; vertexNormal[1] = (vertexNormal[1] + vertexNormalTemp[1])*0.5; vertexNormal[2] = (vertexNormal[2] + vertexNormalTemp[2])*0.5; vtkIdType id = cell[0]; normals->SetTuple(id,vertexNormal); id = cell[cellSize-1]; normals->SetTuple(id,vertexNormal); - int normalDirection(-1); - - if(m_NegativeNormalCounter < m_PositiveNormalCounter) + if(m_NegativeNormalCounter > m_PositiveNormalCounter) { - normalDirection = 1; + for(vtkIdType n = 0; n < cellSize; n++) + { + double normal[3]; + normals->GetTuple(offSet+n, normal); + normal[0] = (-1)*normal[0]; + normal[1] = (-1)*normal[1]; + normal[2] = (-1)*normal[2]; + normals->SetTuple(offSet+n, normal); + } } - for(unsigned int n = 0; n < normals->GetNumberOfTuples(); n++) - { - double normal[3]; - normals->GetTuple(n,normal); - normal[0] = normalDirection*normal[0]; - normal[1] = normalDirection*normal[1]; - normal[2] = normalDirection*normal[2]; - } + m_NegativeNormalCounter = 0; + m_PositiveNormalCounter = 0; + offSet += cellSize; }//end for all cells Surface::Pointer surface = this->GetOutput(i); surface->GetVtkPolyData()->GetCellData()->SetNormals(normals); }//end for all inputs //Setting progressbar if (this->m_UseProgressBar) mitk::ProgressBar::GetInstance()->Progress(this->m_ProgressStepSize); } mitk::Surface::Pointer mitk::ComputeContourSetNormalsFilter::GetNormalsAsSurface() { //Just for debugging: vtkSmartPointer newPolyData = vtkSmartPointer::New(); vtkSmartPointer newLines = vtkSmartPointer::New(); vtkSmartPointer newPoints = vtkSmartPointer::New(); unsigned int idCounter (0); //Debug end for (unsigned int i = 0; i < this->GetNumberOfIndexedOutputs(); i++) { Surface* currentSurface = const_cast( this->GetOutput(i) ); vtkPolyData* polyData = currentSurface->GetVtkPolyData(); vtkSmartPointer currentCellNormals = vtkDoubleArray::SafeDownCast(polyData->GetCellData()->GetNormals()); vtkSmartPointer existingPolys = polyData->GetPolys(); vtkSmartPointer existingPoints = polyData->GetPoints(); existingPolys->InitTraversal(); vtkIdType* cell (NULL); vtkIdType cellSize (0); for( existingPolys->InitTraversal(); existingPolys->GetNextCell(cellSize, cell);) { for ( unsigned int j = 0; j < cellSize; j++ ) { double currentNormal[3]; currentCellNormals->GetTuple(cell[j], currentNormal); vtkSmartPointer line = vtkSmartPointer::New(); line->GetPointIds()->SetNumberOfIds(2); double newPoint[3]; double p0[3]; existingPoints->GetPoint(cell[j], p0); newPoint[0] = p0[0] + currentNormal[0]; newPoint[1] = p0[1] + currentNormal[1]; newPoint[2] = p0[2] + currentNormal[2]; line->GetPointIds()->SetId(0, idCounter); newPoints->InsertPoint(idCounter, p0); idCounter++; line->GetPointIds()->SetId(1, idCounter); newPoints->InsertPoint(idCounter, newPoint); idCounter++; newLines->InsertNextCell(line); }//end for all points }//end for all cells }//end for all outputs newPolyData->SetPoints(newPoints); newPolyData->SetLines(newLines); newPolyData->BuildCells(); mitk::Surface::Pointer surface = mitk::Surface::New(); surface->SetVtkPolyData(newPolyData); return surface; } void mitk::ComputeContourSetNormalsFilter::SetMaxSpacing(double maxSpacing) { m_MaxSpacing = maxSpacing; } void mitk::ComputeContourSetNormalsFilter::GenerateOutputInformation() { Superclass::GenerateOutputInformation(); } void mitk::ComputeContourSetNormalsFilter::Reset() { for (unsigned int i = 0; i < this->GetNumberOfIndexedInputs(); i++) { this->PopBackInput(); } this->SetNumberOfIndexedInputs(0); this->SetNumberOfIndexedOutputs(0); mitk::Surface::Pointer output = mitk::Surface::New(); this->SetNthOutput(0, output.GetPointer()); } void mitk::ComputeContourSetNormalsFilter::SetUseProgressBar(bool status) { this->m_UseProgressBar = status; } void mitk::ComputeContourSetNormalsFilter::SetProgressStepSize(unsigned int stepSize) { this->m_ProgressStepSize = stepSize; }