图像处理边缘分割法

2019-12-14 23:09:58 qq_43571150 阅读数 707

Matlab-图像分割与边缘检测实验-采用阈值处理方法进行图像分割

代码链接:https://download.csdn.net/download/qq_43571150/12033271

问题
实现直方图阈值法,具体方法为采用灰度直方图求双峰或多峰,选择两峰之间的谷底作为阈值,将图像转换为2值图像。

图像结果👇
在这里插入图片描述

Matlab代码👇

I=imread('05.jpg');       %读取当前路径下的图片
I1=rgb2gray(I);
subplot(2,2,1);imshow(I1);title('灰度图像');

grid on;                        %显示网格线
axis on;                        %显示坐标系
[m,n]=size(I1);                 %测量图像尺寸参数
GK=zeros(1,256);                %预创建存放灰度出现概率的向量
for k=0:255
	 GK(k+1)=length(find(I1==k))/(m*n);             %计算每级灰度出现的概率,将其存入GK中相应位置
end
subplot(2,2,2),bar(0:255,GK,'g')                    %绘制直方图

title('灰度直方图')
xlabel('灰度值')
ylabel('出现概率')
I2=im2bw(I,200/255); 	
subplot(2,2,3),imshow(I2);title('直方图阈值处理分割图像')
imwrite(I2,'05 直方图阈值200的分割图像.jpg');
grid on;                         %显示网格线
axis on;                         %显示坐标系
2017-10-30 11:20:54 u010189457 阅读数 26833

一、图像边缘检测

    基本思路:基于边缘检测的图像分割方法的基本思路是先确定图像中的边缘像素,然后再把这些像素连接在一起就构成所需的区域边界。

    图像边缘:图像边缘,即表示图像中一个区域的终结和另一个区域的开始,图像中相邻区域之间的像素集合构成了图像的边缘。所以,图像边缘可以理解为图像灰度发生空间突变的像素的集合。图像边缘有两个要素,即:方向和幅度。沿着边缘走向的像素值变化比较平缓;而沿着垂直于边缘的走向,像素值则变化得比较大。因此,根据这一变化特点,通常会采用一阶和二阶导数来描述和检测边缘。

    综上,图像中的边缘检测可以通过对灰度值求导数来确定,而导数可以通过微分算子计算来实现。在数字图像处理中,通常是利用差分计算来近似代替微分运算。


这里写图片描述
图1:图像边缘类型及导数曲线规律示例

    梯度幅值计算

    设f(x,y)为连续图像函数,GxGy分别为x方向和y方向的梯度,且在点(x,y)处的梯度可以表示为一个矢量,梯度定义如下:

G(f(x,y))=[f(x,y)x f(x,y)y]T

    对应欧式距离梯度幅值:

|G(x,y)|=G2x+G2y

    对应棋盘距离梯度幅值:

|G4(x,y)|=|Gx|+|Gy|

    对应街区距离梯度幅值:

|G8(x,y)|=max{|Gx|+|Gy|}

这里写图片描述

    
    梯度矢量幅角表示的梯度方向是函数f(x,y)增加最快的方向:

ϕ(x,y)=arctan(Gx/Gy)

二、微分算子

    常用的一阶微分算子有Roberts、Prewitt、Sobel等算子,常用的二阶微分算子有Laplace和Kirsh等算子。在实际处理操作中常用模板矩阵与图像像素值矩阵卷积来实现微分运算。

    由于垂直边缘的方向上的像素点和噪声都是灰度不连续点,所以变换到频域时,在频域均为高频分量,直接采用微分运算不可避免地会受到噪声的很大影响。 因此,微分算子只适用于图像噪声比较少的简单图像。针对此问题,LoG算子(Laplace of Gaussian)和Canny算子采取的方法是,先对图像进行平滑滤波,然后再用微分算子与图像进行卷积操作,这样处理会得到比较好的边缘检测结果。其中,LoG算子是采用Laplacian算子计算高斯函数的二阶导数,Canny算子是高斯函数的一阶导数,两种算子在抑制噪声和检测边缘之间取得了比较好的平衡。

    

1. Roberts算子

    Robert算子是一种利用局部差分算子检测边缘的算子,对具有陡峭的低噪声图像处理的效果较好。其定义如下:

G[f(x,y)]={[f(x+1,y+1)f(x,y)]2+[f(x+1,y)f(x,y+1)]2}12

    上述公式计算量较大,在实际操作中通常采用绝对差算法近似代替上述公式:

G[f(x,y)]|f(x+1,y)f(x,y)|+|f(x,y+1)f(x,y)|

G[f(x,y)]|f(x+1,y+1)f(x,y)|+|f(x,y+1)f(x+1,y)|

    
    Roberts算子卷积核:

[1001] [0110]

    Roberts算子概念简单,算法计算复杂度较低,对低噪声图像操作可以得到不错的效果,但是在稍复杂图像上则难以胜任。

    

2. Sobel算子

    Sobel算子有两个矩阵算子,也称卷积核,分别计算x方向和y方向上的方向梯度,两个核分别与图像进行卷积计算,一个对水平方向上的边缘敏感,一个对垂直方向上的边缘敏感。Sobel算子定义如下:

S=(d2x+d2y)12

dx=[f(x1,y1)+2f(x,y1)+f(x+1,y1)][f(x1,y+1)+2f(x,y+1)+f(x+1,y+1)]

dy=[f(x+1,y1)+2f(x+1,y)+f(x+1,y+1)][f(x1,y1)+2f(x1,y)+f(x1,y+1)]

    
    用模板表示dxdy如下:

101202101 121000121

    Sobel算子结构简洁,能较好地抑制噪声。

    

3. Prewitt算子

    Prewitt算子和Sobel算子类似,也有两个卷积核,区别在于卷积核中心系数的权值不同。Prewitt算子定义:
Sp=(d2x+d2y)12
卷积核表示为:

101101101 111000111

    Prewitt算子实现起来比Sobel算子更为简单,也可以一定程度上抑制噪声。

    

4. LoG算子

    LoG(Laplace of Gaussian),即拉普拉斯高斯算子。拉普拉斯算子是对二维函数求二阶导数的算子(f(x,y)2/x2+f(x,y)2/y2),拉普拉斯高斯算子则是对二维高斯函数求二阶导数的算子。
    二维高斯函数:

G(x,y)=ex2+y22σ2

    LoG算子:

