分水岭算法opencv
A. 分水岭算法的应用
数学形态学一个应用是分水岭算法,为了便于理解,可以将图像的灰度空间与地球表面的地形高度相类比,据此,发明了应用于图像领域的分水岭算法。
假设,如下图所示的一个岛屿,要从 点走到 点,虚线所表示的是最短的直线距离,也就是欧式距离,考虑到现实情况,不能穿过水面到达目标地点,所以,能够从起点到终点的实际通行路线中最短的距离成为测地线距离。
通过以上分析,给出测地线距离的定义:
给定指定连通域 ,测地线距离就是 中两个像素点 和 之间的最短(可执行)路径的长度,用公式定义如下:
如下图所示,假定一个连通域 包含了若干个子区域 ,用公式表示 所表示的测地线影响域为:
以上公式可以理解为,区域 中的像素点到 域的测地线距离比其他域更小的点的轨迹的集合,也就是以 域中的种子点出发,其测地线距离比其他域的种子点都要小的点集所构成的区域。如下图所示:
SKIZ表示区域 中的点不属于任何一个测地线影响域,也就是域 中的点到两个测地线影响域的中测地线距离相等。区域 中构成 的SKIZ,记作 ,用公式的表述如下:
注意:, 表示区域 以外的 中的所有点的集合集合
如下图所示的山脉地形图,包含山谷和山峰,在水平面不断上升的过程中,会逐渐淹没掉一些较低的区域,而为了防止水溢出,需要不断在山脊上修建大坝,这个过程不断进行,最后会得到一个区域分割的效果。
在一副图像上实现分水岭算法,与上述过程相似,只不过是通过灰度值充当水平面的角色,对图像进行不断的填埋,最后得到区域分割的效果图。
如上图所示的动画中,不断用灰度值代表的水平面淹没图像中的最小值,最后得到分割后的图像。综上,分水岭算法的步骤可以总结如下:
如下图所示,另外一种分水岭算法的原理是,指定初始的种子点,只对种子点所在的邻域像素进行分类,而不考虑其他区域。
如下图所示的图片,以最小点开始,进行分水岭算法,会将整幅图分割成许多小区域,造成过分割的效果。为了解决这一问题,有以下三种解决方案:
最后,通过合并一些小区域再利用分水岭算法进行分割的效果如下图所示:
如下图所示,展示了通过分水岭算法分割血细胞的流程:
B. 图像分割——分水岭算法
姓名:谢意远
学号:19021110366T
嵌牛导读:图像中的目标物体是连接在一起的,则分割起来很困难,分水岭分割算法经常用于处理这类问题,通常会取得比较好的效果。
嵌牛鼻子:图像分割、分水岭绝源算法
嵌牛提问:分水岭算法具体有哪些步骤?
嵌牛正文:
一、综述
分水岭分割算法把图像看成一幅“地形图”,其中亮度比较强的区域像素值较大,而比较暗的区域像素值较小,通过寻找“汇水盆地”和“分水岭界限”,对图像进行分割。而直接应用分水岭分割算法的效果往往并不好,如果在图像中对前景对象和背景对象进行标注区别,再应用分水岭算法会取得较好的分割效果。基于标记控制的分水岭分割方法有以下基本步骤:
1 综述
分水岭分割算法把图像看成一幅“地形图”,其中亮度比较强的区域像素值较大,而比较暗的区域像素值较小,通过寻找“汇水盆地”和“分水岭界限”,对图像进行分割。直接应用分水岭分割算法的效果往往并不好,如果在图像中对前景对象和背景对象进行标注区别,再应用分水岭算法会取得较好的分割效果。基于标记控制的分水岭分割方法有以下基本步骤:
1.计算分割函数。图像中较暗的区域是要分割的对象
2.计算前景标志。这些是并运态每个对象内部连接的斑点像素。
3.计算背景标志。这些是不属于任何对象的要素。
4.修改分割函数,使其仅在前景和后景标记位置有极小值。
5.对修改后的分割函数做分水岭变换计算。
使用MATLAB图像处理工具箱
注:期间用到了很多图像处理工具箱的函数,例如fspecial、imfilter、watershed、label2rgb、imopen、imclose、imreconstruct、imcomplement、imregionalmax、bwareaopen、graythresh和imimposemin函数等。
2 步骤
第一步:读入彩色图像,将其转化成灰度图像
clc; clear all; close all;
rgb = imread('pears.png');
if ndims(rgb) == 3
I = rgb2gray(rgb);
else
I = rgb;
end
figure('units', 'normalized', 'position', [0 0 1 1]);
第2步:将梯度幅值作为分割函数
使用Sobel边缘算子对图像进行水平和垂直方向的滤波,然后求取模值,sobel算子滤波后的图像在边界处会显示比较大的值,在没有边界处的值会很小。
hy = fspecial('sobel');
hx = hy';
Iy = imfilter(double(I), hy, 'replicate');
Ix = imfilter(double(I), hx, 'replicate');
gradmag = sqrt(Ix.^2 + Iy.^2);
figure('units', 'normalized', 'position', [0 0 1 1]);
subplot(1, 2, 1); imshow(I,[]), title('灰度图像')
subplot(1, 2, 2); imshow(gradmag,[]), title('梯度幅值图像')
可否直接对梯度幅值图像使用分水岭算法?
L = watershed(gradmag);
Lrgb = label2rgb(L);
figure('units', 'normalized', 'position', [0 0 1 1]);
subplot(1, 2, 1); imshow(gradmag,[]), title('梯度幅值图像')
subplot(1, 2, 2); imshow(Lrgb); title('梯度幅值做分水岭变换')
直接使用梯度模值图像进行分水岭算法得到的结果往往会存在过度分割的现悄指象。因此通常需要分别对前景对象和背景对象进行标记,以获得更好的分割效果。
第3步:标记前景对象
有多种方法可以应用在这里来获得前景标记,这些标记必须是前景对象内部的连接斑点像素。这个例子中,将使用形态学技术“基于开的重建”和“基于闭的重建”来清理图像。这些操作将会在每个对象内部创建单位极大值,使得可以使用imregionalmax来定位。
开运算和闭运算:先腐蚀后膨胀称为开;先膨胀后腐蚀称为闭。开和闭这两种运算可以除去比结构元素小的特定图像细节,同时保证不产生全局几何失真。开运算可以把比结构元素小的突刺滤掉,切断细长搭接而起到分离作用;闭运算可以把比结构元素小的缺口或孔填充上,搭接短的间隔而起到连接作用。
开操作是腐蚀后膨胀,基于开的重建(基于重建的开操作)是腐蚀后进行形态学重建。下面比较这两种方式。首先,用imopen做开操作。
se = strel('disk', 20);
Io = imopen(I, se);
figure('units', 'normalized', 'position', [0 0 1 1]);
subplot(1, 2, 1); imshow(I, []); title('灰度图像');
subplot(1, 2, 2); imshow(Io), title('图像开操作')
接下来,通过腐蚀后重建来做基于开的重建计算。
Ie = imerode(I,se)
Iobr = imreconstruct(Ie,I);
figure('units', 'normalized', 'position', [0 0 1 1]);
subplot(1, 2, 1); imshow(I, []); title('灰度图像');
subplot(1, 2, 2); imshow(Iobr, []), title('基于开的重建图像')
开操作后,接着进行闭操作,可以移除较暗的斑点和枝干标记。对比常规的形态学闭操作和基于闭的重建操作。首先,使用imclose:
Ioc = imclose(Io, se);
Ic = inclose(I,se);
figure('units', 'normalized', 'position', [0 0 1 1]);
subplot(2, 2, 1); imshow(I, []); title('灰度图像');
subplot(2, 2, 2); imshow(Io, []); title('开操作图像');
subplot(2, 2, 3); imshow(Ic, []); title('闭操作图像');
subplot(2, 2, 4); imshow(Ioc, []), title('开闭操作');
现在使用imdilate,然后使用imreconstruct。注意必须对输入图像求补,对imreconstruct输出图像求补。IM2 = imcomplement(IM)计算图像IM的补集。IM可以是二值图像,或者RGB图像。IM2与IM有着相同的数据类型和大小。
Iobrd = imdilate(Iobr, se);
Iobrcbr = imreconstruct(imcomplement(Iobrd), imcomplement(Iobr));
Iobrcbr = imcomplement(Iobrcbr);
figure('units', 'normalized', 'position', [0 0 1 1]);
subplot(2, 2, 1); imshow(I, []); title('灰度图像');
subplot(2, 2, 2); imshow(Ioc, []); title('开闭操作');
subplot(2, 2, 3); imshow(Iobr, []); title('基于开的重建图像');
subplot(2, 2, 4); imshow(Iobrcbr, []), title('基于闭的重建图像');
通过比较Iobrcbr和loc可以看到,在移除小污点同时不影响对象全局形状的应用下,基于重建的开闭操作要比标准的开闭重建更加有效。计算Iobrcbr的局部极大来得到更好的前景标记。
fgm = imregionalmax(Iobrcbr);
figure('units', 'normalized', 'position', [0 0 1 1]);
subplot(1, 3, 1); imshow(I, []); title('灰度图像');
subplot(1, 3, 2); imshow(Iobrcbr, []); title('基于重建的开闭操作');
subplot(1, 3, 3); imshow(fgm, []); title('局部极大图像');
为了帮助理解这个结果,叠加前景标记到原图上。
It1 = rgb(:, :, 1);
It2 = rgb(:, :, 2);
It3 = rgb(:, :, 3);
It1(fgm) = 255; It2(fgm) = 0; It3(fgm) = 0;
I2 = cat(3, It1, It2, It3);
figure('units', 'normalized', 'position', [0 0 1 1]);
subplot(2, 2, 1); imshow(rgb, []); title('原图像');
subplot(2, 2, 2); imshow(Iobrcbr, []); title('基于重建的开闭操作');
subplot(2, 2, 3); imshow(fgm, []); title('局部极大图像');
subplot(2, 2, 4); imshow(I2); title('局部极大叠加到原图像');
注意到大多闭塞处和阴影对象没有被标记,这就意味着这些对象在结果中将不会得到合理的分割。而且,一些对象的前景标记会一直到对象的边缘。这就意味着应该清理标记斑点的边缘,然后收缩它们。可以通过闭操作和腐蚀操作来完成。
se2 = strel(ones(5,5));
fgm2 = imclose(fgm, se2);
fgm3 = imerode(fgm2, se2);
figure('units', 'normalized', 'position', [0 0 1 1]);
subplot(2, 2, 1); imshow(Iobrcbr, []); title('基于重建的开闭操作');
subplot(2, 2, 2); imshow(fgm, []); title('局部极大图像');
subplot(2, 2, 3); imshow(fgm2, []); title('闭操作');
subplot(2, 2, 4); imshow(fgm3, []); title('腐蚀操作');
这个过程将会留下一些偏离的孤立像素,应该移除它们。可以使用bwareaopen,用来移除少于特定像素个数的斑点。BW2 = bwareaopen(BW,P)从二值图像中移除所以少于P像素值的连通块,得到另外的二值图像BW2。
fgm4 = bwareaopen(fgm3, 20);
It1 = rgb(:, :, 1);
It2 = rgb(:, :, 2);
It3 = rgb(:, :, 3);
It1(fgm4) = 255; It2(fgm4) = 0; It3(fgm4) = 0;
I3 = cat(3, It1, It2, It3);
figure('units', 'normalized', 'position', [0 0 1 1]);
subplot(2, 2, 1); imshow(I2, []); title('局部极大叠加到原图像');
subplot(2, 2, 2); imshow(fgm3, []); title('闭腐蚀操作');
subplot(2, 2, 3); imshow(fgm4, []); title('去除小斑点操作');
subplot(2, 2, 4); imshow(I3, []); title('修改局部极大叠加到原图像');
第4步:计算背景标记
现在,需要标记背景。在清理后的图像Iobrcbr中,暗像素属于背景,所以可以从阈值操作开始。
bw =im2bw(Iobrcbr, graythresh(Iobrcbr));
figure('units', 'normalized', 'position', [0 0 1 1]);
subplot(1, 2, 1); imshow(Iobrcbr, []); title('基于重建的开闭操作');
subplot(1, 2, 2); imshow(bw, []); title('阈值分割');
背景像素在黑色区域,但是理想情形下,不必要求背景标记太接近于要分割的对象边缘。通过计算“骨架影响范围”来“细化”背景,或者SKIZ,bw的前景。这个可以通过计算bw的距离变换的分水岭变换来实现,然后寻找结果的分水岭脊线(DL==0)。D = bwdist(BW)计算二值图像BW的欧几里得矩阵。对BW的每一个像素,距离变换指定像素和最近的BW非零像素的距离。bwdist默认使用欧几里得距离公式。BW可以由任意维数,D与BW有同样的大小。
D = bwdist(bw);
DL = watershed(D);
bgm = DL == 0;
figure('units', 'normalized', 'position', [0 0 1 1]);
subplot(2, 2, 1); imshow(Iobrcbr, []); title('基于重建的开闭操作');
subplot(2, 2, 2); imshow(bw, []); title('阈值分割');
subplot(2, 2, 3); imshow(label2rgb(DL), []); title('分水岭变换示意图');
subplot(2, 2, 4); imshow(bgm, []); title('分水岭变换脊线图');
第5步:计算分割函数的分水岭变换
函数imimposemin可以用来修改图像,使其只是在特定的要求位置有局部极小。这里可以使用imimposemin来修改梯度幅值图像,使其只在前景和后景标记像素有局部极小。
gradmag2 = imimposemin(gradmag, bgm | fgm4);
figure('units', 'normalized', 'position', [0 0 1 1]);
subplot(2,2,1)imshow(bgm,[]);title('分水岭变换脊线图');
subplot(2, 2, 2); imshow(fgm4, []); title('前景标记');
subplot(2, 2, 3); imshow(gradmag, []); title('梯度幅值图像');
subplot(2, 2, 4); imshow(gradmag2, []); title('修改梯度幅值图像');
最后,可以做基于分水岭的图像分割计算。
第6步:查看结果
一个可视化技术是叠加前景标记、背景标记、分割对象边界到初始图像。可以使用膨胀来实现某些要求,比如对象边界,更加清晰可见。对象边界定位于L==0的位置。
It1 = rgb(:, :, 1);
It2 = rgb(:, :, 2);
It3 = rgb(:, :, 3);
fgm5 = imdilate(L == 0, ones(3, 3)) | bgm | fgm4;
It1(fgm5) = 255; It2(fgm5) = 0; It3(fgm5) = 0;
I4 = cat(3, It1, It2, It3);
figure('units', 'normalized', 'position', [0 0 1 1]);
subplot(1, 2, 1); imshow(rgb, []); title('原图像');
subplot(1, 2, 2); imshow(I4, []); title('标记和对象边缘叠加到原图像');
可视化说明了前景和后景标记如何影响结果。在几个位置,部分的较暗对象与它们相邻的较亮的邻接对象相融合,这是因为受遮挡的对象没有前景标记。
另外一个有用的可视化技术是将标记矩阵作为彩色图像进行显示。标记矩阵,比如通过watershed和bwlabel得到的,可以使用label2rgb转换到真彩图像来显示。
Lrgb = label2rgb(L,'jet', 'w', 'shuffle');
figure('units', 'normalized', 'position', [0 0 1 1]);
subplot(1, 2, 1); imshow(rgb, []); title('原图像');
subplot(1, 2, 2); imshow(Lrgb); title('彩色分水岭标记矩阵');
可以使用透明度来叠加这个伪彩色标记矩阵在原亮度图像上进行显示。
figure('units', 'normalized', 'position', [0 0 1 1]);
subplot(1, 2, 1); imshow(rgb, []); title('原图像');
subplot(1, 2, 2); imshow(rgb, []); hold on;
himage = imshow(Lrgb);
set(himage, 'AlphaData', 0.3);
title('标记矩阵叠加到原图像');
C. 图像分割最好方法
1.基于阈值的分割方法
阈值法的基本思想是基于图像的灰度特征来计算一个或多个灰度阈值,并将图像中每个像素的灰度值与阈值作比较,最后将像素根据比较结果分到合适的类别中。因此,该方法最为关键的一步就是按照某个准则函数来求解最佳灰度阈值。
阈值法特别适用于目标和背景占据不同灰度级范围的图。图像若只有目标和背景两大类,那么只需要选取一个阈值进行分割,此方法成为单阈值分割;但是如果图像中有多个目标需要提取,单一阈值的分割就会出现作物,在这种情况下就需要选取多个阈值将每个目标分隔开,这种分割方法相应的成为多阈值分割。
2.基于区域的图像分割方法
基于区域的分割方法是以直接寻找区域为基础的分割技术,基于区域提取方法有两种基本形式:一种是区域生长,从单个像素出发,逐步合并以形成所需要的分割区域;另一种是从全局出发,逐步切割至所需的分割区域。
分水岭算法
分水岭算法是一个非常好理解的算法,它根据分水岭的构成来考虑图像的分割,现实中我们可以想象成有山和湖的景象,那么一定是水绕山山围水的景象。
分水岭分割方法,是一种基于拓扑理论的数学形态学的分割方法,其基本思想是把图像看作是测地学上的拓扑地貌,图像中每一点像素的灰度值表示该点的海拔高度,每一个局部极小值及其影响区域称为集水盆,而集水盆的边界则形成分水岭。分水岭的概念和形成可以通过模拟浸入过程来说明。在每一个局部极小值表面,刺穿一个小孔,然后把整个模型慢慢浸入水中,随着浸入的加深,每一个局部极小值的影响域慢慢向外扩展,在两个集水盆汇合处构筑大坝,即形成分水岭。
D. 分水岭图像分割中,常常用梯度图像代替原始图像作为分水岭算法的输入的原因
分水岭算法是数学形态学分割方法中的经典算法,它将图像看作是地形学上被水覆盖的自然地貌,图像中的每一像素的灰度值表示该点的海拔高度,其每一个局部极小值及其影响区域称为集水盆,集水盆的边界则是分水岭,在各极小区域的表面打一个小孔,同时让水从小孔中涌出,并慢慢淹没极小区域周围的区域,那么各极小区域波及的范围,即是相应的集水盆,对应图像中的区域;不同区域的水流相遇时的界限,就是期望得到的分水岭,对应区域的边缘。分水岭变换可以保证分割区域的连续性和封闭性。
分水岭变换是从局部极小点开始,即只能是在梯度图中用, 原始图是转换后才能用于分水岭变换的
一般图像中存在多个极小值点,通常会存在过分割现象,可以采用梯度阈值分割改进或者采用标记分水岭算法将多个极小值区域连在一起
opencv提供分水岭的代码 可以找来看一下
E. 图像分割与提取
在图像处理的过程中,经常需要从图像中将前景对象作为目标图像分割或者提取出来。
例如,在视频监控中,观测到的是固定背景下的视频内容,而我们对背景本身并无兴趣,感兴趣的是背景中出现的车辆、行人或者其他对象。我们希望将这些对象从视频中提取出来,而忽略那些没有对象进入背景的视频内容。
在前面的章节中,我们讨论了如何使用诸如:
图像分割是图像处理过程中一种非常重要的操作。分水岭算法将图像形象地比喻为地理学上的地形表面,实现图像分割,该算法非常有效。
冈萨雷斯在《数字图像处理》一书中,对分水岭算法进行了细致的分析与介绍。OpenCV的官网建议学习者阅读国立巴黎高等矿业学校图像处理实验室(TheImage Processing Laboratory of MINES ParisTech)的CMM(Centre forMathematical Morphology)网站上关于分水岭算法的介绍和动画演示。
任何一幅灰度图像,都可以被看作是地理学上的地形表面,灰度值高的区域可以被看成是山峰,灰度值低的区域可以被看成是山谷。如图17-1所示,其中左图是原始图像,右图是其对应的“地形表面”。
如果我们向每一个山谷中“灌注”不同颜色的水(这里采并纯用了OpenCV官网的表述,冈萨雷斯将灌注表述为在山谷中打洞,然后让水穿过洞以均匀的速率上升)。那么,随着水位不断地升高,不敏盯同山谷的水就会汇集到一起。在这个过程中,为了防止不同山谷的水交汇,我们需要在水流可能汇合的地方构建堤坝。该过程将图像分成两个不同的集合:集水盆地和分水岭线。我们构建的堤坝就是分水岭线,也即对原始图像的分割。这就是分水岭算法桥蔽和。
在图17-2中,左图是原始图像,右图是使用分水岭算法得到的图像分割结果。在CMM的网站上不仅提供了该示例图像,还提供了动画演示效果
由于噪声等因素的影响,采用上述基础分水岭算法经常会得到过度分割的结果。过度分割会将图像划分为一个个稠密的独立小块,让分割失去了意义。
为了改善图像分割效果,人们提出了基于掩模的改进的分水岭算法。改进的分水岭算法允许用户将他认为是同一个分割区域的部分标注出来(被标注的部分就称为掩模)。这样,分水岭算法在处理时,就会将标注的部分处理为同一个分割区域。大家可以尝试使用微软PowerPoint中的“删除背景”功能,加深对此改进算法的理解。
F. 图像分割
图像阈值化分割是一种传统的最常用的图像分割方法,因其实现简单、计算量小、性能较稳定而成为图像分割中最基本和应用最广泛的分割技术。它特别适用于目标和背景占据不同灰度级范围的图像。它不仅可以极大的压缩数据量,而且也大大简化了分析和处理步骤,因此在很多情况下,是进行图像分析、特征提取与模式识别之前的必要的图像预处理过程。
图像阈值化的目的是要按照灰度级,对像素集合进行一个划分,得到的每个子集形成一个与现实景物相对应的区域,各个区域内部具有一致的属性,而相邻区域不具有这种一致属性。这样的划分可以通过从灰度级出发选取一个或多个阈值来实现。
基本原理是:通过设定不同的特征阈值,把图像象素点分为若干类。
常用的特征包括:直接来自原始图像的灰度或彩色特征;由原始灰度或彩色值变换得到的特征。
设原始图像为f(x,y),按照一定的准则f(x,y)中找到特征值T,将图像分割为两个部分,分割后的图像为:
若取:b0=0(黑),b1=1(白),即为我们通常所说的图像二值化。
阈值分割方法实际上是输入图像f到输出图像g的如下变换:
其中,T为阈值,对于物体的图像元素g(i,j)=1,对于背景的图像元素g(i,j)=0。
由此可见,阈值分割算法的关键是确定阈值,如果能确定一个合适的阈值就可准确地将图像分割开来。阈值确定后,将阈值与像素点的灰度值逐个进行比较,而且像素分割可对各像素并行地进行,分割的结果直接给出图像区域。
阈值分割的优点是计算简单、运算效率较高、速度快。有着各种各样的阈值处理技术,包括全局阈值、自适应阈值、最佳阈值等等。
阈值处理技术参看:
区域分割是讲图像按照相似性准则分成不同的区域,主要包括区域增长,区域分裂合并和分水岭等几种类型。
区域生长是一种串行区域分割的图像分割方法。区域生长是指从某个像素出发,按照一定的准则,逐步加入邻近像素,当满足一定的条件时,区域生长终止。区域生长的好坏决定于1. 初始点(种子点)的选取。 2. 生长准则。 3. 终止条件 。区域生长是从某个或者某些像素点出发,最后得到整个区域,进而实现目标的提取。
区域生长的基本思想是将具有相似性质的像素集合起来构成区域。具体先对每个需要分割的区域找一个种子像素作为生长的起点,然后将种子像素周围邻域中与种子像素有相同或相似性质的像素(根据某种事先确定的生长或相似准则来判定)合并到种子像素所在的区域中。将这些新像素当作新的种子像素继续进行上面的过程,直到再没有满足条件的像素可被包括进来。这样一个区域就长成了。
区域生长需要选择一组能正确代表所需区域的种子像素,确定在生长过程中的相似性准则,制定让生长停止的条件或准则。相似性准则可以是灰度级、彩色、纹理、梯度等特性。选取的种子像素可以是单个像素,也可以是包含若干个像素的小区域。大部分区域生长准则使用图像的局部性质。生长准则可根据不同原则制定,而使用不同的生长准则会影响区域生长的过程。
图1是区域增长的示例。
区域生长是一种古老的图像分割方法,最早的区域生长图像分割方法是由Levine等人提出的。该方法一般有两种方式,一种是先给定图像中要分割的目标物体内的一个小块或者说种子区域(seed point),再在种子区域基础上不断将其周围的像素点以一定的规则加入其中,达到最终将代表该物体的所有像素点结合成一个区域的目的;另一种是先将图像分割成很多的一致性较强,如区域内像素灰度值相同的小区域,再按一定的规则将小区域融合成大区域,达到分割图像的目的,典型的区域生长法如T. C. Pong等人提出的基于小面(facet)模型的区域生长法,区域生长法固有的缺点是往往会造成过度分割,即将图像分割成过多的区域
区域生长实现的步骤如下:
区域分裂合并算法的基本思想是先确定一个分裂合并的准则,即区域特征一致性的测度,当图像中某个区域的特征不一致时就将该区域分裂成4个相等的子区域,当相邻的子区域满足一致性特征时则将它们合成一个大区域,直至所有区域不再满足分裂合并的条件为止。当分裂到不能再分的情况时,分裂结束,然后它将查找相邻区域有没有相似的特征,如果有就将相似区域进行合并,最后达到分割的作用。在一定程度上区域生长和区域分裂合并算法有异曲同工之妙,互相促进相辅相成的,区域分裂到极致就是分割成单一像素点,然后按照一定的测量准则进行合并,在一定程度上可以认为是单一像素点的区域生长方法。区域生长比区域分裂合并的方法节省了分裂的过程,而区域分裂合并的方法可以在较大的一个相似区域基础上再进行相似合并,而区域生长只能从单一像素点出发进行生长(合并)。
反复进行拆分和聚合以满足限制条件的算法。
令R表示整幅图像区域并选择一个谓词P。对R进行分割的一种方法是反复将分割得到的结果图像再次分为四个区域,直到对任何区域Ri,有P(Ri)=TRUE。这里是从整幅图像开始。如果P(R)=FALSE,就将图像分割为4个区域。对任何区域如果P的值是FALSE.就将这4个区域的每个区域再次分别分为4个区域,如此不断继续下去。这种特殊的分割技术用所谓的四叉树形式表示最为方便(就是说,每个非叶子节点正好有4个子树),这正如图10.42中说明的树那样。注意,树的根对应于整幅图像,每个节点对应于划分的子部分。此时,只有R4进行了进一步的再细分。
如果只使用拆分,最后的分区可能会包含具有相同性质的相邻区域。这种缺陷可以通过进行拆分的同时也允许进行区域聚合来得到矫正。就是说,只有在P(Rj∪Rk)=TRUE时,两个相邻的区域Rj和Rk才能聚合。
前面的讨论可以总结为如下过程。在反复操作的每一步,我们需要做:
可以对前面讲述的基本思想进行几种变化。例如,一种可能的变化是开始时将图像拆分为一组图象块。然后对每个块进一步进行上述拆分,但聚合操作开始时受只能将4个块并为一组的限制。这4个块是四叉树表示法中节点的后代且都满足谓词P。当不能再进行此类聚合时,这个过程终止于满足步骤2的最后的区域聚合。在这种情况下,聚合的区域可能会大小不同。这种方法的主要优点是对于拆分和聚合都使用同样的四叉树,直到聚合的最后一步。
分水岭分割方法,是一种基于拓扑理论的数学形态学的分割方法,其基本思想是把图像看作是测地学上的拓扑地貌,图像中每一点像素的灰度值表示该点的海拔高度,每一个局部极小值及其影响区域称为集水盆,而集水盆的边界则形成分水岭。分水岭的概念和形成可以通过模拟浸入过程来说明。在每一个局部极小值表面,刺穿一个小孔,然后把整个模型慢慢浸入水中,随着浸入的加深,每一个局部极小值的影响域慢慢向外扩展,在两个集水盆汇合处构筑大坝,即形成分水岭。
分水岭的计算过程是一个迭代标注过程。分水岭比较经典的计算方法是L. Vincent提出的。在该算法中,分水岭计算分两个步骤,一个是排序过程,一个是淹没过程。首先对每个像素的灰度级进行从低到高排序,然后在从低到高实现淹没过程中,对每一个局部极小值在h阶高度的影响域采用先进先出(FIFO)结构进行判断及标注。
分水岭变换得到的是输入图像的集水盆图像,集水盆之间的边界点,即为分水岭。显然,分水岭表示的是输入图像极大值点。因此,为得到图像的边缘信息,通常把梯度图像作为输入图像,即
分水岭算法对微弱边缘具有良好的响应,图像中的噪声、物体表面细微的灰度变化,都会产生过度分割的现象。但同时应当看出,分水岭算法对微弱边缘具有良好的响应,是得到封闭连续边缘的保证的。另外,分水岭算法所得到的封闭的集水盆,为分析图像的区域特征提供了可能。
为消除分水岭算法产生的过度分割,通常可以采用两种处理方法,一是利用先验知识去除无关边缘信息。二是修改梯度函数使得集水盆只响应想要探测的目标。
为降低分水岭算法产生的过度分割,通常要对梯度函数进行修改,一个简单的方法是对梯度图像进行阈值处理,以消除灰度的微小变化产生的过度分割。即
程序可采用方法:用阈值限制梯度图像以达到消除灰度值的微小变化产生的过度分割,获得适量的区域,再对这些区域的边缘点的灰度级进行从低到高排序,然后在从低到高实现淹没的过程,梯度图像用Sobel算子计算获得。对梯度图像进行阈值处理时,选取合适的阈值对最终分割的图像有很大影响,因此阈值的选取是图像分割效果好坏的一个关键。缺点:实际图像中可能含有微弱的边缘,灰度变化的数值差别不是特别明显,选取阈值过大可能会消去这些微弱边缘。
参考文章:
图像分割的一种重要途径是通过边缘检测,即检测灰度级或者结构具有突变的地方,表明一个区域的终结,也是另一个区域开始的地方。这种不连续性称为边缘。不同的图像灰度不同,边界处一般有明显的边缘,利用此特征可以分割图像。
图像中边缘处像素的灰度值不连续,这种不连续性可通过求导数来检测到。对于阶跃状边缘,其位置对应一阶导数的极值点,对应二阶导数的过零点(零交叉点)。因此常用微分算子进行边缘检测。常用的一阶微分算子有Roberts算子、Prewitt算子和Sobel算子,二阶微分算子有Laplace算子和Kirsh算子等。在实际中各种微分算子常用小区域模板来表示,微分运算是利用模板和图像卷积来实现。这些算子对噪声敏感,只适合于噪声较小不太复杂的图像。
由于边缘和噪声都是灰度不连续点,在频域均为高频分量,直接采用微分运算难以克服噪声的影响。因此用微分算子检测边缘前要对图像进行平滑滤波。LoG算子和Canny算子是具有平滑功能的二阶和一阶微分算子,边缘检测效果较好,
在边缘检测算法中,前三个步骤用得十分普遍。这是因为大多数场合下,仅仅需要边缘检测器指出边缘出现在图像某一像素点的附近,而没有必要指出边缘的精确位置或方向.边缘检测误差通常是指边缘误分类误差,即把假边缘判别成边缘而保留,而把真边缘判别成假边缘而去掉.边缘估计误差是用概率统计模型来描述边缘的位置和方向误差的.我们将边缘检测误差和边缘估计误差区分开,是因为它们的计算方法完全不同,其误差模型也完全不同.
Roberts算子 :边缘定位准,但是对噪声敏感。适用于边缘明显且噪声较少的图像分割。Roberts边缘检测算子是一种利用局部差分算子寻找边缘的算子,Robert算子图像处理后结果边缘不是很平滑。经分析,由于Robert算子通常会在图像边缘附近的区域内产生较宽的响应,故采用上述算子检测的边缘图像常需做细化处理,边缘定位的精度不是很高。
Prewitt算子 :对噪声有抑制作用,抑制噪声的原理是通过像素平均,但是像素平均相当于对图像的低通滤波,所以Prewitt算子对边缘的定位不如Roberts算子。
Sobel算子 :Sobel算子和Prewitt算子都是加权平均,但是Sobel算子认为,邻域的像素对当前像素产生的影响不是等价的,所以距离不同的像素具有不同的权值,对算子结果产生的影响也不同。一般来说,距离越远,产生的影响越小。
Isotropic Sobel算子 :加权平均算子,权值反比于邻点与中心点的距离,当沿不同方向检测边缘时梯度幅度一致,就是通常所说的各向同性。
在边沿检测中,常用的一种模板是Sobel 算子。Sobel 算子有两个,一个是检测水平边沿的;另一个是检测垂直平边沿的 。Sobel算子另一种形式是各向同性Sobel(Isotropic Sobel)算子,也有两个,一个是检测水平边沿的,另一个是检测垂直平边沿的 。各向同性Sobel算子和普通Sobel算子相比,它的位置加权系数更为准确,在检测不同方向的边沿时梯度的幅度一致。由于建筑物图像的特殊性,我们可以发现,处理该类型图像轮廓时,并不需要对梯度方向进行运算,所以程序并没有给出各向同性Sobel算子的处理方法。
1971年,R.Kirsch[34]提出了一种能检测边缘方向的Kirsch算子新方法:它使用了8个模板来确定梯度幅度值和梯度的方向。
图像中的每个点都用8个掩模进行卷积,每个掩模对某个特定边缘方向作出最大响应。所有8个方向中的最大值作为边缘幅度图像的输出。最大响应掩模的序号构成了对边缘方向的编码。
Kirsch算子的梯度幅度值用如下公式:
不同检测算子的对比:
参考文章:
文章引用于 木夜溯
编辑 Lornatang
校准 Lornatang
G. 如何从入门开始学习OpenCV
方法如下:
先去下载最新版OpenCV,网址如下:http://nchc.dl.sourceforge.net/project/opencvlibrary/opencv-win/2.4.3/OpenCV-2.4.3.exe。下载完成后解压到相应目录。本人解压到D:Program FilesOpenCV2.4.3。
有的文章提到使用CMake把OpenCV下面的范例生成为Visual Studio的工程,此处我没有这样做。直接使用范例。这里先把OpenCV目录下面的几个重要目录做个说明:
doc目录:主要包含OpenCV的帮助文档。其中opencv2refman.pdf主要是OpenCV的各种类和函数的使用说明。
opencv_tutorials.pdf,主要是下面教学代码目录里面各个教学范例的简单讲解。
opencv_cheatsheet.pdf主要是最常用OpenCV类和函数的集合。此3个PDF文档对自学者帮助最大。
samplescpp utorial_code目录:里面包含基本教学代码。和上面的opencv_tutorials.pdf文档遥相呼应,构成一个完整的自学体系。
build目录:包含编译,调试,发布所需要的各类动态库,静态库,头文件等。因为OpenCV2.4.3好像只支持Visual Studio 2008以上版本,我在这里以Visual Studio 2008为例讲解如何让范例跑起来。
添加环境变量:此处我在path环境变量中添加如下目录:D:Program FilesOpenCV2.4.3uildx86vc9in。记住在前面一个目录后面加分号。
在Visual Studio中包含头文件目录:见附件中的图片,已经用红色矩形框标识如何操作。
在Visual Studio中包含库文件目录:见附件中的图片,已经用红色矩形框标识如何操作。4
建立一个新建Visual Studio VC win32控制台应用工程,这里我选择带预编译头的工程,省去添加cpp文件的工作。
代码创建:这里我选择samplescpp utorial_codeImgProcMorphology_2.cpp文件。先添加包含目录,如下(以后所有范例均可以如下添加):#include <opencv2/opencv.hpp>#include <stdio.h>然后复制代码。
编译文件:自然少不了要包含静态库,要添加的库(debug版和release差别就是文件名后多了一个d标识是debug版)如下:
debug版:
opencv_calib3d243d.lib
opencv_contrib243d.lib
opencv_core243d.lib
opencv_features2d243d.lib
opencv_flann243d.lib
opencv_gpu243d.lib
opencv_haartraining_engined.lib
ibrelease版:
opencv_calib3d243.lib
opencv_contrib243.lib
opencv_core243.lib
opencv_features2d243.lib
opencv_flann243.lib
opencv_gpu243.lib
字符集设置:如果编译过程中出现如下错误:不能将参数 1 从“_TCHAR *”转换为“const std::string &”原因如下: 无法从“_TCHAR *”转换为“const std::string”。请字符集设置为“使用多字节字符集”。
最后指定命令后参数:方法见附件。这样就可以不用在windows命令行下输入参数了,方便调试,但是要注意,图片必须放在你所建立的工程目录下(和.cpp以及.h文件同一目录)。否则就要加上相应的路径。如果参数多于1个,请以空格分开。
支持所有参数设置完成,开始编译运行吧。如果Visual Studio无问题的话,按照以上按部就班操作,每个范例均可以正常运行。