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_search_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;
else
    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);
        else
            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_search_f.m函数代码:

function Iamge_class = ratio_search_f( input_image,contour )
% 作用:利用图像的占空比判断图像是什么类型
% input_image:输入的局部图,二值图,有效区域是标签(1,2,3...),背景是0
% Iamge_class:图像类型名称,例如:矩形
% contour: 局部图对应的轮廓图
% 思路:
%   将三角形,矩形,五角形,六角形,圆形的占空比预先保存到一个元组中;
%   对输入图像计算占空比,然后和数组中的个元组素对比;
%   这只是个粗略的结果,根据得到了占空比进行邻近的几个排序,后续还需要进行轮廓验证

% 占空比模板库
Class_Module = {'triangle','rectangle','pentagon','hexagon','circle'};
Ratio_Module = [0.5,1,0.7,0.75,0.79];
% 图像大小
[m,n] = size(input_image);
% 计算占空比
index_vector = find(input_image ~= 0);      % 统计有效点
%计算占空比,因为前面做局部图是给四周添加的2个像素宽度的背景,所以这里需要减去
RATIO = size(index_vector,1)/((m*n)-4*m - 4*(n-4)); 
% 占空比和模板中的占空比进行比较大小
TEMP = abs(Ratio_Module - RATIO);
ind = find(TEMP == min(TEMP));

% 图形轮廓校验,暂时这里只添加了圆形的检测
check_flag = circle_check_f(contour);
% 圆形轮廓检查
if ind == 5
    if check_flag == 1
        Iamge_class = Class_Module{ind};
        disp('这个圆非常的圆!!!');
    else
        fprintf('这个图形可能是圆形,但是严格的圆形检查未通过!');
    end
else
    % 其他图形轮廓
    Iamge_class = Class_Module{ind};
end
end

测试图片:

matlab实现简单图形的识别二_第1张图片

试验结果

matlab实现简单图形的识别二_第2张图片matlab实现简单图形的识别二_第3张图片
在这里插入图片描述
代码中的图形内边沿提取代码虽然针对矩形,圆形都没有问题,其他图形提取效果尚不明确。
后续需要做的工作就是将其他图形校验的函数添加到 ratio_search_f.m 函数文件尾部的校验部分即可。

你可能感兴趣的:(图像识别,MATLAB,简单图形的识别)