ΔG(x,y)=[x2+y22σ2σ4]ex2+y22σ2

    LoG卷积核:

010141010111181111

    LoG算子可以根据需要进行“调整”以便在期望的尺寸上起作用(比如下面的5x5的卷积核),可使得大的算子可用于检测模糊边缘,小的算子则可以用于检测锐度集中的精细细节。

0010001210121621012100010024442408044824844080424442

5x5卷积核

    LoG算子的特点:
    1. 图像与高斯滤波器进行卷积,既平滑了图像又降低了噪声,孤立的噪声点和较小的结构组织将被滤除。
    2. 在边缘检测时则仅考虑那些具有局部梯度最大值的点为边缘点,用拉普拉斯算子将边缘点转换成零交叉点,通过零交叉点的检测来实现边缘检测。
    3. 缺点是在过滤噪声的同时使得原有的边缘一定程度上被平滑了。

    

5. Canny算子

    Canny算子检测边缘点的方法基本思想是寻找图像梯度的局部最大值。
    评价一个边缘检测算子的,一般考虑如下三个指标:
    1. 低失误概率:在尽可能把所有边缘检测到的同时,减少将非边缘误判为边缘;
    2. 高位置精度:检测出的边缘是真正的边界,检测到的边缘位置足够精确;
    3. 检测得到的边界是单像素宽。
    针对这三个指标,Canny在设计检测算子时提出了边缘检测算子的三个准则:
    1. 信噪比准则;
    2. 定义精度准则;
    3. 单边缘响应准则。

    遵循这三个准则,Canny算子设计实现的步骤如下:
    (1)首先用高斯滤波模板进行卷积以平滑图像;
    (2)利用微分算子,计算梯度的幅值和方向;
    (3)对梯度幅值进行非极大值抑制。即遍历图像,若某个像素的灰度值与其梯度方向上前后两个像素的灰度值相比不是最大,那么这个像素值置为0,即不是边缘;
    (4)使用双阈值算法检测和连接边缘。即使用累计直方图计算两个阈值,凡是大于高阈值的一定是边缘;凡是小于低阈值的一定不是边缘。如果检测结果大于低阈值但又小于高阈值,那就要看这个像素的邻接像素中有没有超过高阈值的边缘像素,如果有,则该像素就是边缘,否则就不是边缘。
    边缘连接:上述方法仅得到处在边缘上的像素点。噪声和不均匀的照明而产生的边缘间断的影响,使得经过边缘检测后得到的边缘像素点很少能完整地描绘实际的一条边缘。可以在使用边缘检测算法后,紧接着使用连接方法将边缘像素组合成有意义的边缘。

    

2019-05-13 09:13:18 mary_0830 阅读数 10847

说明:图像分割就是把图像分成若干个特定的、具有独特性质的区域并提出感兴趣目标的技术和过程。它是由图像处理到图像分析的关键步骤。现有的图像分割方法主要分以下几类:基于阈值的分割方法、基于区域的分割方法、基于边缘的分割方法以及基于特定理论的分割方法等。从数学角度来看,图像分割是将数字图像划分成互不相交的区域的过程。图像分割的过程也是一个标记过程,即把属于同一区域的像索赋予相同的编号。(来自百度百科)

(一)点、线和边缘检测

(1)点检测

概念:将嵌在一幅图像的恒定区域或亮度几乎不变的区域里的孤立点的检测,就是点检测。可以用点检测的模板来将孤立的点检测出来:这个模板的作用就是当模板中心是孤立点时,模板的相应最强,而在非模板中心时,相应为零。
在这里插入图片描述
在MATLAB中进行点检测操作,基本语法为:

g = abs(imfilter(tofloat(f),w))>=T;  %g是包含检测点的图像;f是输入图像;w是点检测模板

运用上面的语法编写实验代码:

f = imread('C:\Users\Public\Pictures\Sample Pictures\Fig0903(a).tif');
subplot(121),imshow(f);
w = [-1 -1 -1;-1 8 -1;-1 -1 -1];
g = abs(imfilter(tofloat(f),w));
T = max(g(:));  %在滤波后图像中选择的最大值
g = g >=T;
subplot(122),imshow(g);

在这里插入图片描述
点检测的另一种方法是在大小为m×n的所有邻点中寻找一些点,最大值和最小值的差超出了T的值,可以用函数ordfilt2进行操作:

g = ordfilt2(f,m*n,ones(m,n))-ordfilt2(f,1,ones(m,n));
g = g>=T;

(2)线检测

线检测比点检测更加复杂一些,模板如图所示:
在这里插入图片描述
同样的,当检测的线是在中间那行或者是由“2”组成的行或列中,则此时的相应最大,其他部分的相应为零。

编写实验代码:

f = imread('C:\Users\Public\Pictures\Sample Pictures\Fig0513(a).tif');
subplot(231),imshow(f),title('原始图像');
w = [2 -1 -1;-1 2 -1;-1 -1 2];
g = imfilter(tofloat(f),w);
subplot(232),imshow(g,[]),title('45°处理后的图像');
gtop = g(1:120,1:120);
gtop = pixeldup(gtop,4);
subplot(233),imshow(gtop,[]),title('左上角放大的图像');
gbot = g(end -119:end,end -119:end);
gbot = pixeldup(gbot,4);
subplot(234),imshow(gbot,[]),title('右下角放大的图像');
g =abs(g);
subplot(235),imshow(g,[]),title('绝对值的图像');
T =max(g(:));
g =g >=T;
subplot(236),imshow(g),title('所有点满足g>=T的图像');

在这里插入图片描述在这里插入图片描述实验分析: 在进行45°的边缘检测中,只能够检测到45°或者135°的边缘,并在matlab中进行显示,发现在第二幅图中,45°的边缘检测并不是清楚的看出45°的边缘,而只能看到由点组成的边缘,这是因为原图像中基本没有呈对角线的线条,因此并不能显示对角线的边缘。绝对值的图像是将图像变成了二值图像(只有黑与白),比灰度图像更加清晰看出检测到的线条边缘。

(3)使用函数edge的边缘检测

