MedicalDemo4
Repository source: MedicalDemo4
Description¶
Volume rendering of the dataset.
Usage
MedicalDemo4 FullHead.mhd
Note
The original source code for this example is here.
Info
The example uses src/Testing/Data/FullHead.mhd which references src/Testing/Data/FullHead.raw.gz.
Other languages
See (Python), (PythonicAPI), (Java)
Question
If you have a question about this example, please use the VTK Discourse Forum
Code¶
MedicalDemo4.cxx
// Derived from VTK/Examples/Cxx/Medical4.cxx
// This example reads a volume dataset and displays it via volume rendering.
//
#include <vtkCamera.h>
#include <vtkCameraOrientationRepresentation.h>
#include <vtkCameraOrientationWidget.h>
#include <vtkColorTransferFunction.h>
#include <vtkFixedPointVolumeRayCastMapper.h>
#include <vtkImageChangeInformation.h>
#include <vtkImageData.h>
#include <vtkInteractorStyleSwitch.h>
#include <vtkMapper.h>
#include <vtkMetaImageReader.h>
#include <vtkNamedColors.h>
#include <vtkNew.h>
#include <vtkOutlineFilter.h>
#include <vtkPiecewiseFunction.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkStringFormatter.h>
#include <vtkTransform.h>
#include <vtkTransformFilter.h>
#include <vtkVolume.h>
#include <vtkVolumeProperty.h>
#include <vtk_cli11.h>
#include <vtk_fmt.h>
// clang-format off
#include VTK_FMT(fmt/format.h)
// clang-format on
#include <array>
#include <filesystem>
namespace fs = std::filesystem;
namespace {
class Permute
{
// clang-format off
/*
* These transformations permute image and other geometric data to maintain
* proper orientation regardless of the acquisition order. After applying
* these transforms with vtkTransformFilter, a view up of 0, -1, 0 will
* result in the body part facing the viewer.
*
* NOTE: Some transformations have a -1 scale factor for one of the components.
* To ensure proper polygon orientation and normal direction,
* you must apply the vtkPolyDataNormals filter.
*
* Naming (the nomenclature is medical):
* si - superior to inferior (top to bottom)
* is - inferior to superior (bottom to top)
* ap - anterior to posterior (front to back)
* pa - posterior to anterior (back to front)
* lr - left to right
* rl - right to left
*
*/
// clang-format on
public:
/**
* Generate the transforms corresponding to the slice order.
*/
Permute()
{
GenerateTransforms();
}
virtual ~Permute() = default;
public:
/**
* Returns the vtkTransform corresponding to the permutation.
*
* @param permutation: The permutation.
* @return The vtkTransform corresponding to the permutation.
*/
vtkSmartPointer<vtkTransform> GetTransform(std::string const& permutation);
/**
* Print the homogenous matrix corresponding to the permutation.
*
* @param order: The permutation.
*/
void PrintTransform(std::string const& permutation);
/**
* Print all the homogenous matrices corresponding to the permutations.
*
*/
void PrintAlltransforms();
private:
/**
* @brief Generate the transforms and collect them into a map.
*
*/
void GenerateTransforms();
private:
std::map<std::string, vtkSmartPointer<vtkTransform>> transform;
// Used to generate the the homogenous matrices corresponding to the
// permutations.
std::array<double, 16> si_arr{1, 0, 0, 0, 0, 0, 1, 0,
0, -1, 0, 0, 0, 0, 0, 1};
std::array<double, 16> is_arr{1, 0, 0, 0, 0, 0, -1, 0,
0, -1, 0, 0, 0, 0, 0, 1};
std::array<double, 16> lr_arr{0, 0, -1, 0, 0, -1, 0, 0,
1, 0, 0, 0, 0, 0, 0, 1};
std::array<double, 16> rl_arr{0, 0, 1, 0, 0, -1, 0, 0,
1, 0, 0, 0, 0, 0, 0, 1};
std::array<double, 16> hf_arr{-1, 0, 0, 0, 0, 1, 0, 0,
0, 0, -1, 0, 0, 0, 0, 1};
// Used to print out the homogenous matrices in the order
// entered into the transform map.
std::vector<std::string> sort_order{};
};
class COWPlacement
{
public:
COWPlacement()
{
MakeLabelColor();
}
virtual ~COWPlacement() = default;
public:
/**
* @brief Make a camera orientation widget for a given renderer.
* * position has these values
* 0: LowerLeft,
* 1: UpperLeft,
* 2: LowerRight,
* 3: UpperRight - the default
*
* @param ren The renderer.
* @param lcKey The key specifying the desired labels and colors for the axes.
* @param position Where to position the camera orientation widget.
* @return The camera orientation widget.
*/
vtkNew<vtkCameraOrientationWidget>
MakeCOW(vtkRenderer* ren, std::string lcKey = "XYZ", int const& position = 3);
private:
typedef std::map<std::string, std::string> TAP;
typedef std::map<std::string, TAP> TAPS;
std::map<std::string, std::pair<TAP, TAP>> labelColor;
/**
* @brief Gather the defined axes labels and colors into a map.
* */
void MakeLabelColor();
};
} // namespace
int main(int argc, char* argv[])
{
CLI::App app{"Read a volume dataset and display it via volume rendering."};
// Define options
std::string fileName;
app.add_option("fileName", fileName,
"The path to the data file e.g. FullHead.mhd.")
->required()
->check(CLI::ExistingFile);
CLI11_PARSE(app, argc, argv);
vtkNew<vtkNamedColors> colors;
std::array<unsigned char, 4> bkg{{51, 77, 102, 255}};
colors->SetColor("BkgColor", bkg.data());
// Create the renderer, the render window, and the interactor. The renderer
// draws into the render window, the interactor enables mouse- and
// keyboard-based interaction with the scene.
vtkNew<vtkRenderer> ren;
ren->SetBackground(colors->GetColor3d("BkgColor").GetData());
vtkNew<vtkRenderWindow> renWin;
renWin->SetSize(640, 480);
auto appFn = fs::path((app.get_name())).stem().string();
renWin->SetWindowName(appFn.c_str());
renWin->AddRenderer(ren);
vtkNew<vtkRenderWindowInteractor> iren;
iren->SetRenderWindow(renWin);
auto is = vtkInteractorStyleSwitch::SafeDownCast(iren->GetInteractorStyle());
if (is)
{
is->SetCurrentStyleToTrackballCamera();
}
// The following reader is used to read a series of 2D slices (images)
// that compose the volume. The slice dimensions are set, and the
// pixel spacing. The data Endianness must also be specified. The reader
// uses the FilePrefix in combination with the slice number to construct
// filenames using the format FilePrefix.%d. (In this case the FilePrefix
// is the root name of the file: quarter.)
vtkNew<vtkMetaImageReader> reader;
reader->SetFileName(fileName.c_str());
reader->SetDataByteOrderToLittleEndian();
reader->Update();
// Get the image metadata.
auto extent = reader->GetDataExtent();
auto spacing = reader->GetDataSpacing();
auto origin = reader->GetDataOrigin();
// Calculate the dimensions in voxels.
std::array<double, 3> dimsV{0, 0, 0};
for (auto i = 0; i < 6; i += 2)
{
dimsV[i / 2] = extent[i + 1] - extent[i] + 1;
}
// Calculate the physical center of the volume.
std::array<double, 3> center{0, 0, 0};
for (auto i = 0; i < 3; ++i)
{
center[i] = origin[i] + 0.5 * spacing[i] * dimsV[i];
}
// Apply the shift using vtkImageChangeInformation.
vtkNew<vtkImageChangeInformation> changeInformation;
changeInformation->SetInputConnection(reader->GetOutputPort());
// Center the image by shifting it by the negative center coordinates.
changeInformation->SetOriginTranslation(-center[0], -center[1], -center[2]);
// An outline provides context around the data.
vtkNew<vtkOutlineFilter> outlineFilter;
outlineFilter->SetInputConnection(changeInformation->GetOutputPort());
// We need to transform the outline so that it outlines the head.
auto transform = vtkSmartPointer<vtkTransform>::New();
// Move the outline from the origin to the new center inside the head.
transform->Translate(-center[0] * 2.0, -center[1] / 32.0, -center[2] * 2.0);
// Apply the transform to the geometry
auto transformFilter = vtkSmartPointer<vtkTransformFilter>::New();
transformFilter->SetInputConnection(outlineFilter->GetOutputPort());
transformFilter->SetTransform(transform);
transformFilter->Update();
vtkNew<vtkPolyDataMapper> outlineMapper;
outlineMapper->SetInputConnection(transformFilter->GetOutputPort());
vtkNew<vtkProperty> outlineProperty;
outlineProperty->SetDiffuseColor(colors->GetColor3d("Black").GetData());
vtkNew<vtkActor> outline;
outline->SetMapper(outlineMapper);
outline->SetProperty(outlineProperty);
// The volume will be displayed by ray-cast alpha compositing.
// A ray-cast mapper is needed to do the ray-casting.
vtkNew<vtkFixedPointVolumeRayCastMapper> volumeMapper;
volumeMapper->SetInputConnection(changeInformation->GetOutputPort());
// The color transfer function maps voxel intensities to colors.
// It is modality-specific, and often anatomy-specific as well.
// The goal is to one color for flesh (between 500 and 1000)
// and another color for bone (1150 and over).
vtkNew<vtkColorTransferFunction> volumeColor;
volumeColor->AddRGBPoint(0, 0.0, 0.0, 0.0);
volumeColor->AddRGBPoint(500, 240.0 / 255.0, 184.0 / 255.0, 160.0 / 255.0);
volumeColor->AddRGBPoint(1000, 240.0 / 255.0, 184.0 / 255.0, 160.0 / 255.0);
volumeColor->AddRGBPoint(1150, 1.0, 1.0, 240.0 / 255.0); // Ivory
// The opacity transfer function is used to control the opacity
// of different tissue types.
vtkNew<vtkPiecewiseFunction> volumeScalarOpacity;
volumeScalarOpacity->AddPoint(0, 0.00);
volumeScalarOpacity->AddPoint(500, 0.15);
volumeScalarOpacity->AddPoint(1000, 0.15);
volumeScalarOpacity->AddPoint(1150, 0.85);
// The gradient opacity function is used to decrease the opacity
// in the "flat" regions of the volume while maintaining the opacity
// at the boundaries between tissue types. The gradient is measured
// as the amount by which the intensity changes over unit distance.
// For most medical data, the unit distance is 1mm.
vtkNew<vtkPiecewiseFunction> volumeGradientOpacity;
volumeGradientOpacity->AddPoint(0, 0.0);
volumeGradientOpacity->AddPoint(90, 0.5);
volumeGradientOpacity->AddPoint(100, 1.0);
// The VolumeProperty attaches the color and opacity functions to the
// volume, and sets other volume properties. The interpolation should
// be set to linear to do a high-quality rendering. The ShadeOn option
// turns on directional lighting, which will usually enhance the
// appearance of the volume and make it look more "3D". However,
// the quality of the shading depends on how accurately the gradient
// of the volume can be calculated, and for noisy data the gradient
// estimation will be very poor. The impact of the shading can be
// decreased by increasing the Ambient coefficient while decreasing
// the Diffuse and Specular coefficient. To increase the impact
// of shading, decrease the Ambient and increase the Diffuse and Specular.
vtkNew<vtkVolumeProperty> volumeProperty;
volumeProperty->SetColor(volumeColor);
volumeProperty->SetScalarOpacity(volumeScalarOpacity);
volumeProperty->SetGradientOpacity(volumeGradientOpacity);
volumeProperty->SetInterpolationTypeToLinear();
volumeProperty->ShadeOn();
volumeProperty->SetAmbient(0.4);
volumeProperty->SetDiffuse(0.6);
volumeProperty->SetSpecular(0.2);
// The vtkVolume is a vtkProp3D (like a vtkActor) and controls the position
// and orientation of the volume in world coordinates.
vtkNew<vtkVolume> volume;
volume->SetMapper(volumeMapper);
volume->SetProperty(volumeProperty);
// This transform positions the actors correctly.
// The face of the head will now face to the left.
auto permute = Permute();
auto rsp = permute.GetTransform("hfis");
outline->SetUserTransform(rsp);
volume->SetUserTransform(rsp);
// Finally, add the volume to the renderer
ren->AddActor(volume);
ren->AddActor(outline);
// Set up an initial view of the volume. The focal point will be the
// center of the volume, and the camera position will be 400mm to the
// patient's left (which is our right).
vtkCamera* camera = ren->GetActiveCamera();
camera->SetPosition(-400, 0, 0);
camera->Elevation(30);
camera->Dolly(0.8);
ren->ResetCameraClippingRange();
// Interact with the data.
renWin->Render();
// Important: The interactor must be set prior to enabling the widget.
auto category = "RSP";
auto cp = COWPlacement();
auto cow = cp.MakeCOW(ren, category);
// Enable the widget.
cow->On();
iren->Initialize();
iren->Start();
return EXIT_SUCCESS;
}
namespace {
void Permute::GenerateTransforms()
{
vtkNew<vtkMatrix4x4> si_mat;
si_mat->SetData(this->si_arr.data());
vtkNew<vtkMatrix4x4> is_mat;
is_mat->SetData(this->is_arr.data());
vtkNew<vtkMatrix4x4> lr_mat;
lr_mat->SetData(this->lr_arr.data());
vtkNew<vtkMatrix4x4> rl_mat;
rl_mat->SetData(this->rl_arr.data());
// The previous transforms assume radiological views of the slices
// (viewed from the feet).
// Other modalities such as physical sectioning may view from the head.
// The following transforms modify the original with a 180° rotation
// about the y-axis.
vtkNew<vtkMatrix4x4> hf_mat;
hf_mat->SetData(this->hf_arr.data());
vtkNew<vtkTransform> si_trans;
si_trans->SetMatrix(si_mat);
this->transform["si"] = si_trans;
this->sort_order.push_back("si");
vtkNew<vtkTransform> is_trans;
is_trans->SetMatrix(is_mat);
this->transform["is"] = is_trans;
this->sort_order.push_back("is");
vtkNew<vtkTransform> ap_trans;
ap_trans->Scale(1, -1, 1);
this->transform["ap"] = ap_trans;
this->sort_order.push_back("ap");
vtkNew<vtkTransform> pa_trans;
pa_trans->Scale(1, -1, -1);
this->transform["pa"] = pa_trans;
this->sort_order.push_back("pa");
vtkNew<vtkTransform> lr_trans;
lr_trans->SetMatrix(lr_mat);
this->transform["lr"] = lr_trans;
this->sort_order.push_back("lr");
vtkNew<vtkTransform> rl_trans;
lr_trans->SetMatrix(rl_mat);
this->transform["rl"] = rl_trans;
this->sort_order.push_back("rl");
vtkNew<vtkTransform> hf_trans;
hf_trans->SetMatrix(hf_mat);
this->transform["hf"] = hf_trans;
this->sort_order.push_back("hf");
vtkNew<vtkTransform> hf_si_trans;
hf_si_trans->SetMatrix(hf_mat);
hf_si_trans->Concatenate(si_mat);
this->transform["hfsi"] = hf_si_trans;
this->sort_order.push_back("hfsi");
vtkNew<vtkTransform> hf_is_trans;
hf_is_trans->SetMatrix(hf_mat);
hf_is_trans->Concatenate(is_mat);
this->transform["hfis"] = hf_is_trans;
this->sort_order.push_back("hfis");
vtkNew<vtkTransform> hf_ap_trans;
hf_ap_trans->SetMatrix(hf_mat);
hf_ap_trans->Scale(1, -1, 1);
this->transform["hfap"] = hf_ap_trans;
this->sort_order.push_back("hfap");
vtkNew<vtkTransform> hf_pa_trans;
hf_pa_trans->SetMatrix(hf_mat);
hf_pa_trans->Scale(1, -1, -1);
this->transform["hfpa"] = hf_pa_trans;
this->sort_order.push_back("hfpa");
vtkNew<vtkTransform> hf_lr_trans;
hf_lr_trans->SetMatrix(hf_mat);
hf_lr_trans->Concatenate(lr_mat);
this->transform["hflr"] = hf_lr_trans;
this->sort_order.push_back("hflr");
vtkNew<vtkTransform> hf_rl_trans;
hf_rl_trans->SetMatrix(hf_mat);
hf_rl_trans->Concatenate(rl_mat);
this->transform["hfrl"] = hf_rl_trans;
this->sort_order.push_back("hfrl");
// Identity
this->transform["I"] = vtkNew<vtkTransform>();
this->sort_order.push_back("I");
// Zero
vtkNew<vtkTransform> z_trans;
z_trans->Scale(0, 0, 0);
this->transform["Z"] = z_trans;
this->sort_order.push_back("Z");
}
void Permute::PrintTransform(std::string const& permutation)
{
auto m = this->transform[permutation]->GetMatrix();
vtk::println(permutation);
for (int i = 0; i < 4; ++i)
{
for (int j = 0; j < 4; ++j)
{
if (j < 3)
{
vtk::print("{:>6.2g}", m->GetElement(i, j));
}
else
{
vtk::println("{:>6.2g}", m->GetElement(i, j));
}
}
}
}
void Permute::PrintAlltransforms()
{
for (auto const& k : this->sort_order)
{
PrintTransform(k);
}
}
vtkSmartPointer<vtkTransform>
Permute::GetTransform(std::string const& permutation)
{
return this->transform[permutation];
}
void COWPlacement::MakeLabelColor()
{
vtkNew<vtkNamedColors> nc;
// Define the axes labels and colors.
// The three digit key refers to the positive X,Y,Z axes.
// clang-format off
TAPS labels {
// Labels are: Anterior, Posterior, Dorsal, Ventral, Left, Right
{"ADL",{{"+X", "A"}, {"+Y", "D"}, {"+Z", "L"}, {"-X", "P"}, {"-Y", "V"}, {"-Z", "R"}}},
{"ALV",{{"+X", "A"}, {"+Y", "L"}, {"+Z", "V"}, {"-X", "P"}, {"-Y", "R"}, {"-Z", "D"}}},
{"ADR",{{"+X", "A"}, {"+Y", "D"}, {"+Z", "R"}, {"-X", "P"}, {"-Y", "V"}, {"-Z", "L"}}},
{"ARV",{{"+X", "A"}, {"+Y", "R"}, {"+Z", "V"}, {"-X", "P"}, {"-Y", "L"}, {"-Z", "D"}}},
{"PDL",{{"+X", "P"}, {"+Y", "D"}, {"+Z", "L"}, {"-X", "A"}, {"-Y", "V"}, {"-Z", "R"}}},
// Labels are: Left, Right, Superior, Inferior, Anterior, Posterior
{"LAS",{{"+X", "L"}, {"+Y", "A"}, {"+Z", "S"}, {"-X", "R"}, {"-Y", "P"}, {"-Z", "I"}}},
{"LPA",{{"+X", "L"}, {"+Y", "P"}, {"+Z", "A"}, {"-X", "R"}, {"-Y", "A"}, {"-Z", "S"}}},
{"LPS",{{"+X", "L"}, {"+Y", "P"}, {"+Z", "S"}, {"-X", "R"}, {"-Y", "A"}, {"-Z", "I"}}},
{"LSA",{{"+X", "L"}, {"+Y", "S"}, {"+Z", "A"}, {"-X", "R"}, {"-Y", "I"}, {"-Z", "A"}}},
{"RAP",{{"+X", "R"}, {"+Y", "A"}, {"+Z", "P"}, {"-X", "L"}, {"-Y", "I"}, {"-Z", "S"}}},
{"RAS",{{"+X", "R"}, {"+Y", "A"}, {"+Z", "S"}, {"-X", "L"}, {"-Y", "P"}, {"-Z", "I"}}},
{"RPS",{{"+X", "R"}, {"+Y", "P"}, {"+Z", "S"}, {"-X", "L"}, {"-Y", "A"}, {"-Z", "I"}}},
{"RSP",{{"+X", "R"}, {"+Y", "S"}, {"+Z", "P"}, {"-X", "L"}, {"-Y", "I"}, {"-Z", "A"}}},
{"SAL",{{"+X", "S"}, {"+Y", "A"}, {"+Z", "L"}, {"-X", "I"}, {"-Y", "P"}, {"-Z", "R"}}},
// Default labels.
{"XYZ", {}},
};
TAP c1{
{"+X", "IndianRed"},{"-X", "FireBrick"},
{"+Y", "LimeGreen"},{"-Y", "DarkGreen"},
{"+Z", "SkyBlue"}, {"-Z", "DeepSkyBlue"}
};
TAPS colors {
{"ADL", c1},
{"ALV", c1},
{"ADR", c1},
{"ARV", c1},
{"PDL", c1},
// Default colors.
{"LAS", {}},
{"LPS", {}},
{"LPA", {}},
{"LSA", {}},
{"RAP", {}},
{"RAS", {}},
{"RPS", {}},
{"RSP", {}},
{"SAL", {}},
// The default.
{"XYZ", {}},
};
// clang-format on
// The keys must be the same in the labels and colors variables.
// Get the keys.
std::set<std::string> labelKeys;
for (auto&& label : labels)
{
labelKeys.insert(label.first);
}
std::set<std::string> colorKeys;
for (auto&& label : colors)
{
colorKeys.insert(label.first);
}
std::vector<std::string> commonKeys;
std::set_intersection(labelKeys.begin(), labelKeys.end(), colorKeys.begin(),
colorKeys.end(), std::back_inserter(commonKeys));
for (auto&& k : commonKeys)
{
this->labelColor[k] = {labels[k], colors[k]};
}
};
vtkNew<vtkCameraOrientationWidget>
COWPlacement::MakeCOW(vtkRenderer* ren, std::string lcKey, int const& position)
{
std::set<std::string> keys;
for (auto&& label : this->labelColor)
{
keys.insert(label.first);
}
auto it = keys.find(lcKey);
if (it == keys.end())
{
std::string res =
"Invalid key for axes labels and colors.\nValid keys are: ";
for (const auto& [key, value] : this->labelColor)
{
res += fmt::format("{:s}, ", key);
}
if (res.length() >= 2)
{
auto pos = res.length() - 2;
res.replace(pos, 2, "");
}
res += "\nUsing the key: XYZ";
vtkfmt::println("{:}", res);
lcKey = "XYZ";
}
auto lc = this->labelColor[lcKey];
vtkNew<vtkCameraOrientationRepresentation> rep;
switch (position)
{
case 0:
rep->AnchorToLowerLeft();
break;
case 1:
rep->AnchorToUpperLeft();
break;
case 2:
rep->AnchorToLowerRight();
break;
default:
rep->AnchorToUpperRight();
}
if (!lc.first.empty())
{
rep->SetXPlusLabelText(lc.first["+X"]);
rep->SetXMinusLabelText(lc.first["-X"]);
rep->SetYPlusLabelText(lc.first["+Y"]);
rep->SetYMinusLabelText(lc.first["-Y"]);
rep->SetZPlusLabelText(lc.first["+Z"]);
rep->SetZMinusLabelText(lc.first["-Z"]);
}
if (!lc.second.empty())
{
vtkNew<vtkNamedColors> colors;
rep->SetXAxisColor(colors->GetColor3d(lc.second["+X"]).GetData());
rep->SetYAxisColor(colors->GetColor3d(lc.second["+Y"]).GetData());
rep->SetZAxisColor(colors->GetColor3d(lc.second["+Z"]).GetData());
}
vtkNew<vtkCameraOrientationWidget> cow;
cow->SetParentRenderer(ren);
cow->SetRepresentation(rep);
cow->Off();
return cow;
}
} // namespace
CMakeLists.txt¶
cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
project(MedicalDemo4)
find_package(VTK COMPONENTS
CommonColor
CommonCore
CommonDataModel
IOImage
InteractionStyle
RenderingContextOpenGL2
RenderingCore
RenderingFreeType
RenderingGL2PSOpenGL2
RenderingOpenGL2
RenderingVolume
RenderingVolumeOpenGL2
)
if (NOT VTK_FOUND)
message(FATAL_ERROR "MedicalDemo4: Unable to find the VTK build folder.")
endif()
# Prevent a "command line is too long" failure in Windows.
set(CMAKE_NINJA_FORCE_RESPONSE_FILE "ON" CACHE BOOL "Force Ninja to use response files.")
add_executable(MedicalDemo4 MACOSX_BUNDLE MedicalDemo4.cxx )
target_link_libraries(MedicalDemo4 PRIVATE ${VTK_LIBRARIES}
)
# vtk_module_autoinit is needed
vtk_module_autoinit(
TARGETS MedicalDemo4
MODULES ${VTK_LIBRARIES}
)
Download and Build MedicalDemo4¶
Click here to download MedicalDemo4 and its CMakeLists.txt file. Once the tarball MedicalDemo4.tar has been downloaded and extracted,
cd MedicalDemo4/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:
./MedicalDemo4
WINDOWS USERS
Be sure to add the VTK bin directory to your path. This will resolve the VTK dll's at run time.