今天给大家带来的是分割算法中的经典:区域生长。相信看这篇文章的你绝不会对这个词陌生的,so,具体含义本文就不解释了,直接上代码。
itk算法库中提供的类名叫:itkConnectedThresholdImageFilter
typedef itk::ConnectedThresholdImageFilter<ImageType, ImageType> ConnectedFilterType;
ConnectedFilterType::Pointer connectedThreshold = ConnectedFilterType::New ();
ConnectedFilterType->SetInput( input_image);
ImageType::IndexType seed0;
seed0[0] = 75;
seed0[1] = 142;
//seed0[2] = 21;//这里可以设置多维的点,具体要看ImageType定义的维度
connectedThreshold ->AddSeed(seed0);//这里可以设置多个seed的,方法就是不停的add
connectedThreshold ->SetLower( 800 );
connectedThreshold ->SetUpper( 3000 ); connectedThreshold ->SetReplaceValue(255);
connectedThreshold ->Update();
output_image = connectedThreshold ->Getoutput();
是不是很简单?嗯,接口就是这样的easy。接下来看类中的具体实现。
template <class TInputImage, class TOutputImage>
void
ConnectedThresholdImageFilter<TInputImage,TOutputImage>
::GenerateData()
{
InputImageConstPointer inputImage = this->GetInput();//输入图像
OutputImagePointer outputImage = this->GetOutput();//输出图像
typename InputPixelObjectType::Pointer lowerThreshold=this->GetLowerInput();//最低阈值
typename InputPixelObjectType::Pointer upperThreshold=this->GetUpperInput();//最高阈值
m_Lower = lowerThreshold->Get();
m_Upper = upperThreshold->Get();
// Zero the output 先用0填充输出图像
OutputImageRegionType region = outputImage->GetRequestedRegion();
outputImage->SetBufferedRegion( region );
outputImage->Allocate();
outputImage->FillBuffer ( NumericTraits<OutputImagePixelType>::Zero );
//先将输入图像二值化
typedef BinaryThresholdImageFunction<InputImageType, double> FunctionType;
typename FunctionType::Pointer function = FunctionType::New();
function->SetInputImage ( inputImage );
function->ThresholdBetween ( m_Lower, m_Upper );
ProgressReporter progress(this, 0, region.GetNumberOfPixels());//这句忽略
if (this->m_Connectivity == FaceConnectivity)//分类一:二维上的4邻域
{
typedef FloodFilledImageFunctionConditionalIterator<OutputImageType, FunctionType> IteratorType;//这里惊现FloodFill,相信一路看前面文章的同学很熟悉了
IteratorType it ( outputImage, function, m_SeedList );
it.GoToBegin();
while( !it.IsAtEnd())
{
it.Set(m_ReplaceValue);
++it;
progress.CompletedPixel(); // potential exception thrown here
}
}
else if (this->m_Connectivity == FullConnectivity)//分类二:二维上的8邻域
{
// use the fully connected iterator here. The fully connected iterator
// below is a superset of the above. However, it is reported to be 20%
// slower. Hence we use this "if" block to use the old iterator when
// we don't need full connectivity.
typedef ShapedFloodFilledImageFunctionConditionalIterator<OutputImageType, FunctionType> IteratorType;//一个加强版本的FloodFilled
IteratorType it ( outputImage, function, m_SeedList );
it.FullyConnectedOn();
it.GoToBegin();
while( !it.IsAtEnd())
{
it.Set(m_ReplaceValue);
++it;
progress.CompletedPixel(); // potential exception thrown here
}
}
#endif
}
代码不要太简单,思路就是先二值化,然后通过seed来定位,再然后floodfilled填充,然后没了~
所以,关键点在floodfilled,如果看到这里不太明白,请细翻翻我之前的文章,谢谢。
珍惜你现在拥有的一切,用真诚的笑容来面对他们,用全部的力量来保护他们,真希望这一刻就是永恒!
参考文献:
1.https://itk.org/Wiki/ITK/Examples/Broken/Images/ConnectedThresholdImageFilter