# PoissonExtractSurface

VTKExamples/Cxx/Points/PoissonExtractSurface

### Description

This example uses the PoissonReconstruction remote module to reconstruct surfaces from unorganized points. This code was, with permission, adapted directly from the original implementation by Kazhdan, Bolitho, and Hugues. The original implementation can be found here.

PoissonReconstruction requires that the vtkPolyData input have vtkNormals. If normals are not included in the vtkPointData, the example uses vtkPCANormalEstimation to create normals.

If the example is run without an argument, the example uses random points on a spherical shell. With a filename, the example uses the points on the vtkPolyData.

Cite

The VTK Journal paper Poisson Surface Reconstruction for VTK describes the VTK implementaion.

Info

CompareExtractSurface compares three surface extraction algorithms.

Seealso

ExtractSurface reconstructs surfaces and is included with the VTK distribution. PowercrustExtractSurface reconstructs surfaces and is implemented as a VTK remote module.

Info

PoissonReconstruction is implemented as a VTK Remote Module.

To use PoissonReconstruction in VTK:

1. Download PoissonReconstruction.remote.cmake and place it in your VTK/Remote directory.
2. Reconfigure your VTK build with cmake
3. Enable the remote module by setting Module_PoissonReconstruction:BOOL=ON.
4. `make`

### Code

PoissonExtractSurface.cxx

    #include <vtkSmartPointer.h>

    #include <vtkBYUReader.h>
    #include <vtkOBJReader.h>
    #include <vtkPLYReader.h>
    #include <vtkPolyDataReader.h>
    #include <vtkSTLReader.h>
    #include <vtkXMLPolyDataReader.h>

    #include <vtkPointSource.h>
    #include <vtkPoissonReconstruction.h>
    #include <vtkPCANormalEstimation.h>

    #include <vtkPointData.h>
    #include <vtkPolyDataMapper.h>
    #include <vtkProperty.h>
    #include <vtkRenderWindow.h>
    #include <vtkRenderWindowInteractor.h>
    #include <vtkRenderer.h>
    #include <vtkCamera.h>

    #include <vtkNamedColors.h>
    #include <vtksys/SystemTools.hxx>

    namespace
    {
    vtkSmartPointer<vtkPolyData> ReadPolyData(const char *fileName);
    }

    int main (int argc, char *argv[])
    {
      vtkSmartPointer<vtkPolyData> polyData = ReadPolyData(argc > 1 ? argv[1] : "");;
      std::cout << "# of points: " << polyData->GetNumberOfPoints() << std::endl;

      vtkSmartPointer<vtkPoissonReconstruction> surface =
        vtkSmartPointer<vtkPoissonReconstruction>::New();
      surface->SetDepth(12);

      int sampleSize = polyData->GetNumberOfPoints() * .00005;
      if (sampleSize < 10)
      {
        sampleSize = 10;
      }
      if (polyData->GetPointData()->GetNormals())
      {
        std::cout << "Using normals from input file" << std::endl;
        surface->SetInputData (polyData);
      }
      else
      {
        std::cout << "Estimating normals using PCANormalEstimation" << std::endl;
        vtkSmartPointer<vtkPCANormalEstimation> normals =
          vtkSmartPointer<vtkPCANormalEstimation>::New();
        normals->SetInputData (polyData);
        normals->SetSampleSize(sampleSize);
        normals->SetNormalOrientationToGraphTraversal();
        normals->FlipNormalsOff();
        surface->SetInputConnection(normals->GetOutputPort());
      }

      vtkSmartPointer<vtkPolyDataMapper> surfaceMapper =
        vtkSmartPointer<vtkPolyDataMapper>::New();
      surfaceMapper->SetInputConnection(surface->GetOutputPort());

      vtkSmartPointer<vtkNamedColors> colors =
        vtkSmartPointer<vtkNamedColors>::New();

      vtkSmartPointer<vtkProperty> back =
        vtkSmartPointer<vtkProperty>::New();
      back->SetColor(colors->GetColor3d("banana").GetData());

      vtkSmartPointer<vtkActor> surfaceActor =
        vtkSmartPointer<vtkActor>::New();
      surfaceActor->SetMapper(surfaceMapper);
      surfaceActor->GetProperty()->SetColor(colors->GetColor3d("Tomato").GetData());
      surfaceActor->SetBackfaceProperty(back);

      // Create graphics stuff
      //
      vtkSmartPointer<vtkRenderer> ren1 =
        vtkSmartPointer<vtkRenderer>::New();
      ren1->SetBackground(colors->GetColor3d("SlateGray").GetData());

      vtkSmartPointer<vtkRenderWindow> renWin =
        vtkSmartPointer<vtkRenderWindow>::New();
      renWin->AddRenderer(ren1);
      renWin->SetSize(512,512);

      vtkSmartPointer<vtkRenderWindowInteractor> iren =
        vtkSmartPointer<vtkRenderWindowInteractor>::New();
      iren->SetRenderWindow(renWin);

      // Add the actors to the renderer, set the background and size
      //
      ren1->AddActor(surfaceActor);

      // Generate an interesting view
      //
      ren1->ResetCamera();
      ren1->GetActiveCamera()->Azimuth(120);
      ren1->GetActiveCamera()->Elevation(30);
      ren1->GetActiveCamera()->Dolly(1.0);
      ren1->ResetCameraClippingRange();

      renWin->Render();
      iren->Initialize();
      iren->Start();

      return EXIT_SUCCESS;
    }

    namespace
    {
    vtkSmartPointer<vtkPolyData> ReadPolyData(const char *fileName)
    {
      vtkSmartPointer<vtkPolyData> polyData;
      std::string extension = vtksys::SystemTools::GetFilenameExtension(std::string(fileName));
      if (extension == ".ply")
      {
        vtkSmartPointer<vtkPLYReader> reader =
          vtkSmartPointer<vtkPLYReader>::New();
        reader->SetFileName (fileName);
        reader->Update();
        polyData = reader->GetOutput();
      }
      else if (extension == ".vtp")
      {
        vtkSmartPointer<vtkXMLPolyDataReader> reader =
          vtkSmartPointer<vtkXMLPolyDataReader>::New();
        reader->SetFileName (fileName);
        reader->Update();
        polyData = reader->GetOutput();
      }
      else if (extension == ".vtk")
      {
        vtkSmartPointer<vtkPolyDataReader> reader =
          vtkSmartPointer<vtkPolyDataReader>::New();
        reader->SetFileName (fileName);
        reader->Update();
        polyData = reader->GetOutput();
      }
      else if (extension == ".obj")
      {
        vtkSmartPointer<vtkOBJReader> reader =
          vtkSmartPointer<vtkOBJReader>::New();
        reader->SetFileName (fileName);
        reader->Update();
        polyData = reader->GetOutput();
      }
      else if (extension == ".stl")
      {
        vtkSmartPointer<vtkSTLReader> reader =
          vtkSmartPointer<vtkSTLReader>::New();
        reader->SetFileName (fileName);
        reader->Update();
        polyData = reader->GetOutput();
      }
      else if (extension == ".g")
      {
        vtkSmartPointer<vtkBYUReader> reader =
          vtkSmartPointer<vtkBYUReader>::New();
        reader->SetGeometryFileName (fileName);
        reader->Update();
        polyData = reader->GetOutput();
      }
      else
      {
        vtkSmartPointer<vtkPointSource> points =
          vtkSmartPointer<vtkPointSource>::New();
        points->SetNumberOfPoints(1000);
        points->SetRadius(1.0);
        points->SetCenter(vtkMath::Random(-1, 1),
                          vtkMath::Random(-1, 1),
                          vtkMath::Random(-1, 1));
        points->SetDistributionToShell();
        points->Update();
        polyData = points->GetOutput();
      }
      return polyData;
    }
    }

