ProcrustesAlignmentFilter
Repository source: ProcrustesAlignmentFilter
Description¶
This example aligns three objects (deformed spheres) using the Procrustes algorithm. The original shapes are shown on the left. The alignment using a rigid transform is shown in the middle, and the alignment using a similarity transform is shown on the right.
Question
If you have a question about this example, please use the VTK Discourse Forum
Code¶
ProcrustesAlignmentFilter.cxx
#include <vtkActor.h>
#include <vtkCamera.h>
#include <vtkDataSetMapper.h>
#include <vtkLandmarkTransform.h>
#include <vtkMultiBlockDataGroupFilter.h>
#include <vtkMultiBlockDataSet.h>
#include <vtkNamedColors.h>
#include <vtkNew.h>
#include <vtkPointSet.h>
#include <vtkPolyData.h>
#include <vtkPolyDataMapper.h>
#include <vtkProcrustesAlignmentFilter.h>
#include <vtkProperty.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkSphereSource.h>
#include <vtkTransform.h>
#include <vtkTransformPolyDataFilter.h>
int main(int, char*[])
{
vtkNew<vtkNamedColors> colors;
// create a sphere
vtkNew<vtkSphereSource> sphereSource;
sphereSource->SetPhiResolution(31);
sphereSource->SetThetaResolution(31);
// make two copies of the shape and distort them a little
vtkNew<vtkTransform> transform1;
transform1->Translate(0.2, 0.1, 0.3);
transform1->Scale(1.3, 1.1, 0.8);
vtkNew<vtkTransform> transform2;
transform2->Translate(0.3, 0.7, 0.1);
transform2->Scale(1.0, 0.1, 1.8);
vtkNew<vtkTransformPolyDataFilter> transformer1;
transformer1->SetInputConnection(sphereSource->GetOutputPort());
transformer1->SetTransform(transform1);
vtkNew<vtkTransformPolyDataFilter> transformer2;
transformer2->SetInputConnection(sphereSource->GetOutputPort());
transformer2->SetTransform(transform2);
// map these three shapes into the first renderer
vtkNew<vtkPolyDataMapper> map1a;
map1a->SetInputConnection(sphereSource->GetOutputPort());
vtkNew<vtkActor> Actor1a;
Actor1a->SetMapper(map1a);
Actor1a->GetProperty()->SetDiffuseColor(
colors->GetColor3d("Tomato").GetData());
vtkNew<vtkPolyDataMapper> map1b;
map1b->SetInputConnection(transformer1->GetOutputPort());
vtkNew<vtkActor> Actor1b;
Actor1b->SetMapper(map1b);
Actor1b->GetProperty()->SetDiffuseColor(
colors->GetColor3d("Banana").GetData());
vtkNew<vtkPolyDataMapper> map1c;
map1c->SetInputConnection(transformer2->GetOutputPort());
vtkNew<vtkActor> Actor1c;
Actor1c->SetMapper(map1c);
Actor1c->GetProperty()->SetDiffuseColor(
colors->GetColor3d("Peacock").GetData());
// align the shapes using Procrustes (using SetModeToRigidBody)
vtkNew<vtkProcrustesAlignmentFilter> procrustes1;
vtkNew<vtkMultiBlockDataGroupFilter> group;
group->AddInputConnection(sphereSource->GetOutputPort());
group->AddInputConnection(transformer1->GetOutputPort());
group->AddInputConnection(transformer2->GetOutputPort());
procrustes1->SetInputConnection(group->GetOutputPort());
procrustes1->GetLandmarkTransform()->SetModeToRigidBody();
// map the aligned shapes into the second renderer
vtkNew<vtkDataSetMapper> map2a;
procrustes1->Update();
map2a->SetInputData(
dynamic_cast<vtkDataSet*>(procrustes1->GetOutput()->GetBlock(0)));
vtkNew<vtkActor> Actor2a;
Actor2a->SetMapper(map2a);
Actor2a->GetProperty()->SetDiffuseColor(
colors->GetColor3d("Tomato").GetData());
vtkNew<vtkDataSetMapper> map2b;
procrustes1->Update();
map2b->SetInputData(
dynamic_cast<vtkDataSet*>(procrustes1->GetOutput()->GetBlock(1)));
vtkNew<vtkActor> Actor2b;
Actor2b->SetMapper(map2b);
Actor2b->GetProperty()->SetDiffuseColor(
colors->GetColor3d("Banana").GetData());
vtkNew<vtkDataSetMapper> map2c;
procrustes1->Update();
map2c->SetInputData(
dynamic_cast<vtkDataSet*>(procrustes1->GetOutput()->GetBlock(2)));
vtkNew<vtkActor> Actor2c;
Actor2c->SetMapper(map2c);
Actor2c->GetProperty()->SetDiffuseColor(
colors->GetColor3d("Peacock").GetData());
// align the shapes using Procrustes (using SetModeToSimilarity (default))
vtkNew<vtkProcrustesAlignmentFilter> procrustes2;
procrustes2->SetInputConnection(group->GetOutputPort());
// map the aligned shapes into the third renderer
vtkNew<vtkDataSetMapper> map3a;
procrustes2->Update();
map3a->SetInputData(
dynamic_cast<vtkDataSet*>(procrustes2->GetOutput()->GetBlock(0)));
vtkNew<vtkActor> Actor3a;
Actor3a->SetMapper(map3a);
Actor3a->GetProperty()->SetDiffuseColor(
colors->GetColor3d("Tomato").GetData());
vtkNew<vtkDataSetMapper> map3b;
procrustes2->Update();
map3b->SetInputData(
dynamic_cast<vtkDataSet*>(procrustes2->GetOutput()->GetBlock(1)));
vtkNew<vtkActor> Actor3b;
Actor3b->SetMapper(map3b);
Actor3b->GetProperty()->SetDiffuseColor(
colors->GetColor3d("Banana").GetData());
vtkNew<vtkDataSetMapper> map3c;
procrustes2->Update();
map3c->SetInputData(
dynamic_cast<vtkDataSet*>(procrustes2->GetOutput()->GetBlock(2)));
vtkNew<vtkActor> Actor3c;
Actor3c->SetMapper(map3c);
Actor3c->GetProperty()->SetDiffuseColor(
colors->GetColor3d("Peacock").GetData());
// Create the RenderWindow and its three Renderers
vtkNew<vtkRenderer> ren1;
vtkNew<vtkRenderer> ren2;
vtkNew<vtkRenderer> ren3;
vtkNew<vtkRenderWindow> renWin;
renWin->AddRenderer(ren1);
renWin->AddRenderer(ren2);
renWin->AddRenderer(ren3);
renWin->SetSize(600, 300);
renWin->SetWindowName("ProcrustesAlignmentFilter");
vtkNew<vtkRenderWindowInteractor> interactor;
interactor->SetRenderWindow(renWin);
// Add the actors to the renderer
ren1->AddActor(Actor1a);
ren1->AddActor(Actor1b);
ren1->AddActor(Actor1c);
ren2->AddActor(Actor2a);
ren2->AddActor(Actor2b);
ren2->AddActor(Actor2c);
ren3->AddActor(Actor3a);
ren3->AddActor(Actor3b);
ren3->AddActor(Actor3c);
// set the properties of the renderers
ren1->SetBackground(colors->GetColor3d("Bisque").GetData());
ren1->SetViewport(0.0, 0.0, 0.33, 1.0);
ren1->GetActiveCamera()->SetPosition(1, -1, 0);
ren1->ResetCamera();
ren2->SetBackground(colors->GetColor3d("Cornsilk").GetData());
ren2->SetViewport(0.33, 0.0, 0.66, 1.0);
ren2->ResetCamera();
ren2->GetActiveCamera()->SetPosition(1, -1, 0);
ren2->ResetCamera();
ren3->SetBackground(colors->GetColor3d("Eggshell").GetData());
ren3->SetViewport(0.66, 0.0, 1.0, 1.0);
ren3->ResetCamera();
ren3->GetActiveCamera()->SetPosition(1, -1, 0);
ren3->ResetCamera();
renWin->Render();
interactor->Start();
return EXIT_SUCCESS;
}
CMakeLists.txt¶
cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
project(ProcrustesAlignmentFilter)
find_package(VTK COMPONENTS
CommonColor
CommonCore
CommonDataModel
CommonTransforms
FiltersGeneral
FiltersHybrid
FiltersSources
InteractionStyle
RenderingContextOpenGL2
RenderingCore
RenderingFreeType
RenderingGL2PSOpenGL2
RenderingOpenGL2
)
if (NOT VTK_FOUND)
message(FATAL_ERROR "ProcrustesAlignmentFilter: 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(ProcrustesAlignmentFilter MACOSX_BUNDLE ProcrustesAlignmentFilter.cxx )
target_link_libraries(ProcrustesAlignmentFilter PRIVATE ${VTK_LIBRARIES}
)
# vtk_module_autoinit is needed
vtk_module_autoinit(
TARGETS ProcrustesAlignmentFilter
MODULES ${VTK_LIBRARIES}
)
Download and Build ProcrustesAlignmentFilter¶
Click here to download ProcrustesAlignmentFilter and its CMakeLists.txt file. Once the tarball ProcrustesAlignmentFilter.tar has been downloaded and extracted,
cd ProcrustesAlignmentFilter/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:
./ProcrustesAlignmentFilter
WINDOWS USERS
Be sure to add the VTK bin directory to your path. This will resolve the VTK dll's at run time.