这一次,我们运用学到的Opencv的知识,一起来完成一个简单的数字识别项目,作者本人也是初学者,所以我将以初学者的角度思考要怎么完成这个项目。我将介绍对下图中的数字进行识别的方法:

在这里插入图片描述

思考问题:

1、Q:要怎么对一幅待检测的图像提取出我们要识别的数字呢?
A:首先我们可以对图像进行简单的操作转化为二值图像,提取处其中的轮廓后取最小外接矩形,将得到的一个个矩形储存在定义的vector容器当中,等待下一步处理。
2、Q:我们要怎么对提取出的轮廓进行识别得出其中为数字的轮廓呢?
A:首先我们得提前准备好0~9十个数字的模板图片。注意,由于我们用的方法是分割出最小外接矩形,所以我们选取匹配的数字模板图片需尽量为每个数字的最小外接图片。然后我们将分割出的图片与模板图片通过遍历像素对比,得出相似度,相似度最高对应的模板图片数字即为识别出的数字。

完成了这两个问题的思考,我们也就知道了完成这个项目的大概思路,加下来介绍具体实现步骤:

实现步骤:

1、我们可以创建一个用于记录轮廓数量和坐标的结构体,方便我们对提取到的轮廓根据其坐标进行排序。

//创建记录轮廓数量和坐标的结构体
struct num_contours
{
 double x, y;                       //轮廓的x、y坐标
 int index;				  //轮廓的顺序
 bool operator <(num_contours &m)
 {
  if (y > m.y+50) return false;
  else if (y > m.y-50)
  {
   if (x < m.x) return true;
   else return false;
  }
  else return true;
 }
}num_contours[100];

2、有了记录轮廓的结构体,我们就可以提取出检测图像的轮廓,取最小外接矩形储存在vector容器中,得到矩形中心点作为轮廓中心点,根据坐标进行排序。

vector<vector<Point>> contours;
 vector<Vec4i> hierarchy;
 findContours(dest, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_NONE, Point(0, 0));    //提取轮廓

 vector<Rect> rect;
 Rect min_bounding_rect,re_rect;
 float tl_x, br_y, width, height;
 for (int i = 0; i < contours.size(); i++)
 {
  min_bounding_rect = boundingRect(contours[i]);
  rect.push_back(boundingRect(contours[i]));      //储存最小外接矩形

  tl_x = (float)min_bounding_rect.tl().x;
  br_y = (float)min_bounding_rect.br().y;
  width = (float)min_bounding_rect.width;
  height = (float)min_bounding_rect.height;

  num_contours[i].x = (tl_x * 2 + width) / 2.0;          //计算轮廓中心点
  num_contours[i].y = (br_y * 2 + height) / 2.0;
  num_contours[i].index = i;
 }

3、加载模板图像,储存在vector容器中

vector<Mat> imread_model()
{
 vector<Mat> myTemplate;

 //加载模板图像
 for (int i = 0; i < 10; i++)
 {
  char name[64];
  sprintf_s(name, "C:/Users/86159/Desktop/num_text/%d.png", i);
  Mat temp = imread(name, 0);
  myTemplate.push_back(temp);
 }

  return myTemplate;
}

4、我们需要对加载的图像也进行预处理,将其转化为二值图像。

5、模板图像与分割出的待检测图像的比较与匹配,由于都经过预处理都转化成了二值图像,所以我们只要遍历两张图的像素,检测每个像素点各自的像素值是否相等,记录相等像素点的个数,除以像素点总个数,即可作为两幅图像的相似度。

double compare(Mat &src, Mat &model)               //模板与图像对比计算相似度
{
 Mat re_model;
 resize(model, re_model, src.size());
 int rows, cols;
 uchar *src_data, *model_data;
 rows = re_model.rows;
 cols = re_model.cols*src.channels();
 double percentage,same=0.0,different=0.0;

for (int i = 0; i < rows; i++)       //遍历图像像素
 {
  src_data = src.ptr<uchar>(i);
  model_data = re_model.ptr<uchar>(i);
  for (int j = 0; j < cols; j++)
  {
   if (src_data[j] == model_data[j])
   {
    same++;         //记录像素值相同的个数
   }
   else
   {
    different++;    //记录像素值不同的个数
   }
  }
 }
 percentage = same / (same + different);
 return percentage;                     //返回相似度
}

6、创建一个记录相似度和结果顺序的结构体,方便我们输出结果。

//创建记录结果的结构体
struct result
 {
 double data;
 int num;

bool operator<(result &m)
 {
  if (data < m.data)return true;
  else return false;
 }
}result[100];

7、最后我们就可以输出结果啦。

if (result[9].data>0.7)          //过滤不是数字的结果
 {
  cout << "第" << num << "个数字为 " << result[9].num << endl;
  cout << "识别精度为 " << result[9].data << endl << endl;
 }

效果展示:

识别后:

在这里插入图片描述

输出结果:

在这里插入图片描述
完整代码下载:Opencv数字识别
(刚上传的几天可能在审核,会进不去页面)

之后作者也会将源代码的下载地址放在微信公众号的推送中,到时读者可以通过扫描下方二维码在公众号中查找推送下载源代码。

希望对读者有所帮助,喜欢的话可以关注一下我的公众号,我会把学习笔记发在上面,大家可以一起共同学习!

在这里插入图片描述
Alt

GitHub 加速计划 / opencv31 / opencv
77.38 K
55.71 K
下载
OpenCV: 开源计算机视觉库
最近提交(Master分支:2 个月前 )
c3747a68 Added Universal Windows Package build to CI. 10 天前
9b635da5 - 10 天前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