使用Opencv+VS2015做數字影象識別
阿新 • • 發佈:2019-02-15
一、首先建立數字的模板(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;
}
用畫圖軟體製作識別用的影象
執行程式結果如下: