1、先把这个图片中的数字分割,分割成为5张小图片,每张图片包含一个数字,为啥要分割呢?因为我们没办法让计算机知道这个数字是多少,所以只能根据特征,让计算机去识别特征,然后每一个特征对应一个值,首先贴出分割图片的程序,然后在程序下方会有一段思路解释
#include opencv2/core/core.hpp>
#include opencv.hpp>
#include opencv2/highgui/highgui.hpp>
#include opencv2/features2d/features2d.hpp>
#include opencv2/imgproc/imgproc.hpp>
#include iostream>
#include ctime>
using namespace std ;
using namespace cv;
#include map>
Mat src_threshold;
Mat src_dil;
int sunImage(Mat image);
vectorMat>ROI_image;//待测图片
int main()
{
clock_t start ,finish;
start=clock();
Mat src;
src=imread("D:\\vspic\\picture\\number6.jpg");
resize(src,src,Size(src.cols/7,src.rows/7));
imshow("src",src);
Mat src_gray;
cvtColor(src,src_gray,COLOR_BGR2GRAY);
//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;
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);
vectorvectorPoint>>contours_src;
vectorVec4i>hierarchy_src(contours_src.size());
findContours(src_canny,contours_src,hierarchy_src,RETR_EXTERNAL,CHAIN_APPROX_NONE);
Rect rect_s;
Rect choose_rect;
for (size_t i=0;icontours_src.size();i++)
{
rect_s=boundingRect(contours_src[i]);
double width=rect_s.width;
double height= rect_s.height;
double bizhi=width/height;
if (bizhi>1.5height>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_BGR2GRAY);
// 高斯模糊
Mat img_gau;
GaussianBlur(gray_img, img_gau, Size(3, 3), 0, 0);
// 阈值分割
Mat img_seg;
threshold(img_gau, img_seg, 0, 255, THRESH_BINARY + THRESH_OTSU);
Mat element;
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);
vectorvectorPoint>> contours;
vectorVec4i> hierarchy(contours.size());
findContours(img_canny, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE, Point());//寻找轮廓
int size = (int)(contours.size());//轮廓的数量
//coutsizeendl;6个
// 保存符号边框的序号
vectorint> num_order;//定义一个整型int容器
mapint, int> num_map;//容器,需要关键字和模板对象两个模板参数,此处定义一个int作为索引,并拥有相关连的指向int的指针
for (int i = 0; i size; i++)
{
// 获取边框数据
Rect number_rect = boundingRect(contours[i]);
int width = number_rect.width;//获取矩形的宽
int height = number_rect.height;//获取矩形的高
// 去除较小的干扰边框,筛选出合适的区域
if (width > img.cols/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值一起放入map容器中,形成一一对应的键值对
*/
}
}
// 按符号顺序提取
sort(num_order.begin(), num_order.end());/*把number_order容器中的内容按照从小到大的顺序排列,这里面是X的坐标*/
for (int i = 0; i num_order.size(); i++) {
Rect number_rect = boundingRect(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:\\vs2012\\model\\%d.jpg",i);//保存模板
imwrite(name, number_img);
}
cout"图片分割完毕"endl;
//加载模板
vectorMat>temptImage;//存放模板
for (int i=0;i4;i++)
{
char name[50];
sprintf_s(name,"D:\\vs2012\\model\\%d.jpg",i);
Mat temp;
temp=imread(name);
//cout"加载模板图片通道数:"temp.channels()endl;
temptImage.push_back(temp);
}
vectorint>seq;//存放顺序结果
for (int i=0;iROI_image.size();i++)
{
Mat subImage;
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(subImage);//统计像素和
if (summin)
{
min=sum;
seq_min=j;
}
sum=0;
}
seq.push_back(seq_min);
}
cout"输出数字匹配结果:";//endl是换行的意思
for (int i=0;iseq.size();i++)//输出结果,小数点固定在第3位
{
coutseq[i];
if (i==1)
{
cout".";
}
}
finish=clock();
double all_time=double(finish-start)/CLOCKS_PER_SEC;
/*cout"运行总时间是:"all_timeendl;*/
waitKey(0);
return 0;
}
//计算像素和
int sunImage(Mat image)
{
int sum=0;
for (int i=0;iimage.cols;i++)
{
for (int j=0;jimage.rows;j++)
{
sum+=image.atuchar>(j,i);
}
}
return sum;
}
整体思路是这样子的:0-9这10个数字也都是已经被分割好的,并且保存好了,也就是模板,然后我们把待测的图片也分割掉,然后从0-9模板文件夹中去读取模板图片,让待测的分割完毕的图片去和10个模板逐个相减,然后去统计他们相减后的像素和,如果这个在这10个中最低,那么他们就是同一个数字,然后输出值就可以了,分割后的大概是这样
到此这篇关于如何基于opencv实现简单的数字识别的文章就介绍到这了,更多相关opencv实现数字识别内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!