以上两种方法在图像分割中很重要,但是所常用的方法是边缘检测,这种方法是检测亮度的不连续性。这样的不连续是用一阶和二阶导数来检测的。
首先,我们先介绍二阶函数的梯度向量公式:
在这里插入图片描述
这个向量的幅值可以简化为如下形式:通常使用梯度的幅值或近似值来作为“梯度”。
在这里插入图片描述
梯度向量的基本性质是:梯度向量指向(x,y)坐标处f的最大变化率方向。
最大变化率处发生的角度是:
在这里插入图片描述
在图像处理工具箱中,可以使用函数edge来作为边缘估计器。

[g,t] = edge(f,'method',parameters)

在这里插入图片描述下面分别介绍表格中的边缘检测算子:

  1. sobel边缘检测算子
    在这里插入图片描述
    调用语法是:
[g,t] = edge(f,'sobel',T,dir)  %T是阈值,dir是边缘检测首选方向:'horizontal'、'vertical'、‘both’
  1. prewitt边缘检测算子
    在这里插入图片描述
    调用语法为:(较容易产生噪声)
[g,t] = edge(f,'prewitt',T,dir)  %T是阈值,dir是边缘检测首选方向:'horizontal'、'vertical'、‘both’
  1. Roberts边缘检测算子
    在这里插入图片描述
    调用语法为:
[g,t] = edge(f,'roberts',T,dir)  %T是阈值,dir是边缘检测首选方向:'horizontal'、'vertical'、‘both’
  1. LoG检测算子
    高斯函数:
    在这里插入图片描述
    这个公式表示的是平滑函数。如果此函数和图像进行卷积,则图像会变得模糊,且模糊的程度是由σ决定的。这个函数的拉普拉斯算法是:
    在这里插入图片描述
    这个函数称为LoG算子。原理是:由于求二阶导数是线性操作,所以用这个函数卷积这幅图像与先用平滑函数对图像卷积,再对结果进行拉普拉斯计算的结果是一样的。

这样会得到两种效果:一种是平滑图像,减少了噪声;另一种是计算拉普拉斯,从而产生双边缘图像,然后在双边缘之间定位由发现的零交叉组成的边缘。

调用语法为:

[g,t] = edge(f,'log',T,sigma)  %T是阈值,sigma是标准差,默认为2
  1. 零交叉检测算子
    这种算子与LoG方法类似,不同之处在于卷积使用特殊的滤波函数H来完成的。
    调用语法为:
[g,t] = edge(f,'zerocross',T,H)  %T是阈值
  1. Canny检测算子
    这种算子是edge函数中最强的边缘检测算子
    (1)图像用指定了标准差σ的高斯滤波器来平滑,用来减少噪声;
    (2)局部梯度和边缘方向在每个点都进行计算。边缘点被定义为梯度方向上局部强度最大的点。
    (3)在(2)中决定的边缘点在梯度幅度图像上给出脊。然后算法追踪所有脊的顶部,设置所有的不在脊的顶部的像素为零。因此在输出中给出一条细线,这是非最大值抑制处理。脊像素使用称为“滞后阈值”的技术进行阈值处理,这种技术以使用两个阈值为基础,即T1和T2,且T1<T2。值大于T2的脊像素称为强边缘像素,T1和T2之间的脊像素称为弱边缘像素。
    (4)算法用合并8连接的弱像素点到强像素点的方法执行边缘连接。
    调用语法为:
[g,t] = edge(f,'canny',T,sigma)  %T是向量=[T1,T2];sigma是标准差,默认为1

编写实验代码:

f = imread('C:\Users\Public\Pictures\Sample Pictures\Fig0309(a).tif');
subplot(231),imshow(f),title('原始图像');
[gv,t] = edge(f,'sobel','vertical');
subplot(232),imshow(gv),title('默认阈值垂直的sobel图像');
t
gv = edge(f,'sobel',0.15,'vertical');
subplot(233),imshow(gv),title('阈值0.15垂直的sobel图像')
gboth = edge(f,'sobel',0.15);
subplot(234),imshow(gboth),title('阈值为0.15垂直水平的sobel图像')
wneg45 = [-2 -1 0;-1 0 1;0 1 2];
gneg45 = imfilter(tofloat(f),wneg45,'replicate');
T =0.3*max(abs(gneg45(:)));
gneg45 = gneg45>=T;
subplot(235),imshow(gneg45),title('阈值45°边缘图像')

在这里插入图片描述
在这里插入图片描述在这里插入图片描述

在这里插入图片描述实验分析: 当参数是默认垂直的sobel边缘检测时,得到边缘细节是垂直的,水平的边缘线是没有能够检测出来的。当加入参数0.15之后,之前能够检测到的细节却不能够检测出来了,是因为这已经超出了阈值的范围;当采用垂直水平的边缘检测,将之前没有能够检测出的水平线能够检测并显示出来了;当所检测的边缘线是45°的时候,该算法只能够检测到45°或135°的边缘线条,并显示出来。

sobel、Log和canny边缘检测算子进行比较,编写实验代码:

f = tofloat(f);
subplot(221),imshow(f),title('原始图像')
[gSobel_dafault,ts] = edge(f,'sobel');
[gLog_dafault,tlog] = edge(f,'log');
[gCanny_dafault,tc] = edge(f,'canny');
subplot(222),imshow(gSobel_dafault),title('默认的sobel图像');
subplot(223),imshow(gLog_dafault),title('默认的log图像');
subplot(224),imshow(gCanny_dafault),title('默认的canny图像');

gSobel_best = edge(f,'sobel',0.05);
gLog_best = edge(f,'log',0.003,2.25);
gCanny_best = edge(f,'canny',[0.04 0.1],1.5);
subplot(222),imshow(gSobel_best),title('最好效果的sobel图像');
subplot(223),imshow(gLog_best),title('最好效果的log图像');
subplot(224),imshow(gCanny_best),title('最好效果的canny图像');

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述在这里插入图片描述实验分析: 同样的一幅图像,使用默认的sobel边缘检测得到的图像中线条是比较其他两种是比较少的,而且获取的边缘细节不是很完整,缺失了很多重要的细节,比如说草地上的细节等。但是在最佳的sobel边缘检测中,所得到的图像是比较完整的,线条细节基本上都被获取并显示出来,相比较其他两种方法,所得到的边缘细节是最完整的。在canny边缘检测中,默认参数的canny检测是最好的,所获得细节是最多的,其边缘基本都可以完整的检测到。

(二)使用霍夫变换的线检测

