diff --git a/Modules/MitkExt/Algorithms/mitkImageToSurfaceFilter.cpp b/Modules/MitkExt/Algorithms/mitkImageToSurfaceFilter.cpp index 702f06fc63..6b2633a228 100644 --- a/Modules/MitkExt/Algorithms/mitkImageToSurfaceFilter.cpp +++ b/Modules/MitkExt/Algorithms/mitkImageToSurfaceFilter.cpp @@ -1,232 +1,234 @@ /*=================================================================== 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 "mitkException.h" #include #include #include #include #include #include #include #include #include #include #include "mitkProgressBar.h" mitk::ImageToSurfaceFilter::ImageToSurfaceFilter(): m_Smooth(false), m_Decimate( NoDecimation), m_Threshold(1.0), m_TargetReduction(0.95f), m_SmoothIteration(50), m_SmoothRelaxation(0.1) { } mitk::ImageToSurfaceFilter::~ImageToSurfaceFilter() { } void mitk::ImageToSurfaceFilter::CreateSurface(int time, vtkImageData *vtkimage, mitk::Surface * surface, const ScalarType threshold) { vtkImageChangeInformation *indexCoordinatesImageFilter = vtkImageChangeInformation::New(); indexCoordinatesImageFilter->SetInput(vtkimage); indexCoordinatesImageFilter->SetOutputOrigin(0.0,0.0,0.0); //MarchingCube -->create Surface vtkMarchingCubes *skinExtractor = vtkMarchingCubes::New(); skinExtractor->ComputeScalarsOff(); skinExtractor->SetInput(indexCoordinatesImageFilter->GetOutput());//RC++ indexCoordinatesImageFilter->Delete(); skinExtractor->SetValue(0, threshold); vtkPolyData *polydata; polydata = skinExtractor->GetOutput(); polydata->Register(NULL);//RC++ skinExtractor->Delete(); if (m_Smooth) { vtkSmoothPolyDataFilter *smoother = vtkSmoothPolyDataFilter::New(); //read poly1 (poly1 can be the original polygon, or the decimated polygon) smoother->SetInput(polydata);//RC++ smoother->SetNumberOfIterations( m_SmoothIteration ); smoother->SetRelaxationFactor( m_SmoothRelaxation ); smoother->SetFeatureAngle( 60 ); smoother->FeatureEdgeSmoothingOff(); smoother->BoundarySmoothingOff(); smoother->SetConvergence( 0 ); polydata->Delete();//RC-- polydata = smoother->GetOutput(); polydata->Register(NULL);//RC++ smoother->Delete(); } ProgressBar::GetInstance()->Progress(); //decimate = to reduce number of polygons if(m_Decimate==DecimatePro) { vtkDecimatePro *decimate = vtkDecimatePro::New(); decimate->SplittingOff(); decimate->SetErrorIsAbsolute(5); decimate->SetFeatureAngle(30); decimate->PreserveTopologyOn(); decimate->BoundaryVertexDeletionOff(); decimate->SetDegree(10); //std-value is 25! decimate->SetInput(polydata);//RC++ decimate->SetTargetReduction(m_TargetReduction); decimate->SetMaximumError(0.002); polydata->Delete();//RC-- polydata = decimate->GetOutput(); polydata->Register(NULL);//RC++ decimate->Delete(); } else if (m_Decimate==QuadricDecimation) { vtkQuadricDecimation* decimate = vtkQuadricDecimation::New(); decimate->SetTargetReduction(m_TargetReduction); decimate->SetInput(polydata); polydata->Delete(); polydata = decimate->GetOutput(); polydata->Register(NULL); decimate->Delete(); } polydata->Update(); ProgressBar::GetInstance()->Progress(); polydata->SetSource(NULL); if(polydata->GetNumberOfPoints() > 0) { mitk::Vector3D spacing = GetInput()->GetGeometry(time)->GetSpacing(); vtkPoints * points = polydata->GetPoints(); vtkMatrix4x4 *vtkmatrix = vtkMatrix4x4::New(); GetInput()->GetGeometry(time)->GetVtkTransform()->GetMatrix(vtkmatrix); double (*matrix)[4] = vtkmatrix->Element; unsigned int i,j; for(i=0;i<3;++i) for(j=0;j<3;++j) matrix[i][j]/=spacing[j]; unsigned int n = points->GetNumberOfPoints(); vtkFloatingPointType point[3]; for (i = 0; i < n; i++) { points->GetPoint(i, point); mitkVtkLinearTransformPoint(matrix,point,point); points->SetPoint(i, point); } vtkmatrix->Delete(); } ProgressBar::GetInstance()->Progress(); // determine point_data normals for the poly data points. vtkSmartPointer normalsGenerator = vtkSmartPointer::New(); normalsGenerator->SetInput( polydata ); vtkSmartPointer cleanPolyDataFilter = vtkSmartPointer::New(); cleanPolyDataFilter->SetInput(normalsGenerator->GetOutput()); cleanPolyDataFilter->PieceInvariantOff(); cleanPolyDataFilter->ConvertLinesToPointsOff(); cleanPolyDataFilter->ConvertPolysToLinesOff(); cleanPolyDataFilter->ConvertStripsToPolysOff(); cleanPolyDataFilter->PointMergingOn(); cleanPolyDataFilter->Update(); surface->SetVtkPolyData(cleanPolyDataFilter->GetOutput(), time); polydata->UnRegister(NULL); } void mitk::ImageToSurfaceFilter::GenerateData() { mitk::Surface *surface = this->GetOutput(); mitk::Image * image = (mitk::Image*)GetInput(); + if(image == NULL || !image->IsInitialized()) + mitkThrow() << "No input image set, please set an valid input image!"; + mitk::Image::RegionType outputRegion = image->GetRequestedRegion(); int tstart=outputRegion.GetIndex(3); int tmax=tstart+outputRegion.GetSize(3); //GetSize()==1 - will aber 0 haben, wenn nicht zeitaufgeloest if ((tmax-tstart) > 0) { ProgressBar::GetInstance()->AddStepsToDo( 4 * (tmax - tstart) ); } int t; for( t=tstart; t < tmax; ++t) { vtkImageData *vtkimagedata = image->GetVtkImageData(t); CreateSurface(t,vtkimagedata,surface,m_Threshold); ProgressBar::GetInstance()->Progress(); } } void mitk::ImageToSurfaceFilter::SetSmoothIteration(int smoothIteration) { m_SmoothIteration = smoothIteration; } void mitk::ImageToSurfaceFilter::SetSmoothRelaxation(float smoothRelaxation) { m_SmoothRelaxation = smoothRelaxation; } void mitk::ImageToSurfaceFilter::SetInput(const mitk::Image *image) { // Process object is not const-correct so the const_cast is required here this->ProcessObject::SetNthInput(0, const_cast< mitk::Image * >( image ) ); } const mitk::Image *mitk::ImageToSurfaceFilter::GetInput(void) { if (this->GetNumberOfInputs() < 1) { return 0; } return static_cast ( this->ProcessObject::GetInput(0) ); } void mitk::ImageToSurfaceFilter::GenerateOutputInformation() { mitk::Image::ConstPointer inputImage =(mitk::Image*) this->GetInput(); //mitk::Image *inputImage = (mitk::Image*)this->GetImage(); mitk::Surface::Pointer output = this->GetOutput(); itkDebugMacro(<<"GenerateOutputInformation()"); if(inputImage.IsNull()) return; //Set Data } diff --git a/Modules/MitkExt/Testing/CMakeLists.txt b/Modules/MitkExt/Testing/CMakeLists.txt index 6a10de0dc0..9874b913ef 100644 --- a/Modules/MitkExt/Testing/CMakeLists.txt +++ b/Modules/MitkExt/Testing/CMakeLists.txt @@ -1,7 +1,8 @@ MITK_CREATE_MODULE_TESTS(EXTRA_DRIVER_INIT "RegisterCoreExtObjectFactory();;" EXTRA_DRIVER_INCLUDE "mitkCoreExtObjectFactory.h") if(BUILD_TESTING AND MODULE_IS_ENABLED) mitkAddCustomModuleTest(mitkLabeledImageToSurfaceFilterTest_BinaryBall mitkLabeledImageToSurfaceFilterTest ${MITK_DATA_DIR}/BallBinary30x30x30.pic.gz) +mitkAddCustomModuleTest(mitkImageToSurfaceFilterTest_BinaryBall mitkImageToSurfaceFilterTest ${MITK_DATA_DIR}/BallBinary30x30x30.nrrd) endif() diff --git a/Modules/MitkExt/Testing/files.cmake b/Modules/MitkExt/Testing/files.cmake index 056f064c56..fb643c22ea 100644 --- a/Modules/MitkExt/Testing/files.cmake +++ b/Modules/MitkExt/Testing/files.cmake @@ -1,38 +1,38 @@ set(MODULE_TESTS mitkAutoCropImageFilterTest.cpp mitkBoundingObjectCutterTest.cpp mitkCoreExtObjectFactoryTest mitkDataNodeExtTest.cpp mitkExternalToolsTest.cpp mitkMeshTest.cpp mitkMultiStepperTest.cpp mitkOrganTypePropertyTest.cpp mitkPipelineSmartPointerCorrectnessTest.cpp mitkPlaneFitTest.cpp mitkPointLocatorTest.cpp # mitkSegmentationInterpolationTest.cpp # mitkTestTemplate.cpp mitkUnstructuredGridTest.cpp mitkSimpleHistogramTest.cpp mitkToolManagerTest.cpp - mitkImageToSurfaceFilterTest.cpp ) set(MODULE_IMAGE_TESTS mitkUnstructuredGridVtkWriterTest.cpp mitkCompressedImageContainerTest.cpp mitkCylindricToCartesianFilterTest.cpp #mitkExtractImageFilterTest.cpp mitkSurfaceToImageFilterTest.cpp ) set(MODULE_CUSTOM_TESTS mitkLabeledImageToSurfaceFilterTest.cpp + mitkImageToSurfaceFilterTest.cpp ) set(MODULE_TESTIMAGES US4DCyl.nrrd Pic3D.nrrd Pic2DplusT.nrrd BallBinary30x30x30.nrrd Png2D-bw.png binary.stl ball.stl ) diff --git a/Modules/MitkExt/Testing/mitkImageToSurfaceFilterTest.cpp b/Modules/MitkExt/Testing/mitkImageToSurfaceFilterTest.cpp index 57e8d01709..1a12bb5487 100644 --- a/Modules/MitkExt/Testing/mitkImageToSurfaceFilterTest.cpp +++ b/Modules/MitkExt/Testing/mitkImageToSurfaceFilterTest.cpp @@ -1,29 +1,101 @@ /*=================================================================== 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 "mitkTestingMacros.h" #include "mitkImageToSurfaceFilter.h" +#include "mitkItkImageFileReader.h" +#include "mitkException.h" + +bool CompareSurfacePointPositions(mitk::Surface::Pointer s1, mitk::Surface::Pointer s2) +{ + vtkPoints* p1 = s1->GetVtkPolyData()->GetPoints(); + vtkPoints* p2 = s2->GetVtkPolyData()->GetPoints(); + + if(p1->GetNumberOfPoints() != p2->GetNumberOfPoints()) + return false; + + for(int i = 0; i < p1->GetNumberOfPoints(); ++i) + { + if(p1->GetPoint(i)[0] != p2->GetPoint(i)[0] || + p1->GetPoint(i)[1] != p2->GetPoint(i)[1] || + p1->GetPoint(i)[2] != p2->GetPoint(i)[2] ) + { + return true; + } + } + return false; +} int mitkImageToSurfaceFilterTest(int argc, char* argv[]) { MITK_TEST_BEGIN("ImageToSurfaceFilterTest"); mitk::ImageToSurfaceFilter::Pointer testObject = mitk::ImageToSurfaceFilter::New(); MITK_TEST_CONDITION_REQUIRED(testObject.IsNotNull(), "Testing instantiation of test object"); + mitk::ItkImageFileReader::Pointer reader = mitk::ItkImageFileReader::New(); + reader->SetFileName(argv[1]); + reader->Update(); + mitk::Image::Pointer tImage = reader->GetOutput(); + + // testing initialization of member variables! + MITK_TEST_CONDITION_REQUIRED(testObject->GetThreshold() == 1.0f, "Testing initialization of threshold member variable"); + MITK_TEST_CONDITION_REQUIRED(testObject->GetSmooth() == false, "Testing initialization of smooth member variable"); + MITK_TEST_CONDITION_REQUIRED(testObject->GetDecimate() == mitk::ImageToSurfaceFilter::NoDecimation, "Testing initialization of decimate member variable"); + MITK_TEST_CONDITION_REQUIRED(testObject->GetTargetReduction() == 0.95f, "Testing initialization of target reduction member variable"); + + // test cases excluded until bug 14530 is fixed, since wrong exception is caught!! + //MITK_TEST_FOR_EXCEPTION_BEGIN(mitk::Exception) + //testObject->Update(); + //MITK_TEST_FOR_EXCEPTION_END(mitk::Exception) + + //mitk::Image::Pointer emptyImage = mitk::Image::New(); + //testObject->SetInput(emptyImage); + //MITK_TEST_FOR_EXCEPTION_BEGIN(mitk::Exception) + //testObject->Update(); + //MITK_TEST_FOR_EXCEPTION_END(mitk::Exception) + + testObject->SetInput(tImage); + MITK_TEST_CONDITION_REQUIRED(testObject->GetInput() == tImage, "Testing set / get input!"); + + testObject->Update(); + mitk::Surface::Pointer resultSurface = NULL; + resultSurface = testObject->GetOutput(); + MITK_TEST_CONDITION_REQUIRED(testObject->GetOutput() != NULL, "Testing surface generation!"); + + mitk::Surface::Pointer testSurface1 = testObject->GetOutput()->Clone(); + + testObject->SetDecimate(mitk::ImageToSurfaceFilter::DecimatePro); + testObject->SetTargetReduction(0.5f); + testObject->Update(); + mitk::Surface::Pointer testSurface2 = testObject->GetOutput()->Clone(); + + MITK_TEST_CONDITION_REQUIRED(testSurface1->GetVtkPolyData()->GetPoints()->GetNumberOfPoints() > testSurface2->GetVtkPolyData()->GetPoints()->GetNumberOfPoints() , "Testing DecimatePro mesh decimation!"); + + testObject->SetDecimate(mitk::ImageToSurfaceFilter::QuadricDecimation); + testObject->SetTargetReduction(0.5f); + testObject->Update(); + mitk::Surface::Pointer testSurface3 = testObject->GetOutput()->Clone(); + + MITK_TEST_CONDITION_REQUIRED(testSurface1->GetVtkPolyData()->GetPoints()->GetNumberOfPoints() > testSurface3->GetVtkPolyData()->GetPoints()->GetNumberOfPoints() , "Testing QuadricDecimation mesh decimation!"); + + testObject->SetSmooth(true); + testObject->SetDecimate(mitk::ImageToSurfaceFilter::NoDecimation); + testObject->Update(); + mitk::Surface::Pointer testSurface4 = testObject->GetOutput()->Clone(); + MITK_TEST_CONDITION_REQUIRED( CompareSurfacePointPositions(testSurface1, testSurface4), "Testing smoothing of surface changes point data!"); // thats it folks MITK_TEST_END(); }