图像分割基于两个性质: 不连续性和相似性。一种是基于灰度的突变(如边缘),另一种是分为相似的区域。
3*3模板在某一点的响应:R= 。
是与之对应的图像像素的灰度。
点检测:
-1-1 -1 这是点检测的模板w,中心是孤立点时响应最强。若
-1 8 -1响应大于某一阈值,则称此处有孤立点。在恒定灰
-1-1 -1 度区域中,响应为零。
g=abs(imfilter(tofloat(f),w))>=T
线检测:
与上类似。
-1-1 -1 -1 2 -1
2 22 -1 2 -1 依次是水平线和垂直线检测模板。
-1-1 -1 -1 2 -1
edge函数检测边缘:
[g,t]=edge(f,‘method’,parameter)
method即边缘检测算子。
cannysobel Roberts Laplacian算子 Prewitt算子等看另一篇笔记。
canny边缘检测器最强。
使用edge等方法可以产生位于边缘上的像素,但因为噪声等因素的存在,会引入其他效应,我们一般在边缘检测算法后把边缘像素连接成线段。一种可行的方法是霍夫变换。
[H,theta,rho]=hough(f) 由图像得到霍夫矩阵,theta,rho
peaks=houghpeaks(H,NumPeaks) 找到指定数量(NumPeaks)的峰值。
lines=houghlines(f,theta,rho,peaks)返回一个结构数组lines.
结构数组的每个元素包括:
point1:[r1,c1] 一条线段的起点坐标
point2:[r2,c2] 这条线段的终点坐标
theta
rho 与线相关的角度和rho值。
画出线段:
fork=1:length(lines)
xy=[lines(k).point1; lines(k).point2]
plot(xy(:,1),xy(:,2)) %每次画一条线
end
阈值处理:
定义: 给定阈值T ,对于一幅图像中的像素f(x,y),若灰度值>T,
则f(x,y)=a; 若灰度值<=T,f(x,y)=b。 一般令a=1,b=0。
函数g=im2bw(f,level) imshow(g)g与f大小相同,f类图像的灰度值最大为max (uint8中为255),最小值为min。 则大于max*level(T)的像素设为max,否则变成min。level 在[0,1]之间。
1、基本的全局阈值处理:
给定初始阈值T,将图像的像素分为两部分。两部分的均值依次是m1和m2。更改
T=1/2(m1+m2) 如此迭代,直到T-Tnext小于某一数值为止。
然后用im2bw处理。灰度图像(grayscale image)转换成二值图像
G=im2bw(f,T/den) 其中,den是一个整数。
den的选取:f中的最大值/den=1
2、Otsu最佳全局阈值处理:
选择阈值K,使得
最大。
P1(K)和P2(K)依次是小于阈值像素的概率和大于阈值像素的概率。
m1(k)和m2(k)分别是这两个集合的均值。
mG是全图的均值。
函数graythresh()可以实现这一功能。
[T,SM]=graythresh(f)。如此,即得到阈值T。
另外,附录中的otsuthresh()函数可以通过输入给定图像的直方图
计算阈值T
[T,SM]=otsuthresh(f)
3、使用图像平滑改进全局阈值处理
当不能在源头上降低噪声并且阈值处理是所选择的分割方法时,首先可以对图像进行平滑,消除噪声的影响。 (均值滤波、中值滤波等等)
4、使用边缘改进全局阈值处理
适用情形:物体比背景小得多时,它们对直方图的贡献可以忽略不计,因此全局阈值处理将会失败,使用边缘信息可以改善这种情况。
(1) 使用任何方法对原图f(x,y)计算一幅边缘图像g(x,y)。边缘图像可以是梯度或者拉普拉斯算子的绝对值。
(2) 指定一个阈值T。
(3) 使用来自步骤2的阈值T对步骤1的图像做阈值处理得到GT(x,y)。
若g(x,y)>T GT(x,y)=1否则GT(x,y)=0
这幅图像用作一幅标记图像,以便在f(x,y)中选取“强边缘”像素。
(4) 仅使用f(x,y)中GT(x,y)为1的像素位置的像素来计算直方图。得到的直方图被0支配。因为我们感兴趣的是在于边界周围的分割值。因此,另直方图hp(1)=0
(5) 使用来自步骤4的直方图,采用Otsu方法全局分割。
附录中的自定义函数I=percentile2i(h,p)可以用来找出T。其中,h是图像的直方图,p是区间[0,1]的百分位。I是对应于第P个百分位的灰度级(也在区间[0,1]内)。
因为我们只想保留强边缘像素,因此T需要取大一些,例如 p=0.999
1、基于局部统计的可变阈值处理
在每个点(x,y)处计算一个阈值。
g=stdfilt(f,nhood)用于计算局部标准差。f是输入图像,nhood是由0和1组成的数组,其中非0元素指定用于计算局部标准差所用的邻域。nhood的尺寸在每个维度上必须为奇数,默认使用ones(3)。
自定义函数localmean用于计算局部均值
mean=localmean(f,nhood)
T=a*局部标准差+b*局部均值
或者
T=a*局部标准差+b*全局均值
自定义函数localthresh()用于实现局部阈值分割
g=localthresh(f,nhood,a,b,meantype)
meantype对应全局阈值或者局部阈值。
2、使用移动平均的图像阈值处理
自定义函数g=movingthresh(f,n,k) n是计算平均时所用的点数,k是[0,1]内的常数。
适用情形:
感兴趣的物体相对于图像尺寸来说较小或者较细(输入或手写文本图像通常满足)。
3、基于区域的分割
(1) 区域生长
区域生长是根据预先定义的生长准则将像素或者子区域组合成为更大区域的过程。基本方法是从一组“种子点”开始,降雨种子性质相似的那些邻域像素附加到每个种子上来形成这些生长区域(如特定的灰度范围或者颜色)。
自定义函数中由regiongrow函数来实现这一功能。
[g,NR,SI,TI]=regiongrow(f,S,T)
f是被分割的图像,参数S可以是一个数组(与f大小相同)或者一个标量。若S是一个数组,则它在种子点坐标处的值为1,其他地方的值为0。同样的,T可以是一个数组(与f大小相同)或者一个标量。如果是一个数组则在每个点都对应一个阈值,否则是一个全局阈值。
G是分割后的图像,每个区域的成员都用一个不同的整数值标注。参数NR是所找到的区域的数量。参数SI是包含种子点的一幅图像。参数TI是包含处理连接性前就已经通过阈值测试的像素的一幅图像。
SI和TI的大小均与f的大小相同。
(2) 区域分离与聚合
将图像细分为一组任意的不相交区域,然后聚合/分离这些区域,完成区域分割。
P(Ri)=TRUE。表示区域Ri满足某种逻辑属性。
令R代表整个图像区域,选择属性P。分割R的一种方法是把R连续地细分成越来越小的象限区域,以便对任何区域Ri都有P(Ri)=TRUE。我们从整个区域开始:如果P(R) =FALSE,就把图像分成4象限;如果对每个4象限来说,P都是FALSE,就再细分象限为子象限,这样继续下去。这种特别的分离技术有一种方便的表现方法,叫做四叉树;这是一棵树,树中的每个节点都恰好有4个后代,如图10-22所示。子图像对应四叉树的节点,有时称为四叉区域或四叉图像。注意,树的根对应整幅图像,每个节点对应被再分为4个后代节点的节点。在这种情况下,只有R4被进一步细分了。
如果只使用分离,最终的部分通常包括具有相同属性的邻近区域,这个缺点可以通过下边的合并及分离来解决。如果满足10.4.1节的限制,将要求只合并邻近的区域,合并像素满足属性P。也就是说,两个邻近的区域Rj和Rk,只有在满足P (Rj∪Rk)=TURE的时候才能合并。
无法进一步聚合时,停止操作。
工具箱中可以使用qtdecomp函数实现四叉树分解。
Z=qtdecomp(f,@split_test,parameters)
f是输入图像,Z是Z是包括四叉树结构的稀疏矩阵。如果Z(k, m)非零,那么(k,m)是分解块的左上角,而且块的大小是Z(k, m)。
为了在四叉树分解中得到实际的四叉区域像素值,使用qtgetblk函数,语法是:
[vals,r,c]=qtgetblk(f,Z,m)
其中,vals是数组,vals包含f中四叉树分解的尺寸为m×m的块的值,Z是由qtdecomp返回的稀疏矩阵。参数r和c是包含块的左上角行和列坐标的向量。
自定义函数splitmerge函数拥有如下调用语法:
g=splitmerge(f,mindim,@predicate)
在这里,f是输入图像,g是输出图像,其中的每个连接区域都用不同的整数标注。参数mindim定义在分解中允许的最小块;该参数必须是2的正整数次幂,允许分解下至1×1像素大小的区域,虽然这么精细的细节在实际中并不常用。函数predicate是用户自定义函数,语法为:
flag=predicate(region)
如果region(区域)中的像素满足函数中由代码定义的属性,函数就必须被写成返回true(逻辑1);否则,flag的值就必须是false(逻辑0)。
函数splitmerge的结构很简单。首先,图像被函数qtdecomp分块。函数split_test使用predicate来决定区域是否应该被分离。因为当区域被分成4个时,我们并不知道产生的4个区域中的哪一个将通过属性测试。在了解了在分离的图像中哪一个区域通过测试之后,考查一下区域是有必要的。函数predicate也用于这个目的。任何通过测试的四叉区域都用1填充,任何没有通过测试的用0填充。标识数组可在每个被填充了1的区域通过选择元素来创建。标识数组连同分割的图像一起被用于决定区域的连通性(邻接性);函数imreconstruct也用于这一目的。
4、使用分水岭变换的分割
将灰度图像视为一个拓扑平面,f(x,y)的值被解释为高度。分水岭变换将找到灰度图像中的集水盆地和脊线,集水盆地就是我们要识别的物体或者区域。
(1) 使用距离变换的分水岭分割
距离变换可以使用bwdist函数来实现
D=bwdist(f)
D与f大小相同,每个点的值是f中该点距离最近的非零值的距离。
首先,正如10.3.1节中描述的那样,使用im2bw和graythresh把图像变换为二值图像。
下一步是对图像求补,计算距离变换。然后,用函数watershed计算距离变换的负分水岭变换。该函数的调用语法是:
L=watershed(A,conn)
其中,L是在9.4节讨论和定义过的标记矩阵。A是输入数组(一般可以是任何维数,但在本章是二维),并且conn指定了连通性(对于二维数组是4或8(默认值))。在L中,正整数与汇水盆地相对应,零值指出分水岭的脊线像素
gc=~g;
D=bwdist(gc);
L=watershed(-D);
w=L==0;
图10-26(b)和(c)显示了求补后的图像及其距离变换。因为L的0值像素是分水岭的脊线像素,前面代码的最后一行计算二值图像w,图中仅显示这些像素。分水岭的脊线图像显示于图10-26(d)中。最后,使用原始的二值图像和图像w的"补",通过逻辑AND操作完成分割,如图10-26(e)所示:
g2=g&-w;
常出现过分割问题。
(2)使用梯度的分水岭分割
在使用分水岭变换进行分割之前,常用梯度幅度来对灰度图像进行预处理。
即在梯度幅度图像g上做分水岭变换。
一种处理过分割的方法是:在分水岭变换之前,首先平滑梯度图像。
(3)标记符控制的分水岭分割
一种控制过分割的方法基于标记符这一概念。在每个感兴趣的物体的内部有一组标记符,在背景中有一组标记符。
一部分是由于存在大量的小区域,工具箱函数imreginalmin计算图像中所有的局部小区域的位置,调用语法为:
rm=imregionalmin(f)
其中,f是灰度图像,rm是二值图像,rm的前景像素标记出局部小区域的位置。可以把imregionalmin函数用于梯度图像,并查看为什么分水岭函数会产生许多小的汇水盆地:
rm=imregionalmin(g);
图10-28(c)显示的多数局部小区域的位置非常浅,并且表现的细节与我们的分割问题不相干。为了消除这些无关的小区域,可以使用工具箱函数imextendedmin,计算比近邻点更暗(用某个高度阈值)的图像中"低点"的集合。这个函数的调用语法为:
im=imextendedmin(f,h)
其中,f是灰度图像,h是高度阈值,im是一幅二值图像,im的前景像素标记了深的局部小区域的位置。在这里,我们用函数imextendedmin来得到内部标记符的集合:
im=imexrendedmin(f,2);
fim=f;
fim(im)=175;
最后两行将灰斑点的最小区域位置叠加在原始图像上,如图10-28(d)所示。可以看到,得到的斑点的确很合理地标记了我们想要分割的物体。
接下来,我们必须寻找外部标记符,或者我们确信的属于背景的像素。此处遵循的方法是用已找到的像素来标记背景,这些像素恰好位于内部标记符的中间。令人惊讶的是,通过解决其他分水岭问题,可以做到这些;特别是计算内部标记符图像im的距离变换的分水岭变换:
Lim=watershed(bwdist(im));
em=Lim==0;
图10-28(e)显示了二值图像em中的分水岭脊线。因为这些脊线位于由im标记的暗斑点之间,所以它们应该是很好的外部标记符。
我们用内部和外部标记符可以采用称为最小覆盖的过程改进梯度图像。最小覆盖技术可以改进灰度图像,因此,局部最小区域仅发生在标记过的位置。如果需要移动所有的局部最小区域,其他像素值就需要上推。工具箱函数imimposition可实现这种技术,调用语法如下:
mp=imimposemin(f,mask)
其中,f是灰度图像,mask是二值图像,mask的前景像素标记了输出图像mp中局部最小区域的期望位置。通过在内部和外部标记符的位置覆盖局部最小区域,可以改进梯度图像:
g2=imimposemin(g,im|em);
图10-28(f)显示了结果。最后,我们准备计算改进了标记符的梯度图像的分水岭变换,并研究ridgelines函数的调用结果:
L2=watershed(g2);
ff2=f;
f2(L2==0)=255;