形态学图像处理
- 预备知识
- 集合论中的基本概念
- 膨胀和腐蚀
- 膨胀
- 结构元素的分解
- 函数strel
- 腐蚀
- 膨胀与腐蚀的组合
- 开运算和闭运算
- 击中或击不中变换
- 使用查找表
- 函数bwmorph
一.预备知识
集合论中的基本概念
在数学形态语境中使用“形态学”提取图像分量,在表示和描述区域形状(如边界、骨骼、凸壳)时很有用。
集合中四种基本的状态:
或(并),与(交),非(补),差
符号分别是:
| , & , ~ ,&~
执行基本操作
>> f = Fig0903;
>> g = Fig0904;
>> subplot(231), imshow(f);
>> subplot(232), imshow(g);
>> subplot(233), imshow(f|g);
>> subplot(234), imshow(f&g);
>> subplot(235), imshow(f&~g);
>> subplot(236), imshow(~g);
二.膨胀和腐蚀
膨胀
膨胀是在二值图像中“加长”或“变粗”的操作。这种特殊的方式和变粗的程度由一个称为结构元素的集合控制。(实际就是将结构元素的原点与二值图像中的1重叠,将二值图像中重叠部分不是1的值变为1,完成膨胀)
结构元素基于原点的映像,就是把结构元素转180度。类似于==空间卷积==。
- 膨胀函数
A2 = imdilate(A, B)
A和A2都是二值图像,B是指定结构元素由0和1组成的矩阵。
>> A = Fig0906;
>> B = [0 1 0; 1 1 1; 0 1 0];
>> A2 = imdilate(A, B);
>> subplot(121), imshow(A);
>> subplot(122), imshow(A2);
明显可以看出图片中字体的加粗。
结构元素的分解
A ⊕ B = A ⊕ (B1 ⊕ B2) = (A ⊕ B1) ⊕ B2
B膨胀A等同于B1先膨胀A,再用B2膨胀之前的结果。
一个行矩阵和一个列矩阵可以膨胀为一个完整的m x n 的矩阵。
函数strel
IPT函数strel可以构造各种形状和大小的结构元素。
se = strel(shape, parameters)
shape表示希望形状的字符串,parameters表示指定形状信息的参数(如大小等)。
可按照下表构造形状
>> se = strel('diamond', 5);
>> se
se =
strel is a diamond shaped structuring element with properties:
Neighborhood: [11×11 logical]
Dimensionality: 2
显示出se是一个返回水平和垂直扩展+-5个像素的菱形结构元素(红线标出)
- getsequence函数
decomp = getsequence(se)
用于提取并检查分解中的单个结构元素。
decomp =
4×1 strel array with properties:
Neighborhood
Dimensionality
分解后得到四个元素结构向量,可以通过索引来逐一查看。
>> decomp(1)
ans =
strel is a arbitrary shaped structuring element with properties:
Neighborhood: [3×3 logical]
Dimensionality: 2
腐蚀
与膨胀相反,对二值图像中的对象进行“收缩”或“细化”。(实际上将结构元素的原点覆盖在每一个二值图像的1上,只要二值图像上有0和结构元素的1重叠,那么与原点重叠的值为0)
同样由集合与结构元素完成。
- 腐蚀函数
IPT函数imerode执行腐蚀
A2 = imerode(A, se)
>> f = Fig0908;
>> se = strel('disk', 10);
>> g = imerode(f, se);
>> se = strel('disk', 5);
>> g1 = imerode(f, se);
>> g2 = imerode(f, strel('disk', 20));
>> subplot(221), imshow(f), title('原图');
>> subplot(222), imshow(g), title('disk 10');
>> subplot(223), imshow(g1), title('disk 5');
>> subplot(224), imshow(g2), title('disk 20');
要把原图中的细线去掉,要找一个足够小的结构元素来进行腐蚀处理,可以看出,在结构元素指定参数在20时细线基本都被处理掉了。
三.膨胀与腐蚀的组合
开运算和闭运算
- 开运算
A ○ B
A被B腐蚀后,再用B膨胀腐蚀后的结果(先腐蚀再膨胀)
C = imopen(A, B)
- 闭运算
A • B
A被B膨胀后,再用B腐蚀膨胀后的结果(先膨胀再腐蚀)
C = imclose(A, B)
A为二值图像,B为0,1矩阵组成的指定结构元素。
>> f = Fig0910;
>> se = strel('square', 40);
>> fo = imopen(f, se);
>> fc = imclose(f, se);
>> foc = imclose(fo, se);
>> subplot(221), imshow(f), title('原图');
>> subplot(222), imshow(fo), title('开');
>> subplot(223), imshow(fc), title('闭');
>> subplot(224), imshow(foc), title('开运算的闭运算');
在实际应用中,可以用开运算和闭运算处理指纹,以达到使图像清晰的效果。
>> f = Fig0911;
>> se = strel('square', 6);
>> fo = imopen(f, se);
>> foc = imclose(fo, se);
>> subplot(131), imshow(f), title('原图');
>> subplot(132), imshow(fo), title('开');
>> subplot(133), imshow(foc), title('开运算的闭运算');
开运算的闭运算可以给指纹填充缺口。
击中或击不中变换
击中击不中变换(HMT),HMT变换可以同时探测图像的内部和外部。研究解决目标图像识别和模式识别等领域,在处理目标图像和背景的关系上能够取得更好的效果。
- 识别像素特定形状函数
C = bwhitmiss(A, B1, B2)
A表示集合,B1、B2表示结构元素
>> f = Fig0913;
>> B1 = strel([0 0 0; 0 1 1; 0 1 0]);
>> B2 = strel([1 1 1; 1 0 0; 1 0 0]);
>> C = bwhitmiss(f, B1, B2);
>> subplot(121), imshow(f), title('原图');
>> subplot(122), imshow(C), title('击中击不中变换');
在孤立的点或者线段的端点像素,击中或击不中变换对这类问题会有更好的处理。
使用查找表
当击中或击不中变换中的结构元素较小时,可以使用查找表计算击中击不中更快,定义一个函数endpoints处理该类问题。
- endpoints函数
%endpoints函数
function g = endpoints(f)
persistent lut
if isempty(lut)
lut = makelut(@endpoint_fcn, 3);
end
g = applylut(f, lut);
%endpoint_fcn函数
function is_end_point = endpoint_fcn(nhood)
is_end_point = nhood(2, 2) & (sum(nhood(:)) == 2);
函数创建了nhoos任意形状由0和1组成的元素结构的函数句柄,并构造一个3 x 3的查找表,并将函数句柄写入。
- 使用查找表执行击中或击不中
>> f = Fig0914;
>> g = endpoints(f);
>> subplot(121), imshow(f);
>> subplot(122), imshow(g);
函数bwmorph
该函数是基于膨胀、腐蚀和查找表操作的组合实现。
g = bwmorph(f, operation, n)
operation表示指定期望操作的字符串;n表示重复操作的次数(n为Inf时表示为无穷多次)。
>> f = Fig0917;
>> g = bwmorph(f, 'thin', 1);
>> g1 = bwmorph(f, 'thin', 3);
>> subplot(131), imshow(f), title('原图');
>> subplot(132), imshow(g), title('细化1次');
>> subplot(133), imshow(g1), title('细化3次');
可以明显看出细化一次和细化三次的区别,到三次细化后,一些细小的线有消失的迹象。
- 函数bwlabel
IPT函数bwlabel用来计算二值图像中所有的连接分量。
[L, num] = bwlabel(f, conn)
L表示标记矩阵,num给出找到的连接分量总数,conn用于指定期望连接(4或8)。
- 示例:计算和显示连接分量的质心
函数find在处理标记矩阵时很有用,可以返回某个对象所有像素的行索引和列索引。
>> [L, n] = bwlabel(f);
>> [r, c] = find(L == 3);
>> rbar = mean(r);
>> cbar = mean(c);
>> imshow(f);
>> hold on
>> for k = 1:n
[r, c] = find(L == k);
rbar = mean(r);
cbar = mean(c);
plot(cbar, rbar, 'Marker', 'o', 'MarkerEdgeColor', 'k',...
'MarkerFaceColor', 'k', 'MarkerSize', 10);
plot(cbar, rbar, 'Marker', '*', 'MarkerEdgeColor', 'w');
end