1. 预备知识
1.1 集合论中的基本概念
集合其实对我们来说并不陌生,无非就是几种运算(交,并,补)。然后因为本章主要面向形态学处理,然后它有两个特殊的运算符,这两个运算符是特别针对于元素均为像素坐标的集合的。
首先设一个集合B和A。
1. 映像
B的映像记为^B,定义为
2. 平移
点z=(z1,z2)对集合A的平移记为(A)z,定义为
1.2 二值图像、集合和逻辑运算符
~(补集) 运算
b=imread('E:\matlab书中资源\素材图片\images_chapter_09\FigProb9.20(left).jpg');
subplot(2,3,1),imshow(b);
c=~b;
subplot(2,3,3),imshow(c);
title('取反运算');
|(合集) 运算
d=imread('E:\matlab书中资源\素材图片\images_chapter_09\Fig9.07(a).jpg');
h=b|d;
subplot(2,3,4),imshow(h);
&(交集)运算
h=b&d;
&~(差集)运算
h=b&~d;
图像b和d都是上面的图。
2. 膨胀和腐蚀
2.1 膨胀
膨胀是在二值图像中“加长”或“变粗”的操作。这种特殊的方式和变粗的程度由一个称为结构元素的集合控制。IPT函数imdilate执行膨胀运算。
代码示例:
a=imread('E:\matlab书中资源\素材图片\images_chapter_09\Fig9.05(a).jpg');
B=[0 1 0;1 1 1;0 1 0];
a2=imdilate(c,B);
c=~a2;
subplot(1,2,1),imshow(c),title('原图');
subplot(1,2,2),imshow(a2),title('膨胀后的图');
效果如下:
其中c和a2都是二值图像,B是指定结构元素的由0和1组成的矩阵。图像中包含有字符残缺的文本。
2.2 结构元素的分解
膨胀满足结合律。结合律很重要,因为计算膨胀所需要的时间正比于结构元素中的非零像素的个数。比如考虑一个大小为3*3且其元素为1的数组膨胀:
1 1 1
1 1 1
1 1 1
这个结构元素可分解为值一个为1的三元素行矩阵和一个值为1的三元素列矩阵。
[1 1 1]⊕[1
1
1]
原始结构数组中的元素个数为9,但在行列分解中的总元素只有6个,这意味着首先用行元素膨胀,再用列元素膨胀,能够比3*3的数组膨胀快1.5倍。实际中,速度并不会达到理论值,因为在每个膨胀运算中总会有些其他开销,至少在用分解形式时需要两次膨胀运算。然而,分解的实现对速度的提升仍然有很大意义。
2.3 函数strel
IPT函数strel运用各种形状和大小构造结构元素。如下代码,总结了函数strel的各种语法形式
se=strel('diamond',1); % 1表示结构元素原点到菱形最远端的距离
0 1 0
1 1 1
0 1 0
se=strel('disk',2); % 2表示圆盘的半径
0 0 1 0 0
0 1 1 1 0
1 1 1 1 1
0 1 1 1 0
0 0 1 0 0
se=strel('line',5,45); % 5表示长度,45表示线的角度(从水平轴起逆时针方向度量)
0 0 1
0 1 0
1 0 0
se=strel('octagon',3); % 得到一个平坦的八边形结构元素,3是从原点到边的距离(水平和垂直),而且必须是3的非负倍数
0 0 1 1 1 0 0
0 1 1 1 1 1 0
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
0 1 1 1 1 1 0
0 0 1 1 1 0 0
首先函数strel是返回一个称为strel对象的特殊量,它包含4个元素:
- 邻域
- 结构元素中值为1的像素数
- 分解中的结构元素数
- 分解的结构元素中值为1的总像素数
函数getsequence可用于提取并检查分解中的单个结构元素。
decomp=getsequence(se)
decomp =
4x1 array of STREL objects
decomp是strel对象的四元素向量。分解中的四结构可通过索引到decomp中来逐个检查。
2.4 腐蚀
腐蚀“收缩”或“细化”二值图像中的对象。和膨胀类似,收缩的方式和程度有一个结构元素控制。腐蚀的数学定义与膨胀相似,A被B腐蚀是所有结构元素的原点位置的集合,其中平移的B与A的背景并不叠加。
腐蚀通常用函数imerode。
代码实例:
b=imread('C:\Users\sh qian\Desktop\临时文档\matlab练习图像\TIM图片20170626160858.png');
b=rgb2gray(b);
imshow(b);
se=strel('disk',10);
A2=imerode(b,se);
imshow(A2);
subplot(1,2,1),imshow(b);
title('原图');
subplot(1,2,2),imshow(A2);
title('去掉细线后的图');
效果如下:
假设我们要去除原图中的线,但保留其它结构,需要选取一个较小的结构元素来匹配中心方块,但是选取的方块过小,会导致有些线不被删除。
3. 膨胀与腐蚀的组合
3.1 开运算和闭运算
1. A被B的形态学开运算可以记做A。B,这种运算是A被B腐蚀后再用B来膨胀腐蚀的结果。形态学开运算完全删除了不能包含结构元素的平滑区域,平滑了对象的轮廓,断开了狭窄的连接,去掉了细小的突出部分。
2. A被B的形态学闭运算是先膨胀再腐蚀。与开运算不同的是,闭运算一般会将狭窄的缺口连接起来形成细长的弯口,并填充比结构元素小的洞。
这两种运算在工具箱也有对应的两个函数(imopen和imclose),实例如下:
b=imread('C:\Users\sh qian\Desktop\临时文档\matlab练习图像\TIM图片20170627155457.png');
b=im2bw(b);
se=strel('square',20);
fo=imopen(b,se);
subplot(2,2,1),imshow(b);
title('原图');
subplot(2,2,2),imshow(fo);
title('开运算后的图像');
fc=imclose(b,se);
subplot(2,2,3),imshow(fc);
title('闭运算后的图像');
foc=imopen(fo,se);
subplot(2,2,4),imshow(foc);
foc=imclose(fo,se);
subplot(2,2,4),imshow(foc);
title('上图经闭运算后的结果');
运行效果如下:
调用这两个函数时,第一个参数是一幅二值图像,第二个参数是一个只含0,1的矩阵,表示一个结构元素。strel对象可以代替这个结构元素。从上面的开运算效果可以看出,细长的突出部分、细长的连线、弯口等等被消除了。从闭运算的效果可以看出,细长的突出部分和指向外部的齿状边缘已被消除。细长的连线以及小的孤立物也已被删除。
现在存在一幅杂散点的指纹图像,使用这两种运算后的结果如下:
3.2 击中或不集中变换
通常,能够识别像素的特定形状是很有用的,例如孤立的前景像素或者是线段的端点像素。这一名称基于运算结果被这两次腐蚀影响的方式。击中或不击中变换在工具箱中用函数bwhitmiss。
代码实例:
b1=strel([0 0 0;0 1 1;0 1 0]);
b2=strel([1 1 1;1 0 0;1 0 0]);
b=imread('E:\matlab书中资源\素材图片\images_chapter_09\Fig9.07(a).jpg');
g=bwhitmiss(b,b1,b2);
subplot(1,2,1),imshow(b);
title('原图像');
subplot(1,2,2),imshow(g);
title('应用击中或不击中变换后的结果');
效果如下:
考虑用击中或不击中变换定位图像中的对象的左上角像素。原图中显示了包括一些正方形的简单图像。我们要定位有东、南邻域像素(“击中”)和其他方向没被击中的前景像素。
3.3 使用查找表
当击中或不击中结构元素较小时,计算击中或不击中的较快方法是使用查找表(LUT)。这种方法是预先计算出每个可能邻域形状的像素值,然后把这些值存到一个表中,以备以后使用。工具箱中提供了两个函数makelut和applylut,其中,makelut基于一个提供给用户的函数构造一个查找表,而applylut则使用这个查找表来处理二值图像,可以写一个函数endpoints,使用makelut和applylut在二值图像中检测端点。我们定义一个端点作为前景像素,它有一个确切的前景邻域。函数endpoints计算并应用查找表在输入图像中检测端点。
函数endpoints代码如下:
function g=endpoints(f)
persistent lut
if isempty(lut)
lut=makelut(@endpoint_fcn,3);
end
g=applylut(f,lut);
%------------------
function is_end_point=endpoint_fcn(nhood)
%决定了如果这个像素是一个终点。
is_end_point=nhood(2,2)&(sum(nhood(:))==2);
可以测试一下这个代码
b=imread('C:\Users\sh qian\Desktop\临时文档\matlab练习图像\TIM图片20170628102825.png');
b=rgb2gray(b);
g=endpoints(b);
imshow(g);
subplot(1,2,1),imshow(b);
title('形态学骨骼的二值图像');
subplot(1,2,2),imshow(g);
title('经endpoints后的图像');
效果如下:
3.4 函数bwmorph
IPT函数bwmorph可基于膨胀、腐蚀和查找表操作的组合实现许多有用的操作,这个函数可支持的操作有:
基本语法是:
g=bwmorph(f,operation,n)
f是一幅输入二值图像,operation是一个指定期望操作的字符串,n是一个用于指定将被重复的操作次数的正整数。输入参量n是可选的。这个函数主要用于细化和骨骼化。
关于细化的操作代码:
g1=bwmorph(foc,'thin',1);
g2=bwmorph(foc,'thin',2);
subplot(1,3,2),imshow(g1);
title('细化一次后的图');
subplot(1,3,3),imshow(g2);
title('细化两次后的图');
效果如下:
细化 是在图像中将二值物体和形状减小为单个像素宽的线。可以看到第一张图的指纹脊很粗,因此我们首要任务就是把每条脊线都是一个像素粗。bwmorph的细化操作的每次应用都会从二值图像的厚度中删除一个或两个像素。这个细化的次数可以设置为无穷大(Inf),设置为无穷大之后的效果如下:
和上面的几个图,细化的效果更明显。
骨骼化 是另一种将二值图像中的对象约简为一组细骨骼的方法,这些细骨骼仍保留原始对象形状的重要信息。而使用bwmorph函数时,我们只要把operation参数置为’skel’即可。
效果如下:
我们可以看到,细化后会产生一些无关的“毛刺”。消除这些“毛刺”的过程称为修剪。