基于SVM的车牌判别(二)

本文介绍了一个基于OpenCV的C++项目,使用SVM进行车牌识别。文章详细阐述了特征提取(自定义特征与HOG特征)、数据加载、模型训练和测试的过程。在测试中,HOG特征提取的SVM模型达到98%以上的准确率。
部署运行你感兴趣的模型镜像

3 代码实现

本项目主要借助于OpenCV库,在Visual Studio 2017平台开发,用C++语言编写代码。代码主要分为四个模块,分别是特征提取,数据加载,模型训练以及模型测试。下面对这四个模块的代码进行一一解析。

3.1 特征提取

本项目在开发过程中,一共设计了两种特征提取方式,分别是自拟的特征提取和HOG特征提取。下面结合代码对这两种特征提取方式一一介绍。

自拟特征提取的思路是提取每行每列中二值化结果为255的个数。首先,将输入图像经过灰度化转化为灰度图,再经过自适应二值化转化为二值图,最后创建一个一维的矩阵用于存放统计的数据作为特征向量,如下所示。

Mat getFeatures(Mat src,int rows,int cols) {
 Mat grayImage;
 cvtColor(src, grayImage, COLOR_RGB2GRAY);
 Mat img_threshold;
 threshold(grayImage, img_threshold, 0, 255, THRESH_OTSU + THRESH_BINARY);
 Mat out = Mat::zeros(1, rows+cols, CV_8UC1);
 for (int h = 0; h < rows; h++) {
  for (int l = 0; l < cols; l++) {
   if (img_threshold.at<uchar>(h, l) == 255) {
    out.at<uchar>(h)++;
   }
  }
 }
 for (int l = 0; l < cols; l++) {
  for (int h = 0; h < rows; h++) {
   if (img_threshold.at<uchar>(h, l) == 255) {
    out.at<uchar>(rows + l)++;
   }
  }
 }
 return out;
}

HOG特征提取先要对图像大小进行裁剪,有几种效果较好的图像尺寸,本文选用的是128×64。接着,选取8×8的滑动窗口对图像计算特征,这里直接调用OpenCV中的内置函数。最后将提取的特征保存到矩阵out中,过程如下所示。

Mat HOGgetFeatures(Mat src){
 //these parameters work well
 HOGDescriptor hog(Size(128, 64), Size(16, 16), Size(8, 8), Size(8, 8), 3); 
 std::vector<float> descriptor;
 // resize input image to (128,64) for compute
 Size dsize = Size(128, 64);
 Mat trainImg = Mat(dsize, CV_32S);
 resize(src, trainImg, dsize);
 // compute descripter
 hog.compute(trainImg, descriptor, Size(8, 8));
 // copy the result
 Mat features(descriptor);
 Mat out;
 transpose(features, out);
 return out;
}

经过测试,发现用HOG特征提取的方式,提取到的特征输入SVM中训练,得到的模型准确率更高。因此,本项目最终采用的是HOG特征提取。

3.2 数据加载

数据加载包括从车牌数据加载和非车牌数据加载。本项目将车牌数据和非车牌数据分开保存在特定文件夹中,便于给数据打上标签。通过文件路径访问,从相应文件夹中依次读取数据,通过特征提取生成一维特征向量,同时根据数据所属类别生成一个数据标签,最后将这个一维特征和数据标签分别append()到两个大矩阵里。

void getPlate(Mat &trainingImages, vector<int>& trainingLabels, int getfeatureway) {
 string pattern_jpg = "C:\\Users\\nicor\\Desktop\\test_has\\*.jpg";    //从一个文件夹中读取所有图片
 vector<cv::String> image_files;
 cv::glob(pattern_jpg, image_files);
 if (image_files.size() == 0) {          //文件夹中没有车牌图片
  cout << "No image files[jpg]" << endl;
 }
 else {
  switch (getfeatureway)
  {
  case Binary:
   for (unsigned int frame = 0; frame < image_files.size(); ++frame) {//image_file.size()代表文件中总共的图片个数
    Mat src = imread(image_files[frame]);
    Mat out = getFeatures(src, src.rows, src.cols);
    out = out.reshape(1, 1);
    trainingImages.push_back(out);
    trainingLabels.push_back(1);
   }
   break;
  case HOG:
   for (unsigned int frame = 0; frame < image_files.size(); ++frame) {//image_file.size()代表文件中总共的图片个数
    Mat src = imread(image_files[frame]);
    Mat out = HOGgetFeatures(src);
    out = out.reshape(1, 1);
    trainingImages.push_back(out);
    trainingLabels.push_back(1);
   }
   break;
  case SIFT:
   break;
  case LBP:
   break;
  default:
   break;
  }
 }
}

这段代码主要利用先前定义的HOG特征提取函数,提取每张图像的特征,并reshape成一维向量,最后压栈到特征矩阵中。

这样,我们就完成了训练数据的加载,并生成了输入到模型中训练的特征矩阵和标签矩阵。

3.3 模型训练

训练时首先通过调用OpenCV中的一个机器学习库生成一个SVM对象,接着设置参数初始化这个SVM模型,参数的设置参照一些网上其他人的经验值。具体过程如下所示。

