Region Growth

<< Click to Display Table of Contents >>

Navigation:  XStream® HDVR® SDK > Implementation Concepts > Segmentation >

Region Growth

Previous pageReturn to chapter overviewNext page

C++ C++ Java Java .NET .NET

Summary

 

The XStream® HDVR® SDK supports segmentation using region growing algorithms. This technique supports several different methods for automatically segmenting volume material based on voxel segmentation criteria. This can be used to highlight or hide a structural feature, such as a specific tissue or material type, to improve the visibility of specific dataset components. In general, the region growth techniques work by first selecting an individual 'seed' voxel in the dataset, and then recursively sampling each of the voxel's 27 neighbor voxels to test if they meet the segmentation criteria. The segmentation growth region propagates outward from the seed voxel until adjacent voxels no longer meet the segmentation criteria.

 

The region growth technique supports four separate algorithms for generating a segmented region. The first is Min/Max, in which voxels are analyzed by comparing their individual values to an input min/max range of dataset values. The remaining algorithms, Min/Max Gradient, Min/Max Gradient Expand, and Min/Max Bone use gradient analysis of dataset values to determine the tissue type to select.

 

For more information about preparing a dataset for segmentation, and setting an active transfer function, see Segmentation. A seed point within the dataset can be selected for region growth segmentation, either programmatically using SDK methods, or with mouse selection using the Connectivity mouse adaptor.

 

RegionGrowth

Liver and gall bladder segmented with region growth

 

Region Growth

 

Segmentation by region growth is implemented using the IVolumeSegmentationContext::Segment() method. This method automatically segments the volume based on criteria set in the input SEGMENTATION_PARAMS structure. Some other IVolumeSegmentationContext methods can affect how the IVolumeSegmentationContext::Segment() method operates. These are discussed in the Enabling Segmentation section.

 

The IVolumeSegmentationContext::Segment() method takes three parameters. The first is the SEGMENTATION_PARAMS structure that contains all the parameters upon which the segmentation operation will be based. The second and third parameters are the address of variables that will be set with the size of the segmented region in voxels and cubic dataset units, usually cubic millimeters.

 

 

Segmentation by region growth is implemented using the hdrcIVolumeSegmentation.segment() method. This method automatically segments the volume based on criteria set in the input SEGMENTATION_PARAMS structure. Some other hdrcIVolumeSegmentation methods can affect how the hdrcIVolumeSegmentation::segment() method operates. These are discussed in the Enabling Segmentation section.

 

The hdrcIVolumeSegmentation::segment() method takes three parameters. The first is the SEGMENTATION_PARAMS structure that contains all the parameters upon which the segmentation operation will be based. The method returns a SEGMENTATION_VOLUME structure containing the size of the segmented region in voxels and cubic dataset units, usually cubic millimeters.

 

The SEGMENTATION_PARAMS member fields are described in the table below.

 

ConnectivityMax

The maximum voxel value to grow into. Only voxels with values less than or equal this will be considered.

ConnectivityMin

The minimum voxel value to grow into. Only voxels with values greater than or equal this will be considered.

ConnectivityOrigin

The seed coordinate from which the segmented region will grow. This coordinate can be entered manually, or determined from a call to the ShootRay() method.

ConnectivityRadius

Maximum distance from the seed point that the segmentation will grow.

CustomKernelParamsPtr

If a custom kernel is used, this will point to data that can be set by caller for the custom kernel to use.

CustomKernelParamsSize

Size of the data buffer pointed to by CustomKernelParamsPtr.

GradientNeighborhoodSize

Size of subcube used to calculate average gradient over. For example, if this is 3, then a 3x3x3 subcube centered around the current voxel will be considered.

GradientThreshold

Unitless parameter controlling strength of gradient that the growing will cross over. Valid values are -1 to +1. A smaller value will include less, a greater value will include more.

PostCloseSize

This parameter can be used to close holes in the segmented volume by applying successive dilate and erode passes. For example, if this is set to 5, then the segmented region will be dilated 5 times, then eroded 5 times. Some smoothing of the segmentation volume surface will result.

PostDilateCount

Number of layers to dilate after the segmentation operation completes. This is applied before any erode operations.

PostErodeCount

Number of layers to erode after the segmentation operation completes. This is applied after any dilate operations.

PostOpenSize

This parameter can be used to remove small objects at the segmentation boundary by applying successive erode and dilate passes. For example, if this is set to 5, then the segmented region will be eroded 5 times, then dilated 5 times. Some smoothing of the segmentation volume surface will result.

SegAlgoKernel

A value from the ENUM_SEGKERNEL enumeration that determines the segmentation kernel to apply.

StepSize

The number of voxels to jump in each direction for each step. Values of 1 and above may be used. Poor segmentation may result if large values are used.

 