在理想情况下,只能产生边缘上的像素,为了更好的得到边缘特性,因此下面介绍霍夫变换的线检测方法。
霍夫变换:是一种特征检测(feature extraction),被广泛应用在图像分析(image analysis)、计算机视觉(computer vision)以及数位影像处理(digital image processing)。霍夫变换是用来辨别找出物件中的特征,例如:线条。他的算法流程大致如下,给定一个物件、要辨别的形状的种类,算法会在参数空间(parameter space)中执行投票来决定物体的形状,而这是由累加空间(accumulator space)里的局部最大值(local maximum)来决定。(来自百度百科)

霍夫变换的原理:

我们将用极坐标系来表示直线。此时,直线的表达式为:
在这里插入图片描述
将其化简为:
在这里插入图片描述
一般来说,一条直线能够通过在平面θ-ρ 寻找交于一点的曲线数量来进行检测。 越多曲线交于一点也就意味着这个交点表示的直线由更多的点组成.。一般来说我们可以通过设置直线上点的阈值来定义多少条曲线交于一点,此时认为检测到了一条直线。霍夫线变换要做的就是:它追踪图像中每个点对应曲线间的交点。 如果交于一点的曲线的数量超过了 阈值, 那么可以认为这个交点所代表的参数对 (θ, ρ) 在原图像中为一条直线。

在图像处理工具箱中提供了以下函数:
函数hough实现了所描述的概念;
函数houghpeaks寻找霍夫变换的峰值(累加单元的高计数);
函数houghlines在原图像上提取线段。

  1. 函数hough
    调用函数:
 [H,theta,rho] = hough(f)   
 或 [H,theta,rho] = hough(f,'ThetaRes',val1,'RhoRes',val2) 

其中,H是霍夫变换矩阵,theta和rho是ρ和θ值向量。f是二值图像,val1是0-90的标量,指定沿θ轴霍夫变换的间距(默认为1);val2是0<val2<hypot(size(I,2),size(I,2))的实际量,指定沿ρ轴的霍夫变换的间距(默认为1)。

编写实验代码:

f = zeros(101,101);
f(1,1) = 1;f(101,1) = 1;f(1,101) = 1;
f(101,101) = 1;f(51,51) = 1;
H = hough(f)
imshow(H,[])

 [H,theta,rho] = hough(f);
 imshow(H,[],'XData',theta,'YData',rho,'InitialMagnification','fit')
 axis on,axis normal
 xlabel('\theta'),ylabel('\rho')

在这里插入图片描述
在这里插入图片描述实验分析: 三条曲线(直线也可以考虑为曲线)在±45°处的交点指出:f中有两组三个共线的点。两条曲线在(ρ,θ)=(0,-90)、(-100,-90)、(0,0)和(100,0)处的交点指出:有4组位于垂直线和水平线上的共线点。(需要将图像放大以方便观察其坐标)

  1. 函数houghpeaks:寻找霍夫变换的峰值(累加单元的高计数)

调用语法:

peaks = houghpeaks(H,NumPeaks)
或 peaks = houghpeaks(H,‘Threshold’,val1,'NHoodSize',val2)

其中,val1可以从0到Inf变换,默认是0.5*max(H(:)),val2是指定量围绕峰值的邻域大小。
这个过程的基本思想是:通过把峰值的直接邻域中的霍夫变换单元置0来清理峰值。

  1. 函数houghlines:当峰值在霍夫变换中被识别出来,则可用此函数来决定线的起始点和终点。
    调用函数:
lines = houghlines(f,theta,rho,peaks)
或lines = houghlines(f,'FillGap',val1,'MinLength',val2)

其中,theta和rho是来自函数hough的输出,peaks是来自houghpeaks的输出。val1指定了与相同的霍夫变换相关的两条线段的距离。当两条线段之间的鹅咀里小于指定的值时,则把线段合并为一条线段(默认20);val2指定合并的线是保留还是去掉,如果合并的线比val2指定的值短,则丢掉(默认是40)。

编写实验代码:

f = imread('C:\Users\Public\Pictures\Sample Pictures\Fig1006(a).tif');
subplot(131),imshow(f),title('原始图像');
[H,theta,rho] = hough(f,'ThetaRes',0.2) 
subplot(132),imshow(H,[ ],'XData',theta,'YData',rho,'InitialMagnification','fit')
axis on,axis normal
xlabel('\theta'),ylabel('\rho')

peaks =houghpeaks(H,5);
hold on
plot(theta(peaks(:,2)),rho(peaks(:,1)),'linestyle','none','marker','s','color','w')

lines = houghlines(f,theta,rho,peaks);
subplot(133),imshow(f);
for k = 1:length(lines)
xy = [lines(k).point1;lines(k).point2];
plot(xy(:,1),xy(:,2),'LineWidth',4,'Color',[0.8 0.8 0.8]);
end

(三)阈值处理

(1)基础知识

一般情况下,一张图片分为前景和背景,我们感兴趣的一般的是前景部分,所以我们一般使用阈值将前景和背景分割开来,使我们感兴趣的图像的像素值为1,不感兴趣的我0,有时一张图我们会有几个不同的感兴趣区域(不在同一个灰度区域),这时我们可以用多个阈值进行分割,这就是阈值处理。
单个阈值:
在这里插入图片描述
两个阈值:
在这里插入图片描述
示意图如下:
在这里插入图片描述

(2)基本全局阈值处理

一般选取阈值就是图像直方图的视觉检测。将区分度大的两个灰度级部分之间进行划分,取T为阈值来分开它们。在此基础上学习一种自动地选择阈值的算法,方法如下:

  1. 针对全局阈值选择初始估计值T;
  2. 用T分割图像,G1是所有灰度值大于T的像素组成,G2是所有灰度值小于等于T的像素组成;
  3. 分别计算G1和G2区域内的平均灰度值m1和m2;
  4. 计算出新的阈值,取他们的m1和m2平均值数;
  5. 重复步骤2.-4.,直到在连续的重复中,T的差异比预先设定的参数小为止;
  6. 使用函数im2bw分割图像:g = im2bw(f,T/den)

编写实验代码:

f = imread('C:\Users\Public\Pictures\Sample Pictures\Fig0309(a).tif');
f = imnoise(f,'gaussian');
count = 0;
T = mean2(f);
done = false;
while ~done
count  = count+1;
g = f>T;
Tnext = 0.5*(mean(f(g))+mean(f(~g)));
done = abs(T-Tnext)<0.5;
T =Tnext;
end

count
T

