GenerateModelsFromLabels
VTKExamples/Cxx/Medical/GenerateModelsFromLabels
Description
This example creates polydata models from a 3D volume that contains discrete labels. These volume are normally the output of a segmentation algorithm. The polydata for each label will be output into a separate file. If you want to see the segmentation results as cube models, see the example [cubes from labeled volume data]]. The input volume must be in [ MetaIO/Documentation| META format].
Once you generate the models, you can view them with Paraview
Code
GenerateModelsFromLabels.cxx
//
// GenerateModelsFromLabels
// Usage: GenerateModelsFromLabels InputVolume Startlabel Endlabel
// where
// InputVolume is a meta file containing a 3 volume of
// discrete labels.
// StartLabel is the first label to be processed
// EndLabel is the last label to be processed
// NOTE: There can be gaps in the labeling. If a label does
// not exist in the volume, it will be skipped.
//
//
#include <vtkMetaImageReader.h>
#include <vtkImageAccumulate.h>
#include <vtkDiscreteMarchingCubes.h>
#include <vtkWindowedSincPolyDataFilter.h>
#include <vtkMaskFields.h>
#include <vtkThreshold.h>
#include <vtkGeometryFilter.h>
#include <vtkXMLPolyDataWriter.h>
#include <vtkSmartPointer.h>
#include <vtkImageData.h>
#include <vtkPointData.h>
#include <vtkUnstructuredGrid.h>
#include <sstream>
int main (int argc, char *argv[])
{
if (argc < 4)
{
std::cout << "Usage: " << argv[0] << " InputVolume StartLabel EndLabel" << std::endl;
return EXIT_FAILURE;
}
// Create all of the classes we will need
vtkSmartPointer<vtkMetaImageReader> reader =
vtkSmartPointer<vtkMetaImageReader>::New();
vtkSmartPointer<vtkImageAccumulate> histogram =
vtkSmartPointer<vtkImageAccumulate>::New();
vtkSmartPointer<vtkDiscreteMarchingCubes> discreteCubes =
vtkSmartPointer<vtkDiscreteMarchingCubes>::New();
vtkSmartPointer<vtkWindowedSincPolyDataFilter> smoother =
vtkSmartPointer<vtkWindowedSincPolyDataFilter>::New();
vtkSmartPointer<vtkThreshold> selector =
vtkSmartPointer<vtkThreshold>::New();
vtkSmartPointer<vtkMaskFields> scalarsOff =
vtkSmartPointer<vtkMaskFields>::New();
vtkSmartPointer<vtkGeometryFilter> geometry =
vtkSmartPointer<vtkGeometryFilter>::New();
vtkSmartPointer<vtkXMLPolyDataWriter> writer =
vtkSmartPointer<vtkXMLPolyDataWriter>::New();
// Define all of the variables
unsigned int startLabel = atoi(argv[2]);
unsigned int endLabel = atoi(argv[3]);
std::string filePrefix = "Label";
unsigned int smoothingIterations = 15;
double passBand = 0.001;
double featureAngle = 120.0;
// Generate models from labels
// 1) Read the meta file
// 2) Generate a histogram of the labels
// 3) Generate models from the labeled volume
// 4) Smooth the models
// 5) Output each model into a separate file
reader->SetFileName(argv[1]);
histogram->SetInputConnection(reader->GetOutputPort());
histogram->SetComponentExtent(0, endLabel, 0, 0, 0, 0);
histogram->SetComponentOrigin(0, 0, 0);
histogram->SetComponentSpacing(1, 1, 1);
histogram->Update();
discreteCubes->SetInputConnection(reader->GetOutputPort());
discreteCubes->GenerateValues(
endLabel - startLabel + 1, startLabel, endLabel);
smoother->SetInputConnection(discreteCubes->GetOutputPort());
smoother->SetNumberOfIterations(smoothingIterations);
smoother->BoundarySmoothingOff();
smoother->FeatureEdgeSmoothingOff();
smoother->SetFeatureAngle(featureAngle);
smoother->SetPassBand(passBand);
smoother->NonManifoldSmoothingOn();
smoother->NormalizeCoordinatesOn();
smoother->Update();
selector->SetInputConnection(smoother->GetOutputPort());
selector->SetInputArrayToProcess(0, 0, 0,
vtkDataObject::FIELD_ASSOCIATION_CELLS,
vtkDataSetAttributes::SCALARS);
// Strip the scalars from the output
scalarsOff->SetInputConnection(selector->GetOutputPort());
scalarsOff->CopyAttributeOff(vtkMaskFields::POINT_DATA,
vtkDataSetAttributes::SCALARS);
scalarsOff->CopyAttributeOff(vtkMaskFields::CELL_DATA,
vtkDataSetAttributes::SCALARS);
geometry->SetInputConnection(scalarsOff->GetOutputPort());
writer->SetInputConnection(geometry->GetOutputPort());
for (unsigned int i = startLabel; i <= endLabel; i++)
{
// see if the label exists, if not skip it
double frequency =
histogram->GetOutput()->GetPointData()->GetScalars()->GetTuple1(i);
if (frequency == 0.0)
{
continue;
}
// select the cells for a given label
selector->ThresholdBetween(i, i);
// output the polydata
std::stringstream ss;
ss << filePrefix << i << ".vtp";
std::cout << argv[0] << " writing " << ss.str() << std::endl;
writer->SetFileName(ss.str().c_str());
writer->Write();
}
return EXIT_SUCCESS;
}
CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
PROJECT(GenerateModelsFromLabels)
find_package(VTK REQUIRED)
include(${VTK_USE_FILE})
add_executable(GenerateModelsFromLabels MACOSX_BUNDLE GenerateModelsFromLabels.cxx)
target_link_libraries(GenerateModelsFromLabels ${VTK_LIBRARIES})
Download and Build GenerateModelsFromLabels
Click here to download GenerateModelsFromLabels and its CMakeLists.txt file. Once the tarball GenerateModelsFromLabels.tar has been downloaded and extracted,
cd GenerateModelsFromLabels/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:
./GenerateModelsFromLabels
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.