1、资料:
只是训练数据集:
链接:https://pan.baidu.com/s/1Wvr54HDOHSd4Qs6g2syN4Q
提取码:2ozv
总工程文件:(包括训练工程、测试工程、训练数据集)
链接:https://pan.baidu.com/s/10JiJfJawtye8s9x1dGkvNQ
提取码:dhri
今天弄出了10个的数字识别
2、训练程序
/**********************************************************************
2018.5.23:SVM训练 //在 配置SVM训练器参数CvSVMParams SVM_params;这里有问题
2018.5.25:1、因为例程是opencv2的,opencv3里的svm的一些声明格式有了些许变化,修改了
2、批量读取图片出现错误,原来是一个参数变量出现错误,说明警告也可能造成致命错误
2018.05.31: 之前的svm训练只是二分类,而且特征提取是简单的像素值特征,现在训0-9的数字,且hog特征
2018.6.13 重新训练,成功了,但是自己本身带的训练不行
***************************************************************/
#include "opencv2/opencv.hpp"
#include <opencv2/objdetect/objdetect.hpp> //hog特征的c文件
#include <opencv/cv.h>
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/ml/ml.hpp>
#include <io.h> //查找文件相关函数
#include <stdio.h>
#include <time.h> //测试程序运行时间
#include "windows.h"
#include "fstream"
using namespace std;
using namespace cv;
using namespace cv::ml;
int main()
{
检测窗口(128,128),块尺寸(16,16),块步长(8,8),cell尺寸(8,8),直方图bin个数9
//HOGDescriptor hog(Size(128, 128), Size(16, 16), Size(8, 8), Size(8, 8), 9);
HOG检测器,用来计算HOG描述子的
//int DescriptorDim;//HOG描述子的维数,由图片大小、检测窗口大小、块大小、细胞单元中直方图bin个数决定
//Mat sampleFeatureMat;//所有训练样本的特征向量组成的矩阵,行数等于所有样本的个数,列数等于HOG描述子维数
//Mat sampleLabelMat;//训练样本的类别向量,行数等于所有样本的个数,列数等于1;1表示有人,-1表示无人
Mat classes;
vector<string> img_path;//输入文件名变量
vector<int> img_catg;
int nLine = 0;
string buf;
ifstream svm_data("E:/OCR_Recognition/opencv_project/SVM_train_data/hb.txt");//训练样本图片的路径都写在这个txt文件中,使用bat批处理文件可以得到这个txt文件
unsigned long n;
while (svm_data)//将训练样本文件依次读取进来
{
if (getline(svm_data, buf))
{
nLine++;
if (nLine % 2 == 0)//注:奇数行是图片全路径,偶数行是标签
{
//标签
img_catg.push_back(atoi(buf.c_str()));//atoi将字符串转换成整型,标志(0,1,2,...,9),注意这里至少要有两个类别,否则会出错
}
else
{
//图片
img_path.push_back(buf);//图像路径
}
}
}
svm_data.close();//关闭文件
Mat data_mat, labels_mat;
int nImgNum = nLine / 2; //nImgNum是样本数量,只有文本行数的一半,另一半是标签
cout << " 共有样本个数为: " << nImgNum << endl;
//data_mat为所有训练样本的特征向量组成的矩阵,行数等于所有样本的个数,列数等于HOG描述子维数
data_mat =Mat(nImgNum, 8100, CV_32FC1); //行、列、类型;第二个参数,即矩阵的列是由下面的descriptors的大小决定的,可以由descriptors.size()得到,且对于不同大小的输入训练图片,这个值是不同的
//类型矩阵,存储每个样本的类型标志
//labels_mat为训练样本的类别向量,行数等于所有样本的个数,列数等于1;暂时,后面会修改,比如样本0,就为0,样本1就为1
labels_mat = Mat(nImgNum, 1, CV_32SC1);
Mat src;
Mat trainImg = Mat(Size(128, 128), CV_8UC1);//需要分析的图片,这里默认设定图片是28*28大小,所以上面定义了324,如果要更改图片大小,可以先用debug查看一下descriptors是多少,然后设定好再运行
//处理HOG特征
for (string::size_type i = 0; i <img_path.size(); i++)
{
cout << " \n第 " << i << " 次循环\n" << endl;
src = imread(img_path[i].c_str(),-1);
if (src.empty())
{
cout << " can not load the image: " << img_path[i].c_str() << endl;
continue;
}
cout << " 处理: " << img_path[i].c_str() << endl;
resize(src, trainImg, trainImg.size());
imshow("调整后的图片128*128", trainImg);
waitKey(1);
//检测窗口(64,128),块尺寸(16,16),块步长(8,8),cell尺寸(8,8),直方图bin个数9 ,需要修改
HOGDescriptor *hog = new HOGDescriptor(Size(128, 128), Size(16, 16), Size(8, 8), Size(8, 8), 9);
vector<float>descriptors;//存放结果 为HOG描述子向量
hog->compute(trainImg, descriptors, Size(1, 1), Size(0, 0)); //Hog特征计算,检测窗口移动步长(1,1)
cout << "HOG描述子向量维数 : " << descriptors.size() << endl;
for (vector<float>::size_type j = 0; j < descriptors.size(); j++)
{
data_mat.at<float>(i, j) = descriptors[j];
}
labels_mat.at<int>(i, 0) = img_catg[i];
cout << " 处理完毕: " << img_path[i].c_str() << " " << img_catg[i] << endl;
}
// 创建分类器并设置参数
Ptr<SVM> SVM_params = SVM::create();
SVM_params->setType(SVM::C_SVC);
SVM_params->setKernel(SVM::LINEAR); //注意必须使用线性SVM进行训练,因为HogDescriptor检测函数只支持线性检测!!!
SVM_params->setDegree(10.0);
SVM_params->setGamma(0.09);
SVM_params->setCoef0(1.0);
SVM_params->setC(10.0);
SVM_params->setNu(0.5);
SVM_params->setP(1.0);
//SVM_params->setTermCriteria(TermCriteria(CV_TERMCRIT_EPS, 1000, FLT_EPSILON));
//SVM_params->setKernel(SVM::LINEAR); //核函数
/*SVM_params->setDegree(0);
SVM_params->setGamma(1);
SVM_params->setCoef0(0);
SVM_params->setC(1);
SVM_params->setNu(0);
SVM_params->setP(0);*/
SVM_params->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER + TermCriteria::EPS, 1000, 0.01));
cout << "开始训练..." << endl;
// 训练分类器
SVM_params->train(data_mat, ROW_SAMPLE, labels_mat);
//保存模型
SVM_params->save("svm6_13.xml");
cout << "训练好了!!!" << endl;
/**********************************************************************************************************************/
//检测样本
Mat test_img;
char result[512];
vector<string> img_tst_path;
//
ifstream img_tst("E:\\OCR_Recognition\\opencv_project\\SVM_train_data\\4\\num.txt"); //加载需要预测的图片集合,这个文本里存放的是图片全路径,不要标签
while (img_tst)
{
if (getline(img_tst, buf))
{
img_tst_path.push_back(buf);
}
}
img_tst.close();
ofstream predict_txt("SVM_PREDICT.txt");//把预测结果存储在这个文本中
for (string::size_type j = 0; j != img_tst_path.size(); j++)//依次遍历所有的待检测图片
{
test_img = imread(img_tst_path[j].c_str(), -1);
namedWindow("测试图片", 0);
imshow("测试图片", test_img);
waitKey(10);
if (test_img.empty())
{
cout << " can not load the image: " << img_tst_path[j].c_str() << endl;
continue;
}
Mat trainTempImg = Mat::zeros(Size(128, 128), CV_8UC1);
resize(test_img, trainTempImg, trainTempImg.size());
HOGDescriptor *hog = new HOGDescriptor(Size(128, 128), Size(16, 16), Size(8, 8), Size(8, 8), 9);
vector<float>descriptors;//结果数组
hog->compute(trainTempImg, descriptors, Size(1, 1), Size(0, 0));
cout << "HOG描述子向量维数 " << descriptors.size() << endl;
Mat SVMtrainMat = Mat(1, descriptors.size(), CV_32FC1);
// int n = 0;
int number1 = descriptors.size();
//将计算好的HOG描述子复制到样本特征矩阵data_mat
for (int i = 0; i < number1; i++)
{
data_mat.at<float>(0, i) = descriptors[i];//第i个样本的特征向量中的第n个元素
// n++;
}
int ret = (int)SVM_params->predict(SVMtrainMat);//检测结果
cout << "识别的数字为:" << ret << endl;
sprintf_s(result, "%s %d\r\n", img_tst_path[j].c_str(), ret);
predict_txt << result; //输出检测结果到文本
}
predict_txt.close();
return 0;
}
//
//
//
//
//
//
//#include <stdio.h>
//#include <time.h>
//#include <opencv2/opencv.hpp>
//#include <opencv/cv.h>
//#include <iostream>
//#include <opencv2/core/core.hpp>
//#include <opencv2/highgui/highgui.hpp>
//#include <opencv2/ml/ml.hpp>
//#include <io.h> //查找文件相关函数
//
//using namespace std;
//using namespace cv;
//
//using namespace cv::ml;
//
//void getFiles(string path, vector<string>& files);
//void getBubble(Mat& trainingImages, vector<int>& trainingLabels);
//void getNoBubble(Mat& trainingImages, vector<int>& trainingLabels);
//
//int main()
//{
// //获取训练数据
// Mat classes;
// Mat trainingData;
// Mat trainingImages;
//
//
//
// vector<int> trainingLabels;
//
// //getBubble()与getNoBubble()将获取一张图片后会将图片(特征)写入
// // 到容器中,紧接着会将标签写入另一个容器中,这样就保证了特征
// // 和标签是一一对应的关系push_back(0)或者push_back(1)其实就是
// // 我们贴标签的过程。
// getBubble(trainingImages, trainingLabels);
// getNoBubble(trainingImages, trainingLabels);
//
// //在主函数中,将getBubble()与getNoBubble()写好的包含特征的矩阵拷贝给trainingData,将包含标签的vector容器进行类
// //型转换后拷贝到trainingLabels里,至此,数据准备工作完成,trainingData与trainingLabels就是我们要训练的数据。
// Mat(trainingImages).copyTo(trainingData);
// trainingData.convertTo(trainingData, CV_32FC1);
// Mat(trainingLabels).copyTo(classes);
// //classes.convertTo(classes, CV_32SC1);
//
// // 创建分类器并设置参数
// Ptr<SVM> SVM_params = SVM::create();
// SVM_params->setType(SVM::C_SVC);
// SVM_params->setKernel(SVM::LINEAR); //核函数
//
// SVM_params->setDegree(0);
// SVM_params->setGamma(1);
// SVM_params->setCoef0(0);
// SVM_params->setC(1);
// SVM_params->setNu(0);
// SVM_params->setP(0);
// SVM_params->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER + TermCriteria::EPS, 1000, 0.01));
//
//
// Ptr<TrainData> tData = TrainData::create(trainingData, ROW_SAMPLE, classes);
//
// // 训练分类器
// SVM_params->train(tData);
//
// //保存模型
// SVM_params->save("svm.xml");
// cout << "训练好了!!!" << endl;
// getchar();
// return 0;
//}
//
//
//
//void getFiles(string path, vector<string>& files)
//{
// intptr_t hFile = 0;
// struct _finddata_t fileinfo;
// string p;
// int i = 30;
// if ((hFile = _findfirst(p.assign(path).append("\\*").c_str(), &fileinfo)) != -1)
// {
//
// do
// {
// if ((fileinfo.attrib & _A_SUBDIR))
// {
// if (strcmp(fileinfo.name, ".") != 0 && strcmp(fileinfo.name, "..") != 0)
// getFiles(p.assign(path).append("\\").append(fileinfo.name), files);
// }
// else
// {
// files.push_back(p.assign(path).append("\\").append(fileinfo.name));
// }
//
// }
// while (_findnext(hFile, &fileinfo) == 0);
//
// _findclose(hFile);
// }
//}
//
//
//
//
获取正样本
并贴标签为1
//void getBubble(Mat& trainingImages, vector<int>& trainingLabels)
//{
//
//
// char * filePath = "E:\\SVM_train_data\\positive\\train"; //正样本路径
// vector<string> files;
// getFiles(filePath, files);
// int number = files.size();
// for (int i = 0; i < number; i++)
// {
// Mat SrcImage = imread(files[i].c_str());
// SrcImage = SrcImage.reshape(1, 1);
// trainingImages.push_back(SrcImage);
// trainingLabels.push_back(1);//该样本为数字5
// }
//
//}
//
获取负样本
并贴标签为0
//void getNoBubble(Mat& trainingImages, vector<int>& trainingLabels)
//{
// //char * filePath = "D:\\train\\no\\train"; //负样本路径
// //char * filePath = "E:\\OCR_Recognition\\opencv_project\\SVM_train_data\\negative\\train"; //负样本路径
// char * filePath = "E:\\SVM_train_data\\negative\\train"; //负样本路径
// vector<string> files;
// getFiles(filePath, files);
// int number = files.size();
// for (int i = 0; i < number; i++)
// {
// Mat SrcImage = imread(files[i].c_str());
// SrcImage = SrcImage.reshape(1, 1);
// trainingImages.push_back(SrcImage);
// trainingLabels.push_back(0); //该样本不是数字5
// }
//}
#测试程序一:单个图片
#include <stdio.h>
#include <time.h>
#include <math.h>
#include <opencv2/opencv.hpp>
#include <opencv/cv.h>
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/ml/ml.hpp>
#include <io.h>
#include "windows.h"
#include "fstream"
using namespace std;
using namespace cv;
using namespace cv::ml;
int main()
{
Ptr<ml::SVM>SVM_params = ml::SVM::load("svm6_13.xml");
//Ptr<SVM> SVM_params = SVM::create();
///SVM_params->load("svm6_1.xml");//加载训练好的xml文件,这里训练的是10K个手写数字
//检测样本
Mat test;
char result[300]; //存放预测结果
test = imread("11.jpg", 1); //你自己随便在绘图板里写一个程序
if (test.empty())
{
MessageBox(NULL, TEXT("待预测图像不存在!"), TEXT("提示"), MB_ICONWARNING);
return -1;
}
Mat trainTempImg = Mat::zeros(Size(128, 128), CV_8UC3);
resize(test, trainTempImg, trainTempImg.size());
HOGDescriptor *hog = new HOGDescriptor(Size(128, 128), Size(16, 16), Size(8, 8), Size(8, 8), 9);
vector<float>descriptors;//存放结果
hog->compute(trainTempImg, descriptors, Size(1, 1), Size(0, 0)); //Hog特征计算
cout << "HOG dims: " << descriptors.size() << endl; //打印Hog特征维数 ,这里是324
Mat SVMtrainMat = Mat(1, descriptors.size(), CV_32FC1);
int n = 0;
for (vector<float>::iterator iter = descriptors.begin(); iter != descriptors.end(); iter++)
{
SVMtrainMat.at<float>(0, n) = *iter;//第i个样本的特征向量中的第n个元素
n++;
}
SVMtrainMat.convertTo(SVMtrainMat, CV_32FC1);
int response = (int)SVM_params->predict(SVMtrainMat);
cout << "识别的数字为:" << response << endl;
// int ret = SVM_params->predict(SVMtrainMat);//检测结果
sprintf_s(result, "%d\r\n", response);
cvNamedWindow("dst", 1);
imshow("dst", test);
waitKey(30);
//cout << "识别的数字为:" << result << endl;
return 0;
}
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//#include <stdio.h>
//#include <time.h>
//#include <math.h>
//#include <opencv2/opencv.hpp>
//#include <opencv/cv.h>
//#include <iostream>
//#include <opencv2/core/core.hpp>
//#include <opencv2/highgui/highgui.hpp>
//#include <opencv2/ml/ml.hpp>
//#include <io.h>
//
//using namespace std;
//using namespace cv;
//
//void getFiles(string path, vector<string>& files);
//
//int main()
//{
//
//
// int result = 0; //
// char * filePath = "E:\\SVM_train_data\\positive\\test";
// vector<string> files;
// getFiles(filePath, files);
// int number = files.size();
// cout <<"共有测试图片 " <<number <<" 张\n"<< endl;
//
// Ptr<ml::SVM>svm = ml::SVM::load("svm.xml");
//
// for (int i = 0; i < number; i++)
// {
// clock_t start = clock();
//
// Mat inMat = imread(files[i].c_str());
// Mat p = inMat.reshape(1, 1);
// p.convertTo(p, CV_32FC1);
// int response = (int)svm->predict(p);
// cout << "识别的数字为:" << response << endl;
//
// if (response > 1)
// {
// result++;
// }
//
// clock_t ends = clock();
//
// cout << "Running Time : " << (double)(ends - start) / CLOCKS_PER_SEC << endl;
//
// }
// cout << result << endl;
//
// getchar();
// return 0;
//}
//void getFiles(string path, vector<string>& files)
//{
// intptr_t hFile = 0;
// struct _finddata_t fileinfo;
// string p;
// if ((hFile = _findfirst(p.assign(path).append("\\*").c_str(), &fileinfo)) != -1)
// {
// do
// {
// if ((fileinfo.attrib & _A_SUBDIR))
// {
// if (strcmp(fileinfo.name, ".") != 0 && strcmp(fileinfo.name, "..") != 0)
// getFiles(p.assign(path).append("\\").append(fileinfo.name), files);
// }
// else
// {
// files.push_back(p.assign(path).append("\\").append(fileinfo.name));
// }
// } while (_findnext(hFile, &fileinfo) == 0);
// _findclose(hFile);
// }
//}
//
//
//
//
//
//
//
//
#测试程序二:多个图片
#include <stdio.h>
#include <time.h>
#include <math.h>
#include <opencv2/opencv.hpp>
#include <opencv/cv.h>
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/ml/ml.hpp>
#include <io.h>
#include "windows.h"
#include "fstream"
using namespace std;
using namespace cv;
using namespace cv::ml;
void getFiles(string path, vector<string>& files);
int main()
{
Ptr<ml::SVM>svm = ml::SVM::load("svm6_13.xml");//加载训练好的xml文件,
char result[300]; //存放预测结果
int aaa_0 = 0;
int aaa_1 = 0;
int aaa_2 = 0;
int aaa_3 = 0;
int aaa_4 = 0;
int aaa_5 = 0;
int aaa_6 = 0;
int aaa_7 = 0;
int aaa_8 = 0;
int aaa_9 = 0;
char * filePath = "E:\\OCR_Recognition\\opencv_project\\SVM_test_data";
vector<string> files;
getFiles(filePath, files);
int number = files.size();
cout << "共有测试图片 " << number << " 张\n" << endl;
//检测样本
Mat test_img;
//char result[300]; //存放预测结果
for (int i = 0; i < number; i++)
{
clock_t start = clock();
Mat test_img = imread(files[i].c_str(), 1);
/* namedWindow("测试图片", 0);
imshow("测试图片", test_img);
waitKey(10);*/
if (test_img.empty())
{
cout << " 待预测图像不存在: " << files[i].c_str() << endl;
continue;
}
Mat trainTempImg = Mat::zeros(Size(128, 128), CV_8UC3);
resize(test_img, trainTempImg, trainTempImg.size());
HOGDescriptor *hog = new HOGDescriptor(Size(128, 128), Size(16, 16), Size(8, 8), Size(8, 8), 9);
vector<float>descriptors;//结果数组
hog->compute(trainTempImg, descriptors, Size(1, 1), Size(0, 0));
cout << "HOG描述子向量维数 " << descriptors.size() << endl;
Mat SVMtrainMat = Mat(1, descriptors.size(), CV_32FC1);
int n = 0;
//将计算好的HOG描述子复制到样本特征矩阵SVMtrainMat
for (vector<float>::iterator iter = descriptors.begin(); iter != descriptors.end(); iter++)
{
SVMtrainMat.at<float>(0, n) = *iter;//第i个样本的特征向量中的第n个元素
n++;
}
SVMtrainMat.convertTo(SVMtrainMat, CV_32FC1);
int response = (int)svm->predict(SVMtrainMat);
cout << "识别的数字为:" << response << endl;
sprintf_s(result, "%d\r\n", response);
cvNamedWindow("dst", 1);
imshow("dst", test_img);
waitKey(1);
// cout << "识别的数字为:" << response << endl;
if (response == 0)
{
aaa_0++;
}
if (response == 1)
{
aaa_1++;
}
if (response == 2)
{
aaa_2++;
}
if (response == 3)
{
aaa_3++;
}
if (response == 4)
{
aaa_4++;
}
if (response == 5)
{
aaa_5++;
}
if (response == 6)
{
aaa_6++;
}
if (response == 7)
{
aaa_7++;
}
if (response == 8)
{
aaa_8++;
}
if (response == 9)
{
aaa_9++;
}
clock_t ends = clock();
cout << "Running Time : " << (double)(ends - start) / CLOCKS_PER_SEC << endl;
}
cout << "识别出0的个数为:" << aaa_0 << endl;
cout << "识别出1的个数为:" << aaa_1 << endl;
cout << "识别出2的个数为:" << aaa_2 << endl;
cout << "识别出3的个数为:" << aaa_3 << endl;
cout << "识别出4的个数为:" << aaa_4 << endl;
cout << "识别出5的个数为:" << aaa_5 << endl;
cout << "识别出6的个数为:" << aaa_6 << endl;
cout << "识别出7的个数为:" << aaa_7 << endl;
cout << "识别出8的个数为:" << aaa_8 << endl;
cout << "识别出9的个数为:" << aaa_9 << endl;
getchar();
return 0;
}
void getFiles(string path, vector<string>& files)
{
intptr_t hFile = 0;
struct _finddata_t fileinfo;
string p;
if ((hFile = _findfirst(p.assign(path).append("\\*").c_str(), &fileinfo)) != -1)
{
do
{
if ((fileinfo.attrib & _A_SUBDIR))
{
if (strcmp(fileinfo.name, ".") != 0 && strcmp(fileinfo.name, "..") != 0)
getFiles(p.assign(path).append("\\").append(fileinfo.name), files);
}
else
{
files.push_back(p.assign(path).append("\\").append(fileinfo.name));
}
} while (_findnext(hFile, &fileinfo) == 0);
_findclose(hFile);
}
}