// Create an IVolumeSegmentationContext object.

IVolumeSegmentationContext *pSegmentationContext;

pServer->CreateVolumeSegmentation(&pSegmentationContext);

 

// Set the octree for the IVolumeSegmentationContext object. 

pSegmentationContext->Initialize(pOctree);

 

// Segmentation operations will apply to transfer function 2 (index 1).

pSegmentationContext->SetSegLabelIndex(1);

 

// Set additive segmentation.

pSegmentationContext->SetSegType(ST_ADDITIVE);

 

// Set all 8 label volumes as valid for segmentation.

pSegmentationContext->SetSegLabelMask(255, 0, 0, 0);

 

// Get render paramaters.

RENDER_PARAMS rp;

pEngine->GetRenderParams(&rp);

 

// Compute the center point of the image.

POINT pt;

pt.x = rp.RenderImageSize.cx / 2;

pt.y = rp.RenderImageSize.cy / 2;

 

// Shoot a ray to get the 3D volume coordinates for the voxel at the center of the image.

RAYSTOPINFO rsi;

pEngine->ShootRay(&pt, &rsi, 1);

VECTOR3D origin = VECTOR3D(rsi.vtx.x, rsi.vtx.y, rsi.vtx.z);

 

// Configure a SEGMENTATION_PARAMS structure.

SEGMENTATION_PARAMS segParams;

segParams.ConnectivityMax = 1000;

segParams.ConnectivityMin = 0;

segParams.ConnectivityOrigin = origin;

segParams.ConnectivityRadius = 100;

segParams.CustomKernelParamsPtr = NULL;

segParams.CustomKernelParamsSize = 0;

segParams.GradientNeighborhoodSize = 3;

segParams.GradientThreshold = 0;

segParams.PostCloseSize = 0;

segParams.PostDilateCount = 0;

segParams.PostErodeCount = 0;

segParams.PostOpenSize = 0;

segParams.SegAlgoKernel = SK_MIN_MAX;

segParams.StepSize = 1;

 

// Apply region growth segmentation.

h_int64 sizeVoxels = 0; 

double sizeMMs = 0;

pSegmentationContext->Segment(&segParams, &sizeVoxels, &sizeMMs);

 

// Create an hdrcIVolumeSegmentation object.

hdrcIVolumeSegmentation segmentationContext;

segmentationContext = server.createVolumeSegmentation();

 

// Set the octree for the IVolumeSegmentationContext object. 

segmentationContext.initialize(octree);

 

// Segmentation operations will apply to transfer function 2 (index 1).

segmentationContext.setSegLabelIndex(1);

 

// Set additive segmentation.

segmentationContext.setSegType(hdrcDefines.ST_ADDITIVE);

 

// Set all 8 label volumes as valid for segmentation.

segmentationContext.setSegLabelMask(255, 0, 0, 0);

 

// Get render paramaters.

RENDER_PARAMS rp = new RENDER_PARAMS();

rp = engine.getRenderParams();

 

// Compute the center point of the image.

POINT pt = new POINT();

pt.x = rp.RenderImageSize.cx / 2;

pt.y = rp.RenderImageSize.cy / 2;

 

POINT[] shootPoint = new POINT[1];

shootPoint[0] = pt;

 

RAYSTOPINFO[] rayInfo = new RAYSTOPINFO[1];

RAYSTOPINFO[0] = new RAYSTOPINFO();

 

// Shoot a ray to get seed voxel data.

pEngine.shootRay(shootPoint, rayInfo, 1);

VECTOR3D origin = new VECTOR3D(rsi[0].vtx.x, rsi[0].vtx.y, rsi[0].vtx.z);

 

// Configure a SEGMENTATION_PARAMS structure.

SEGMENTATION_PARAMS segParams = new SEGMENTATION_PARAMS;

segParams.ConnectivityMax = 1000;

segParams.ConnectivityMin = 0;

segParams.ConnectivityOrigin = origin;

segParams.ConnectivityRadius = 100;

segParams.CustomKernelParamsPtr = NULL;

segParams.CustomKernelParamsSize = 0;

segParams.GradientNeighborhoodSize = 3;

segParams.GradientThreshold = 0;

segParams.PostCloseSize = 0;

segParams.PostDilateCount = 0;

segParams.PostErodeCount = 0;

segParams.PostOpenSize = 0;

segParams.SegAlgoKernel = hdrcDefines.SK_MIN_MAX;

segParams.StepSize = 1;

 

// Apply region growth segmentation.

SEGMENTATION_VOLUME segVolume;

segVolume = segmentationContext.segment(segParams);

 

Segmentation Kernels

 

