现在很多场景需要使用的数字识别,比如银行卡识别,以及车牌识别等,在人工智能领域有很多图像识别算法,大多是居于opencv或者谷歌开源的超正方体识别,下面这篇文章主要给大家介绍了关于如何基于opencv实现简单的数字识别,需要的朋友可以参考下
目录
前言要解决的问题解决问题的思路总结
前言
由于自己学识尚浅,不能用大蟒深度学习来识别这里的数字,所以就完全采用opencv来识别数字,然后在这里分享、记录一下自己在学习过程中的一些所见所得和所想
要解决的问题
这是一个要识别的数字,我这里首先是对图像进行一个投资收益率的提取,提取结果就仅仅剩下数字,把其他的一些无关紧要的要素排除在外,
这是投资收益率图片,我们要做的就是识别出该照片中的数字,
解决问题的思路
1、先把这个图片中的数字分割,分割成为5张小图片,每张图片包含一个数字,为啥要分割呢?因为我们没办法让计算机知道这个数字是多少,所以只能根据特征,让计算机去识别特征,然后每一个特征对应一个值,首先贴出分割图片的程序,然后在程序下方会有一段思路解释
#包含opencv2/core/core.hpp
#包含opencv.hpp
#包含opencv2/highgui/highgui.hpp
#包含opencv 2/特性2d/特性2d。HPP
#包含opencv2/imgproc/imgproc.hpp
#包括输入输出流
#包括ctime
使用命名空间标准
使用名称空间cv;
#包含地图
Mat src _阈值;
Mat src _ dil
int太阳图像(Mat图像);
vectorMatROI _ image//待测图片
int main()
{
时钟_t开始,结束;
开始=时钟();
Mat src
src=im read( D: vs pic picture number 6。jpg’);
resize(src,src,Size(src.cols/7,src。行数/7));
imshow(src ,src);
Mat src _ gray
cvtColor(src,src_gray,COLOR _ bgr 2 gray);
//imshow(gsrc_ray ,src _ gray);
Mat src _ blur
blur(src_gray,src_blur,Size(9,9));
//GaussianBlur(src_gray,src_blur,Size(11,11),1,1);
Mat src _阈值;
threshold(src_blur,src_threshold,150,255,THRESH _ OTSU);
//imshow(src_threshold ,src _ threshold);
Mat src _ canny
Canny(src_threshold,src_canny,125,255,3);
//imshow(src_canny ,src _ canny);
vectorvectorPointcontours _ src
vec 4 I hierarchy _ src(contours _ src。size());
findContours(src_canny,contours_src,hierarchy_src,RETR)外部,CHAIN _ approximate _ NONE);
rect rect _ s;
Rect选择_ rect
for(size _ t I=0;图标旅游_ src。size();我)
{
rect _ s=边界矩形(contours _ src[I]);
双倍宽度=矩形宽度
双倍高度=rect _ s.height
double bizhi=宽度/高度;
如果(比直1.5高50)
{
/*rectangle(src,rect_s.tl(),rect_s.br(),Scalar(255,255,255),1,1,0);*/
choose_rect=Rect(rect_s.x 20,rect_s.y 30,rect_s.x-30,Rect _ s . y-108);
}
}
Mat roi
ROI=src(choose _ rect);
//imshow(src_ ,ROI);
Mat img=roi
Mat gray _ img
//生成灰度图像
cvtColor(img,gray_img,CV _ bgr 2 gray);
//高斯模糊
Mat img _ gau
GaussianBlur(gray_img,img_gau,Size(3,3),0,0);
//阈值分割
材料img _ seg
threshold(img_gau,img_seg,0,255,THRESH _ BINARY THRESH _ OTSU);
垫元素;
element=getStructuringElement(MORPH _ RECT,Size(8,8));
erode(img_seg,src_dil,element);
//imshow(src_dil ,src _ dil);
//边缘检测,提取轮廓
Mat img _ canny
Canny(src_dil,img_canny,200,100);
//imshow(canny ,img _ canny);
向量向量点轮廓;
vectorVec4i层次结构(轮廓。size());
查找轮廓(img_canny,轮廓,层次,CV _ RETR _外部,CV_CHAIN_APPROX_NONE,Point());//寻找轮廓
int size=(int)(等高线。size());//轮廓的数量
//coutsizeendl;6个
//保存符号边框的序号
矢量数量顺序;//定义一个整型(同国际组织)国际组织容器
mapint,int num _ map//容器,需要关键字和模板对象两个模板参数,此处定义一个(同国际组织)国际组织作为索引,并拥有相关连的指向(同国际组织)国际组织的指针
for(int I=0;我尺寸;我)
{
//获取边框数据
rect number _ rect=bounding rect(contours[I]);
int width=number _ rect.width//获取矩形的宽
int height=number _ rect.height//获取矩形的高度
//去掉较小的干扰边框,筛选出合适的区域。
如果(宽度为20毫米/列)
{
rectangle(img,number_rect.tl(),number_rect.br(),Scalar(255,255,255),1,1,0);//绘制一个矩形
imshow(img ,img);//显示矩形框
num _ order . push _ back(number _ rect . x);//将矩形的x坐标放入number_order容器,在vector后面添加一个新元素,
//位置是当前元素的下一个元素
num _ map[number _ rect . x]=I;//在map中存储键值对,number_rect.x是关键字,I是值
/*将矩形框的X坐标与对应的I值一起放入地图容器,形成一对一的键值对。
*/
}
}
//按符号顺序提取
sort(num_order.begin()、num _ order . end());/*按从小到大的顺序排列number_order容器的内容,其中是x的坐标*/
for(int I=0;I num _ order . size();i ) {
rect number _ rect=bounding rect(contours[num _ map . find(num _ order[I])-second]);//num_order包含坐标。
cout num _ map的值为: num _ map . find(num _ order[I])-secondendl;
Rect choose_rect(number_rect.x,0,number_rect.width,img . rows);//矩形左上角的x,y坐标以及矩形的宽度和高度
mat number _ img=img(choose _ rect);
resize(number_img,number_img,Size(30,100));//规范化大小
ROI _ image . push _ back(number _ img);//另存为要测试的图片
//imshow(number to_string(i),number _ img);
char name[50];
sprintf_s(name, D:vs2012model%d.jpg ,I);//保存模板
imwrite(姓名,号码_ img);
}
Cout“图片分割完成”endl
//加载模板
vectorMattemptImage//存储模板
for(int I=0;i4;我)
{
char name[50];
sprintf_s(name, D:vs2012model%d.jpg ,I);
Mat温度;
temp=im read(name);
//cout 加载模板图像的通道数: temp . channels()endl;
temptimage . push _ back(temp);
}
vectorintseq//存储序列结果
for(int I=0;iROI _ image . size();我)
{
Mat子图像;
int sum=0;
int min=50000
int seq _ min=0;//记录最小和对应的数字
for(int j=0;j4;j)
{
absdiff(ROI_image[i],temptImage[j],subImage);//从待测图片的像素中减去模板图片的像素
sum=sunImage(子图像);//计算像素的总和
如果(总和)
{
min=sum
seq _ min=j;
}
sum=0;
}
seq . push _ back(seq _ min);
}
Cout 输出数字匹配结果:;//endl表示换行。
for(int I=0;iseq . size();I )//输出结果,小数点固定在第三位。
{
cout seq[I];
如果(i==1)
{
cout . ;
}
}
finish=clock();
double all_time=double(完成-开始)/CLOCKS _ PER _ SEC;
/*cout 总运行时间为: all _ timeendl*/
wait key(0);
返回0;
}
//计算像素的总和
中间太阳图像(Mat图像)
{
int sum=0;
for(int I=0;iimage.cols我)
{
for(int j=0;jimage.rowsj)
{
sum=image.atuchar(j,I);
}
}
返回总和;
}
整体思路是这样的:0-9这10个数字被分割保存,也就是模板。然后我们对待测图像进行分割,从0-9模板文件夹中读取模板图像,从10个模板中逐一减去分割后的图像,然后统计相减后的像素和。如果这是10个中最低的,那么它们是相同的数。然后
以上是第一种方法,然后还有第二种方法,就是穿线法,根据晶体管的数字特性来识别。
这就是晶体管数的特点。从0到9的每个数字都不一样。我们将在下一篇文章中详细介绍。
总结
关于如何基于opencv实现简单的数字识别的文章到此结束。有关opencv数字识别的更多信息,请搜索我们以前的文章或继续浏览下面的相关文章。希望你以后能支持我们!