//训练模型
 cv::Ptr<cv::ml::SVM> svm_ = cv::ml::SVM::create();
 //SVM模型参数设置
 svm_->setType(ml::SVM::C_SVC);
 svm_->setKernel(cv::ml::SVM::RBF);
 svm_->setDegree(0.1);
 svm_->setGamma(0.1);
 svm_->setCoef0(0.1);
 svm_->setC(1);
 svm_->setNu(0.1);
 svm_->setP(0.1);
 svm_->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER, 20000, 0.0001));

接着,加载数据,并将特征矩阵和标签矩阵转换格式后,生成一个训练数据集,最终输入到SVM中进行训练,过程如下所示。

Mat classes;    //标签
Mat trainingData;    //数据

Mat trainingImages;    //训练数据
vector<int> trainingLabels;     //数据标签
//特征提取方式
getPlate(trainingImages, trainingLabels, HOG);
getNoPlate(trainingImages, trainingLabels, HOG);

Mat(trainingImages).copyTo(trainingData);
trainingData.convertTo(trainingData, CV_32FC1);   //格式转化后的数据
Mat(trainingLabels).copyTo(classes);
classes.convertTo(classes, CV_32SC1);    //格式转换后的标签
Ptr<ml::TrainData> trainData=ml::TrainData::create(trainingData, ml::SampleTypes::ROW_SAMPLE, classes);

最终训练模型时,调用的是CvSVM中的trainAuto函数,这个函数会根据输入的数据自适应训练,自动调整参数,效果好,但耗费时间较长。

svm_->trainAuto(trainData, 10,                 //自适应训练,自动调整参数,效果好,耗费时间大
  ml::SVM::getDefaultGrid(ml::SVM::C),ml::SVM::getDefaultGrid(ml::SVM::GAMMA), 
  ml::SVM::getDefaultGrid(ml::SVM::P),ml::SVM::getDefaultGrid(ml::SVM::NU), 
  ml::SVM::getDefaultGrid(ml::SVM::COEF),ml::SVM::getDefaultGrid(ml::SVM::DEGREE), true);

3.4 模型测试

   Ptr<ml::SVM> svm_ = cv::ml::StatModel::load<cv::ml::SVM>("C:\\Users\\nicor\\Desktop\\svm_HOG.xml");  //加载训练好的模型
   int response = 0;
   for (unsigned int frame = 0; frame < image_files.size(); ++frame) {//image_file.size()代表文件中总共的图片个数
    Mat src = imread(image_files[frame]);
    Mat test = HOGgetFeatures(src);
    Mat test_;
    test.convertTo(test_, CV_32FC1);
    response = 0;
    response = (int)(svm_->predict(test_));
    if (isplate) {
     if (response) {
      correct_cnt++;
     }
    }
    else {
     if (!response) {
      correct_cnt++;
     }
    }

模型训练结束后,会生成一个.xml文件。测试时,我们首先要将该权重模型加载到程序中,之后从测试集里依次读取图像,通过HOG特征提取生成一维特征向量,最后将该一维特征向量输入到模型中,做一次前向传播得到输出。输出会有两个结果,0或1,分别代表预测的类别为车牌和非车牌。经过统计,我们就可以大概得出模型预测的准确率。

4 测试结果

4.1 SVM模型准确率测试

训练结束后,我们调用代码中的模型测试模块,对训练得到的SVM权重模型的准确率进行测试。跟训练集一样,测试集同样分为车牌测试集和非车牌测试集。在代码中加载该权重模型,分别对两个测试集进行判别,得出如图4-1所示结果。可以看到,训练得到的SVM权重模型对车牌数据和非车牌数据的误判都很少,其中利用HOG特征提取训练所得的模型准确率达到了98%以上。

在这里插入图片描述
在这里插入图片描述
从测试集中另取一张原始车辆图像,按照车牌识别流程对图像中的车牌进行提取。经过高斯模糊,灰度化,边缘检测,二值化,闭操作,取轮廓,轮廓外接矩形框,按车牌尺寸筛选车牌区域等一系列操作后,得到如图4-2所示结果。
在这里插入图片描述

此时,提取的区域包含车牌区域和非车牌区域,利用常规方法已很难将它们分离开来,此时就用到了我们上面训练所得的SVM模型进行判别。将这些疑似区域旋转仿射至水平后,尺寸统一调整为136x36,经过HOG特征提取后生成相应一维特征向量,输入SVM模型中。根据模型输出结果,若为1,则表示为车牌;若为0,则是非车牌。最终从图像中提取的车牌如图4-3所示。
在这里插入图片描述

此外,本车牌定位算法配合SVM分类模型有较好的适用性,在多车辆复杂图像中也能有效地提取到车牌区域,结果如图4-4所示。
在这里插入图片描述

您可能感兴趣的与本文相关的镜像

Stable-Diffusion-3.5

Stable-Diffusion-3.5

图片生成
Stable-Diffusion

Stable Diffusion 3.5 (SD 3.5) 是由 Stability AI 推出的新一代文本到图像生成模型,相比 3.0 版本,它提升了图像质量、运行速度和硬件效率

评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值