What does the vtkImageData look like? It has a multi-layered point set. In the following example, I show all points in a vtkImageData object in the left reader and its polydata in the right render.
#define vtkSPtr vtkSmartPointer
#define vtkSPtrNew(Var, Type) vtkSPtr<Type> Var = vtkSPtr<Type>::New();
unsigned char inval = 255;
unsigned char outval = 0;
double spacingVal = 0.5;
vtkSPtr<vtkImageData> ConvertPolydataToImage(vtkPolyData *polydata)
{
double spacingVal = 2;
double bounds[6];
polydata->GetBounds(bounds);
int dim[3];
for (int i = 0; i < 3; i++)
{
dim[i] = static_cast<int>( ceil((bounds[2 * i + 1] - bounds[2 * i]) / spacingVal) );
}
double origin[3];
origin[0] = bounds[0] + spacingVal / 2;
origin[1] = bounds[2] + spacingVal / 2;
origin[2] = bounds[4] + spacingVal / 2;
vtkSPtrNew(imageData, vtkImageData)
imageData->SetSpacing(spacingVal, spacingVal, spacingVal);
imageData->SetDimensions(dim);
imageData->SetOrigin(origin);
imageData->AllocateScalars(VTK_UNSIGNED_CHAR, 1);
imageData->SetExtent( 0, dim[0] - 1, 0, dim[1] - 1, 0, dim[2] - 1 );
// fill the imageData with foreground voxels
vtkIdType count = imageData->GetNumberOfPoints();
for (vtkIdType i = 0; i < count; ++i)
{
imageData->GetPointData()->GetScalars()->SetTuple1(i, inval);
}
// polygonal data --> imageData stencil:
vtkSPtrNew(pd2stenc, vtkPolyDataToImageStencil);
pd2stenc->SetInputData(polydata);
pd2stenc->SetOutputOrigin(origin);
pd2stenc->SetOutputSpacing(spacingVal, spacingVal, spacingVal);
pd2stenc->SetOutputWholeExtent(imageData->GetExtent());
pd2stenc->Update();
// cut the corresponding white imageData and set the background:
vtkSPtrNew(imgstenc, vtkImageStencil);
imgstenc->SetInputData(imageData);
imgstenc->SetStencilConnection(pd2stenc->GetOutputPort());
imgstenc->ReverseStencilOff();
imgstenc->SetBackgroundValue( outval );
imgstenc->Update();
imageData->DeepCopy(imgstenc->GetOutput());
return imageData;
}
int main(int, char *[])
{
setbuf( stdout, nullptr );
vtkSPtrNew( sphereSource, vtkSphereSource );
sphereSource->SetRadius(20);
sphereSource->SetPhiResolution(10);
sphereSource->SetThetaResolution(10);
sphereSource->Update();
vtkSPtr<vtkPolyData> spherePd = sphereSource->GetOutput();
vtkSPtr<vtkImageData> sphereImage = ConvertPolydataToImage( spherePd );
// ============= start to show image data ===================
vtkSPtrNew( spheres, vtkAppendPolyData );
cout << "spherePd->GetNumberOfPoints(): " << sphereImage->GetNumberOfPoints() << endl;
for( int i = 0; i < sphereImage->GetNumberOfPoints(); ++i )
{
PointStruct pt( sphereImage->GetPoint( i ) );
vtkSPtrNew( tmpSphere, vtkSphereSource );
tmpSphere->SetCenter( pt.point );
tmpSphere->SetRadius( 0.1 );
tmpSphere->Update();
spheres->AddInputData( tmpSphere->GetOutput() );
}
spheres->Update();
vtkSPtrNew( sphereMapper, vtkPolyDataMapper );
sphereMapper->SetInputData( spheres->GetOutput() );
sphereMapper->Update();
vtkSPtrNew( sphereActor, vtkActor );
sphereActor->SetMapper( sphereMapper );
sphereActor->GetProperty()->SetColor( 0, 1, 0 );
// ============= Finish: show image data ===================
// ============== convert image ===============
vtkSPtrNew( marchingCubes, vtkImageMarchingCubes );
marchingCubes->SetInputData( sphereImage );
marchingCubes->SetValue( 0, (inval + outval)/2 );
marchingCubes->SetNumberOfContours( 1 );
marchingCubes->Update();
// Fill the holes
auto fillHoles = vtkSmartPointer<vtkFillHolesFilter>::New();
fillHoles->SetInputConnection( marchingCubes->GetOutputPort() );
fillHoles->SetHoleSize(1000.0);
// Make the triangle winding order consistent
auto normals = vtkSmartPointer<vtkPolyDataNormals>::New();
normals->SetInputConnection(fillHoles->GetOutputPort());
normals->ConsistencyOn();
normals->SplittingOff();
normals->GetOutput()->GetPointData()->SetNormals(
marchingCubes->GetOutput()->GetPointData()->GetNormals());
normals->Update();
// ==============finished: convert image ===============
vtkSPtrNew( imageMapper, vtkPolyDataMapper );
imageMapper->SetInputData( normals->GetOutput() );
imageMapper->Update();
vtkSPtrNew( imageActor, vtkActor );
imageActor->SetMapper( imageMapper );
double leftViewport[4] = {0.0, 0.0, 0.5, 1.0};
double rightViewport[4] = {0.5, 0.0, 1.0, 1.0};
// Setup renderers
vtkSPtrNew( leftRenderer, vtkRenderer );
leftRenderer->SetViewport( leftViewport );
leftRenderer->AddActor( sphereActor );
leftRenderer->SetBackground(.6, .5, .4);
leftRenderer->ResetCamera();
vtkSPtrNew( rightRenderer, vtkRenderer );
rightRenderer->SetViewport(rightViewport);
rightRenderer->AddActor( imageActor );
rightRenderer->SetBackground(.4, .5, .6);
rightRenderer->ResetCamera();
// Setup render window
vtkSPtrNew( renderWindow, vtkRenderWindow );
renderWindow->AddRenderer( leftRenderer );
renderWindow->AddRenderer( rightRenderer );
renderWindow->SetSize( 900, 300 );
// Setup render window interactor
vtkSPtrNew( renderWindowInteractor, vtkRenderWindowInteractor );
// Render and start interaction
renderWindowInteractor->SetRenderWindow(renderWindow);
renderWindowInteractor->Start();
return EXIT_SUCCESS;
}
Header files in the project:
#include <vtkVersion.h>
#include <vtkImageData.h>
#include <vtkImageMapper3D.h>
#include <vtkImageStencil.h>
#include <vtkImageStencilData.h>
#include <vtkImageToImageStencil.h>
#include <vtkJPEGReader.h>
#include <vtkPointData.h>
#include <vtkSmartPointer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkInteractorStyleImage.h>
#include <vtkRenderer.h>
#include <vtkImageActor.h>
#include <vtkPolyDataToImageStencil.h>
#include <vtkPolyData.h>
#include <vtkSTLReader.h>
#include <vtkProperty.h>
#include <vtkImageProperty.h>
#include <vtkSphereSource.h>
#include <vtkPolyDataMapper.h>
#include <vtkImageDataGeometryFilter.h>
#include <vtkImageMarchingCubes.h>
#include <vtkPolyDataNormals.h>
#include <vtkFillHolesFilter.h>
#include <vtkCleanPolyData.h>
#include <vtkTriangleFilter.h>
#include <vtkAppendPolyData.h>
#include <vtkImageMarchingCubes.h>
#include <vtkImageWeightedSum.h>
#include <vtkConeSource.h>
#include <vtkPolyDataConnectivityFilter.h>
#include "../share/tool.h"