OPENCV中使用SVM训练并识别车牌的初步应用

来源:互联网 发布:图标上下不停跳动js 编辑:程序博客网 时间:2024/06/06 20:16

    opencv的CvSVM的实现基于libsvm,libsvm是台湾大学林智仁(Lin Chih-Jen)教授写的一个世界知名的svm库(可能算是目前业界使用率最高的一个库)。svm的perdict方法的输入是待预测数据的特征,也称之为features。在这里,我们输入的特征是图像全部的像素。由于svm要求输入的特征应该是一个向量,而Mat是与图像宽高对应的矩阵,因此在输入前我们需要使用reshape(1,1)方法把矩阵拉伸成向量。

    在训练之前要先将待训练的样例分类,一类是车牌图像,一类是非车牌图片,可称为正样例和反样例,分类过程需要很多时间来做。分类好后,就可以把正样例和反样例存入程序中,并做好预处理,具体代码如下:

<span style="background-color: rgb(240, 240, 240);">//先定义两个全局变量</span>
vector<Mat> trainingImages;vector<int> trainingLabels;
//--------------文件读取--------------------void file_open(string filedir,int flag){long lf;vector<string> files;_finddata_t file;string path;if ((lf = _findfirst(path.assign(filedir).append("\\*").c_str(), &file)) == -1){cout << "File Not Found!" << endl;}else{while (_findnext(lf, &file) == 0)  //循环处理文件夹中所有文件,但这里并没有对子文件夹进行检查{if (strcmp(file.name, "..") == 0) continue; //去掉第一个无用文件名".."files.push_back(path.assign(filedir).append("\\").append(file.name));  //文件路径+文件名保存到files中//cout << file.name << endl;}}_findclose(lf); //关闭文件查找cout << "the number of file is :" << files.size() << endl;int size = files.size();if (0 == size)cout << "No File Found in train HasPlate!" << endl;for (int i = 0; i <files.size(); i++)  // {Mat img = imread(files[i].c_str());//imshow("adad", img);Mat line_i = img.reshape(1, 1); //将待训练图片一维化(如果是提取图片特征进行学习,也需要将特征进行一维化才能用SVM学习)trainingImages.push_back(line_i);   //将一维化的img保存trainingLabels.push_back(flag);    //对应的类别标识}}

这里flag参数是传递过来对应训练图片的标识,如果为1则是正样例,如果为0则为反样例,在学习时最好将正例和反例分别放在不到文件夹下,且图像尺寸一致。

其实这里是将图像的所有像素都做为特征进行训练,效果不是很好,实验结果大概只有80%多的正确率,应该找到更好的特征进行训练。

图像读取好后,在主函数中进行调用,代码如下:

Mat classes;//保存所有正负样例类标char * filedir = "E:\\data\\plate_detect_svm\\learn\\HasPlate";//正样例的路径file_open(filedir, 1);  //正样例文件读取filedir = "E:\\data\\plate_detect_svm\\learn\\NoPlate";//负样例路径file_open(filedir, 0);//负样例文件读取cout << trainingImages[0].cols << "number"<<trainingImages.size()<< endl;Mat trainingData(trainingImages.size(), trainingImages[0].cols, CV_32FC1);//用来保存所有的正负样例图片或特征for (int i = 0; i<trainingImages.size(); i++)//将每个一维的训练图像保存至trainingData中{Mat temp(trainingImages[i]);temp.copyTo(trainingData.row(i));//存至trainingData的第i行上}//trainingData.convertTo(trainingData, CV_32FC1); Mat(trainingLabels).copyTo(classes);classes.convertTo(classes, CV_32FC1);<span style="font-family: Arial, Helvetica, sans-serif;">//转成SVM要求的格式</span>
下面进行SVM参数设置和训练:

//SVM参数设置,这里的参数很多,设置的好坏直接影响学习的结果CvSVMParams SVM_params;SVM_params.svm_type = CvSVM::C_SVC;SVM_params.kernel_type = CvSVM::LINEAR; //CvSVM::LINEAR;SVM_params.degree = 0;SVM_params.gamma = 1;SVM_params.coef0 = 0;SVM_params.C = 1;SVM_params.nu = 0;SVM_params.p = 0;SVM_params.term_crit = cvTermCriteria(CV_TERMCRIT_ITER, 1000, 0.01);//开始训练(学习)CvSVM svm(trainingData, classes, Mat(), Mat(), SVM_params);//保存训练模型FileStorage fsTo("E:/data/svm_plate.xml", FileStorage::WRITE);svm.write(*fsTo, "svm");
最后是拿一个图片进行测试:

void test(){CvSVM svm ;svm.clear();svm.load("E:\\data\\svm_plate.xml");Mat test_img = imread("E:\\data\\plate_detect_svm\\test\\HasPlate\\A03_AAQ839_3.jpg");Mat line_test_img = test_img.reshape(1, 1);line_test_img.convertTo(line_test_img, CV_32FC1);int response = (int)svm.predict(line_test_img);if (response == 1)cout << "是车牌" << endl;elsecout << "不是车牌" << endl;}

因为要获得训练结果的准确识别率不能只用一张一张的图像进行测试,需要用循环来调用test()函数,并记录测试的成功率,而要得知成功率就要有事先标定好的测试集来测试,这一步骤不难,想必大家都能实现。



0 0
原创粉丝点击