区域生长算法被证实是一个有效的图像分割方法。区域生长的基本方法是从被分割对象里作为种子区域 ( 通常是一个或多个像素 ) 的一个区域开始,在种子区域的相邻像素寻找与种子像素有相同或相似性质的像素,并将这些像素合并到种子像素所在的区域中。将这些新像素当作新的种子区域继续进行上述过程。区域生长算法主要取决于用来选择确定为种子区域像素的标准、用来确定相邻像素的连通性类型和用来访问相邻像素的策略。
连接门限
在生长区域中包含像素的一个简单标准是以一个特殊的间距来计算亮度值。
接下来的例子阐述了 itk:: ConnectedThresholdImageFilter 的用法。这个滤波器使用注水迭代器。区域生长方法最主要的算法复杂性是访问相邻像素。注水迭代器承担起这个责任并大大简化了区域生长算法的执行。剩下的算法就是确定一个是否应该将一个特殊的像素包含到当前区域中的标准。ConnectedThresholdImageFilter 使用的标准是基于用户提供的一个亮度值间距,需要提供上下限的值。区域生长算法将包括那些亮度在亮度值间距标准中的像素。
I(X) ∈ [lower,upper]
实例17 连接门限对脑部切片PNG图像进行二维分割
#include "itkConnectedThresholdImageFilter.h"//连接门限头文件
#include "itkImage.h"
#include "itkCastImageFilter.h"
#include "itkCurvatureFlowImageFilter.h"
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
//图像中存在的噪声将大大降低滤波器生长大面积区域的能力。当面对噪声图像时,通常
//是使用一个边缘保留平滑滤波器。
int main( int argc, char *argv[])
{
/*if( argc < 7 )
{
std::cerr << "Missing Parameters " << std::endl;
std::cerr << "Usage: " << argv[0];
std::cerr << " inputImage outputImage seedX seedY lowerThreshold upperThreshold" << std::endl;
return EXIT_FAILURE;
}*/
/*我们基于一个特殊的像素类型和维来定义图像类型。由于平滑滤波器的需要,在这里我
们使用浮点型数据定义像素*/
typedef float InternalPixelType;
const unsigned int Dimension = 2;
typedef itk::Image< InternalPixelType, Dimension > InternalImageType;
typedef unsigned char OutputPixelType;
typedef itk::Image< OutputPixelType, Dimension > OutputImageType;
typedef itk::CastImageFilter< InternalImageType, OutputImageType >
CastingFilterType;
CastingFilterType::Pointer caster = CastingFilterType::New();
//图像读取与图像写类型定义
typedef itk::ImageFileReader< InternalImageType > ReaderType;
typedef itk::ImageFileWriter< OutputImageType > WriterType;
//图像读取与图像写对象实例化
ReaderType::Pointer reader = ReaderType::New();
WriterType::Pointer writer = WriterType::New();
reader->SetFileName( "BrainProtonDensitySlice.png" );
writer->SetFileName( "BrainProtonDensitySlice_huizhi.png" );
//使用图像类型作为模板参数来对平滑滤波器进行实例化
typedef itk::CurvatureFlowImageFilter< InternalImageType, InternalImageType >
CurvatureFlowImageFilterType;
//调用 New() 方式来创建滤波器并将接指向 itk::SmartPointer
//平滑滤波器实例化对象smoothing
CurvatureFlowImageFilterType::Pointer smoothing =
CurvatureFlowImageFilterType::New();
//声明区域生长滤波器的类型,本例中使用 ConnectedThresholdImageFilter
typedef itk::ConnectedThresholdImageFilter< InternalImageType,
InternalImageType > ConnectedFilterType;
//使用 New( ) 方式构造这种类的一个滤波器
//连接门限滤波器实例化对象connectedThreshold
ConnectedFilterType::Pointer connectedThreshold = ConnectedFilterType::New();
//读取图像进行平滑滤波
smoothing->SetInput( reader->GetOutput() );
//滤波后进行连接门限
connectedThreshold->SetInput( smoothing->GetOutput() );
/*由于只有一小部分图像文件格式支持浮点型数据类型,所以使
用 cast filter 将浮点型数据类型转换成整型*/
caster->SetInput( connectedThreshold->GetOutput() );
//处理后输出数据到writer
writer->SetInput( caster->GetOutput() );
/*CurvatureFlowImageFilter(平滑滤波器)需要定义两个参数。下面是一个二维图像的常见值。
当然它们也需要根据输入图像存在的噪声的数量进行适当的调整*/
smoothing->SetNumberOfIterations( 5 );
smoothing->SetTimeStep( 0.125 );
/*ConnectedThresholdImageFilter(连通门限图像滤波)有两个主要的
参数(lowerThreshold和upperThreshold)需要定义,
它们分别是为了确定是否包含在区域中的亮度值而制定的标准的上门限和下门限。
这两个值设定得太接近势必会降低区域生长的机动性,而设定得太远必将整个图像都卷入区域中*/
const InternalPixelType lowerThreshold = atof( "180" );
const InternalPixelType upperThreshold = atof( "210" );
connectedThreshold->SetLower( lowerThreshold );
connectedThreshold->SetUpper( upperThreshold );
/*这个滤波器的输出是一个二值图像,这个二值图像除了分割出的区域外到处都是零值像
素。区域中的亮度值是由 SetReplaceValue() 方式来选择的*/
connectedThreshold->SetReplaceValue( 255 );
InternalImageType::IndexType index;
/*这个算法的实例化需要用户提供一个种子点index。将这个点选在被分割的解剖学结构的典型
区域是很便捷的。种子是以一种 itk::Index 的形式传递给 SetSeed() 方式的*/
index[0] = atoi( "107" );
index[1] = atoi( "69" );
connectedThreshold->SetSeed( index );
/*writer 上的 Updata() 方法引发了管道的运行。通常在出现错误和抛出异议时, 从一个
try / catch 模块调用 updata :*/
try
{
writer->Update();
}
catch( itk::ExceptionObject & excep )
{
std::cerr << "Exception caught !" << std::endl;
std::cerr << excep << std::endl;
}
return EXIT_SUCCESS;
}
脑部组织结构图像进行分割时可参考的参数:
输入图像 分割出的白质组织 分割出的脑室组织 分割出的灰质组织
注意:灰质部分并没有被完全分割,这就是区域生长方法在对被分割的解剖学结构在图像空间上没有相似的统计分布时进行分割的弱点。你可以通过使用不同的上下限值进行分割,以达到扩展可接受区域的目的。
区域分割的另外一个选择是利用由 ConnectedThresholdImageFilter 在处理多种子时提供的优点。使用 AddSeed( ) 方式可以将一个接一个的传递给滤波器。你可以想象一个用户界面,在这个界面中被分割对象的多个点是都有一个操作键并且没个选择点作为一个种子传递给这个滤波器。
ITK系列目录:
注:例程配套素材见系列目录