g = im2bw(f,T/255);
subplot(131),imshow(f),title('带噪声的图像');
subplot(132),imhist(f),title('图像的直方图');
subplot(133),imshow(g),title('全局阈值分割的结果')

在这里插入图片描述
在这里插入图片描述
实验分析: count是表示含有的灰度级数目,则T表示阈值。当我们对图像进行噪声处理时,基本全局阈值分割出来的结果也会或多或少带有一些噪声,使得图像并不是很美观。因此下面的方法将对含有噪声的图像进行修改。

(3)使用Otsu’s方法的最佳全局阈值处理

Otsu’s方法的最佳方法是选择阈值k,最大类间方差σ2(k)来定义的:在这里插入图片描述
当设置的方差越大,则完全分割一幅图像的阈值就会越接近。公式中的k就是我们所要寻找的最佳阈值,当k不唯一时,则将所有的最佳阈值进行取平均值即可。

调用的语法是:

[T,SM] = graythresh(f)   %SM是可分性度量,T是归一化的阈值

编写实验代码:

f = imread('C:\Users\Public\Pictures\Sample Pictures\Fig0309(a).tif');
f = imnoise(f,'gaussian');
[T,SM] = graythresh(f)
T*255

(基本全局算法)一般来说,高SM值说明灰度分成两类的可能性比较高。
在这里插入图片描述

f2 = imread('C:\Users\Public\Pictures\Sample Pictures\Fig1014(a).tif');
subplot(221),imshow(f2),title('原始图像');
subplot(222),imhist(f2),title('原始图像直方图');
count = 0;
T = mean2(f2);
done = false;
while ~done
count  = count+1;
g = f2>T;
Tnext = 0.5*(mean(f2(g))+mean(f2(~g)));
done = abs(T-Tnext)<0.5;
T =Tnext;
end
g = im2bw(f2,T/255);
subplot(223),imshow(g,[]),title('用基本全局算法分割结果')
[T,SM] = graythresh(f2);
SM
T*255
g = im2bw(f2,T);
subplot(224),imshow(g),title('用Otsu’s算法分割结果')

在这里插入图片描述
在这里插入图片描述实验分析: 可以看出,用基本全局阈值处理时细胞的分割效果并不是很好,没有能够分割清楚,是由于前景和背景的灰度级比较相近而不能够完全分离开,因此当使用了otsu’s算法进行分割时,可以完全将细胞(前景)和背景分割开来。尽管分离度的度量值比较低,但是还是可以准确地从背景中提取细胞。

(4)使用图像平滑改进全局阈值处理

噪声可以影响阈值的选择,当噪声不能够在源头减少,在阈值处理之前可以将图像进行平滑处理,这样可以更好地进行阈值处理。

编写实验代码:

f = imread('C:\Users\Public\Pictures\Sample Pictures\Fig0513(a).tif');
subplot(241),imshow(f),title('原始图像');
fn = imnoise(f,'gaussian',0,0.038);
subplot(242),imshow(fn),title('具有高斯噪声的图像');
subplot(243),imhist(fn),title('具有高斯噪声的直方图');
Tn = graythresh(fn);
gn = im2bw(fn,Tn);
subplot(244),imshow(gn),title('用otsu’s分割的图像');
w = fspecial('average',5);
fa = imfilter(fn,w,'replicate');
subplot(245),imshow(fa),title('平滑后的图像');
subplot(246),imhist(fa),title('平滑后的直方图');
Ta = graythresh(fa);
ga =im2bw(fa,Ta);
subplot(247),imshow(ga),title('平滑后并用otsu’s分割的图像');

在这里插入图片描述在这里插入图片描述实验分析: 当加入高斯噪声的图像,所显示的直方图并不能使用阈值处理进行分割图像,所以经过otsu’s全局阈值处理操作后发现,原始图像和噪声并不能够分离开。当使用平滑滤波器进行图像改善之后,从其直方图看出,可以使用阈值处理进行分割图像了,所以最后的效果图显示,图像与噪声分割开来,因此可以使用otsu’s全局阈值处理对图像进行操作。

(5)使用边缘改进全局阈值处理

边缘改进的阈值处理:主要是处理那些位于或接近物体和背景间边缘的像素,使得这些像素分离开的操作。

具体算法过程如下:

  1. 用一种边缘查找方式计算图像的模板的值。
  2. 通过百分比指定阈值。由于计算的边缘模板值中有很多噪声,所以可以将计算值排序,并选择百分比相对高的值(大于百分下的值的阈值)作为阈值。
  3. 根据指定的阈值,对第一步的图像边缘的值进行选择。使高于阈值的像素点值为1,低于的值为零,由此选择出部分边缘点的二值图像(模板)。
  4. 用刚才计算出来的模板与原图像相乘,获得一幅新的图像。
  5. 对新的图像使用otsu进行分割。

用自定义的函数percentile2i来计算灰度值I的对应指定的百分比:

I = percentile2i(h,p)

编写实验一代码:基于梯度边缘信息改进全局阈值处理

f = tofloat(imread('C:\Users\Public\Pictures\Sample Pictures\Fig1013(a).tif'));
subplot(231),imshow(f),title('原图像');
subplot(232),imhist(f),title('原图像直方图');
sx = fspecial('sobel');
sy = sx';
gx = imfilter(f,sx,'replicate');
gy = imfilter(f,sy,'replicate');
grad = sqrt(gx.*gx+gy.*gy);
grad = grad/max(grad(:));

h =imhist(grad);
Q = percentile2i(h,0.999);

markerImage = grad>Q;
subplot(233),imshow(markerImage),title('以99.9%进行阈值处理后的梯度幅值图像');
fp = f.*markerImage;
subplot(234),imshow(fp),title('原图像与梯度幅值乘积的图像');
hp = imhist(fp);
hp(1) = 0;
subplot(235),bar(hp),title('原图像与梯度幅值乘积的直方图');
T = otsuthresh(hp);
T*(numel(hp)-1)
g = im2bw(f,T);
subplot(236),imshow(g),title('改进边缘后的图像')

在这里插入图片描述
在这里插入图片描述
实验分析: 原始图像本身具有高斯噪声,由其直方图单峰可以知道,此时的图像分割是不可能进行操作的,使用基本全局阈值处理是失败的。因此,实验只能够用梯度幅值处理后,将图像进行明显的灰度级分离,把阈值处理接近模式的中点,这样就可以得到基本完美的图像分割。

