区域生长算法

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_27668313/article/details/77964165

数字图像分割算法一般是基于灰度值的两个基本特性之一:不连续性和相似性。前一种性质的应用途径是基于图像灰度的不连续变化分割图像,比如图像的边缘。第二种性质的主要应用途径是依据实现指定的准则将图像分割为相似的区域。区域生长算法就是基于图像的第二种性质,即图像灰度值的相似性。

因此区域生长算法一般分为三个步骤实现:

(1)确定生长种子点;

(2)规定生长准则;

(3)确定生长停止条件。

区域生长(region seeds growing, RSG)算法在实践中关键的问题是种子的选取和相似区域判定准则的确定。种子的选择可以人工选择,也可以通过一些方法自动选取;灰度图的判定准则一般用灰度差值小于某个阈值来表示,不同的判定准则可能会产生不同的分割结果。区域生长法固有的缺点是往往会造成过度分割,即将图像分割成过多的区域,空间和时间开销都比较大,噪声和灰度不均可能会导致空洞和过分割,并在对图像中的阴影效果处理上往往不是很好。其优点是基本思想相对简单,通常能将具有相同特征的联通区域分割出来,并能提供很好的边界信息和分割结果。在没有先验知识可以利用时,可以取得最佳的性能,可以用来分割比较复杂的图像,如自然景物。

区域生长实现的步骤如下:

1.对图像顺序扫描,找到第1个还没有归属的像素,设该像素为(x0, y0);

2.(x0, y0)为中心,考虑(x0, y0)8邻域像素(xy),如果(xy)满足生长准则,(x, y)(x0, y0)合并(在同一区域内),同时将(x, y)压入堆栈;

3.从堆栈中取出一个像素把它当作(x0,y0)返回到步骤2;

4.当堆栈为空时,返回到步骤1;

5.重复步骤1 - 4直到图像中的每个点都有归属时,生长结束。

进一步解释:注意“没有归属”四个字,从种子点出发,在其8领域内查找满足生长准则的点归并到种子点所在区域内,在程序中就是通过 push stack 堆栈中来实现,每一个被遍历的元素都会被标记,凡是被标记的元素在下次检测的时候都不会被考虑,因为它已经有了归属,区域生长的目的也就是将归属于种子点区域的部分分割出来而已。随着迭代次数的增加,每次在 top 一个元素并 pop 后加入到 stack中的元素慢慢变少,直到停止生长为止。


Matlab代码实现:

% Segment based on area, Region Growing基于区域生长算法的图像分割;
clear  ; 
[fileName,pathName] = uigetfile('*.*','Please select an image');%文件筐,选择文件
if(fileName)
    fileName = strcat(pathName,fileName);
    fileName = lower(fileName);%一致的小写字母形式
else 
    J = 0;%记录区域生长所分割得到的区域
    msgbox('Please select an image');
    return; %退出程序
end

I = imread(fileName);
figure; imshow(I);
if( ~( size(I,3)-3 ))
    I = rgb2gray(I);%转化为单通道灰度图
end
I = im2double(I); %图像灰度值归一化到[0,1]之间
% Ireshape = imresize(I,[600,800]);
% I = Ireshape(51:475,200:699);
% gausFilter = fspecial('gaussian',[5 5],0.5);
% I = imfilter(I,gausFilter,'replicate');

%种子点的交互式选择
[y,x] = getpts;%鼠标取点 , 回车确定
x = round(x);
y = round(y);
% if( exist('x','var') == 0 && exist('y','var') == 0)
%     subplot(2,2,1),imshow(I,[]);
%     hold on;
%     [y,x] = getpts;%鼠标取点  回车确定
%     x = round(x(1));%选择种子点
%     y = round(y(1));
% end

% if( nargin == 0)
%     reg_maxdist = 0.1;
%     %nargin是matlab代码编写中常用的一个技巧,主要用于计算当前主函数的输入参数个
%     %数,一般可以根据nargin的返回值来确定主函数输入参数的缺省值。在实现中,如果
%     %用户输入的参数个数为零,那么默认为0.2
% end
J = zeros(size(I)); % 主函数的返回值,记录区域生长所得到的区域
Isizes = size(I);
reg_mean = I(x,y);%表示分割好的区域内的平均值,初始化为种子点的灰度值
reg_size = 1;%分割的到的区域,初始化只有种子点一个
neg_free = 10000; %动态分配内存的时候每次申请的连续空间大小
neg_list = zeros(neg_free,3);%第一列行坐标,第二列列坐标,第三列存储灰度值
%定义邻域列表,并且预先分配用于储存待分析的像素点的坐标值和灰度值的空间,加速
%如果图像比较大,需要结合neg_free来实现matlab内存的动态分配
neg_pos = 0;%用于记录neg_list中的待分析的像素点的个数
pixdist = 0;
%记录最新像素点增加到分割区域后的距离测度
%下一次待分析的四个邻域像素点和当前种子点的距离
%如果当前坐标为(x,y)那么通过neigb我们可以得到其四个邻域像素的位置
neigb = [ -1 0;
          1  0;
          0 -1;
          0  1];
 %开始进行区域生长,当所有待分析的邻域像素点和已经分割好的区域像素点的灰度值距离
 %大于reg_maxdis,区域生长结束
 
 while (pixdist < 0.06 && reg_size < numel(I))
     %增加新的邻域像素到neg_list中
     for j=1:4
         xn = x + neigb(j,1);
         yn = y + neigb(j,2);
         %检查邻域像素是否超过了图像的边界
         ins = (xn>=1)&&(yn>=1)&&(xn<=Isizes(1))&&(yn<=Isizes(2));
         %如果邻域像素在图像内部,并且尚未分割好;那么将它添加到邻域列表中
         if( ins && J(xn,yn)==0)  %J(xn,yn)==0表示图像中该点还没有被分割
             neg_pos = neg_pos+1;
             neg_list(neg_pos,:) =[ xn, yn, I(xn,yn)];%存储对应点的灰度值
             J(xn,yn) = 1;%标注该邻域像素点已经被访问过 并不意味着,他在分割区域内
         end
     end
    %如果分配的内存空问不够,申请新的内存空间
    if (neg_pos+10>neg_free)
        neg_free = neg_free + 100000;
        neg_list((neg_pos +1):neg_free,:) = 0;
    end
    %从所有待分析的像素点中选择一个像素点,该点的灰度值和已经分割好区域灰度均值的
    %差的绝对值时所待分析像素中最小的
    dist = abs(neg_list(1:neg_pos,3)-reg_mean);
    [pixdist,index] = min(dist);
    %计算区域的新的均值
    reg_mean = (reg_mean * reg_size +neg_list(index,3))/(reg_size + 1);
    reg_size = reg_size + 1;
    %将旧的种子点标记为已经分割好的区域像素点
    J(x,y)=2;%标志该像素点已经是分割好的像素点
    x = neg_list(index,1);
    y = neg_list(index,2);
    %将新的种子点从待分析的邻域像素列表中移除
    neg_list(index,:) = neg_list(neg_pos,:);
    neg_pos = neg_pos -1;
 end
 
 J = (J==2);%我们之前将分割好的像素点标记为2
 hold off;
 figure;
 subplot(2,2,2),imshow(J);
 J = bwmorph(J,'dilate');%补充空洞
 subplot(2,2,3),imshow(J);
 subplot(2,2,4),imshow(I+J);

猜你喜欢

转载自blog.csdn.net/qq_27668313/article/details/77964165