基于Matlab的数字识别(摄像头版)
学校的机器视觉课程发布的大作业课题为基于Matlab的数字识别,但因为疫情缘故,网课又不怎么好,导致这个课程基本没学,这就很为难我了,于是乎我通过大量搜索数字识别,人脸识别,车牌识别的matlab程序,参考了不少大佬写的内容,每个函数我都单独拿出来查看意思和作用,最终弄出来一个看上去还行的matlab数字识别。
这个第一段是主程序,顺序为对数据识别库库进行处理裁剪,开摄像头,将摄像头的图像进行处理,裁剪,对照数据库找出最符合的图片所在的数字库位置,然后返回所识别出来的数字
clear
clc
%统一图片大小
y=28;
z=28;
%导入数据库各数字个数
geshu=11;
zongshu=geshu*10;
%导入数据库
u=[];
picSize=[y,z];
shang=1;xia=1;zuo=1;you=1;
%预处理数据库,要求图片黑底白色数字
for s=0:9
for t=0:geshu-1
q=im2double(imread(strcat('D:\Documents\MATLAB\shujuku\',num2str(s),'_', num2str(t),'.jpg')));
q=im2bw(q,0.1);
[heng,zong]=size(q);
hs=sum(q);
hs0=sum(q,2); %这里表示行之和,这时应该是竖着写了两个数字及其以上,除了那种奇葩写得贼长那种
hs1=hs0'; %将行之和转置
while(hs1(xia)==0&&xia<heng) %找到图中白像素点,即有数字的部分,按行之和找
xia=xia+1;
end
shang=xia;
while(hs1(shang)>0&&shang<heng) %按列找找到不存在白像素的列,由于找到上边最先出现白像素的列直到找到最下边没有白像素的行,之间的就是整个数字
shang=shang+1;
end
while(hs(zuo)==0&&zuo<zong) %找到图中白像素点,即有数字的部分,按列之和找
zuo=zuo+1;
end
you=zuo;
while(hs(you)>0&&you<zong) %按列找找到不存在白像素的列,由于找到左边最先出现白像素的列直到找到最右边没有白像素的列,之间的就是整个数字
you=you+1;
end
q=q(xia:shang,zuo:you);
q=imresize(q,picSize);
u=[u,q];
shang=1;xia=1;zuo=1;you=1;
end
end
d=[];
%打开摄像头
obj = videoinput('winvideo',1,'MJPG_640x480');
h=preview(obj);
start(obj);
figure;
while ishandle(h)
frame = getsnapshot(obj); % 获取帧
%图像增强
% h=ones(5,5)/25; %过滤器h
% I=imfilter(I,h);%真彩色增强
% figure('name','真彩色增强');imshow(I);title('真彩色增强');
I1=rgb2gray(frame); % RGB图像转灰度图像
I1=imadjust(I1,[0.3,0.7],[]);
I1=medfilt2(I1);
% figure,imshow(I1);title('中值滤波');
%边缘检测:sobel,roberts,canny,prewitt等
I2=edge(I1,'roberts',0.25,'both'); %边缘检测算法,强度小于阈值0.15的边缘被省略掉,'both'两个方向检测(缺省默认)
% figure('name','边缘检测'),imshow(I2);title('robert算子边缘检测')
se=[1];
I3=imerode(I2,se);% 腐蚀Imerode(X,SE).其中X是待处理的图像,SE是结构元素对象
% figure('name','腐蚀后图像'),imshow(I3);title('腐蚀后的图像');
se=strel('rectangle',[30,30]);% 25X25的矩形 strel???
I4=imclose(I3,se);% 用25*25的矩形对图像进行闭运算(先膨胀后腐蚀)有平滑边界作用
% figure('name','平滑处理'),imshow(I4);title('平滑图像的轮廓');
I5=bwareaopen(I4,800);% 从二进制图像中移除所有少于2000像素的连接对象,消失的是连续的白色像素数量少于2000的字符
% figure('name','移除小对象'),imshow(I5);title('从对象中移除小对象');
%裁剪程序
[r,c]=find(I5);%找出I5中即只剩下数字的图里白元素所在行列,r记录行,c记录列
nextresult=I5(min(r) :max(r),min(c):max(c));
subplot(121),imshow(nextresult);title('抓取的数字图');
cj1=min(r) ;%记录裁剪尺寸
cj2=max(r);
cj3=min(c);
cj4=max(c);
[g,w]=size(nextresult);
[splitfs,points]=shuziqiege(nextresult,r,c,g,w);
xs=[splitfs,points];
dechushuzi=[];
jishu0=zeros(1,geshu);jishu1=ones(1,geshu);jishu2=ones(1,geshu)*2;jishu3=ones(1,geshu)*3;jishu4=ones(1,geshu)*4;jishu5=ones(1,geshu)*5;
jishu6=ones(1,geshu)*6;jishu7=ones(1,geshu)*7;jishu8=ones(1,geshu)*8;jishu9=ones(1,geshu)*9;
jishuqi=[jishu0,jishu1,jishu2,jishu3,jishu4,jishu5,jishu6,jishu7,jishu8,jishu9];
x=1;
for m_520=1:size(xs,2)-1
p=xs{m_520};
p=imresize(p,picSize);
for n_520=1:zongshu
nn=(n_520-1)*z+1;
ff=n_520*z;
d=u(1:y,nn:ff); %取识别库一张图所化为的矩阵
matchrs(n_520)=corr2(p,d);
end
[~,k]=max(matchrs);
dechushuzi(x)=jishuqi(k);
% lastresult=strcat(lastresult, fonts(k));
x=x+1;
end
x=1;
%开始标记
label_str = ['The number is: ' num2str(dechushuzi,'%d') ''];
cj5=cj2-cj1;
cj6=cj4-cj3;
cj=[cj3 cj1 cj6 cj5];
rgb = insertObjectAnnotation(frame, 'rectangle', cj, label_str,'textboxopacity', 0.9, 'fontsize', 18,'color','r');
subplot(122),imshow(rgb),title('数字识别系统');
drawnow
end
delete(obj);
然后下面是数字切割,针对于摄像头图像处理后的切割,程序有对横着顺序写数字或者对竖着顺序写的数字切割处理。
function[splitfs,points]=shuziqiege(nextresult,r,c,g,w)
%r非零元素行
%c非零元素对应列
%w多数字图的长
%g多数字图高
%hs一行w列矩阵,每列数字为g行数字相加,用来找到哪列有数字的白元素
%nextresult所有数字所在的区域
a=1;b=1;c=1;d=1;e=1;i=1;
splitfs={};points=[];
hs=sum(nextresult); %将图片矩阵转化为一行w列矩阵,每列数字为h行数字相加
hs0=sum(nextresult,2); %这里表示行之和,这时应该是竖着写了两个数字及其以上,除了那种奇葩写得贼长那种
hs1=hs0';%将行之和转置
if c<g
while(hs1(c)==0&&c<g) %找到图中白像素点,即有数字的部分,按行之和找
c=c+1;
end
d=c;
while(hs1(d)>0&&d<g) %按列找找到不存在白像素的列,由于找到上边最先出现白像素的列直到找到最下边没有白像素的行,之间的就是整个数字
d=d+1;
end
end
e=d+1;
if e<g
while(hs1(e)==0&&e<g) %按列找找到不存在白像素的列,由于找到下边最先出现白像素的列直到找到最上边没有白像素的行,之间的就是整个数字
e=e+1;
end
end
%判断多数字横向写还是纵向写
if e<g||7*w<2*g %这里说明纵向发现第二个数字,这里有一大限制,如果纵向写,却数字在纵向上没有空隙,且还把数字在竖向上写的扁扁的团在一起,这种是我能力有限,没办法编出来
%执行裁剪
while(a<g) %这里是横向裁剪程序,适用于数字竖着写的图
while(hs1(a)==0&&a<g) %找到图中白像素点,即有数字的部分,按行之和找
a=a+1;
end
b=a;
while(hs1(b)>0&&b<g) %按列找找到不存在白像素的列,由于找到下边最先出现白像素的列直到找到最上边没有白像素的列,之间的就是整个数字
b=b+1;
end
if(b-a>2) %如果左右能差两列像素
hresult=nextresult(a:b,:); %图片按列的横线切割
[r,c]=find(hresult);
% result2=hresult(:,min(c):max(c)); %图片按横线切
m=min(c);n=max(c);
xi=hresult(:,m:n); %图片按纵线切
splitfs{i}=xi;
points=[points;a,b,m,n];%a下,b上,m左,n右
% subplot(3,6,i),imshow(result2),title('裁剪出的数字');
i=i+1;
end
a=b;
end
else
while(a<w) %这里是数字横着写,进行纵向裁剪
while(hs(a)==0&&a<w) %找到图中白像素点,即有数字的部分,按列之和找
a=a+1;
end
b=a;
while(hs(b)>0&&b<w) %按列找找到不存在白像素的列,由于找到左边最先出现白像素的列直到找到最右边没有白像素的列,之间的就是整个数字
b=b+1;
end
if(b-a>2) %如果左右能差两列像素
hresult=nextresult(:,a:b); %图片按列的竖线切割
[r,c]=find(hresult);
% result2=hresult(min(r):max(r),:); %图片按横线切
m=min(r);n=max(r);
xi=hresult(m:n,:); %图片按横线切
splitfs{i}=xi;
points=[points;m,n,a,b];%m下,n上,a左,b右
% subplot(3,6,i),imshow(result2),title('裁剪出的数字');
i=i+1;
end
a=b;
end
end
这个是主程序开头处理的数据库,是我做大作业小组的伙伴们自己写的,所以不标准,要靠我开头程序切割处理下识别才好一些。
然后这是我开摄像头得到的结果
我参考的大佬们程序很多,我列举部分:
插入框文字
摄像头安装
车牌识别
人脸识别
有的大佬博客我找不到了,还请见谅。
学校matlab没怎么教,我也没有让程序整洁的习惯,整个程序它就有点。。。。乱,而且应该有很多地方可以优化,如果有建议希望得到指点,万分感谢。
这个是我程序加数据库压缩包链接matlab数字识别
这个资源积分老是在上涨,都重新上传两次了,不知道咋回事。。。。反正我全部程序都在博客上,数据库可以自己拿一个黑底板用画笔直接画的,资源包有很多积分就下载一下,积分少就不用了