编写实验二代码:用拉普拉斯边缘信息改进全局阈值处理

f = tofloat(imread('C:\Users\Public\Pictures\Sample Pictures\Fig1017(a).tif'));
subplot(231),imshow(f),title('原始图像');
subplot(232),imhist(f),title('原始图像的直方图');
hf = imhist(f);
[Tf SMf] = graythresh(f);
gf = im2bw(f,Tf);
subplot(233),imshow(gf),title('对原始图像进行分割的图像');
w= [-1 -1 -1;-1 8 -1;-1 -1 -1];
lap = abs(imfilter(f,w,'replicate'));
lap = lap/max(lap(:));
h = imhist(lap);
Q = percentile2i(h,0.995);
markerImage = lap >Q;
fp = f.*markerImage;
subplot(234),imshow(fp),title('标记图像与原图像的乘积');
hp = imhist(fp);
hp(1) =0;
subplot(235),bar(hp)
T = otsuthresh(hp);
g = im2bw(f,T);
subplot(236),imshow(g),title('修改边缘后的阈值处理图像')

在这里插入图片描述在这里插入图片描述实验分析: 在之前的学习知道,拉普拉斯算法是用于图像的锐化,把图像的边缘提取出来。在这个部分中,用拉普拉斯边缘信息改进全局阈值处理也是一样的,首先将原始图像的边缘提取出来,然后将原始图像与已标记好的图像进行相乘,得到的就是实验中所需要的图像,最终图像就如边缘改进结果那样,修改边缘信息提取出来,再用阈值进行处理。

(6)基于局部统计的可变阈值处理

当背景照明高度不均匀时,需要进行阈值处理的难度就增大,为了解决这个问题,运用局部统计的可变阈值处理的算法进行解决。我们用一幅图像中每个点的邻域中像素的标准差和均值,这是局部对比度和平均灰度的描述子
为了计算局部标准差,使用函数stdfilt进行操作:g = stdfilt(f,nhood);
为了计算局部均值,可以用函数localmean进行操作:

function mean = localmean(f,nhood)
if nargin ==1
    nhood = ones(3)/9;
else
    nhood = nhood/sum(nhood(:));
end
mean = imfilter(tofloat(f),nhood,'replicate');

用于执行局部阈值处理,可以用下面的函数来操作:

function g = localthresh(f,nhood,a,b,meantype)
f = tofloat(f);
SIG = stdfilt(f,nhood);
if nargin == 5 && strcmp(meantype,'global')
    MEAN = mean2(f);
else
    MEAN = localmean(f,nhood);
end
g = (f > a*SIG) & (f > b*MEAN);

编写实验代码:

[TGlobal] = graythresh(f);
gGlobal = im2bw(f,TGlobal);
subplot(131),imshow(gGlobal),title('用otsu方法分割的图像');
g = localthresh(f,ones(3),30,1.5,'global');
SIG = stdfilt(f,ones(3));
subplot(132),imshow(SIG,[]),title('局部标准差图像');
subplot(133),imshow(g),title('局部阈值处理后的图像');

在这里插入图片描述实验分析: 观察原图像发现,图像可以分为三种灰度级,发现除了细胞核的部分,细胞核与细胞的灰度级差别并不是很大,因此当我们使用全局阈值处理时,不能将里面的细胞核与细胞分离开,得到的阈值处理如otsu方法分割图像所示。当实验使用局部可变的阈值处理时,计算出图像的局部标准差,可以将细胞与细胞核分离开,因此当再次使用阈值处理时可以完整的将细胞与细胞核分离开,获得最终的处理结果。

(7)使用移动平均的图像阈值处理

移动平均是一种局部阈值处理方法,该方法以一幅图像的扫描行计算移动平均为基础。移动平均分割能减少光照偏差,且计算简单。当感兴趣的物体与图像尺寸相比较小(或较细)时,基于移动平均的阈值处理会工作的很好。打印图像和手写文本图像满足这一条件。

移动平均需要计算图像中每一个点,因此分割用下面的表示式:
在这里插入图片描述
其中,K是[0,1]范围内的常数,mxy是输入图像的移动平均

可以用如下的函数movingthresh来进行移动平均的操作:

function g = movingthresh(f, n, K)
f = tofloat(f);
[M, N] = size(f);
if (n < 1) || (rem(n, 1) ~= 0)
error('n must be an integer >= 1.')
end
if K < 0 || K > 1
error('K must be a fraction in the range [0, 1].')
end
f(2:2:end, :) = fliplr(f(2:2:end, :));
f = f'; 	% Still a matrix.
f = f(:)'; % Convert to row vector for use in function filter.
maf = ones(1, n)/n; 	% The 1-D moving average filter.
ma = filter(maf, 1, f); % Computation of moving average.
g = f > K * ma;
g = reshape(g, N, M)';
g(2:2:end, :) = fliplr(g(2:2:end, :));

编写实验代码:

f = imread('C:\Users\Public\Pictures\Sample Pictures\Fig1019(a).tif');
subplot(131),imshow(f),title('原始图像');
T =graythresh(f);
g1 = im2bw(f,T);
subplot(132),imshow(g1),title('用otsu全局阈值分割后的图像');
g2 = movingthresh(f,20,0.5);
subplot(133),imshow(g2),title('用移动平均局部阈值分割后的图像');

在这里插入图片描述在这里插入图片描述实验分析: 实验之前就说过,移动平均的图像阈值处理适用于处理打印图像和手写文本图像这种类型。对比房子的移动平均处理看出,最后所获得的图像不是实验所需要的图像,因此这种方法并不适用于这种图像处理。在处理手写文本图像的时候,经过局部移动平均阈值处理后,所获得的结正是我们所需要的。

(四)基于区域的分割

分割的目的是把图像分成一块一块的区域,是基于像素特性的分布,通过阈值处理完成的。

(1)基本表达式

令R表示整个图像区域,分割是把R分成n个子区域的处理,分割必须满足下面5条原则:
在这里插入图片描述

(2)区域生长

区域生长(region growing) 是指将成组的像素或区域发展成更大区域的过程。从种子点的集合开始,从这些点的区域增长是通过将与每个种子点有相似属性像强度、灰度级、纹理颜色等的相邻像素合并到此区域。