### CMakeLists.txt

    cmake_minimum_required(VERSION 3.3 FATAL_ERROR)

    project(PoissonExtractSurface)

    find_package(VTK COMPONENTS
      vtkCommonColor
      vtkCommonCore
      vtkCommonDataModel
      vtkFiltersPoints
      vtkFiltersSources
      vtkIOGeometry
      vtkIOLegacy
      vtkIOPLY
      vtkIOXML
      vtkInteractionStyle
      vtkPoissonReconstruction
      vtkRenderingContextOpenGL2
      vtkRenderingCore
      vtkRenderingFreeType
      vtkRenderingGL2PSOpenGL2
      vtkRenderingOpenGL2 QUIET)
    if (NOT VTK_FOUND)
      message("Skipping PoissonExtractSurface: ${VTK_NOT_FOUND_MESSAGE}")
      return ()
    endif()
    message (STATUS "VTK_VERSION: ${VTK_VERSION}")
    if (VTK_VERSION VERSION_LESS "8.90.0")
      # old system
      include(${VTK_USE_FILE})
      add_executable(PoissonExtractSurface MACOSX_BUNDLE PoissonExtractSurface.cxx )
      target_link_libraries(PoissonExtractSurface PRIVATE ${VTK_LIBRARIES})
    else ()
      # include all components
      add_executable(PoissonExtractSurface MACOSX_BUNDLE PoissonExtractSurface.cxx )
      target_link_libraries(PoissonExtractSurface PRIVATE ${VTK_LIBRARIES})
      # vtk_module_autoinit is needed
      vtk_module_autoinit(
        TARGETS PoissonExtractSurface
        MODULES ${VTK_LIBRARIES}
        )
    endif ()

### Download and Build PoissonExtractSurface

Click here to download PoissonExtractSurface and its CMakeLists.txt file. Once the tarball PoissonExtractSurface.tar has been downloaded and extracted,

    cd PoissonExtractSurface/build

If VTK is installed:

    cmake ..

If VTK is not installed but compiled on your system, you will need to specify the path to your VTK build:

    cmake -DVTK_DIR:PATH=/home/me/vtk_build ..

Build the project:

    make

and run it:

    ./PoissonExtractSurface

WINDOWS USERS

Be sure to add the VTK bin directory to your path. This will resolve the VTK dll's at run time.