题目描述:编一个程序实现如下功能:读入指纹图像,进行形态学骨架提取和基于距离变换的骨架提取,并实现剪裁算法。
1. 读入一幅指纹图像;
(1)代码
% 读取图片
clc;
clear;
I=imread('figureprint.png');
imshow(I)
(2)效果
![](https://i-blog.csdnimg.cn/blog_migrate/f1aa56287eaaecc8b3db751e2fce3ec2.png)
2. 对图像进行二值化(方法自定,可以是阈值法);
(1)代码
%对图像进行二值化(方法自定,可以是阈值法);
thresh = graythresh(I); %自动确定二值化阈值
I2 = im2bw(I,thresh); %对图像二值化
imshow(I2)
(2)效果
![](https://i-blog.csdnimg.cn/blog_migrate/97207d2198309d63bdb7047736aeb362.png)
3. 采用形态学骨架提取和距离变换骨架提取两种算法分别提取图像骨架;
(1)形态学骨架提取
①算法描述
形态学骨架提取算法要求给定提取的迭代次数k,在每次子迭代中主要分为3个步骤,第一步利用结构元B对图像进行腐蚀处理;第二步将腐蚀得到的结果与结构元B做开运算;第三步将前两步得到的结果做差得到下式中的 求并集(在代码中利用“逻辑与”运算实现),得到最终的骨架。
②编写函数getbone1
function result= getbone1(img,B,k)
% 形态学提取骨架
% img:二值图像 B : 结构元 k: 迭代次数
%
M=size(img,1);
N=size(img,2);
SkA=zeros(M,N);
for i = 0:k
% 1.先腐蚀
if i==0
temp1=img;
else
SE=logical(i*B);
temp1=imerode(logical(temp1),SE);
end
% 2.得到的结果再与B做开运算
temp2=imopen(temp1,B);
% 3. Sk(A)等于前两个结果做差, 再求并集,使用逻辑或实现。
SkA=(temp1-temp2)|SkA;
% 画图部分
figure;
subplot(1,3,1), imshow(temp1);
subplot(1,3,2), imshow(temp2)
subplot(1,3,3), imshow(SkA)
end
result=SkA
end
③测试效果
测试代码如下:
img=[0,1,0,0,0,0,0;
0,0,1,1,0,0,0;
0,0,1,1,0,0,0;
0,0,1,1,1,0,0;
0,0,1,1,1,0,0;
0,1,1,1,1,1,0;
0,1,1,1,1,1,0;
0,1,1,1,1,1,0;
0,1,1,1,1,1,0;
0,1,1,1,1,1,0;
0,0,0,0,0,0,0;]
B=[1,1,1;
1,1,1;
1,1,1;]
getbone1(img,B,2);
![](https://i-blog.csdnimg.cn/blog_migrate/f2d8a16ec0a5ec61f6ff4c01d4e9ebe3.png)
![](https://i-blog.csdnimg.cn/blog_migrate/b0fde5c636dbfa9fbdda114ee38c19c3.png)
④最终效果
最终效果如图5所示,指纹图像的骨架提取迭代过程如图4所示,可见除了少量噪声值以外,指纹图像的骨架得到了充分细化,提取成功。
![](https://i-blog.csdnimg.cn/blog_migrate/2dbe4930ce13da35472104d62b2c9de6.png)
![](https://i-blog.csdnimg.cn/blog_migrate/1a70916a40d0ae3de66d09ba455390a8.png)
(2)基于距离的骨架提取
①算法描述
step1:求取二值图像的边界;
step2:对边界二值图像求取距离变换;
step3:求距离变换图中的局部极大值;
step4:落入原二值图像中的局部极大值就是图像的骨架。
②主要函数getbone2编写
function result = getbone2(img)
% GETBONE2 利用距离变换提取骨架
% img为传入的图像
% 1. 求取二值图像的边界
M=size(img,1);
N=size(img,2);
img_boundary=zeros(M,N);
ed=[-1 -1; 0 -1; 1 -1; 1 0; 1 1; 0 1; -1 1; -1 0];
for i=2:M-1
for j=2:N-1
if img(i,j)==1%如果当前像素是前景像素
for k=1:8
ii=i+ed(k,1);
jj=j+ed(k,2);
if img(ii,jj)==0%当前像素周围如果是背景,边界标记图像相应像素标记
img_boundary(ii,jj)=1;
end
end
end
end
end
% 2. 对边界二值图像求取距离变换
D = bwdist(img_boundary)
% 3. 求距离变换图中的局部极大值
m =5; % 方形邻域,即子矩阵范围大小
% 标记
imge_bone=zeros(M,N); % 最终显示的骨架图
subMatrix = zeros(m,m); % 子矩阵,局部最大值为这个矩阵内的最大值
I2=zeropadding(D,m) %由于有方形邻域(类似于卷积核的滑动),故需要将图像进行0填充
I3=zeropadding(img,m) % 将原图像也进行0填充,便于最后的比较这个局部最大值是不是落在图像内部
for x = 1:m:M
for y = 1:m:N
subMatrix = I2(x:x+m-1,y:y+m-1); % 从原图中提取子矩阵,即m*m的邻域
s = sort(subMatrix(:),'descend'); %排序
[r,c] = find(subMatrix == s(1)); % 取最大值
r=x+r-1;c=y+c-1; % 在原图像中,对应的行列坐标应当加上当前位置(x,y)
if I3(r,c)==1 %判断局部最大值是不是落在图像内部
% 4. 这些局部极大值组成骨架
imge_bone(r,c)=1; % 骨架图赋值为1
end
end
end
result=imge_bone
end
③用于调用的main函数代码
clear
% 读取图片
clc;
clear;
I=imread('figureprint.png');
thresh = graythresh(I); %自动确定二值化阈值
I2 = im2bw(I,thresh); %对图像二值化
imshow(I2)
result=getbone2(I2);
imshow(result)
③指纹图像实现效果
基于距离变换的指纹图像骨架提取效果如图6所示,可见,对比之前的形态学骨架提取,该方法在骨架的连续性上不如之前的好。(图6图像在提取之前经过形态学的去噪处理)
![](https://i-blog.csdnimg.cn/blog_migrate/31702d788ff00619fe35b2a49a4f6640.png)
4、采用裁剪算法,并分析其效果。
(1)算法流程
Step1:假设是任何具有三个或小于三个像素长度的分支都将被删除。使用一系列仅设计用来检测端点的结构元对输人集合A进行细化可以得到期望的结果。也就是说,令:
式中,{B}表示结构元序列,这个结构元序列由两种不同的结构组成,每种结构对全部8个元素旋转。
而后4个结构元中的“×”表示一个“不必考虑"的条件,在这种意义上,该位置上的像素的值是0还是1无关紧要。如下图所示:
![](https://i-blog.csdnimg.cn/blog_migrate/fccd30a737f07708acd0ee1af1fa39ae.png)
结构元B对集合A的细化根据击中或击不中变换来定义。
Step2:连续对步骤1三次,再形成一个包含X1中所有端点的集合。
Step3:下式中H是元素值为1的3×3结构元,并且在每一步之后都要与A求交集。如区域填充和提取连通分量的情况一样,这种有条件的膨胀可以防止在我们关注的区域外产生值为1的元素。
Step4: X3和X1的并集就是我们想要的结果
(2)代码编写
cut函数是自定义的剪裁算法,首先定义了所需的8个结构元,其次再进行细化、击中击不中等步骤,由于matlab自带的击中击不中变换需要传入两个结构元,处理时较为麻烦,因此自定义了hitormiss函数。具体代码如下:
①cut函数
function X4= cut(A)
%CUT 此处显示有关此函数的摘要
% 此处显示详细说明
%8个结构元{B}
A=logical(A);
B1=[2,0,0;
1,1,0;
2,0,0];
B2=[2,1,2;
0,1,0;
0,0,0];
B3=[0,0,2;
0,1,1;
0,0,2];
B4=[0,0,0;
0,1,0;
2,1,2];
B5=[1,0,0;
0,1,0;
0,0,0];
B6=[0,0,1;
0,1,0;
0,0,0];
B7=[0,0,0;
0,1,0;
0,0,1];
B8=[0,0,0;
0,1,0;
1,0,0];
B={B1,B2,B3,B4,B5,B6,B7,B8};
X1=A;
% 1. 细化 X1=A细化符号{B}
for i=1:3 %连续3次
for j=1:8
temp=cell2mat(B(j));
img_hit=hitormiss(X1,temp);
X1=X1&(~img_hit);%hitormiss 击中击不中变换(调用自定义hitormiss)
X1=logical(X1);
end
end
% imshow(X1)
% 2. 连续式子1三次,得到图中的集合下一步是将字符“复原"成其原来的形状,但要去掉寄生分支。为做到这一点,首先需要求形成一个包含XI中所有端点的集合X2
figure
imshow(img_hit)
figure
imshow(X1) %X1没问题了
X2=zeros(size(A));
for k=1:8
temp=cell2mat(B(k));
img_hit2=hitormiss(X1,temp);
X2=X2|img_hit2;
end
for n=1:8
temp=cell2mat(B(n));
X2=X2|hitormiss(X2,temp);
end
figure
imshow(X2)
% 3. 三次膨胀
X3=X2;
H=[1,1,1;
1,1,1;
1,1,1;];
for m=1:3
X3=imdilate(X3,H)&A;
end
figure
imshow(X3)
% 4 求并集
X4=X1|X3;
End
②自定义hitormiss函数
function imge_hit =hitormiss(img,B)
% 只传入一个B,进行hitormiss判断,此时检测img中有没有与B完全相同的
[M,N]=size(img);
m =size(B,2); % B的大小,一般是3
% 原结构元中X是用2表示的
flag=false;
[r,c] = find(B == 2);
if size(r,1)~=0
flag=true;
end
imge_hit=zeros(M,N); % 最终显示的骨架图
subMatrix = zeros(m,m); % 子窗口,用于滑动
I2=zeros(M+2,N+2);
I2(2:M+1,2:N+1)=img;
for x = 2:M-1
for y =2:N-1
% subMatrix = I2(x-1:x+1,y-1:y+1); % 从原图中提取子矩阵,即m*m的邻域
subMatrix = img(x-1:x+1,y-1:y+1);
if ~flag
if subMatrix==B %判断提取的矩阵是不是和结构元B一样,一样就击中
imge_hit(x,y)=1; % 击中的点1
end
else % flag 为true ,即有X的情况
[r0,c0] = find(B == 0); %r[2,3] c[2,2]
key=true;
for i =1:size(r0,1) % size(r,1)=2
if subMatrix(r0(i),c0(i))~=0 %不等于1
key=false;
end
end
[r1,c1] = find(B == 1); %r[2,3] c[2,2]
for i =1:size(r1,1) % size(r,1)=2
if subMatrix(r1(i),c1(i))~=1 %不等于1
key=false;
end
end
if key
imge_hit(x,y)=1; % 击中的点1
end
end
end
end
imge_hit=logical(imge_hit);
end
(3)测试效果
①测试代码
%测试
%裁剪
clear
% 读取图片
clc;
img=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0;
0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0;
0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0;
0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0;
0,1,0,1,0,0,0,0,0,0,1,0,0,0,0,0;
0,1,1,0,0,0,0,0,0,0,1,1,0,0,0,0;
0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0;
0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,0;
0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0;
0,0,1,0,0,0,0,0,1,0,0,1,0,0,1,0;
0,0,0,1,1,1,1,1,0,0,0,0,1,1,0,0;
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0;]
imshow(img)
result=cut(img);
imshow(result)
②测试代码的运行过程
![](https://i-blog.csdnimg.cn/blog_migrate/21f60733ab46fce9e765da489506289c.png)
![](https://i-blog.csdnimg.cn/blog_migrate/0c80c6716f3191ebf5528a5459847fc2.png)
图8 测试过程的运行效果
与书上结果对比
![](https://i-blog.csdnimg.cn/blog_migrate/098770d923cf667f13221675d191402b.png)
由图8和图9的结果可以看出,自定义的裁剪算法与书上效果基本一致。
③指纹图像运行效果
![](https://i-blog.csdnimg.cn/blog_migrate/03e963aacfa30df2dd64e132e161513b.png)
由图10可以看出,指纹图像的一些边缘部分已被裁剪掉。
参考
主要参考书籍:冈萨雷斯图像处理第4版本
未经允许禁止转载~