The XStream HDVR SDK supports a number of different segmentation kernels, or algorithms, for performing segmentation operations. The segmentation kernels are defined by the ENUM_SEGKERNEL enumeration. These segmentation kernels are set in the SEGMENTATION_PARAMS.SegAlgoKernel field. The supported kernels are described in the table below.

 

SK_MIN_MAX

The simplest Kernel algorithm, voxels are included if they are connected to the origin within the radius and the voxel value is between the min and max

SK_MIN_MAX_GRADIENT

This Kernel algorithm will also evaluate a local subcube of gradients to determine if the growing should continue.

SK_MIN_MAX_GRADIENT_EXPAND

As the subcube size gets larger the above algorithm tends to under-estimate the object, this algorithm expands near the edges.

SK_MIN_MAX_BONE

This Kernel algorithm looks for tiny partial volume spaces between dense bones and so tries to separate almost-touching bones.

SK_CUSTOM

This will run a user-defined custom kernel. See the Custom Segmentation Kernel section for more information.

 

Custom Segmentation Kernel

 

Documentation on the custom kernel feature can be obtained from your Fovia representative.

 

Asynchronous Segmentation

 

In C++, the region growth algorithm is computationally intensive and can take a number of seconds to complete. For this reason, performing an asynchronous segmentation operation may be desirable. This allows the application to continue other tasks while the server application runs the segmentation algorithm. Asynchronous segmentation is accomplished with the IVolumeSegmentationContext::StartJobSegment(), IServerContext::GetJobInfo(), and IVolumeSegmentationContext::FinishJobSegment() methods.

 

The IVolumeSegmentationContext::StartJobSegment() method begins the segmentation process. This method takes two parameters. The first parameter is a pointer to an integer used to store the job ID associated with the segmentation process, which will be returned as an output parameter when the IVolumeSegmentationContext::StartJobSegment() method returns. The second parameter is the address of a the SEGMENTATION_PARAMS structure that contains all the parameters upon which the segmentation operation will be based.

 

The IServerContext::GetJobInfo() method is used to return information on the progress and status of the segmentation operation. This method takes as an input parameter the jobID value returned from the IVolumeSegmentationContext::StartJobSegment() method which is used to identify the asynchronous segmentation operation. The IServerContext::GetJobInfo() method returns as an output parameter a pointer to a JOBINFO structure. The JOBINFO::jobprog value stores the job progress. The JOBINFO::jobprog value will be 0 to 100, representing a percentage of job completion, with a value of 100 indicating completion of the job. The JOBINFO::jobret value stores the return value from the server side custom segmentation function when it has completed.

 

The IVolumeSegmentationContext::FinishJobSegment() method is used to finalize the segmentation operation. This method takes three parameters. The first is the jobID value of the asynchronous segmentation operation. The second and third parameters are the address of variables that will be set with the size of the segmented region in voxels and cubic dataset units, usually cubic millimeters.

 

// Create an IVolumeSegmentationContext object.

IVolumeSegmentationContext *pSegmentationContext;

pServer->CreateVolumeSegmentation(&pSegmentationContext);

 

// Set the octree for the IVolumeSegmentationContext object. 

pSegmentationContext->Initialize(pOctree);

 

// Segmentation operations will apply to transfer function 2 (index 1).

pSegmentationContext->SetSegLabelIndex(1);

 

// Set additive segmentation.

pSegmentationContext->SetSegType(ST_ADDITIVE);

 

// Set all 8 label volumes as valid for segmentation.

pSegmentationContext->SetSegLabelMask(255, 0, 0, 0);

 

// Get render paramaters.

RENDER_PARAMS rp;

pEngine.getRenderParams(&rp);

 

// Compute the center point of the image.

POINT pt = new POINT();

pt.x = rp.RenderImageSize.cx / 2;

pt.y = rp.RenderImageSize.cy / 2;

 

RAYSTOPINFO rayInfo;

 

// Shoot a ray to get seed voxel data.

pEngine->ShootRay(&pt, &rayInfo, 1);

 

// Configure segmentation parameters.

SEGMENTATION_PARAMS segParams;

segParams.ConnectivityMax = 1000;

segParams.ConnectivityMin = 0;

segParams.ConnectivityOrigin = origin;

segParams.ConnectivityRadius = 100;

segParams.CustomKernelParamsPtr = NULL;

segParams.CustomKernelParamsSize = 0;

segParams.GradientNeighborhoodSize = 3;

segParams.GradientThreshold = 0;

segParams.PostCloseSize = 0;

segParams.PostDilateCount = 0;

segParams.PostErodeCount = 0;

segParams.PostOpenSize = 0;

segParams.SegAlgoKernel = hdrcDefines.SK_MIN_MAX;

segParams.StepSize = 1;

 

// Start an asynchronous path finding operation.

h_int64 jobID;

pSegmentationContext->StartJobSegment(&jobID, &segParams);

 

// Check the progress of the path finding operation.

