PoissonExtractSurface
vtk-examples/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:
- Download PoissonReconstruction.remote.cmake and place it in your VTK/Remote directory.
- Reconfigure your VTK build with cmake
- Enable the remote module by setting Module_PoissonReconstruction:BOOL=ON.
make
Question
If you have a question about this example, please use the VTK Discourse Forum
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 <vtkPCANormalEstimation.h>
#include <vtkPointSource.h>
#include <vtkPoissonReconstruction.h>
#include <vtkCamera.h>
#include <vtkPointData.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.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;
}
} // namespace
CMakeLists.txt¶
cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
project(PoissonExtractSurface)
find_package(VTK COMPONENTS
)
if (NOT VTK_FOUND)
message(FATAL_ERROR "PoissonExtractSurface: Unable to find the VTK build folder.")
endif()
# Prevent a "command line is too long" failure in Windows.
set(CMAKE_NINJA_FORCE_RESPONSE_FILE "ON" CACHE BOOL "Force Ninja to use response files.")
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}
)
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.