第一部分.图像分割的含义

       图像分割是根据图像的灰度、颜色、几何形状、空间纹理等特征把图像分割为若干个互不相交的区域;实际上就是将自己在图片中的目标给提取出来,与背景分离;

第二部分.Matlab的图像分割的种类

   1.边缘检测法(利用目标与背景之间交界处的差别,提取边缘)

   2.阈值分割法(设定一个阈值,低于该阈值的地方为0黑,高于该阈值的地方为1白)

   3.区域分割法()

第三部分.边缘检测法

主要的检测方式:微分算子(Roberts算子、Sobel算子、Prewit算子),LOG算子,Canny算子; 

1.图像中线段的检测:

和滤波一样,要有模板,总共四种最基本的模板:

[-1 -1 -1; 2 2 2; -1 -1 -1] 水平检测

[-1 -1 2; -1 2 -1; 2 -1 -1] +45度检测

[-1 2 -1; -1 2 -1; -1 2 -1] 竖直检测

[2 -1 -1; -1 2 -1; -1 -1 2] -45度检测

然后将模板和图像进行结合滤波,用imfilter函数

2.微分算子

<1>Roberts算子:

clc
clear all
I = imread('dream.jpg');
I=rgb2gray(I);
[J, thresh] = edge(I, 'Roberts', 30/255); %进行边缘检测 ,Roberts算子, 分割阈值为30/255
figure;
subplot(121),imshow(I);
subplot(122),imshow(J);

里面的30/255是分割阈值,实际的阈值为thresh*256,这里的thresh为归一化后的值;

<2>Sobel算子:用法和Roberts算子的用法一样,只需将edge中的参数改成Sobel

<3>Prewit算子:用法和Roberts算子的用法一样,只需将edge中的参数改成Prewit

3.LOG算子:

在edge函数应用中,log和canny都对应着sigma参数,其是对应滤波器的标准差;Canny对应的是高斯滤波器(默认为sqrt(2)),LOG对应的是高斯拉普拉斯滤波器(默认为2)

4.Canny算子:

其特别的地方是他的阈值包括两个,一个低阈值,一个高阈值;忽略低于低阈值的边缘部分,保留高于高阈值的部分;

第四部分.阈值分割法

1.可以借助直方图来设置阈值,我们首先读取灰度图片,然后用imhist函数去显示直方图;

%图像分割(全局阈值,借助直方图)
clc
clear all
I=rgb2gray(imread('dream.jpg'));
figure (1)
imhist(I);
R=I>125;%大于125的地方为白(1),小于为黑(0)
figure(2);
imshow(R);

 可以看出我们可以从直方图中找出一个阈值,根据这个阈值来判断;

2.Otsu阈值分割,可以借助函数graythresh来自动获取阈值,然后根据这个阈值进行分割;

%Otsu阈值分割
clc
clear all
I=rgb2gray(imread('dream.jpg'));
M=graythresh(I);%自动获取阈值
J=im2bw(I,M);%根据M的大小来进行分割
figure;
imshow(J);

 3.迭代阈值分割,其原理很简单,首先是读取灰度图片,设置一个精度值(这里设的是S),在设置一个初值变量S1等于灰度图最大值和最小值之和的二分之一,再设置两个变量r1和r2,r1是所有大于初值变量S1的元素和,r2是所有小于等于S1的元素和;在设置变量S2等于(r1的平均数+r2的平均数)/2;在进入while循环,经过转换,让S1等于S2,再重复进行前几步,直到精度小于设定的精度S1;这时得到的S2为阈值,再通过im2bw来显示二值图;

%迭代式阈值分隔法
clc
clear all
I=rgb2gray(imread('dream.jpg'));
I=im2double(I);
S=0.1;
S1=(max(I(:))+min(I(:)))/2;
r1=find(I>S1);
r2=find(I<=S1);
S2=(mean(I(r1))+mean(I(r2)))/2;
while abs(S2-S1)>S
   S1=S2;
   r1=find(I>S1);
   r2=find(I<=S1);
   S2=(mean(I(r1))+mean(I(r2)))/2;
end
J=im2bw(I,S2);
figure;
imshow(J);

第五部分.区域分割法

1. 区域生长法:
区域生长是将一个种子(即点)不断地与周身的点进行比较然后融合行程大的区域,融合的条件是与周身邻域的点的相似度要小于一定的精度;然后不断地向外扩张融合,直到所以相似的点都被融合之后停止,这里我们用灰度值来进行测量;

区域生长一般分为以下几步:

1.确定种子点

2.确定是使用8邻域还是4邻域作为融合对象

3.灰度值之差与阈值之比(也可加上其他的判断条件,根据实际情况来设定)

