ProcrustesAlignmentFilter
VTKExamples/Cxx/PolyData/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.
Code¶
ProcrustesAlignmentFilter.cxx
#include <vtkVersion.h> #include <vtkSmartPointer.h> #include <vtkPointSet.h> #include <vtkPolyData.h> #include <vtkLandmarkTransform.h> #include <vtkCamera.h> #include <vtkSphereSource.h> #include <vtkTransform.h> #include <vtkTransformPolyDataFilter.h> #include <vtkPolyDataMapper.h> #include <vtkDataSetMapper.h> #include <vtkActor.h> #include <vtkRenderer.h> #include <vtkRenderWindow.h> #include <vtkRenderWindowInteractor.h> #include <vtkProperty.h> #include <vtkProcrustesAlignmentFilter.h> #if VTK_MAJOR_VERSION > 5 #include <vtkMultiBlockDataSet.h> #include <vtkMultiBlockDataGroupFilter.h> #endif int main(int, char *[]) { //create a sphere vtkSmartPointer<vtkSphereSource> sphereSource = vtkSmartPointer<vtkSphereSource>::New(); // make two copies of the shape and distort them a little vtkSmartPointer<vtkTransform> transform1 = vtkSmartPointer<vtkTransform>::New(); transform1->Translate(0.2, 0.1, 0.3); transform1->Scale(1.3, 1.1, 0.8); vtkSmartPointer<vtkTransform> transform2 = vtkSmartPointer<vtkTransform> ::New(); transform2->Translate(0.3, 0.7, 0.1); transform2->Scale(1.0, 0.1, 1.8); vtkSmartPointer<vtkTransformPolyDataFilter> transformer1 = vtkSmartPointer<vtkTransformPolyDataFilter>::New(); transformer1->SetInputConnection(sphereSource->GetOutputPort()); transformer1->SetTransform(transform1); vtkSmartPointer<vtkTransformPolyDataFilter> transformer2 = vtkSmartPointer<vtkTransformPolyDataFilter>::New(); transformer2->SetInputConnection(sphereSource->GetOutputPort()); transformer2->SetTransform(transform2); // map these three shapes into the first renderer vtkSmartPointer<vtkPolyDataMapper> map1a = vtkSmartPointer<vtkPolyDataMapper>::New(); map1a->SetInputConnection(sphereSource->GetOutputPort()); vtkSmartPointer<vtkActor> Actor1a = vtkSmartPointer<vtkActor> ::New(); Actor1a->SetMapper(map1a); Actor1a->GetProperty()->SetDiffuseColor(1.0000, 0.3882, 0.2784); vtkSmartPointer<vtkPolyDataMapper> map1b = vtkSmartPointer<vtkPolyDataMapper> ::New(); map1b->SetInputConnection(transformer1->GetOutputPort()); vtkSmartPointer<vtkActor> Actor1b = vtkSmartPointer<vtkActor> ::New(); Actor1b->SetMapper(map1b); Actor1b->GetProperty()->SetDiffuseColor(0.3882, 1.0000, 0.2784); vtkSmartPointer<vtkPolyDataMapper> map1c = vtkSmartPointer<vtkPolyDataMapper>::New(); map1c->SetInputConnection(transformer2->GetOutputPort()); vtkSmartPointer<vtkActor> Actor1c = vtkSmartPointer<vtkActor>::New(); Actor1c->SetMapper(map1c); Actor1c->GetProperty()->SetDiffuseColor(0.3882, 0.2784, 1.0000); // align the shapes using Procrustes (using SetModeToRigidBody) vtkSmartPointer<vtkProcrustesAlignmentFilter> procrustes1 = vtkSmartPointer<vtkProcrustesAlignmentFilter>::New(); #if VTK_MAJOR_VERSION <=5 procrustes1->SetNumberOfInputs(3); procrustes1->SetInputConnection(sphereSource->GetOutputPort()); procrustes1->AddInputConnection(transformer1->GetOutputPort()); procrustes1->AddInputConnection(transformer2->GetOutputPort()); #else vtkSmartPointer<vtkMultiBlockDataGroupFilter> group = vtkSmartPointer<vtkMultiBlockDataGroupFilter>::New(); group->AddInputConnection(sphereSource->GetOutputPort()); group->AddInputConnection(transformer1->GetOutputPort()); group->AddInputConnection(transformer2->GetOutputPort()); procrustes1->SetInputConnection(group->GetOutputPort()); #endif procrustes1->GetLandmarkTransform()->SetModeToRigidBody(); // map the aligned shapes into the second renderer vtkSmartPointer<vtkDataSetMapper> map2a = vtkSmartPointer<vtkDataSetMapper>::New(); #if VTK_MAJOR_VERSION <= 5 map2a->SetInputConnection(procrustes1->GetOutputPort(0)); #else procrustes1->Update(); map2a->SetInputData(vtkDataSet::SafeDownCast(procrustes1->GetOutput()->GetBlock(0))); #endif vtkSmartPointer<vtkActor> Actor2a = vtkSmartPointer<vtkActor>::New(); Actor2a->SetMapper(map2a); Actor2a->GetProperty()->SetDiffuseColor(1.0000, 0.3882, 0.2784); vtkSmartPointer<vtkDataSetMapper> map2b = vtkSmartPointer<vtkDataSetMapper>::New(); #if VTK_MAJOR_VERSION <= 5 map2b->SetInputConnection(procrustes1->GetOutputPort(1)); #else procrustes1->Update(); map2b->SetInputData(vtkDataSet::SafeDownCast(procrustes1->GetOutput()->GetBlock(1))); #endif vtkSmartPointer<vtkActor> Actor2b = vtkSmartPointer<vtkActor>::New(); Actor2b->SetMapper(map2b); Actor2b->GetProperty()->SetDiffuseColor(0.3882, 1.0000, 0.2784); vtkSmartPointer<vtkDataSetMapper> map2c = vtkSmartPointer<vtkDataSetMapper>::New(); #if VTK_MAJOR_VERSION <= 5 map2c->SetInputConnection(procrustes1->GetOutputPort(2)); #else procrustes1->Update(); map2c->SetInputData(vtkDataSet::SafeDownCast(procrustes1->GetOutput()->GetBlock(2))); #endif vtkSmartPointer<vtkActor> Actor2c = vtkSmartPointer<vtkActor>::New(); Actor2c->SetMapper(map2c); Actor2c->GetProperty()->SetDiffuseColor(0.3882, 0.2784, 1.0000); //align the shapes using Procrustes (using SetModeToSimilarity (default)) vtkSmartPointer<vtkProcrustesAlignmentFilter> procrustes2 = vtkSmartPointer<vtkProcrustesAlignmentFilter>::New(); #if VTK_MAJOR_VERSION <=5 procrustes2->SetNumberOfInputs(3); procrustes2->SetInputConnection(sphereSource->GetOutputPort()); procrustes2->AddInputConnection(transformer1->GetOutputPort()); procrustes2->AddInputConnection(transformer2->GetOutputPort()); #else procrustes2->SetInputConnection(group->GetOutputPort()); #endif // map the aligned shapes into the third renderer vtkSmartPointer<vtkDataSetMapper> map3a = vtkSmartPointer<vtkDataSetMapper>::New(); #if VTK_MAJOR_VERSION <= 5 map3a->SetInputConnection(procrustes2->GetOutputPort(0)); #else procrustes2->Update(); map3a->SetInputData(vtkDataSet::SafeDownCast(procrustes2->GetOutput()->GetBlock(0))); #endif vtkSmartPointer<vtkActor> Actor3a = vtkSmartPointer<vtkActor>::New(); Actor3a->SetMapper(map3a); Actor3a->GetProperty()->SetDiffuseColor(1.0000, 0.3882, 0.2784); vtkSmartPointer<vtkDataSetMapper> map3b = vtkSmartPointer<vtkDataSetMapper>::New(); #if VTK_MAJOR_VERSION <= 5 map3b->SetInputConnection(procrustes2->GetOutputPort(1)); #else procrustes2->Update(); map3b->SetInputData(vtkDataSet::SafeDownCast(procrustes2->GetOutput()->GetBlock(1))); #endif vtkSmartPointer<vtkActor> Actor3b = vtkSmartPointer<vtkActor>::New(); Actor3b->SetMapper(map3b); Actor3b->GetProperty()->SetDiffuseColor(0.3882, 1.0000, 0.2784); vtkSmartPointer<vtkDataSetMapper> map3c = vtkSmartPointer<vtkDataSetMapper>::New(); #if VTK_MAJOR_VERSION <= 5 map3c->SetInputConnection(procrustes2->GetOutputPort(2)); #else procrustes2->Update(); map3c->SetInputData(vtkDataSet::SafeDownCast(procrustes2->GetOutput()->GetBlock(2))); #endif vtkSmartPointer<vtkActor> Actor3c = vtkSmartPointer<vtkActor>::New(); Actor3c->SetMapper(map3c); Actor3c->GetProperty()->SetDiffuseColor(0.3882, 0.2784, 1.0000); // Create the RenderWindow and its three Renderers vtkSmartPointer<vtkRenderer> ren1 = vtkSmartPointer<vtkRenderer>::New(); vtkSmartPointer<vtkRenderer> ren2 = vtkSmartPointer<vtkRenderer>::New(); vtkSmartPointer<vtkRenderer> ren3 = vtkSmartPointer<vtkRenderer>::New(); vtkSmartPointer<vtkRenderWindow> renWin = vtkSmartPointer<vtkRenderWindow>::New(); renWin->AddRenderer(ren1); renWin->AddRenderer(ren2); renWin->AddRenderer(ren3); renWin->SetSize(300, 100); vtkSmartPointer<vtkRenderWindowInteractor> interactor = vtkSmartPointer<vtkRenderWindowInteractor>::New(); 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(1, 1, 1); ren1->SetViewport(0.0, 0.0, 0.33, 1.0); ren1->ResetCamera(); ren1->GetActiveCamera()->SetPosition(1, -1, 0); ren1->ResetCamera(); ren2->SetBackground(1, 1, 1); ren2->SetViewport(0.33, 0.0, 0.66, 1.0); ren2->ResetCamera(); ren2->GetActiveCamera()->SetPosition(1, -1, 0); ren2->ResetCamera(); ren3->SetBackground(1, 1, 1); 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 2.8) PROJECT(ProcrustesAlignmentFilter) find_package(VTK REQUIRED) include(${VTK_USE_FILE}) add_executable(ProcrustesAlignmentFilter MACOSX_BUNDLE ProcrustesAlignmentFilter.cxx) target_link_libraries(ProcrustesAlignmentFilter ${VTK_LIBRARIES})
Download and Build ProcrustesAlignmentFilter¶
Danger
The generation of tar files has not been ported to the new VTKExamples. Some tarballs may be missing or out-of-date.
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 PLEASE NOTE: Be sure to add the VTK bin directory to your path. This will resolve the VTK dll's at run time.