在区域生长中的主要问题如下:
(1)表示区域的初始化种子的选择:在区域生长过程中,这些不同区域点合适属性的选择。
(2)基于图像具体属性的像素生长不一定是好的分割。在区域生长过程中,不应该使用连通性或邻接信息。
(3)相似性:相似性表示在灰度级中观察在两个空间邻接像素之间或像素集合的平均灰度级间的最小差分,它们将产生不同的区域。如果这个差分比相似度阈值小,则像素属于相同的区域。
(4)区域面积:最小面积阈值与像素中的最小区域大小有关。在分割的图像中,没有区域比这个阈值小,它由用户定义。(来自百度百科)

在图像处理工具中使用函数regiongrow进行区域生长的操作:

[g,NR,SI,TI] = regiongrow(f,S,T)  %f是被分割图像,S/T可以是数组或标量,范围是[0,1]内

编写实验代码:

f = imread('C:\Users\Public\Pictures\Sample Pictures\Fig0309(a).tif');
subplot(221),imshow(f),title('原始图像');
[g,NR,SI,TI]=regiongrow(f,255,65);%种子的像素值为255,65为阈值
subplot(222),imshow(SI),title('种子点的图像');
subplot(223),imshow(TI),title('所有通过阈值测试的像素');
subplot(224),imshow(g),title('对种子点进行8连通分析后的结果');

在这里插入图片描述

(3)区域分离和聚合

这个操作是区域生长的反操作,是将图像中的区域分离或合并这些区域。令R表示整个图像,选择属性P,这个操作将R连续地细分为越来越小的象限区域。如果P(R)=TRUE,就把图像分成4象限;如果对每个4象限来说,P都是FALSE,再细分象限就为子象限,以此类推划分下去,直到无法进一步合并的时候停止分离。这种方法也称作四叉树。(如图所示)
在这里插入图片描述
在图像处理工具箱中使用函数qtdecomp 进行四叉树分解的处理:

z = qtdecomp(f,@split_test,parameters)  %split_test用来决定某个区域是否进行分离

为了在四叉树分解中得到实际的四叉区域像素值,使用函数qtgetblk:

[vals,r,c] = qtgetblk(f,z,m)  %vals是数组,r和c事行列坐标的向量,z是返回的稀疏矩阵

函数splitmerge来计算两个区域的合并

g = splitmerge(f,mindim,@predicate)  %mindim是分解中允许的最小块

predicate函数是用户自定义的,用于考察该区域的是否符合要求

flag = predicate(region)

用代码编写以上过程:

f = imread('C:\Users\Public\Pictures\Sample Pictures\Fig1023(a).tif');
subplot(231),imshow(f),title('原始图像');
g32 = splitmerge(f,32,@predicate) %使用最小块为32进行分割
subplot(232),imshow(g32),title('使用最小块为32进行分割图像');
g16 = splitmerge(f,16,@predicate) %使用最小块为16进行分割
subplot(233),imshow(g16),title('使用最小块为16进行分割图像');
g8= splitmerge(f,8,@predicate) %使用最小块为8进行分割
subplot(234),imshow(g8),title('使用最小块为8进行分割图像');
g4 = splitmerge(f,4,@predicate) %使用最小块为4进行分割
subplot(235),imshow(g4),title('使用最小块为4进行分割图像');
g2 = splitmerge(f,2,@predicate) %使用最小块为2进行分割
subplot(236),imshow(g2),title('使用最小块为2进行分割图像');

在这里插入图片描述在这里插入图片描述

(五)使用分水岭变换的分割

分水岭算法主要用于图像的分割,如果目标物体是连接在一起的,则分割起来会很困难。此时经常采用分水岭分割算法,会得到比较好的效果。分水岭分割算法把图像看成一幅地形图,亮度比较强的区域像素值较大,亮度暗的区域像素值比较小,通过寻找汇水盆地和分水岭界线对图像进行分割。分水岭的计算过程是一个迭代标注过程。分水岭比较经典的计算方法是L. Vincent提出的。在该算法中,分水岭计算分两个步骤,一个是排序过程,一个是淹没过程。首先对每个像素的灰度级进行从低到高排序,然后在从低到高实现淹没过程中,对每一个局部极小值在h阶高度的影响域采用先进先出(FIFO)结构进行判断及标注。

注意:分割结果必须要根据种子区域,以减小过分割造成的影响。

(1)使用距离变换的分水岭分割

最常用的分水岭变换分割的是距离变换,主要是用于二值图像的处理,它是指从每个像素到最接近零值的像素的距离。
在这里插入图片描述
距离变换函数为:D = bwdist(f)

计算距离变换的负分水岭变换,调用函数watershedL = watershed(A,conn)

编写实验代码为:

f = imread('C:\Users\Public\Pictures\Sample Pictures\Fig0513(a).tif');
subplot(231),imshow(f),title('原始图像');
g = im2bw(f,graythresh(f));   %把图像变换成二值图像
subplot(232),imshow(g),title('二值图像');
gc = ~g;
subplot(233),imshow(gc),title('补的图像');
D = bwdist(gc);
subplot(234),imshow(D),title('距离变换图像');
L = watershed(-D);
w = L == 0;
subplot(235),imshow(w),title('负分水岭脊的图像');
g2 = g&-w;
subplot(236),imshow(g2),title('黑色重叠后的图像');

在这里插入图片描述在这里插入图片描述

(2)使用梯度的分水岭分割

梯度处理是在分水岭变换之前的预处理,它将沿着物体的边缘有较高的像素值,而在其他地方的像素值比较低。

编写实验代码:

f = imread('C:\Users\Public\Pictures\Sample Pictures\Fig1014(a).tif');
subplot(221),imshow(f),title('原始图像');
h = fspecial('sobel');
fd = tofloat(f);
g = sqrt(imfilter(fd,h,'replicate').^2+imfilter(fd,h,'replicate').^2);
subplot(222),imshow(g,[]),title('梯度和分水岭分割幅度图像');
L =watershed(g);
wr = L == 0;
subplot(223),imshow(wr),title('严重分割过分割后图像');
g2 = imclose(imopen(g,ones(3,3)),ones(3,3));
L2 = watershed(g2);
wr2 = L2 == 0;
f2 = f;
f2(wr2) = 255;
subplot(224),imshow(f2),title('平滑梯度图像后的分水岭变换');

