# PolyDataContourToImageData

VTKExamples/Cxx/PolyData/PolyDataContourToImageData

### Description

- Contributed by: Lars Friedrich

This example generates a sphere, cuts it with a plane and, therefore, generates a circlular contour vtkPolyData). Subsequently a binary image representation vtkImageData) is extracted from it. Internally vtkPolyDataToImageStencil and vtkLinearExtrusionFilter are utilized. Both the circular poly data (circle.vtp) and the resultant image (labelImage.mhd) are saved to disk.

Note

Similar to example PolyDataToImageData, I am not really sure whether or not the image origin needs to be adjusted as the sphere-image-overlay shows some offset in paraview visualization (at least I think ...). Maybe someone could verify that. Thanks!

Other Languages

See (Python)

### Code

PolyDataContourToImageData.cxx

    #include <vtkSmartPointer.h>
    #include <vtkPolyData.h>
    #include <vtkImageData.h>
    #include <vtkSphereSource.h>
    #include <vtkMetaImageWriter.h>
    #include <vtkPolyDataToImageStencil.h>
    #include <vtkImageStencil.h>
    #include <vtkPointData.h>
    #include <vtkCutter.h>
    #include <vtkPlane.h>
    #include <vtkStripper.h>
    #include <vtkLinearExtrusionFilter.h>
    #include <vtkXMLPolyDataWriter.h>

    // This example generates a sphere, cuts it with a plane and, therefore,
    // generates a circlular contour (vtkPolyData). Subsequently a binary
    // image representation (vtkImageData) is extracted from it. Internally
    // vtkPolyDataToImageStencil and vtkLinearExtrusionFilter are
    // utilized. Both the circular poly data (circle.vtp) and the resultant
    // image (labelImage.mhd) are saved to disk.

    int main(int, char *[])
    {
      // 3D source sphere
      vtkSmartPointer<vtkSphereSource> sphereSource =
        vtkSmartPointer<vtkSphereSource>::New();
      sphereSource->SetPhiResolution(30);
      sphereSource->SetThetaResolution(30);
      sphereSource->SetCenter(40, 40, 0);
      sphereSource->SetRadius(20);

      // generate circle by cutting the sphere with an implicit plane
      // (through its center, axis-aligned)
      vtkSmartPointer<vtkCutter> circleCutter =
        vtkSmartPointer<vtkCutter>::New();
      circleCutter->SetInputConnection(sphereSource->GetOutputPort());
      vtkSmartPointer<vtkPlane> cutPlane =
        vtkSmartPointer<vtkPlane>::New();
      cutPlane->SetOrigin(sphereSource->GetCenter());
      cutPlane->SetNormal(0, 0, 1);
      circleCutter->SetCutFunction(cutPlane);

      vtkSmartPointer<vtkStripper> stripper =
        vtkSmartPointer<vtkStripper>::New();
      stripper->SetInputConnection(circleCutter->GetOutputPort()); // valid circle
      stripper->Update();

      // that's our circle
      vtkSmartPointer<vtkPolyData> circle = stripper->GetOutput();

      // write circle out
      vtkSmartPointer<vtkXMLPolyDataWriter> polyDataWriter =
          vtkSmartPointer<vtkXMLPolyDataWriter>::New();
      polyDataWriter->SetInputData(circle);
      polyDataWriter->SetFileName("circle.vtp");
      polyDataWriter->SetCompressorTypeToNone();
      polyDataWriter->SetDataModeToAscii();
      polyDataWriter->Write();

      // prepare the binary image's voxel grid
      vtkSmartPointer<vtkImageData> whiteImage =
          vtkSmartPointer<vtkImageData>::New();
      double bounds[6];
      circle->GetBounds(bounds);
      double spacing[3]; // desired volume spacing
      spacing[0] = 0.5;
      spacing[1] = 0.5;
      spacing[2] = 0.5;
      whiteImage->SetSpacing(spacing);

      // compute dimensions
      int dim[3];
      for (int i = 0; i < 3; i++)
      {
        dim[i] = static_cast<int>(ceil((bounds[i * 2 + 1] - bounds[i * 2]) /
            spacing[i])) + 1;
        if (dim[i] < 1)
          dim[i] = 1;
      }
      whiteImage->SetDimensions(dim);
      whiteImage->SetExtent(0, dim[0] - 1, 0, dim[1] - 1, 0, dim[2] - 1);
      double origin[3];

      // NOTE: I am not sure whether or not we had to add some offset!
      origin[0] = bounds[0];// + spacing[0] / 2;
      origin[1] = bounds[2];// + spacing[1] / 2;
      origin[2] = bounds[4];// + spacing[2] / 2;
      whiteImage->SetOrigin(origin);
      whiteImage->AllocateScalars(VTK_UNSIGNED_CHAR,1);

      // fill the image with foreground voxels:
      unsigned char inval = 255;
      unsigned char outval = 0;
      vtkIdType count = whiteImage->GetNumberOfPoints();
      for (vtkIdType i = 0; i < count; ++i)
      {
        whiteImage->GetPointData()->GetScalars()->SetTuple1(i, inval);
      }

      // sweep polygonal data (this is the important thing with contours!)
      vtkSmartPointer<vtkLinearExtrusionFilter> extruder =
          vtkSmartPointer<vtkLinearExtrusionFilter>::New();
      extruder->SetInputData(circle);
      extruder->SetScaleFactor(1.);
      extruder->SetExtrusionTypeToVectorExtrusion();
      extruder->SetVector(0, 0, 1);
      extruder->Update();

      // polygonal data --> image stencil:
      vtkSmartPointer<vtkPolyDataToImageStencil> pol2stenc =
        vtkSmartPointer<vtkPolyDataToImageStencil>::New();
      pol2stenc->SetTolerance(0); // important if extruder->SetVector(0, 0, 1) !!!
      pol2stenc->SetInputConnection(extruder->GetOutputPort());
      pol2stenc->SetOutputOrigin(origin);
      pol2stenc->SetOutputSpacing(spacing);
      pol2stenc->SetOutputWholeExtent(whiteImage->GetExtent());
      pol2stenc->Update();

      // cut the corresponding white image and set the background:
      vtkSmartPointer<vtkImageStencil> imgstenc =
        vtkSmartPointer<vtkImageStencil>::New();
      imgstenc->SetInputData(whiteImage);
      imgstenc->SetStencilConnection(pol2stenc->GetOutputPort());
      imgstenc->ReverseStencilOff();
      imgstenc->SetBackgroundValue(outval);
      imgstenc->Update();
      imgstenc->GetOutput()->Print(std::cout);

      vtkSmartPointer<vtkMetaImageWriter> imageWriter =
        vtkSmartPointer<vtkMetaImageWriter>::New();
      imageWriter->SetFileName("labelImage.mhd");
      imageWriter->SetInputConnection(imgstenc->GetOutputPort());
      imageWriter->Write();

      return EXIT_SUCCESS;
    }

