使用Opencv+VS2015做数字图像识别
程序员文章站
2024-03-07 18:26:27
...
本文大部分代码转载自https://blog.csdn.net/huaweiran1993/article/details/80548290
一、首先建立数字的模板(0-9)图像
使用Windows自带的画图软件,制作数字图片
依次类推建立数字0-9的图片
把图片就放在工程目录下,如上图。
二、完整代码如下
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
using namespace std;
int getColSum(Mat src, int col) //统计所有列的总和
{
int sum = 0;
int height = src.rows;
int width = src.cols;
for (int i = 0; i < height; i++)
{
sum = sum + src.at<uchar>(i, col);
}
return sum;
}
int getRowSum(Mat src, int row)//统计所有行的总和
{
int sum = 0;
int height = src.rows;
int width = src.cols;
for (int i = 0; i < width; i++)
{
sum = sum + src.at<uchar>(row,i);
}
return sum;
}
void cutTop(Mat& src, Mat& dstImg) //切掉图片的上下空白
{
int top, bottom;
top = 0;
bottom = src.rows;
int i;
for (i = 0; i < src.rows; i++)
{
int colValue = getRowSum(src, i);
if (colValue > 0)
{
top = i;
break;
}
}
for (; i < src.rows; i++)
{
int colValue = getRowSum(src, i);
if (colValue == 0)
{
bottom = i;
break;
}
}
int height = bottom - top;
Rect rect(0, top, src.cols, height);
dstImg = src(rect).clone();
}
int cutLeft(Mat& src, Mat& leftImg, Mat& rightImg) //切掉左边空白和数字切割
{
int left, right;
left = 0;
right = src.cols;
int i;
for (i = 0; i < src.cols; i++)
{
int colValue = getColSum(src, i);
if (colValue > 0)
{
left = i;
break;
}
}
if (left == 0)
{
return 1;
}
for (; i < src.cols; i++)
{
int colValue = getColSum(src, i);
if (colValue == 0)
{
right = i;
break;
}
}
int width = right - left;
Rect rect(left, 0, width, src.rows);
leftImg = src(rect).clone();
Rect rectRight(right, 0, src.cols-right, src.rows);
rightImg = src(rectRight).clone();
cutTop(leftImg, leftImg);
return 0;
}
void getPXSum(Mat &src, int &a) //计算图像总和
{
threshold(src, src, 100, 255, CV_THRESH_BINARY);
a = 0;
for (int i = 0; i < src.rows; i++)
{
for (int j = 0; j < src.cols; j++)
{
a += src.at<uchar>(i, j);
}
}
}
int getSubtract(Mat &src, int TemplateNum) //用于识别数字
{
Mat img_result;
int min = 1000000;
int serieNum = 0;
for (int i = 0; i <= TemplateNum; i++)
{
char name[20];
sprintf_s(name, "%d.png", i);
Mat Template = imread(name, CV_LOAD_IMAGE_GRAYSCALE);
threshold(Template, Template, 100, 255, CV_THRESH_BINARY);
threshold(src, src, 100, 255, CV_THRESH_BINARY);
resize(src, src, Size(50, 50), 0, 0, CV_INTER_LINEAR);
resize(Template, Template, Size(50, 50), 0, 0, CV_INTER_LINEAR);
absdiff(Template, src, img_result);
int diff = 0;
getPXSum(img_result, diff);
if (diff < min)
{
min = diff;
serieNum = i;
}
}
printf("最小距离是%d", min);
printf("匹配到第%d个模板匹配的数字是%d\n", serieNum, serieNum);
return serieNum;
}
int main()
{
//用于模板建立
for (int i = 0; i < 10; i++)
{
char fileName[10];
sprintf_s(fileName, "%d.png", i);
Mat src = imread(fileName, CV_LOAD_IMAGE_GRAYSCALE);
threshold(src, src, 100, 255, CV_THRESH_BINARY_INV);
Mat rImg,dst;
cutLeft(src, dst, rImg);
imwrite(fileName, dst);
}
//用于识别
//Mat src = imread("z.png", CV_LOAD_IMAGE_GRAYSCALE);
//threshold(src, src, 100, 255, CV_THRESH_BINARY_INV);
//imshow("origin", src);
//Mat leftImg, rightImg;
//int res = cutLeft(src, leftImg, rightImg);
//while (res == 0)
//{
// Mat srcTmp = rightImg;
// getSubtract(leftImg, 9);
// res = cutLeft(srcTmp, leftImg, rightImg);
//}
waitKey(0);
return 0;
}
三、模板建立
使用上面代码运行获得数字的模板,如图
四、识别
将main函数中用于模板建立的代码注释掉,用于识别的代码去掉注释
int main()
{
//用于模板建立
//for (int i = 0; i < 10; i++)
//{
// char fileName[10];
// sprintf_s(fileName, "%d.png", i);
// Mat src = imread(fileName, CV_LOAD_IMAGE_GRAYSCALE);
// threshold(src, src, 100, 255, CV_THRESH_BINARY_INV);
// Mat rImg,dst;
// cutLeft(src, dst, rImg);
// imwrite(fileName, dst);
//}
//用于识别
Mat src = imread("z.png", CV_LOAD_IMAGE_GRAYSCALE);
threshold(src, src, 100, 255, CV_THRESH_BINARY_INV);
imshow("origin", src);
Mat leftImg, rightImg;
int res = cutLeft(src, leftImg, rightImg);
while (res == 0)
{
Mat srcTmp = rightImg;
getSubtract(leftImg, 9);
res = cutLeft(srcTmp, leftImg, rightImg);
}
waitKey(0);
return 0;
}
用画图软件制作识别用的图像
运行程序结果如下: