ExternalContour
Repository source: ExternalContour
Description¶
Compute the external contour of a polydata.
At first, it creates a black and white image of a scene containing the polydata and then extracts the contour of the black shape from the image.
Note
A longstanding bug is fixed, see the discussion here.
Other languages
See (PythonicAPI)
Question
If you have a question about this example, please use the VTK Discourse Forum
Code¶
ExternalContour.cxx
#include <vtkActor.h>
#include <vtkCamera.h>
#include <vtkCleanPolyData.h>
#include <vtkContourFilter.h>
#include <vtkInteractorStyleTrackballCamera.h>
#include <vtkNamedColors.h>
#include <vtkNew.h>
#include <vtkPNGWriter.h>
#include <vtkPolyData.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkSmartPointer.h>
#include <vtkSphereSource.h>
#include <vtkTransform.h>
#include <vtkTransformPolyDataFilter.h>
#include <vtkVersion.h>
#include <vtkWindowToImageFilter.h>
#include <vtkXMLPolyDataReader.h>
int main(int argc, char* argv[])
{
vtkNew<vtkNamedColors> colors;
vtkSmartPointer<vtkPolyData> data3d;
if (argc > 1)
{
// E.g. Bunny.vtp
vtkNew<vtkXMLPolyDataReader> reader;
reader->SetFileName(argv[1]);
reader->Update();
data3d = reader->GetOutput();
}
else
{
vtkNew<vtkSphereSource> source;
source->SetCenter(0.0, 0.0, 5.0);
source->SetRadius(2.0);
source->SetPhiResolution(20.);
source->SetThetaResolution(20.);
source->Update();
data3d = source->GetOutput();
}
double bounds_data[6], center_data[3];
data3d->GetBounds(bounds_data);
data3d->GetCenter(center_data);
// Black and white scene with the data in order to print the view.
vtkNew<vtkPolyDataMapper> mapperData;
mapperData->SetInputData(data3d);
vtkNew<vtkActor> actorData;
actorData->SetMapper(mapperData);
actorData->GetProperty()->SetColor(colors->GetColor3d("Black").GetData());
vtkNew<vtkRenderer> tmpRend;
tmpRend->SetBackground(colors->GetColor3d("White").GetData());
tmpRend->AddActor(actorData);
tmpRend->ResetCamera();
tmpRend->GetActiveCamera()->SetParallelProjection(1);
vtkNew<vtkRenderWindow> tmpRW;
tmpRW->SetOffScreenRendering(1);
tmpRW->AddRenderer(tmpRend);
tmpRW->Render();
// Get a print of the window.
vtkNew<vtkWindowToImageFilter> windowToImageFilter;
windowToImageFilter->SetInput(tmpRW);
#if VTK_MAJOR_VERSION >= 8 || VTK_MAJOR_VERSION == 8 && VTK_MINOR_VERSION >= 90
windowToImageFilter->SetScale(2); // image quality
#else
windowToImageFilter->SetMagnification(2); // image quality
#endif
windowToImageFilter->Update();
/*
vtkNew<vtkPNGWriter> writer;
writer->SetFileName("ExternalContourWindowPrint.png");
writer->SetInputConnection(windowToImageFilter->GetOutputPort());
writer->Write();
*/
// Extract the silhouette corresponding to the black limit of the image.
vtkNew<vtkContourFilter> contFilter;
contFilter->SetInputConnection(windowToImageFilter->GetOutputPort());
contFilter->SetValue(0, 255);
contFilter->Update();
// Clean the data.
vtkNew<vtkCleanPolyData> clean;
clean->SetInputData(contFilter->GetOutput());
clean->Update();
auto contour = clean->GetOutput();
// Make the contour coincide with the data.
double bounds_contour[6], center_contour[3];
double transX = 0.0, transY = 0.0, transZ = 0.0, ratioX = 0.0, ratioY = 0.0;
contour->GetBounds(bounds_contour);
ratioX = (bounds_data[1] - bounds_data[0]) /
(bounds_contour[1] - bounds_contour[0]);
ratioY = (bounds_data[3] - bounds_data[2]) /
(bounds_contour[3] - bounds_contour[2]);
// Rescale the contour so that it shares the same bounds as the
// input data.
vtkNew<vtkTransform> transform1;
transform1->Scale(ratioX, ratioY, 1.0);
vtkNew<vtkTransformPolyDataFilter> tfilter1;
tfilter1->SetInputData(contour);
tfilter1->SetTransform(transform1);
tfilter1->Update();
contour = tfilter1->GetOutput();
// Translate the contour so that it shares the same center as the
// input data.
contour->GetCenter(center_contour);
transX = center_data[0] - center_contour[0];
transY = center_data[1] - center_contour[1];
transZ = center_data[2] - center_contour[2];
vtkNew<vtkTransform> transform2;
transform2->Translate(transX, transY, transZ);
vtkNew<vtkTransformPolyDataFilter> tfilter2;
tfilter2->SetInputData(contour);
tfilter2->SetTransform(transform2);
tfilter2->Update();
contour = tfilter2->GetOutput();
// Render the result : Input data + resulting silhouette
// Updating the color of the data.
actorData->GetProperty()->SetColor(colors->GetColor3d("MistyRose").GetData());
// Create a mapper and actor of the silhouette.
vtkNew<vtkPolyDataMapper> mapperContour;
mapperContour->SetInputData(contour);
vtkNew<vtkActor> actor_contour;
actor_contour->SetMapper(mapperContour);
actor_contour->GetProperty()->SetLineWidth(2.0);
// Create the renderers, render window, and interactor.
vtkNew<vtkRenderer> renderer1;
renderer1->SetViewport(0.0, 0.0, 0.5, 1.0);
renderer1->SetBackground(colors->GetColor3d("DarkSlateGray").GetData());
vtkNew<vtkRenderer> renderer2;
renderer2->SetViewport(0.5, 0.0, 1.0, 1.0);
renderer2->SetBackground(colors->GetColor3d("MidnightBlue").GetData());
vtkNew<vtkRenderWindow> renderWindow;
renderWindow->SetSize(400, 400);
renderWindow->SetWindowName("ExternalContour");
renderWindow->AddRenderer(renderer1);
renderWindow->AddRenderer(renderer2);
vtkNew<vtkInteractorStyleTrackballCamera> style;
vtkNew<vtkRenderWindowInteractor> renderWindowInteractor;
renderWindowInteractor->SetRenderWindow(renderWindow);
renderWindowInteractor->SetInteractorStyle(style);
// Add the actors.
renderer1->AddActor(actorData);
// renderer1->AddActor(actor_contour);
renderer2->AddActor(actor_contour);
// Set the same initial view as in renderer1.
renderWindow->Render();
vtkNew<vtkCamera> ren2Camera;
ren2Camera->DeepCopy(renderer1->GetActiveCamera());
renderer2->SetActiveCamera(ren2Camera);
// If you want the views linked.
// renderer2->SetActiveCamera(renderer1->GetActiveCamera());
renderWindow->Render();
renderWindowInteractor->Start();
return EXIT_SUCCESS;
}
CMakeLists.txt¶
cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
project(ExternalContour)
find_package(VTK COMPONENTS
CommonColor
CommonCore
CommonDataModel
CommonTransforms
FiltersCore
FiltersGeneral
FiltersSources
IOXML
InteractionStyle
RenderingContextOpenGL2
RenderingCore
RenderingFreeType
RenderingGL2PSOpenGL2
RenderingOpenGL2
)
if (NOT VTK_FOUND)
message(FATAL_ERROR "ExternalContour: 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(ExternalContour MACOSX_BUNDLE ExternalContour.cxx )
target_link_libraries(ExternalContour PRIVATE ${VTK_LIBRARIES}
)
# vtk_module_autoinit is needed
vtk_module_autoinit(
TARGETS ExternalContour
MODULES ${VTK_LIBRARIES}
)
Download and Build ExternalContour¶
Click here to download ExternalContour and its CMakeLists.txt file. Once the tarball ExternalContour.tar has been downloaded and extracted,
cd ExternalContour/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:
./ExternalContour
WINDOWS USERS
Be sure to add the VTK bin directory to your path. This will resolve the VTK dll's at run time.