### CMakeLists.txt

    cmake_minimum_required(VERSION 3.3 FATAL_ERROR)

    project(PolyDataContourToImageData)

    find_package(VTK COMPONENTS
      vtkCommonCore
      vtkCommonDataModel
      vtkFiltersCore
      vtkFiltersModeling
      vtkFiltersSources
      vtkIOImage
      vtkIOXML
      vtkImagingStencil QUIET)
    if (NOT VTK_FOUND)
      message("Skipping PolyDataContourToImageData: ${VTK_NOT_FOUND_MESSAGE}")
      return ()
    endif()
    message (STATUS "VTK_VERSION: ${VTK_VERSION}")
    if (VTK_VERSION VERSION_LESS "8.90.0")
      # old system
      include(${VTK_USE_FILE})
      add_executable(PolyDataContourToImageData MACOSX_BUNDLE PolyDataContourToImageData.cxx )
      target_link_libraries(PolyDataContourToImageData PRIVATE ${VTK_LIBRARIES})
    else ()
      # include all components
      add_executable(PolyDataContourToImageData MACOSX_BUNDLE PolyDataContourToImageData.cxx )
      target_link_libraries(PolyDataContourToImageData PRIVATE ${VTK_LIBRARIES})
      # vtk_module_autoinit is needed
      vtk_module_autoinit(
        TARGETS PolyDataContourToImageData
        MODULES ${VTK_LIBRARIES}
        )
    endif ()

### Download and Build PolyDataContourToImageData

Click here to download PolyDataContourToImageData and its CMakeLists.txt file. Once the tarball PolyDataContourToImageData.tar has been downloaded and extracted,

    cd PolyDataContourToImageData/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:

    ./PolyDataContourToImageData

WINDOWS USERS

Be sure to add the VTK bin directory to your path. This will resolve the VTK dll's at run time.