最近用opencv做一个字符识别的例子。参考了CSDN上的文档,把全部代码写下来了。训练100000个样本时候准确率超90%。主要用来识别0-9数字。
详细原理参考了
https://www.cnblogs.com/ronny/p/opencv_road_more_01.html
这位大佬写的文章。
代码如下:可以直接写一个main函数跑,转载请注明,请勿商用。
#include "opencv2\opencv.hpp"
#include "iostream""
#include "string"
#include "stdafx.h"
#include "targetver.h"
#include "opencv2\highgui.hpp"
#include "opencv2\ml.hpp"
#include "opencv2\imgproc.hpp"
using namespace std;
using namespace cv;
/*梯度特征法
void calcGradientFeat(const Mat& imgSrc, vector<float>& feat)
{
float sumMatValue(const Mat& image); // 计算图像中像素灰度值总和
Mat image;
cvtColor(imgSrc, image, CV_BGR2GRAY);
resize(image, image, Size(8, 16));
// 计算x方向和y方向上的滤波
float mask[3][3] = { { 1, 2, 1 }, { 0, 0, 0 }, { -1, -2, -1 } };
Mat y_mask = Mat(3, 3, CV_32F, mask) / 8;
Mat x_mask = y_mask.t(); // 转置
Mat sobelX, sobelY;
filter2D(image, sobelX, CV_32F, x_mask);
filter2D(image, sobelY, CV_32F, y_mask);
sobelX = abs(sobelX);
sobelY = abs(sobelY);
float totleValueX = sumMatValue(sobelX);
float totleValueY = sumMatValue(sobelY);
// 将图像划分为4*2共8个格子,计算每个格子里灰度值总和的百分比
for (int i = 0; i < image.rows; i = i + 4)
{
for (int j = 0; j < image.cols; j = j + 4)
{
Mat subImageX = sobelX(Rect(j, i, 4, 4));
feat.push_back(sumMatValue(subImageX) / totleValueX);
Mat subImageY = sobelY(Rect(j, i, 4, 4));
feat.push_back(sumMatValue(subImageY) / totleValueY);
}
}
}
float sumMatValue(const Mat& image)
{
float sumValue = 0;
int r = image.rows;
int c = image.cols;
if (image.isContinuous())
{
c = r*c;
r = 1;
}
for (int i = 0; i < r; i++)
{
const uchar* linePtr = image.ptr<uchar>(i);
for (int j = 0; j < c; j++)
{
sumValue += linePtr[j];
}
}
return sumValue;
}
*/
int main(){
CvANN_MLP bp;
int times = 0;
int r, t;
Mat imgfeatures(100000, 128, CV_32F);
Mat inputs;
Mat outputs = cv::Mat::zeros(cv::Size(10, 100000), CV_32F); // 全零矩阵
CvANN_MLP_TrainParams params;
cout << "开始训练请输入0" << endl;
cout << "直接测试请输入1" << endl;
int scan;
cin >> scan;
if (scan == 0){
while (times < 100000){
r = rand() % 10;
t = rand() % 50 + 1;
char filename[100];
sprintf_s(filename, "G:\\opencv\\字符识别\\charSamples\\%d\\字符%d (%d).png", r, r, t);
Mat SrcImg, ResImg;
SrcImg = cv::imread(filename, 1);//导入图片
if (SrcImg.empty())//读取失败时
{
cout << "Could not open or find the image" << std::endl;
return -1;
}
cvtColor(SrcImg, ResImg, CV_BGR2GRAY);
resize(ResImg, ResImg, Size(8, 16), 0, 0, CV_INTER_LINEAR);
Mat imgfeature(1, 128, CV_32F);
//Laplacian(ResImg, ResImg, ResImg.depth(), 3, 1);
int p = 0;
for (int i = 0; i < ResImg.rows; i++)
{
for (int j = 0; j < ResImg.cols; j++)
{
imgfeature.at<float>(0, p) = ResImg.at<unsigned char>(i, j);
//auto a = ResImg.at<unsigned char>(i, j);
p++;
}
}
for (int i = 0; i < imgfeature.cols; i++)
{
imgfeatures.at<float>(times, i) = imgfeature.at<float>(0, i);
}
outputs.at<float>(times, r) = 1;
times++;
}
Mat layerSizes = (Mat_<int>(1, 5) << 128, 16, 16, 16, 10);
bp.create(layerSizes, CvANN_MLP::SIGMOID_SYM, 1, 1);
//CvANN_MLP_TrainParams params;
params.train_method = CvANN_MLP_TrainParams::BACKPROP;//训练算法设置为随机序列反向传播
//该系数乘以计算出的权值梯度,推荐值为0.1。
params.bp_dw_scale = 0.1;
//该系数乘以前两次迭代的权值之差,平滑权值的随机影响,取值从0-1(0对应的特征被disable)或更大,0.1左右已经足够了。
params.bp_moment_scale = 0.1;
params.term_crit = cvTermCriteria(CV_TERMCRIT_ITER + CV_TERMCRIT_EPS, 5000, 0.01);
int nSamples = 100000;//设置样本个数
int ndims = 128;//特征向量维数
int nClass = 10;//类别数
inputs = imgfeatures;
/*for (int i = 0; i < 2000; i++)
{
outputs.at<float>(i, r) = 1;
}*/
//outputs.at<float>(times, r) = 1;
cout << "the net is training...." << endl;
bp.train(inputs, outputs, Mat(), Mat(), params);
bp.save("bp.xml");//保存训练结果
cout << "the net has trained over" << endl;
Mat input, Resinput;
Mat bpinput(1, 128, CV_32F);
Mat output(1, 10, CV_32F);
input = imread("G:\\opencv\\字符识别\\charSamples\\5\\字符5 (2).png", 1);
cvtColor(input, Resinput, CV_BGR2GRAY);
resize(Resinput, Resinput, Size(8, 16), 0, 0, CV_INTER_LINEAR);
int p1 = 0;
for (int i = 0; i < Resinput.rows; i++)
{
for (int j = 0; j < Resinput.cols; j++)
{
bpinput.at<float>(0, p1) = Resinput.at<unsigned char>(i, j);
//auto a = ResImg.at<unsigned char>(i, j);
p1++;
}
}
bp.predict(bpinput, output);
float max = 0;
int flag;
for (int i = 0; i < output.cols; i++)
{
if (max < output.at<float>(0, i))
{
max = output.at<float>(0, i);
flag = i;
}
}
switch (flag)
{
case 0: cout << "0" << endl;
cout << output.at<float>(0, 0) << endl;
cout << output.at<float>(0, 1) << endl;
cout << output.at<float>(0, 2) << endl;
cout << output.at<float>(0, 3) << endl;
cout << output.at<float>(0, 4) << endl;
cout << output.at<float>(0, 5) << endl;
cout << output.at<float>(0, 6) << endl;
cout << output.at<float>(0, 7) << endl;
cout << output.at<float>(0, 8) << endl;
cout << output.at<float>(0, 9) << endl;
break;
case 1: cout << "1" << endl;
cout << output.at<float>(0, 0) << endl;
cout << output.at<float>(0, 1) << endl;
cout << output.at<float>(0, 2) << endl;
cout << output.at<float>(0, 3) << endl;
cout << output.at<float>(0, 4) << endl;
cout << output.at<float>(0, 5) << endl;
cout << output.at<float>(0, 6) << endl;
cout << output.at<float>(0, 7) << endl;
cout << output.at<float>(0, 8) << endl;
cout << output.at<float>(0, 9) << endl;
break;
case 2: cout << "2" << endl;
cout << output.at<float>(0, 0) << endl;
cout << output.at<float>(0, 1) << endl;
cout << output.at<float>(0, 2) << endl;
cout << output.at<float>(0, 3) << endl;
cout << output.at<float>(0, 4) << endl;
cout << output.at<float>(0, 5) << endl;
cout << output.at<float>(0, 6) << endl;
cout << output.at<float>(0, 7) << endl;
cout << output.at<float>(0, 8) << endl;
cout << output.at<float>(0, 9) << endl;
break;
case 3: cout << "3" << endl;
cout << output.at<float>(0, 0) << endl;
cout << output.at<float>(0, 1) << endl;
cout << output.at<float>(0, 2) << endl;
cout << output.at<float>(0, 3) << endl;
cout << output.at<float>(0, 4) << endl;
cout << output.at<float>(0, 5) << endl;
cout << output.at<float>(0, 6) << endl;
cout << output.at<float>(0, 7) << endl;
cout << output.at<float>(0, 8) << endl;
cout << output.at<float>(0, 9) << endl;
break;
case 4: cout << "4" << endl;
cout << output.at<float>(0, 0) << endl;
cout << output.at<float>(0, 1) << endl;
cout << output.at<float>(0, 2) << endl;
cout << output.at<float>(0, 3) << endl;
cout << output.at<float>(0, 4) << endl;
cout << output.at<float>(0, 5) << endl;
cout << output.at<float>(0, 6) << endl;
cout << output.at<float>(0, 7) << endl;
cout << output.at<float>(0, 8) << endl;
cout << output.at<float>(0, 9) << endl;
break;
case 5: cout << "5" << endl;
cout << output.at<float>(0, 0) << endl;
cout << output.at<float>(0, 1) << endl;
cout << output.at<float>(0, 2) << endl;
cout << output.at<float>(0, 3) << endl;
cout << output.at<float>(0, 4) << endl;
cout << output.at<float>(0, 5) << endl;
cout << output.at<float>(0, 6) << endl;
cout << output.at<float>(0, 7) << endl;
cout << output.at<float>(0, 8) << endl;
cout << output.at<float>(0, 9) << endl;
break;
case 6: cout << "6" << endl;
cout << output.at<float>(0, 0) << endl;
cout << output.at<float>(0, 1) << endl;
cout << output.at<float>(0, 2) << endl;
cout << output.at<float>(0, 3) << endl;
cout << output.at<float>(0, 4) << endl;
cout << output.at<float>(0, 5) << endl;
cout << output.at<float>(0, 6) << endl;
cout << output.at<float>(0, 7) << endl;
cout << output.at<float>(0, 8) << endl;
cout << output.at<float>(0, 9) << endl;
break;
case 7: cout << "7" << endl;
cout << output.at<float>(0, 0) << endl;
cout << output.at<float>(0, 1) << endl;
cout << output.at<float>(0, 2) << endl;
cout << output.at<float>(0, 3) << endl;
cout << output.at<float>(0, 4) << endl;
cout << output.at<float>(0, 5) << endl;
cout << output.at<float>(0, 6) << endl;
cout << output.at<float>(0, 7) << endl;
cout << output.at<float>(0, 8) << endl;
cout << output.at<float>(0, 9) << endl;
break;
case 8: cout << "8" << endl;
cout << output.at<float>(0, 0) << endl;
cout << output.at<float>(0, 1) << endl;
cout << output.at<float>(0, 2) << endl;
cout << output.at<float>(0, 3) << endl;
cout << output.at<float>(0, 4) << endl;
cout << output.at<float>(0, 5) << endl;
cout << output.at<float>(0, 6) << endl;
cout << output.at<float>(0, 7) << endl;
cout << output.at<float>(0, 8) << endl;
cout << output.at<float>(0, 9) << endl;
break;
case 9: cout << "9" << endl;
cout << output.at<float>(0, 9) << endl;
cout << output.at<float>(0, 0) << endl;
cout << output.at<float>(0, 1) << endl;
cout << output.at<float>(0, 2) << endl;
cout << output.at<float>(0, 3) << endl;
cout << output.at<float>(0, 4) << endl;
cout << output.at<float>(0, 5) << endl;
cout << output.at<float>(0, 6) << endl;
cout << output.at<float>(0, 7) << endl;
cout << output.at<float>(0, 8) << endl;
cout << output.at<float>(0, 9) << endl;
break;
case 10: cout << "A" << endl;
cout << output.at<float>(0, 0) << endl;
cout << output.at<float>(0, 1) << endl;
cout << output.at<float>(0, 2) << endl;
cout << output.at<float>(0, 3) << endl;
cout << output.at<float>(0, 4) << endl;
cout << output.at<float>(0, 5) << endl;
cout << output.at<float>(0, 6) << endl;
cout << output.at<float>(0, 7) << endl;
cout << output.at<float>(0, 8) << endl;
cout << output.at<float>(0, 9) << endl;
break;
case 11: cout << "B" << endl;
cout << output.at<float>(0, 0) << endl;
cout << output.at<float>(0, 1) << endl;
cout << output.at<float>(0, 2) << endl;
cout << output.at<float>(0, 3) << endl;
cout << output.at<float>(0, 4) << endl;
cout << output.at<float>(0, 5) << endl;
cout << output.at<float>(0, 6) << endl;
cout << output.at<float>(0, 7) << endl;
cout << output.at<float>(0, 8) << endl;
cout << output.at<float>(0, 9) << endl;
break;
case 12: cout << "C" << endl;
break;
case 13: cout << "D" << endl;
break;
case 14: cout << "E" << endl;
break;
case 15: cout << "F" << endl;
break;
case 16: cout << "G" << endl;
break;
case 17: cout << "H" << endl;
break;
case 18: cout << "J" << endl;
break;
case 19: cout << "K" << endl;
break;
case 20: cout << "L" << endl;
break;
case 21: cout << "M" << endl;
break;
case 22: cout << "N" << endl;
break;
case 23: cout << "P" << endl;
break;
case 24: cout << "Q" << endl;
break;
case 25: cout << "R" << endl;
break;
case 26: cout << "S" << endl;
break;
case 27: cout << "T" << endl;
break;
case 28: cout << "U" << endl;
break;
case 29: cout << "V" << endl;
break;
case 30: cout << "W" << endl;
break;
case 31: cout << "X" << endl;
break;
case 32: cout << "Y" << endl;
break;
case 33: cout << "Z" << endl;
break;
default:
break;
}
}
else if (scan == 1)
{
CvANN_MLP bp;
CvANN_MLP_TrainParams params;
Mat layerSizes = (Mat_<int>(1, 5) << 128, 16, 16, 16, 10);
bp.create(layerSizes, CvANN_MLP::SIGMOID_SYM, 1, 1);
//CvANN_MLP_TrainParams params;
params.train_method = CvANN_MLP_TrainParams::BACKPROP;//训练算法设置为随机序列反向传播
//该系数乘以计算出的权值梯度,推荐值为0.1。
params.bp_dw_scale = 0.1;
//该系数乘以前两次迭代的权值之差,平滑权值的随机影响,取值从0-1(0对应的特征被disable)或更大,0.1左右已经足够了。
params.bp_moment_scale = 0.1;
params.term_crit = cvTermCriteria(CV_TERMCRIT_ITER + CV_TERMCRIT_EPS, 5000, 0.01);
bp.load("bp.xml");
Mat input, Resinput;
Mat bpinput(1, 128, CV_32F);
Mat output(1, 10, CV_32F);
input = imread("G:\\opencv\\字符识别\\charSamples\\9\\字符9 (13).png", 1);
cvtColor(input, Resinput, CV_BGR2GRAY);
resize(Resinput, Resinput, Size(8, 16), 0, 0, CV_INTER_LINEAR);
int p1 = 0;
for (int i = 0; i < Resinput.rows; i++)
{
for (int j = 0; j < Resinput.cols; j++)
{
bpinput.at<float>(0, p1) = Resinput.at<unsigned char>(i, j);
//auto a = ResImg.at<unsigned char>(i, j);
p1++;
}
}
bp.predict(bpinput, output);
float max = 0;
int flag;
for (int i = 0; i < output.cols; i++)
{
if (max < output.at<float>(0, i))
{
max = output.at<float>(0, i);
flag = i;
}
}
switch (flag)
{
case 0: cout << "0" << endl;
cout << output.at<float>(0, 0) << endl;
cout << output.at<float>(0, 1) << endl;
cout << output.at<float>(0, 2) << endl;
cout << output.at<float>(0, 3) << endl;
cout << output.at<float>(0, 4) << endl;
cout << output.at<float>(0, 5) << endl;
cout << output.at<float>(0, 6) << endl;
cout << output.at<float>(0, 7) << endl;
cout << output.at<float>(0, 8) << endl;
cout << output.at<float>(0, 9) << endl;
break;
case 1: cout << "1" << endl;
cout << output.at<float>(0, 0) << endl;
cout << output.at<float>(0, 1) << endl;
cout << output.at<float>(0, 2) << endl;
cout << output.at<float>(0, 3) << endl;
cout << output.at<float>(0, 4) << endl;
cout << output.at<float>(0, 5) << endl;
cout << output.at<float>(0, 6) << endl;
cout << output.at<float>(0, 7) << endl;
cout << output.at<float>(0, 8) << endl;
cout << output.at<float>(0, 9) << endl;
break;
case 2: cout << "2" << endl;
cout << output.at<float>(0, 0) << endl;
cout << output.at<float>(0, 1) << endl;
cout << output.at<float>(0, 2) << endl;
cout << output.at<float>(0, 3) << endl;
cout << output.at<float>(0, 4) << endl;
cout << output.at<float>(0, 5) << endl;
cout << output.at<float>(0, 6) << endl;
cout << output.at<float>(0, 7) << endl;
cout << output.at<float>(0, 8) << endl;
cout << output.at<float>(0, 9) << endl;
break;
case 3: cout << "3" << endl;
cout << output.at<float>(0, 0) << endl;
cout << output.at<float>(0, 1) << endl;
cout << output.at<float>(0, 2) << endl;
cout << output.at<float>(0, 3) << endl;
cout << output.at<float>(0, 4) << endl;
cout << output.at<float>(0, 5) << endl;
cout << output.at<float>(0, 6) << endl;
cout << output.at<float>(0, 7) << endl;
cout << output.at<float>(0, 8) << endl;
cout << output.at<float>(0, 9) << endl;
break;
case 4: cout << "4" << endl;
cout << output.at<float>(0, 0) << endl;
cout << output.at<float>(0, 1) << endl;
cout << output.at<float>(0, 2) << endl;
cout << output.at<float>(0, 3) << endl;
cout << output.at<float>(0, 4) << endl;
cout << output.at<float>(0, 5) << endl;
cout << output.at<float>(0, 6) << endl;
cout << output.at<float>(0, 7) << endl;
cout << output.at<float>(0, 8) << endl;
cout << output.at<float>(0, 9) << endl;
break;
case 5: cout << "5" << endl;
cout << output.at<float>(0, 0) << endl;
cout << output.at<float>(0, 1) << endl;
cout << output.at<float>(0, 2) << endl;
cout << output.at<float>(0, 3) << endl;
cout << output.at<float>(0, 4) << endl;
cout << output.at<float>(0, 5) << endl;
cout << output.at<float>(0, 6) << endl;
cout << output.at<float>(0, 7) << endl;
cout << output.at<float>(0, 8) << endl;
cout << output.at<float>(0, 9) << endl;
break;
case 6: cout << "6" << endl;
cout << output.at<float>(0, 0) << endl;
cout << output.at<float>(0, 1) << endl;
cout << output.at<float>(0, 2) << endl;
cout << output.at<float>(0, 3) << endl;
cout << output.at<float>(0, 4) << endl;
cout << output.at<float>(0, 5) << endl;
cout << output.at<float>(0, 6) << endl;
cout << output.at<float>(0, 7) << endl;
cout << output.at<float>(0, 8) << endl;
cout << output.at<float>(0, 9) << endl;
break;
case 7: cout << "7" << endl;
cout << output.at<float>(0, 0) << endl;
cout << output.at<float>(0, 1) << endl;
cout << output.at<float>(0, 2) << endl;
cout << output.at<float>(0, 3) << endl;
cout << output.at<float>(0, 4) << endl;
cout << output.at<float>(0, 5) << endl;
cout << output.at<float>(0, 6) << endl;
cout << output.at<float>(0, 7) << endl;
cout << output.at<float>(0, 8) << endl;
cout << output.at<float>(0, 9) << endl;
break;
case 8: cout << "8" << endl;
cout << output.at<float>(0, 0) << endl;
cout << output.at<float>(0, 1) << endl;
cout << output.at<float>(0, 2) << endl;
cout << output.at<float>(0, 3) << endl;
cout << output.at<float>(0, 4) << endl;
cout << output.at<float>(0, 5) << endl;
cout << output.at<float>(0, 6) << endl;
cout << output.at<float>(0, 7) << endl;
cout << output.at<float>(0, 8) << endl;
cout << output.at<float>(0, 9) << endl;
break;
case 9: cout << "9" << endl;
cout << output.at<float>(0, 9) << endl;
cout << output.at<float>(0, 0) << endl;
cout << output.at<float>(0, 1) << endl;
cout << output.at<float>(0, 2) << endl;
cout << output.at<float>(0, 3) << endl;
cout << output.at<float>(0, 4) << endl;
cout << output.at<float>(0, 5) << endl;
cout << output.at<float>(0, 6) << endl;
cout << output.at<float>(0, 7) << endl;
cout << output.at<float>(0, 8) << endl;
cout << output.at<float>(0, 9) << endl;
break;
case 10: cout << "A" << endl;
cout << output.at<float>(0, 0) << endl;
cout << output.at<float>(0, 1) << endl;
cout << output.at<float>(0, 2) << endl;
cout << output.at<float>(0, 3) << endl;
cout << output.at<float>(0, 4) << endl;
cout << output.at<float>(0, 5) << endl;
cout << output.at<float>(0, 6) << endl;
cout << output.at<float>(0, 7) << endl;
cout << output.at<float>(0, 8) << endl;
cout << output.at<float>(0, 9) << endl;
break;
case 11: cout << "B" << endl;
cout << output.at<float>(0, 0) << endl;
cout << output.at<float>(0, 1) << endl;
cout << output.at<float>(0, 2) << endl;
cout << output.at<float>(0, 3) << endl;
cout << output.at<float>(0, 4) << endl;
cout << output.at<float>(0, 5) << endl;
cout << output.at<float>(0, 6) << endl;
cout << output.at<float>(0, 7) << endl;
cout << output.at<float>(0, 8) << endl;
cout << output.at<float>(0, 9) << endl;
break;
case 12: cout << "C" << endl;
break;
case 13: cout << "D" << endl;
break;
case 14: cout << "E" << endl;
break;
case 15: cout << "F" << endl;
break;
case 16: cout << "G" << endl;
break;
case 17: cout << "H" << endl;
break;
case 18: cout << "J" << endl;
break;
case 19: cout << "K" << endl;
break;
case 20: cout << "L" << endl;
break;
case 21: cout << "M" << endl;
break;
case 22: cout << "N" << endl;
break;
case 23: cout << "P" << endl;
break;
case 24: cout << "Q" << endl;
break;
case 25: cout << "R" << endl;
break;
case 26: cout << "S" << endl;
break;
case 27: cout << "T" << endl;
break;
case 28: cout << "U" << endl;
break;
case 29: cout << "V" << endl;
break;
case 30: cout << "W" << endl;
break;
case 31: cout << "X" << endl;
break;
case 32: cout << "Y" << endl;
break;
case 33: cout << "Z" << endl;
break;
default:
break;
}
}
else
exit(-1);
system("pause");
return 0;
}
转载请注明!