VTK/Examples/Cxx/PolyData/PolyDataContourToImageData

From KitwarePublic
< VTK‎ | Examples‎ | Cxx
Jump to navigationJump to search
  • Contributed by: Lars Friedrich

Brief Description

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: Similarily to example VTK/Examples/PolyData/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!

Circle and label.png


PolyDataContourToImageData.cxx

#include <vtkVersion.h>
#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();
#if VTK_MAJOR_VERSION <= 5
  polyDataWriter->SetInput(circle);
#else
  polyDataWriter->SetInputData(circle);
#endif
  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);
#if VTK_MAJOR_VERSION <= 5
  whiteImage->SetScalarTypeToUnsignedChar();
  whiteImage->AllocateScalars();
#else
  whiteImage->AllocateScalars(VTK_UNSIGNED_CHAR,1);
#endif
  // 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();
#if VTK_MAJOR_VERSION <= 5
  extruder->SetInput(circle);
#else
  extruder->SetInputData(circle);
#endif
  extruder->SetScaleFactor(1.);
  extruder->SetExtrusionTypeToNormalExtrusion();
  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();
#if VTK_MAJOR_VERSION <= 5
  imgstenc->SetInput(whiteImage);
  imgstenc->SetStencil(pol2stenc->GetOutput());
#else
  imgstenc->SetInputData(whiteImage);
  imgstenc->SetStencilConnection(pol2stenc->GetOutputPort());
#endif
  imgstenc->ReverseStencilOff();
  imgstenc->SetBackgroundValue(outval);
  imgstenc->Update();

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

  return EXIT_SUCCESS;
}

Please try the new VTKExamples website.

CMakeLists.txt

cmake_minimum_required(VERSION 2.8)

PROJECT(PolyDataContourToImageData)

find_package(VTK REQUIRED)
include(${VTK_USE_FILE})

add_executable(PolyDataContourToImageData MACOSX_BUNDLE PolyDataContourToImageData.cxx)

if(VTK_LIBRARIES)
  target_link_libraries(PolyDataContourToImageData ${VTK_LIBRARIES})
else()
  target_link_libraries(PolyDataContourToImageData vtkHybrid vtkWidgets)
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 PLEASE NOTE: Be sure to add the VTK bin directory to your path. This will resolve the VTK dll's at run time.

After adding visualization, replace current screenshot with div tag for baseline image.