matlab实现简单图形的识别⼆
前⾯写的⼀篇描述了基于占空⽐的⽅法对简单图形的识别,今天继续对⾥⾯的代码进⾏⼀点⼩⼩的补充。主要是对图形的轮廓进⾏校验,仅仅利⽤占空⽐对于不是⼗分严格 的图形很可能造成误判,添加点校验的代码应该会好点。限于时间和能⼒,仅仅对圆形进⾏了简单的代码补充,其他的图形操作基本相同,只是后续填充进⼊相关代码即可。
代码流程:
1 读⼊图像并完成⼆值化;
2 区域标记和分割,并对分割出的局部图进⾏加边框;
3 提取局部图的轮廓;
4 调⽤判别函数进⾏图形形状的判别;
5 显⽰判断结果。
主程序代码:
clc;
clear all;
t0 = clock;
%% 图像读⼊,灰度化,⼆值化,显⽰⼆值图
img=imread('F.jpg');
img = rgb2gray(img);
BW=~im2bw(img); % 背景⽤0表⽰,有效区域⽤1表⽰
figure;imshow(BW),title('⼆值显⽰');
普通朱雀%% 连通域切割,8连通域
% 图像连通域标记
[Local,image_num] = bwlabel(BW,8);
% RGB = label2rgb(Local);
% figure;imshow(RGB),title('rgb显⽰连通域');
% 连通域提取步骤:
Multi_pic = Multi_Local_f(Local,image_num);
MultiPic_cell = cell(1,image_num); % 保存局部图
MultiPic_cell_contour = cell(1,image_num); % 保存局部图的轮廓
for i=1:image_num
Local_shape = [];
Postion_range = EdgeCheck_f(Multi_pic,i);
% 提取的轮廓是经过扩充边界2像素的边框,要注意
Local_shape = Image_Cut_f(Local,Postion_range,i);
% 保存并显⽰局部图像
MultiPic_cell{i} = Local_shape;
figure,imshow(Local_shape);
% 跟踪搜索得轮廓链表,将各图的轮廓进⾏保存
lb = lb_get_f(Local_shape);
MultiPic_cell_contour{i} = lb;
end
%% 判断图像类型并显⽰各个图像
for i =1:image_num
% 占空⽐法判断图像的类型,参数:局部图和局部图轮廓链表
Class_name{i} = ratio_arch_f(MultiPic_cell{i},MultiPic_cell_contour{i});
figure;imshow(MultiPic_cell{i}),title(['this is ', Class_name{i}]);
end
%% 耗时计算
Time_consumed = etime(clock,t0);
circle_check_f.m 函数代码:
function Sim_coe = circle_check_f( coutour_LB )
% 作⽤;对参数传递进来的轮廓进⾏圆效验,检测是否为圆形
% 原理:找到其最⼤最⼩圆,看看⼆者的半径差异有多⼤,⼩于2说明很圆
% coutour_LB:圆形轮廓的坐标链表
% Sim_coe:相似度系数
LB = coutour_LB;
% 取出最⼤和最⼩x,y坐标,计算对称中⼼
Lmax = max(LB(:,2));
Lmin = min(LB(:,2));
Hmax = max(LB(:,1));
Hmin = min(LB(:,1));
L0 = (Lmax + Lmin)/2;
H0 = (Hmax + Hmin)/2;
珍惜的作文
if (Lmax - Lmin) ~= (Hmax - Hmin)
disp('circle_check_f( coutour_LB )函数错误!图像宽⾼不同,不符合标准圆的特征!'); end
M = size(LB,1);
dist_stat = [];
for i =1:3:M
% 取轮廓上的各点到中⼼的距离并保存
x = LB(i,2);
y = LB(i,1);
dist = sqrt((x - L0)^2 + (y - H0)^2);
dist_stat =[dist_stat;dist];
end
% 返回最⼤和最⼩半径的差值,如果⼩于2说明很圆
if max(dist_stat)-min(dist_stat) <= 2
Sim_coe = 1;
el
十篇英语作文
Sim_coe = 0;
end
end
EdgeCheck_f.m 函数代码:
function Position_range = EdgeCheck_f(Multi_Image,num_Label)
% 作⽤:找出标记图像(Multi_Image中标号为num_Label的局部图的坐标范围% Image_Labeled:标记图像
% num_Label:区域标记号
% [x1,y1,x2,y2]:标记区域的左上⾓和右下⾓坐标,x是列,y是⾏
X_MAX=0;X_MIN =0;Y_MAX=0;Y_MIN =0;
Image_Labeled = Multi_Image(:,:,num_Label);
% 计算指定标记的区域范围
H = size(Image_Labeled,1);
% 找出X_MIN和X_MAX
for j=1:H
% 从上到下,逐⾏寻找等于1的⾏
if max(Image_Labeled(j,:))==1
Y_MIN = j;
break;
end
end
for j=1:H
% 从下到上,逐⾏寻找等于1的⾏
if max(Image_Labeled(H+1-j,:))==1
Y_MAX = H+1-j;
break;
end
end
L = size(Image_Labeled,2);
% 找出Y_MIN和Y_MAX
for k=1:L
% 从左到右,逐⾏寻找等于1的列
if max(Image_Labeled(:,k))==1
X_MIN = k;
break;
end
end
for k=1:L
% 从右到左,逐⾏寻找等于1的列
if max(Image_Labeled(:,L+1-k))==1
X_MAX = L+1-k;
break;
end
end
Position_range =[X_MIN,Y_MIN,X_MAX,Y_MAX];
end
Image_Cut_f.m函数代码:
function Image = Image_Cut_f( Labeled_Pic,Position,label )
大乔% 根据参数指定的范围将图像切割出来称为⼀个单独的⼩图⽚
% Labeled_Pic:标记的图像
% Position:要拷贝的区域
% label:标签号
% Image:返回⼀个切割好的局部图
% 截取指定的区域
TEMP = Labeled_Pic(Position(2):Position(4),Position(1):Position(3));
for i = 1:size(TEMP,1)
数学一次函数
for j = 1:size(TEMP,2)
if TEMP(i,j) ~= label
紫叶李花期TEMP(i,j) = 0;
end
余姚美食end
end
% 上下左右各扩展2个像素宽度,便于后续的找轮廓,否则轮廓寻找可能会出错
% 当局部图的像素点在图像边沿时会影响腐蚀,所以需要扩⼤图像使得局部图不和边界相连[M,N] = size(TEMP);
kong = zeros(M + 4,N + 4);
kong(3:M+2,3:N+2) = TEMP;
Image = kong;
end
lb_get_f.m函数代码:
function lb = lb_get_f( img )
% 作⽤:将内轮廓图形中的各个像素点取出并保存到链表LB
% ⽅法:从Xmin的点开始沿顺时针⽅向搜索,直到回到起点。
% local_pic :⼆值图像,周围有2个像素宽度的富裕,有效值为1,背景0;
% lb:轮廓链表,多⾏两列;
% 状态:成功!
[m,n]=size(img);
imgn=zeros(m,n); %边界标记图像
LB = [];
count = 0;
flag = 0;
% 按⾏找出第⼀个轮廓点
for i=1:m
老带新活动策划for j = 1:n
if img(i,j) == 1
IH = i;
IL = j;
flag = 1;
break;
end
end
if flag == 1
break;
end
end
flag = 0;
i = IH ;
j = IL ;
imgn(i,j) = 1; % 标记起始点
LB = [LB;i,j];
ed=[-1 -1;0 -1;1 -1;1 0;1 1;0 1;-1 1;-1 0]; % 从左上⾓像素,逆时针搜索
while (count < m*n)
for k=1:8 %逆时针8邻域搜索
tmpi=i+ed(k,1); %8邻域临时坐标
tmpj=j+ed(k,2);
% 只要k-1 是0 ,k是1,就保存这个点,并更新点
if k == 1
tmpi2=i+ed(8,1); %⼋邻域临时坐标
tmpj2=j+ed(8,2);
el
tmpi2=i+ed(k-1,1); %⼋邻域临时坐标
tmpj2=j+ed(k-1,2);
end
% 只要k-1 是0 ,k是1,就保存这个点,并更新点
if img(tmpi,tmpj)==1 && img(tmpi2,tmpj2)==0
i=tmpi; %更新内部搜寻坐标,继续搜索
j=tmpj;
imgn(i,j)=1; %边界标记图像该像素标记,普通边界为1
LB = [LB;i,j];
if i == IH && j == IL && count >1 % 边界转完⼀圈了,回到了终点 flag = 1;
end
break;
end
end
% 跳出死循环,测试⽤
count = count + 1;
if flag ==1
break;
end
end
figure,imshow(imgn),title('寻找的内边沿轮廓,函数lb_get()');
lb = LB;
end
Multi_Local_f.m函数代码:
function Multi_pic = Multi_Local_f( Labeled_Pic,Label_num)
% 将标记好的图差分成多张图,每张图仅有⼀个标签
% 采⽤list结构存储效率更⾼,可惜MATLAB中没有对应数据类型[m,n] = size(Labeled_Pic);
TEMP = zeros(m,n,Label_num);
for i = 1:m
for j = 1:n
for k = 1:Label_num
if Labeled_Pic(i,j) == k
TEMP(i,j,k) = 1;
break;
end
end
end
end
Multi_pic = TEMP;
end
ratio_arch_f.m函数代码: