7.1.1 点检测
嵌在图像的恒定或近似恒定区域中的孤立点的检测,原理上非常简单。使用图7.1中的模板时,若|R≥T(T是一个非负阈值),则我们说在模板中心处检测出了一个孤立点。
这种点检测方法可使用工具箱函数imfilter及图7.1中的模板来实现。重要的要求是当孤立点位于模板的中心时,模板的响应最强,而在恒定灰度区域中响应为零。
若T已给出,则下面的命令实现刚才讨论的点检测:
`f = imread(“C:\Users\X\Desktop\Matlbe\图片\7.jpg”);
w = [-1 -1 -1; -1 8 -1; -1 -1 -1];
g = abs(imfilter(double(f), w));
T = max(g();
g = g >= T;
subplot(1, 2, 1), imshow(f), title(‘原图’);
subplot(1, 2, 2), imshow(g), title(‘点分割后’);
e115d8f340d9ac16f76a5c8fdfe6.png)
更复杂一点的是线检测。如果图7.3(a)中的模放在一怕约咏工丛应生最大的响应。同样,图7.3中线的响应更强烈。对于恒定的背景,当线通过模板的中间一行时,会产生最大的响应。同样,图7.3中
的第二个模板对+45°的线响应最好。第三个模板对垂直线响应最好。第四个模板对-45°方向的线响
应最好。注意,每个模板的优先方向都用一个比其他可能方向要大的系数加权。每个模板的系数之和为零,表明恒定灰度区域中模板的响应为零。
代码
f = imread(“C:\Users\X\Desktop\Matlbe\图片\7_2.jpg”);
subplot(2, 3, 1), imshow(f), title(‘原图’);
w = [2 -1 -1 ; -1 2 -1; -1 -1 2];
g = imfilter(double(f), w);
subplot(2, 3, 2), imshow(g), title(‘掩模后’);
gtop = g(1:120, 1:120);
gtop = pixeldup(gtop, 4);
subplot(2, 3, 3), imshow(gtop), title(‘左上角的放大图’);
gbot = g(end-119:end, end-119:end);
gbot = pixeldup(gbot, 4);
subplot(2, 3, 4), imshow(gbot), title(‘右上角的放大图’);
g = abs(g);
subplot(2, 3, 5), imshow(g), title(‘掩模后的绝对值’);
T = max(g();
g = g >= T;
subplot(2, 3, 6), imshow(g), title(‘满足g >= T 的点’);
Canny边缘检测器
Canny边缘检测器(Canny[1986])是函数edge中最强大的边缘检测器。方法总结如下:1.使用具有指定标准差r的一个高斯滤波器来平滑图像,以减少噪声。
2.在每个点处计算局部梯度[g+g,和边缘方向arctan(g,/g,)。表7.1中前三项技术的任意一项都可以用来计算这些导数。边缘点定义为梯度方向强度局部最大的点。
3.步骤⒉中确定的边缘点产生梯度中的脊线。然后,算法沿这些脊线的顶部进行追踪,并将实际上不在脊线顶部的像素设置为零,从而在输出中给出一条细线,该过程称为非最大值抑制。然后使用称为滞后阈值处理的方法来对这些脊线像素进行阈值处理,这一处理方法使用两个阈值T和T,其中T
[g,t] = edge(f,'canny ’ , T, sigma)
其中,T是一个向量,T = [T1,T2],它包含前述过程的步骤3中解释过的两个阈值;sigma是平滑滤波器的标准差。如果t包含在输出参数中,那么它是一个包含该算法所用的两个阈值的二元向量。语法中其余参数和其他方法中的解释一样,包括未指定T值时阈值的自动计算。sigma 的默认值是1。
代码
f = imread(“C:\Users\X\Desktop\Matlbe\图片\7_3.jpg”); % 图像大小:486×486
subplot(3,2,1),imshow(f),title(‘(a)原始图像’);
[gv, t] = edge(f,‘sobel’,‘vertical’);
subplot(3,2,2),imshow(gv),title(‘(b)Sobel模板处理后结果’);
gv = edge(f, ‘sobel’, 0.15, ‘vertical’);
subplot(3,2,3),imshow(gv),title(‘©使用指定阈值的结果’);
gboth = edge(f, ‘sobel’, 0.15);
subplot(3,2,4),imshow(gboth),title(‘(d)指点阈值确定垂直边缘和水平边缘的结果’);
w45 = [-2 -1 0;-1 0 1; 0 1 2];
g45 = imfilter(double(f), w45, ‘replicate’);
T = 0.3 * max(abs(g45());
g45 = g45 >= T;
subplot(3,2,5),imshow(g45),title(‘(e)-45°方向边缘’);
f45= [0 1 2;-1 0 1;-2 -1 0];
h45= imfilter(double(f), f45,‘replicate’);
T = 0.3 * max(abs(h45());
h45 = h45 >= T;
subplot(3,2,6),imshow(h45),title(‘(f)+45°方向边缘’);
例7.4 Sobel、LoG和 Canny 边缘检测器的比较。
本例比较Sobel、LoG和 Canny边缘检测器的相关性能,目的是通过提取图7.6(a)中建筑图像f的主要边缘特征来生成一幅干净的边缘图,同时减少不相关的细节,如砖墙和瓦屋顶中的微小纹理。在这一讨论中,我们感兴趣的主要特征是形成建筑物角落、窗户、入口的明亮砖结构、人口本身、屋顶线、距地面高度2/3处的围绕建筑物的混凝土带的边缘。
图7.7的左列显示了使用’sobel’、'log ‘和’ canny’选项的默认语法所得到的边缘图像:
f=tofloat(f);
[gSobel default,ts]=edge(f, ‘sobel’); %Fig. 7.7(a)>>[gLoG default,tlog] =edge(f, ‘log’); %Fig. 7.7©>>[acanny default, tc] =edge(f, ‘canny’);% Fig.7.7(e)
前述计算生成的输出参数中的阈值是ts =0.074、tlog = 0.0025和to=[0.019,0.047]。用于’log’和’ canny’选项的默认sigma值分别是2.0和1.0。除Sobel图像外,由默认值计算得出的图像离清晰的边缘图这一目标差距很大。
从默认值开始,每个选项中的参数随前面提及的显示主要特征这一目标交互地变化,同时尽可能地减少不相关的细节。图7.7右列中的结果是由如下命令得到的:
gSobel best = edge(f, ‘sobel’,0.05);% Fig. 7.7(b)>>gLoG best = edge(f, ‘log’ ,0.003, 2.25);%Fig. 7.7(d)
gCanny best = edge(f, ’ canny’, [0.04 0.10],1.5);%Fig. 7.7(f)
如图7.7(b)所示,Sobel得出的结果与我们试图检测混凝土带的边缘和入口的左边缘这一目标相差太远。图7.7(d)中所示的LoG结果与Sobel结果相比要好一些,与LoG默认值得出的结果相比要好很多,但仍然不能检测出主入口的左边缘和混凝土带的两个边缘。到目前为止, Canny结果[见图7.7(6)]要远远好于前两种结果。特别要注意的是,该结果中已清晰地检测出人口的左边缘、混凝土带的两个边缘,以及诸如主人口上方屋顶通风棚格这样的其他细节。除了检测期望的特征之外,Canny检测器还产生了最清晰的图。
代码
f = imread(“C:\Users\X\Desktop\Matlbe\图片\Fig0438(a)(bld_600by600).tif”); % 图像大小:486×486
[g_sobel_default,ts] = edge(f,‘sobel’);
[g_log_default,tlog] = edge(f,‘log’);
[g_canny_default,tc] = edge(f,‘canny’);
g_sobel_best = edge(f,‘sobel’,0.05);
g_log_best = edge(f,‘log’,0.003,2.25);
g_canny_best = edge(f,‘canny’,[0.04 0.10],1.5);
subplot(3,2,1);imshow(g_sobel_default);title(‘(a)默认sobel’);
subplot(3,2,2);imshow(g_sobel_best);title(‘(b)最佳sobel’);
subplot(3,2,3);imshow(g_log_default);title(‘©默认LoG’);
subplot(3,2,4);imshow(g_log_best);title(‘(d)最佳LoG’);
subplot(3,2,5);imshow(g_canny_default);title(‘(e)默认canny’);
subplot(3,2,6);imshow(g_canny_best);title(‘(f)最佳canny’);
代码
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);
subplot(1, 2, 1), imshow(f), title(‘原图’);
subplot(1, 2, 2), imshow(H), title(‘计算’);
函数houghlines
在霍夫变换中识别出一组候选的峰值后,那么剩下的工作就是确定是否存在与这些峰值相关联的有意义线段,以及这些线段的起点和终点。函数houghlines 使用默认语法
lines = houghlines(f, theta,rho,peaks)
hough1ines
或完整的语法形式
lines = houghlines( … ., 'FillGap ’ , val1,'MinLength ’ ,val2)
来执行这一任务。其中,theta和rho是函数hough 的输出,peaks是函数houghpeaks的输出。输出lines是一个结构数组,该数组的长度等于所找到的线段数。该结构的每个元素识别一条线,并具有如下字段:
point1,一个两元素向量[r1,c1],它指定线段终点的行、列坐标。point2,一个两元素向量[r2,c2],它指定线段其他终点的行、列坐标。theta,与线相关的霍夫变换容器的角度(单位为度)。
rho,与线相关的霍夫变换容器的p轴的位置。
其他参数如下: val1是一个正的标量,它指定与相同霍夫变换容器相关联的两条线段间的距离。当两条线段间的距离小于指定的值时,函数houghlines将把这两条线段聚合为一条线段(默认距离为20像素)。参数val2是一个正的标量,它指定聚合后的线是保留还是丢弃。比 val2中的指定值要短的线则被丢弃(默认值是40)。
代码
f=imread(“C:\Users\X\Desktop\Matlbe\图片\Fig1025(a)(building_original).tif”);
figure(1)
imshow (f);title(‘The Original image’)
level=graythresh(f);
f=im2bw(f);
[H, theta, rho] = hough(f, ‘ThetaResolution’, 0.2);
figure(2)
imshow(H, [], ‘XData’, theta, ‘YData’, rho, ‘InitialMagnification’, ‘fit’)
axis on, axis normal
hold on
xlabel(‘\theta’), ylabel(‘\rho’)
peaks = houghpeaks(H,2);%检测2个峰值点
plot(theta(peaks(:, 2)), rho(peaks(:, 1)), …
‘linestyle’, ‘none’, ‘marker’, ‘s’, ‘color’, ‘w’)
title(‘The peak point location’)
lines = houghlines(f, theta, rho, peaks);
figure(3)
imshow(f), hold on
for k = 1:length(lines)
xy=[lines(k).point1 ; lines(k).point2];
plot(xy(:,1), xy(:,2), ‘LineWidth’, 4, ‘Color’, [.8 .8 .8]);
end
title(‘Hough-transformation result’)
通常,在图像处理中,首选的方法是使用一种能基于图像数据自动地选择阈值的算法。下面的迭代过程就是这样一种方法:
1.为全局阈值选择一个初始估计值T。
2.使用T分割图像。这会产生两组像素:由所有灰度值大于T的像素组成的G,由所有灰度值小于等于T的像素组成的G。
3.分别计算区域G和G中像素的平均灰度值m和 mz。4.计算一个新的阈值:
r='(m+mz)
5.重复步骤⒉到步骤4,直到后续迭代中T的差小于一个预定义的AT值为止。6.使用函数im2bw分割图像:
g = im2bw(f, T/den)
其中,den是一个整数(例如,对于一幅8比特图像,den是255),它把比值T/den的最大值标定为1,就如函数im2bw所要求的那样。
在速度是一个重要问题的情形下,参数AT用于控制迭代次数。一般来说,AT越大,算法执行的迭代次数就越少。可以证明(见Gonzalez and Woods [2008),若初始阈值在图像中的最小和最大灰度之间选择(平均图像灰度就是T的一个较好初始选择),那么算法会在有限的步数内收敛。对于分割而言,在与物体和背景相关的直方图模式间存在明显的峰谷时,该算法会工作得很好。下例将说明如何在MATLAB中实现这一过程。
代码
clear
clc
f = imread(“C:\Users\X\Desktop\Matlbe\图片\Fig1038(a)(noisy_fingerprint).tif”);
L = im2uint8(f);
f = imnoise(L,‘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(‘全局阈值分割的结果’)
令一幅图像的直方图成分表示为
"aa=0.1,2,…,L-1Pq='q=0,1,2,
qn
式中, n是图像中像素的总数,nq是具有灰度级q的像素数量,L是图像中可能的灰度级的总数(记住,灰度级是整数值)。现在,假设已选定一个阈值k,C是灰度级为[0,1,2.…,k]的一组像素,C是灰度级为[k+1,…,L-1]的一组像素。Otsu方法(Otsu [1979])是最佳的,在某种意义上,它选择阈值k,使得其最大类间方差为
(k)=P(k)[m,(k)-m。]+P(k)[m2(k)-me]
式中,P(k)是集合C发生的概率:
R(k)=>p
i=0
例如,如果令k =0,那么具有分配给它的任何像素的集合C的概率就为0;类似地,集合C发生的概率是
P(k)=>pi =1-P(k)
i=k+1
m (k)和m,(k)分别是集合C和C中像素的平均灰度。m。是全局均值(整个图像的平均灰度):
i=0
此外,直到灰度级k的平均灰度由下式给出:
m=>ip.
i=0
代码
f2 = imread(“C:\Users\X\Desktop\Matlbe\图片\Fig1039(a)(polymersomes).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算法分割结果’)
噪声会把简单的阈值处理问题变为不能解决的问题。当不能在源头降低噪声且阈值处理是所选择的分割方法时,增强性能的一种常用技术是在阈值处理前先对图像进行平滑。下面用一个例子来介绍这种方法。
在没有噪声时,图7.15(a)中的原始图像是二值的,可以使用处在两个图像灰度值之间的任何阈值完美地进行阈值处理。图7.15(a)中的图像是在原始的二值图像中加入均值为0、标准差为50个灰度级的高斯噪声后的结果。带噪图像的直方图[见图7.15(b)]清楚地表明,阈值处理对这样的图像来说多半会失败。图7.15©中的结果是用Otsu方法得到的,该结果证实了这一点(物体上的每个暗点和背景上的每个亮点都是阈值处理误差,因此该分割完全不成功)。
图7.15(d)显示了使用一个5x5的均值模板平滑噪声图像(图像尺寸是651×814像素)后的结果,图7.15(e)是其直方图。平滑对直方图形状的改进很明显,且我们可以期望平滑后图像的阈值处理结果趋近于完美。如图7.15(f)所示,事实的确如此。在分割且平滑后的图像中,物体和背景间的边界稍微有点失真,这是由平滑过图像的边界模糊导致的。事实上,对图像平滑得越强烈,分割结果中预期的边界误差就越大。
图7.15中的图像是使用如下命令产生的:
f= imread ( ‘septagon.tif ’ );
要得到图7.15(a),就需使用函数imnoise将均值为0、标准差为50个灰度级的高斯噪声添加到这幅图像中。工具箱使用方差作为输人,且假定灰度范围是[0,1]。因为使用255个灰度级,因此输入到imnoise 的方差是50/2553=0.038:
代码
f = tofloat(imread(“C:\Users\X\Desktop\Matlbe\图片\Fig1042(a)(septagon_small_noisy_mean_0_stdv_10).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 = imbinarize(f,T);
subplot(236),imshow(g),title(‘改进边缘后的图像’)
例7.10使用拉普拉斯算子边缘信息来改进全局阈值处理。
本例考虑一个更复杂的阈值处理问题,并说明如何使用拉普拉斯算子得到能够改善分割的边缘息。图7.17(a)是一幅酵母细胞的8比特图像,我们希望使用全局阈值处理得到对应于亮点的区域首先,图7.17(b)显示了图像的直方图,且图7.17©是直接把Otsu方法应用于图像的结果:
代码
f = tofloat(imread(“C:\Users\X\Desktop\Matlbe\图片\Fig1043(a)(yeast_USC).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(‘修改边缘后的阈值处理图像’)
例7.11 全局和局部阈值处理的比较。
图7.18(a)显示了例7.10的图像。我们想要从背景中分割出细胞,并从细胞体中分割出细胞核(内部的亮区域)。这幅图像中有三个主要的灰度级,因此期待这样的分割是可能的。然而,使用单个阈值来进行分割非常不可靠;这已在图7.18(b)中得到验证,它显示了使用Otsu方法得到的结果:
代码
f = tofloat(imread(“C:\Users\X\Desktop\Matlbe\图片\Fig1043(a)(yeast_USC).tif”));
subplot(2,2,1),imshow(f);title(‘(a) 酵母细胞的图像’);
[TGlobal] = graythresh(f);
gGlobal = im2bw(f, TGlobal);
subplot(2,2,2),imshow(gGlobal);title(‘(b)用 Otsus 方法分割的图像’);
g = localthresh(f, ones(3), 30, 1.5, ‘global’);
SIG = stdfilt(f, ones(3));
subplot(2,2,3), imshow(SIG, [ ]) ;title(‘© 局部标准差图像’);
subplot(2,2,4),imshow(g);title('(d) 用局部阈值处理分割的图像 ');
代码
f = imread(“C:\Users\X\Desktop\Matlbe\图片\Fig1049(a)(spot_shaded_text_image).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(‘用移动平均局部阈值分割后的图像’);
相似性准则的选择不仅取决于所考虑的问题,还取决于可用的图像数据类型。例如,土地利用卫星成像分析主要取决于彩色的使用。如果彩色图像不能提供可用的固有信息,那么解决这个问题将非常困难,甚至无法解决。如果图像是单色图像,就必须使用一组基于灰度级(例如,矩或纹理)和空间特性(如连接性)的描绘子把相同灰度的像素分组形成一个区,从而对区域进行分析。在第8章中,我们将讨论那些对区域特征有用的描绘子。
如果在区域增长的处理中没有用连接信息(或连接性)而只有描述符,可能会产生错误的结果。例如,设想一下仅有三个不同灰度值的像素的一个随机排列。把相同灰度的像素分组形成一个区,而不考虑这些像素的连接性,会产生对当前讨论而言毫无意义的分割结果。
区域生长的另一个问题是终止规则的表述。当不再有像素满足加入某个区域的准则时,区域生长就会停止。像灰度值、纹理和彩色这样的准则,本质上都是局部的,不考虑区域生长的“历史”。增强区域生长算法能力的其他准则,利用了候选像素和已加入生长区域的像素间的大小(如候选像素灰度和生长区域的平均灰度的比较)以及正生长区域的形状。这类描绘子的使用是基于期望结果的一个模型至少部分可用这一假设的。
为了说明在MATLAB中处理区域分割方式的原理,我们开发了下面这个称为regiongrow的M函数来实现基本的区域生长。该函数的语法是
[g,NR,SI,TI] = regiongrow(f,s,T)
其中,f是被分割的图像,参数s可以是一个数组(与f大小相同)或一个标量。若s是一个数组,则它在种子点的所有坐标处必须包含1,而在其他地方包含0。这样一个数组可以通过观察确定,或通过一个外部种子寻找函数确定。如果s是一个标量,它定义一个灰度值,那么f中具有该值的所有点都会成为种子点。类似地,T也可以是一个数组(与f大小相同)或一个标量。若T是一个数组,则它对f中的每个位置包含一个阈值。若T是一个标量,则它定义一个全局阈值。阈值用于测试图像中的一个像素是否与种子足够相似,或者是否与其8连接的种子足够相似。s和T的所有值必须标定到区间[0,1],且与输入图像的类无关。
例如,若s = a和T = b,且我们比较灰度,则当一个像素的灰度和a的差的绝对值小于等于b时,我们说该像素(在通过阈值测试的意义上)与a类似。此外,若所考虑的像素是8连接到一个或多个种子值时,则该像素可认为是一个或多个区域的成员。s或T是数组,类似的结论成立,只是比较的是s和T中相应元素之间的差别。
在输出中,g是分割后的图像,每个区域的成员都用一个不同的整数值标注。参数 NR是所找到的区域的数量。参数sI是包含种子点的一幅图像,参数TI是包含处理连接性前就已通过阈值测试的像素的一幅图像。SI和TI的大小均与f的大小相同。
代码
f = imread(“C:\Users\X\Desktop\Matlbe\图片\Fig0621(a)(weld-original).tif”);
subplot(2,2,1),imshow(f);
title(‘(a)显示有焊接缺陷的图像’);
%函数regiongrow返回的NR为是不同区域的数目,参数SI是一副含有种子点的图像
%TI是包含在经过连通前通过阈值测试的像素
[g,NR,SI,TI]=regiongrow(f,1,0.26);%种子的像素值为255,65为阈值
subplot(2,2,2),imshow(SI);
title(‘(b)种子点’);
subplot(2,2,3),imshow(TI);
title(‘©通过了阈值测试的像素的二值图像(白色)’);
subplot(2,2,4),imshow(g);
title(‘(d)对种子点进行8连通分析后的结果’);
代码
f = imread(“C:\Users\X\Desktop\Matlbe\图片\Fig0938(a)(cygnusloop_Xray_original).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进行分割图像’);
代码
f = tofloat(imread(“C:\Users\X\Desktop\Matlbe\图片\Fig0941(a)(wood_dowels).tif”));
g=im2bw(f,graythresh(f)); %把图像转换为二值图像
subplot(2,3,1),imshow(f);title(‘(a)使用距离和分水岭分割原图’);
subplot(2,3,2),imshow(g);title(‘(b)原图像阈值处理后的图像’);
gc=~g; %对图像求补
subplot(2,3,3),imshow(gc),title(‘©阈值处理后取反图像’);
D=bwdist(gc); %计算其距离变换
subplot(2,3,4),imshow(D),title(‘(d)使用距离变换后的图像’);
L=watershed(-D); %计算负距离变换的分水岭变换
w=L==0; %L 的零值即分水岭的脊线像素
subplot(2,3,5),imshow(w),title(‘(e)距离变换后的负分水岭图像’);
g2=g & ~w; %原始二值图像和图像 w 的 “补” 的逻辑 “与” 操作可完成分割
subplot(2,3,6),imshow(g2),title(‘(f)阈值图像与分水岭图像相与图像’);
在使用分水岭变换进行分割之前,常用梯度幅度来对灰度图像进行预处理。梯度幅度图像沿物体的边缘有较高的像素值,而在其他位置则有较低的像素值。理想情况下,分水岭变换可得到沿物体边缘的分水岭脊线。下例说明了这—概念。
代码
f = imread(“C:\Users\X\Desktop\Matlbe\图片\Fig1056(a)(blob_original).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(‘平滑梯度图像后的分水岭变换’);
如前一节所示,分水岭变换直接用于梯度图像时,由于噪声和梯度的其他局部不规则性,常会导致过分割。由这些因素导致的问题可能会非常严重,以致实际结果不可用。在当前的上下文中,这将意味着具有大量的分割区域。解决这一问题的一种实用方法是通过集成一个预处理阶段(设计用于将额外的知识加到分割过程中)来限制允许区域的数量。
用于控制过分割的一种方法基于标记符这一概念。标记符是属于一幅图像的连接分量。在每个感兴趣物体的内部,我们希望有一组内部标记符,而在背景中有一组外部标记符。这些标记符采用例7.17中描述的过程来修改梯度图像。图像处理文献中提出了许多方法来计算内部和外部标记符,其中许多方法涉及前几章中描述的线性滤波、非线性滤波及形态学处理。为某个特殊应用选择何种方法,将取决于与该应用相关联的图像的特殊属性。
代码
f = imread(“C:\Users\madster\Downloads\DIP3E_Original_Images_CH10\Fig1057(a)(small_blobs-original).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(‘最后的分割图像’);