JOBINFO jobInfo;

while(jobInfo.jobprog < 100) {

   // Get segmentation progress

   pServerContext->GetJobInfo(jobID, &jobInfo);

 

// Finialize the path finding operation.

h_int64 sizeVoxels = 0; 

double sizeMMs = 0;

pSegmentationContext->FinishJobSegment(jobID, &sizeVoxels, &sizeMMs);

 

In Java/.NET, the region growth algorithm is computationally intensive and can take a number of seconds to complete. For this reason, performing an asynchronous segmentation operation may be desirable. This allows the application to continue other tasks while the server application runs the segmentation algorithm. Asynchronous segmentation is accomplished with the hdrcIVolumeSegmentation::startJobSegment(), hdrcServerContext::getJobInfo(), and hdrcIVolumeSegmentation::finishJobSegment() methods.

 

The hdrcIVolumeSegmentation::startJobSegment() method begins the segmentation process. This method takes one parameter, the SEGMENTATION_PARAMS structure that contains all the parameters upon which the segmentation operation will be based. The method will return an integer used to store the job ID associated with the segmentation process

 

The hdrcServerContext::getJobInfo() method is used to return information on the progress and status of the segmentation operation. This method takes as an input parameter the jobID value returned from the hdrcServerContext::startJobSegment() method which is used to identify the asynchronous segmentation operation. The hdrcServerContext::getJobInfo() method returns a reference to a hdrcJobInfo structure. The hdrcJobInfo::m_prog value stores the job progress. The hdrcJobInfo::m_prog value will be 0 to 100 representing the completion percentage of the job. When this value reaches 100 the job is complete. The hdrcJobInfo::m_err value stores the return value from the server side custom segmentation function when it has completed.

 

The hdrcIVolumeSegmentation::finishJobSegment() method is used to finalize the segmentation operation. This method takes one parameter, the jobID value of the asynchronous segmentation operation. The method returns a SEGMENTATION_VOLUME structure containing the size of the segmented region in voxels and cubic dataset units, usually cubic millimeters.

 

// Create an hdrcIVolumeSegmentation object.

hdrcIVolumeSegmentation segmentationContext;

segmentationContext = server.createVolumeSegmentation();

 

// Set the octree for the IVolumeSegmentationContext object. 

segmentationContext.initialize(octree);

 

// Segmentation operations will apply to transfer function 2 (index 1).

segmentationContext.setSegLabelIndex(1);

 

// Set additive segmentation.

segmentationContext.setSegType(hdrcDefines.ST_ADDITIVE);

 

// Set all 8 label volumes as valid for segmentation.

segmentationContext.setSegLabelMask(255, 0, 0, 0);

 

// Get render paramaters.

RENDER_PARAMS rp = new RENDER_PARAMS();

rp = engine.getRenderParams();

 

// Compute the center point of the image.

POINT pt = new POINT();

pt.x = rp.RenderImageSize.cx / 2;

pt.y = rp.RenderImageSize.cy / 2;

 

POINT[] shootPoint = new POINT[1];

shootPoint[0] = pt;

 

RAYSTOPINFO[] rayInfo = new RAYSTOPINFO[1];

RAYSTOPINFO[0] = new RAYSTOPINFO();

 

// Shoot a ray to get seed voxel data.

pEngine.shootRay(shootPoint, rayInfo, 1);

VECTOR3D origin = new VECTOR3D(rsi[0].vtx.x, rsi[0].vtx.y, rsi[0].vtx.z);

 

// Configure a SEGMENTATION_PARAMS structure.

SEGMENTATION_PARAMS segParams = new SEGMENTATION_PARAMS;

segParams.ConnectivityMax = 1000;

segParams.ConnectivityMin = 0;

segParams.ConnectivityOrigin = origin;

segParams.ConnectivityRadius = 100;

segParams.CustomKernelParamsPtr = NULL;

segParams.CustomKernelParamsSize = 0;

segParams.GradientNeighborhoodSize = 3;

segParams.GradientThreshold = 0;

segParams.PostCloseSize = 0;

segParams.PostDilateCount = 0;

segParams.PostErodeCount = 0;

segParams.PostOpenSize = 0;

segParams.SegAlgoKernel = hdrcDefines.SK_MIN_MAX;

segParams.StepSize = 1;

 

// Start an asynchronous segmentation operation.

long jobID = segmentationContext.startJobSegment(segParams);

 

// Check the progress of the segmentation operation.

hdrcJobInfo jobInfo;

while(jobInfo.m_prog < 100) {

   // Get path finding progress

   jobInfo = serverContext.getJobInfo(jobID);

 

// Finialize the segmentation operation.

SEGMENTATION_VOLUME segVolume;

segVolume = segmentationContext.finishJobSegment(jobID);