convert polydata to image data

#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 <vtkImageProperty.h>
#include <vtkSphereSource.h>

#define vSP vtkSmartPointer
#define vSPNew(Var, Type) vSP<Type> Var = vSP<Type>::New();

vSP<vtkImageData> ConvertPolydataToImage(vtkPolyData *polydata)
{
    double spacingVal = 0.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;

    vSPNew(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
    unsigned char inval = 255;
    unsigned char outval = 0;
    vtkIdType count = imageData->GetNumberOfPoints();
    for (vtkIdType i = 0; i < count; ++i)
    {
        imageData->GetPointData()->GetScalars()->SetTuple1(i, inval);
    }

    // polygonal data --> imageData stencil:
    vSPNew(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:
    vSPNew(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 );
    vtkSmartPointer<vtkSphereSource> sphereSource =
      vtkSmartPointer<vtkSphereSource>::New();
    sphereSource->SetRadius(20);
    sphereSource->SetPhiResolution(30);
    sphereSource->SetThetaResolution(30);
    vtkSmartPointer<vtkPolyData> pd = sphereSource->GetOutput();
    sphereSource->Update();

    vSP<vtkImageData> imageData = ConvertPolydataToImage( pd );
    cout << "imageData->GetNumberOfPoints: " << imageData->GetNumberOfPoints() << endl;
    cout << "imageData->GetNumberOfCells: " << imageData->GetNumberOfCells() << endl;

    // Create an actor
    vtkSmartPointer<vtkImageActor> actor = vtkSmartPointer<vtkImageActor>::New();
    actor->GetMapper()->SetInputData( imageData );
    actor->SetScale( 1.0 );
    actor->VisibilityOn();
    actor->Update();

    // Setup renderer
    vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();
    renderer->AddActor(actor);
    renderer->ResetCamera();

    // Setup render window
    vtkSmartPointer<vtkRenderWindow> renderWindow = vtkSmartPointer<vtkRenderWindow>::New();
    renderWindow->AddRenderer(renderer);

    // Setup render window interactor
    vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
        vtkSmartPointer<vtkRenderWindowInteractor>::New();

    // Render and start interaction
    renderWindowInteractor->SetRenderWindow(renderWindow);
    renderWindowInteractor->Start();

    return EXIT_SUCCESS;
}

convert image to polydata

Use vtkImageMarchingCubes to generate isosurface from image.

    vSPNew( marchingCubes, vtkImageMarchingCubes );
    marchingCubes->SetInputData( imageData );
    marchingCubes->SetValue( 0, (inval + outval)/2 );
    marchingCubes->SetNumberOfContours( 1 );
    marchingCubes->Update();

    vSPNew( mapper, vtkPolyDataMapper );
    mapper->SetInputData( marchingCubes->GetOutput() );

There are a lot of holes on the new sphere’s surface, so we may need vtkFillHolesFilter to fill these holes. The algorithm class vtkPolyDataNormals is very powerful, it can reorder the model’s internal polygons and to ensure consistent orientation across polygon neighbors.

    vSPNew( marchingCubes, vtkImageMarchingCubes );
    marchingCubes->SetInputData( imageData );
    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->Update();
    normals->GetOutput()->GetPointData()->SetNormals(
        marchingCubes->GetOutput()->GetPointData()->GetNormals());

    vSPNew( mapper, vtkPolyDataMapper );
    mapper->SetInputData( normals->GetOutput() );

The class vtkImageDataGeometryFilter is used to extract geometry from points, we can find that the points are not distributed on the sphere’s surface evenly.

    vtkSmartPointer<vtkImageDataGeometryFilter> imageDataGeometryFilter =
      vtkSmartPointer<vtkImageDataGeometryFilter>::New();
    imageDataGeometryFilter->SetInputData( imageData );
    imageDataGeometryFilter->Update();

    vSPNew( mapper, vtkPolyDataMapper );
    mapper->SetInputData( imageDataGeometryFilter->GetOutput() );

Categories: VTK

0 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

You cannot copy content of this page