4.直到停止生长,即再也没有满足生长的点

举例:

clc
clear all
I=rgb2gray(imread('dream.jpg'));
if isinteger(I)%判断是否为整数数组,若不为整数数组I的值过大,这样设置的精度就得改变,不能太小,否则无法得到想要的图片
    I=im2double(I);
end
figure 
imshow(I)
[M,N]=size(I);
[y,x]=getpts; %单击取点后,按enter结束
x1=round(x);%获得整数x
y1=round(y);%获得整数y
seed=I(x1,y1); %获取中心像素灰度值

grow1=zeros(M,N);%要绘制二值图,就可以先设置为0数组
grow1(x1,y1)=1;%种子点设为1,满足条件的点在后续判断中也会设为一

growcount=1; %待处理点个数
threshold=0.15;%与isinteger相互结合起来理解,如果没有isinteger,该值应该变得很大

while growcount>0
    growcount=0;
     for i=1:M %让种子去融合图片中满足的所有点
        for j=1:N
            if grow1(i,j)==1 %点在"栈"内,即一开始先检测到种子点,然后根据判断条件去判断种子点邻域的点是否满足条件,若满足为1,然后进行下一轮循环进行判断,直到循环时没有点可以满足添加进行融合了
                if (i-1)>1&(i+1)<M&(j-1)>1&(j+1)<N %确保可以将8邻域完全放置
                    for u=-1:1 %8邻域生长
                        for v=-1:1
                            if (grow1(i+u,j+v)==0&abs(I(i+u,j+v)-seed)<=threshold)%只有在点为0的时候才进行,否则gowtcount会计算错误
                                grow1(i+u,j+v)=1;%种子合并其他点,只要满足条件的点都会和种子点一样置1
                                growcount=growcount+1;  %记录此次新生长的点个数
                            end
                        end
                    end
                end
            end
        end
    end
end

subplot(1,2,1),imshow(I);
title("original image")
subplot(1,2,2),imshow(grow1);
title("growed image")

可以参考基于matlab的区域生长算法实现_minisal的博客-CSDN博客_matlab区域生长代码,内容都在里面注释了,只要把区域生长的步骤弄明白,代码自然就会看懂;

2.分水岭分割法:

分水岭转换法一般包括以下几个步骤:

1.读取灰度图

2.设置前景标记(通过重建开和重建闭来清理图像),腐蚀+重建开

3.膨胀+重建闭

4.形态学重建+图像取反

5.求局部最大值+将灰度图和局部最大值进行结合

6.对局部最大值消除周边杂乱的点(先闭操作,再腐蚀)

7.将修改后的局部最大值与灰度图结合

8.计算背景标记,用清理完的图像(即经过重建开与重建闭的图像)进行二值化

9.但理想情况下,我们不希望背景标记离我们要分割的对象的边缘太近,所以我们可以通过计算bw距离变换的分水岭变换,然后寻找结果的分水岭脊线来完成

10.用imimposemin函数修改梯度幅度图像,让区域最小值显示在前景和背景标记的像素上;

11.对修改的梯度幅度图像进行分水岭分割(分割物体的边界)

12.最后进行可视化的显示,可以将原灰度图与前景标记、背景标记、分割物体的结合到一个图片上,前景和背景标记缩放到不同的整数值,以便为它们分配不同的标签。

举例:

clc
clear all
I=rgb2gray(imread('apple.jpg'));
tidu=imgradient(I);
% figure;
% imshow(tidu,[]);
se=strel('disk',20);
fs=imerode(I,se);
fscj=imreconstruct(fs,I);
pz=imdilate(fscj,se);
pzcj=imcomplement(imreconstruct(imcomplement(pz),imcomplement(fscj)));
figure;
imshow(pzcj);
dgm=imregionalmax(pzcj);
figure;
imshow(dgm);
I2=labeloverlay(I,dgm);
figure;
imshow(I2);
se2 = strel(ones(5,5));
fgm2 = imclose(dgm,se2);
fgm3 = imerode(dgm,se2);
figure;
imshow(fgm3);
fgm4=bwareaopen(fgm3,15);
%I3=labeloverlay(I,fgm4);
I(fgm4)=255;
figure
imshow(I);
bw1=imbinarize(pzcj);
D = bwdist(bw1);
DL = watershed(D);
bgm = DL == 0;
figure;
imshow(bgm);
gmag2 = imimposemin(tidu, bgm|fgm4);
L=watershed(gmag2);
labels = imdilate(L==0,ones(3,3)) + 2*bgm + 3*fgm4;
I4 = labeloverlay(I,labels);
figure;
imshow(I4);

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