Extract Iso Surface#

Synopsis#

Extract the iso surface as one itk::Mesh from a 3D itk::Image

Results#

Input image and resulting mesh

Input 3D image with iso-surface mesh#

Code#

C++#

#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"

#include "itkMesh.h"
#include "itkBinaryThresholdImageFilter.h"
#include "itkBinaryMask3DMeshSource.h"
#include "itkMeshFileWriter.h"

int
main(int argc, char * argv[])
{
  if (argc != 5)
  {
    std::cerr << "Usage: " << std::endl;
    std::cerr << argv[0];
    std::cerr << " <InputFileName> <OutputFileName> <Lower Threshold> <Upper Threshold>";
    std::cerr << std::endl;
    return EXIT_FAILURE;
  }

  const char * inputFileName = argv[1];
  const char * outputFileName = argv[2];

  constexpr unsigned int Dimension = 3;

  using PixelType = unsigned char;
  using ImageType = itk::Image<PixelType, Dimension>;

  const auto input = itk::ReadImage<ImageType>(inputFileName);

  auto lowerThreshold = static_cast<PixelType>(std::stoi(argv[3]));
  auto upperThreshold = static_cast<PixelType>(std::stoi(argv[4]));

  using BinaryThresholdFilterType = itk::BinaryThresholdImageFilter<ImageType, ImageType>;
  auto threshold = BinaryThresholdFilterType::New();
  threshold->SetInput(input);
  threshold->SetLowerThreshold(lowerThreshold);
  threshold->SetUpperThreshold(upperThreshold);
  threshold->SetOutsideValue(0);

  using MeshType = itk::Mesh<double, Dimension>;

  using FilterType = itk::BinaryMask3DMeshSource<ImageType, MeshType>;
  auto filter = FilterType::New();
  filter->SetInput(threshold->GetOutput());
  filter->SetObjectValue(255);

  using WriterType = itk::MeshFileWriter<MeshType>;
  auto writer = WriterType::New();
  writer->SetFileName(outputFileName);
  writer->SetInput(filter->GetOutput());
  try
  {
    writer->Update();
  }
  catch (const itk::ExceptionObject & error)
  {
    std::cerr << "Error: " << error << std::endl;
    return EXIT_FAILURE;
  }

  return EXIT_SUCCESS;
}

Classes demonstrated#

template<typename TInputImage, typename TOutputMesh>
class BinaryMask3DMeshSource : public itk::ImageToMeshFilter<TInputImage, TOutputMesh>

This class tries to construct a 3D mesh surface based on a binary mask. It can be used to integrate a region-based segmentation method and a deformable model into one hybrid framework.

To construct a mesh, we need to construct elements in a voxel and combine those elements later to form the final mesh. Before go through every voxel in the 3D volume, we first construct 2 look up tables. The index of these 2 tables are the on-off combination of the 8 nodes that form the voxel. So both of these tables has the size of $2^8$ bytes. According to previous work, all those $2^8$ combination of the nodes can be grouped into 16 final combinations. In the first table, we record the final combination that can be transformed from the current combination. The entries of the second table are made up of the transforming sequence that is necessary for the current combination transform to one of the final combinations.

We then go through the 3D volume voxel by voxel, using those two tables we have defined to construct elements within each voxel. We then merge all these mesh elements into one 3D mesh.

PARAMETERS

The ObjectValue parameter is used to identify the object. In most applications, pixels in the object region are assigned to “1”, so the default value of ObjectValue is set to “1”

REFERENCE

W. Lorensen and H. Cline, “Marching Cubes: A High Resolution 3D Surface Construction Algorithm”, Computer Graphics 21, pp. 163-169, 1987.

INPUT

The input should be a 3D binary image.

See itk::BinaryMask3DMeshSource for additional documentation.