在这里插入图片描述在这里插入图片描述实验分析: 观察两组图像,当梯度的分水岭分割时,所获得的图像基本上满足实验的效果,但由于严重的过度分割后,图像已不再是需要得到的效果,使得图像分割没有意义了。使用平滑梯度图像的分水岭分割后,虽然产生了一些缺陷(图像上被一些类似噪声污染),但没有影响图像的分割效果。基于梯度的分水岭分割法是修改梯度函数使得集水盆只响应想要探测的目标,再对梯度图像进行阈值处理,以消除灰度的微小变化产生的过度分割。

(3)控制标记符的分水岭分割

当直接用梯度进行分水岭变换时,容易造成过度分割,为了改善这样的情况,采用基于标记符的方式进行分割。

编写实验代码:

f = imread('C:\Users\Public\Pictures\Sample Pictures\Fig1028(a).tif');
subplot(241),imshow(f),title('原始图像');
h = fspecial('sobel');
fd = tofloat(f);
g = sqrt(imfilter(fd,h,'replicate').^2+imfilter(fd,h,'replicate').^2);
L =watershed(g);
wr = L == 0;
subplot(242),imshow(wr),title('梯度幅度图像进行分水岭变换图像');
rm = imregionalmin(g);  %计算图像中所有的局部小区域的位置
subplot(243),imshow(rm),title('梯度幅值的局部小区域图像');
im = imextendedmin(f,2);  %用于计算比临近点更暗的图像中“低点”的集合
fim = f;
fim(im) = 175;
subplot(244),imshow(f,[]),title('内部标记符图像');
Lim = watershed(bwdist(im));
em = Lim == 0;
subplot(245),imshow(em,[]),title('外部标记符图像');
g2 = imimposemin(g,im|em);  %用来修改一幅图像,使得其只在指定的位置处取得局部最小值
subplot(246),imshow(g2),title('修改后的梯度幅值图像');
L2 = watershed(g2);
f2 = f;
f2(L2 == 0) = 255;
subplot(247),imshow(f2),title('最后的分割图像');

在这里插入图片描述在这里插入图片描述实验分析: 当直接使用梯度幅度方法进行分割处理时,发现图像过度分割非常严重,而这样的分割是没有意义的,并不是我们所需要的。当采用控制标记符分水岭分割算法时,能调整过度分割的界限,设置内部标记符和外部标记符,把所需要的内外部标记符联合起来,再次进行分割,因此可以得到我们所需要的分割效果。

2018-08-12 22:36:03 ml_ai_sun 阅读数 15302

一、图像边缘检测原理

基本思路:基于边缘检测的图像分割方法的基本思路是先确定图像中的边缘像素,然后再把这些像素连接在一起就构成所需的区域边界。

图像边缘:图像边缘,即表示图像中一个区域的终结和另一个区域的开始,图像中相邻区域之间的像素集合构成了图像的边缘。所以,图像边缘可以理解为图像灰度发生空间突变的像素的集合。图像边缘有两个要素,即:方向和幅度。沿着边缘走向的像素值变化比较平缓;而沿着垂直于边缘的走向,像素值则变化得比较大。因此,根据这一变化特点,通常会采用一阶和二阶导数来描述和检测边缘。

综上,图像中的边缘检测可以通过对灰度值求导数来确定,而导数可以通过微分算子计算来实现。在数字图像处理中,通常是利用差分计算来近似代替微分运算。 

二、微分算子

    常用的一阶微分算子有Roberts、Prewitt、Sobel等算子,常用的二阶微分算子有Laplace和Kirsh等算子。在实际处理操作中常用模板矩阵与图像像素值矩阵卷积来实现微分运算。

    由于垂直边缘的方向上的像素点和噪声都是灰度不连续点,所以变换到频域时,在频域均为高频分量,直接采用微分运算不可避免地会受到噪声的很大影响。 因此,微分算子只适用于图像噪声比较少的简单图像。针对此问题,LoG算子(Laplace of Gaussian)和Canny算子采取的方法是,先对图像进行平滑滤波,然后再用微分算子与图像进行卷积操作,这样处理会得到比较好的边缘检测结果。其中,LoG算子是采用Laplacian算子计算高斯函数的二阶导数,Canny算子是高斯函数的一阶导数,两种算子在抑制噪声和检测边缘之间取得了比较好的平衡。

1、roberts算子

2、prewitt算子


3、sobel算子

4、LoG算子(二阶微分算子)


LoG算子的特点: 
    1. 图像与高斯滤波器进行卷积,既平滑了图像又降低了噪声,孤立的噪声点和较小的结构组织将被滤除。 
    2. 在边缘检测时则仅考虑那些具有局部梯度最大值的点为边缘点,用拉普拉斯算子将边缘点转换成零交叉点,通过零交叉点的检测来实现边缘检测。 
    3. 缺点是在过滤噪声的同时使得原有的边缘一定程度上被平滑了。

5、canny算子

 Canny算子检测边缘点的方法基本思想是寻找图像梯度的局部最大值。 
    评价一个边缘检测算子的,一般考虑如下三个指标: 
    1. 低失误概率:在尽可能把所有边缘检测到的同时,减少将非边缘误判为边缘; 
    2. 高位置精度:检测出的边缘是真正的边界,检测到的边缘位置足够精确; 
    3. 检测得到的边界是单像素宽。 
    针对这三个指标,Canny在设计检测算子时提出了边缘检测算子的三个准则: 
    1. 信噪比准则; 
    2. 定义精度准则; 
    3. 单边缘响应准则。

    遵循这三个准则,Canny算子设计实现的步骤如下: 
    (1)首先用高斯滤波模板进行卷积以平滑图像; 
    (2)利用微分算子,计算梯度的幅值和方向; 
    (3)对梯度幅值进行非极大值抑制。即遍历图像,若某个像素的灰度值与其梯度方向上前后两个像素的灰度值相比不是最大,那么这个像素值置为0,即不是边缘; 
    (4)使用双阈值算法检测和连接边缘。即使用累计直方图计算两个阈值,凡是大于高阈值的一定是边缘;凡是小于低阈值的一定不是边缘。如果检测结果大于低阈值但又小于高阈值,那就要看这个像素的邻接像素中有没有超过高阈值的边缘像素,如果有,则该像素就是边缘,否则就不是边缘。

 

从左到右依次是原图、roberts、prewitt、sobel、LoG、canny

结论:边缘检测还是比较适用于噪声比较小的图像中,对于复杂图像不是很合适,二阶微分算子对噪声十分的敏感。