您的位置:首页 > 运维架构

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

2015-12-09 17:14 579 查看
    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;
else
cout << "不是车牌" << endl;

}


因为要获得训练结果的准确识别率不能只用一张一张的图像进行测试,需要用循环来调用test()函数,并记录测试的成功率,而要得知成功率就要有事先标定好的测试集来测试,这一步骤不难,想必大家都能实现。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  opencv svm