OpenCV(三)—— 车牌筛选

本篇文章要介绍如何对从候选车牌中选出最终进行字符识别的车牌。

无论是通过 Sobel 还是 HSV 计算出的候选车牌都可能不止一个,需要对它们进行评分,选出最终要进行识别的车牌。这个过程中会用到两个理论知识:支持向量机和 HOG 特征。

1、支持向量机

1.1 SVM 简介

支持向量机(Support Vector Machine,SVM)是一类按监督学习(Supervised Learning)方式对数据进行二元分类的广义线性分类器。用通俗的话来讲,就是用来分类,或者说挑选东西的。

对于车牌识别而言,车牌定位的候选车牌图可以分为两类:车牌与非车牌。SVM 可以对候选图进行测评,告诉我们图中的是不是车牌,相似程度是多少。

当然,SVM 可以进行分类的前提还是我们使用正负样本对其进行了训练。SVM 的训练数据既有特征又有标签,通过训练,让机器可以自己找到特征和标签之间的联系,在面对只有特征没有标签的数据时,可以判断出标签,这属于机器学习中的监督学习。

1.2 核函数

SVM 中有一个重要概念就是核函数。它的目标是找到一个能够将数据点分为不同类别的最优超平面(或者在非线性情况下是最优超曲面)。对于线性可分的情况,存在一个超平面可以完全将两个类别的数据分开。但是,在某些情况下,数据可能无法通过一个线性超平面进行完全分离,这就是线性不可分的情况。

SVM 线性可分:样本数据使用二维的线就可分类:

svm线性可分

SVM 线性不可分:左侧图片中的数据样本无法在二维平面内用线划分,称为线性不可分,只能像右侧图片那样用一个平面分开:

svm线性不可分

为了处理线性不可分的数据,引入了核函数的概念。核函数能够将输入数据从原始的特征空间(通常是低维空间)映射到一个更高维的特征空间,使得在新的特征空间中数据线性可分。这意味着在原始特征空间中无法线性分割的数据,在映射到高维特征空间后可以通过一个超平面进行线性分割。通常我们将这个过程称为提维,分离超平面就是通过提围计算出来的。

核函数的作用是在不显式计算映射到高维特征空间的情况下,直接在低维特征空间中进行计算。这样可以避免高维空间的计算复杂性,并且通过核函数的巧妙选择,可以实现高维特征空间的效果。

常见的核函数包括线性核函数、多项式核函数和径向基函数(Radial Basis Function,RBF)核函数。线性核函数对应于线性可分的情况,而多项式核函数和 RBF 核函数则可以处理线性不可分的情况。

1.3 SVM 训练流程

SVM 训练流程如下图:

svm训练流程

步骤:

  1. 预处理(原始数据 -> 学习数据(无标签)):预处理步骤主要处理的是原始数据到学习数据的转换过程(真正的车牌图片和不是车牌的图片)
  2. 打标签(学习数据(无标签)-> 学习数据(带标签)):将未贴标签的数据转化为贴过标签的学习数据
  3. 分组(学习数据(带标签)-> 分组数据):将数据分为训练集和测试集
  4. 训练(训练数据 -> 模型):加载待训练的车牌数据和非车牌数据,合并数据,配置 SVM 模型的训练参数进行训练

2、HOG 特征

HOG(Histogram of Oriented Gradient)特征是局部归一化的梯度方向直方图,是一种对图像局部重叠区域的密集型描述符,是用于目标检测和图像识别的特征描述方法,它通过计算局部区域的梯度方向直方图来构成特征。它在计算机视觉领域中广泛应用,特别是在行人检测等任务中取得了很好的效果。

HOG 特征的计算步骤如下:

  1. 图像预处理:将输入图像转换为灰度图像,去除颜色信息,以减少计算量。

  2. 梯度计算:计算图像中每个像素点的梯度信息。使用一阶导数(如 Sobel 算子)来计算水平和垂直方向上的梯度值,然后计算每个像素点的梯度幅值和梯度方向。

  3. 单元划分:将图像划分为小的连续区域,称为单元。通常使用 3 × 3 或 4 × 4 像素的单元。

  4. 梯度直方图统计:在每个单元中,对每个像素点的梯度方向进行统计。将梯度方向范围分成若干个区间(通常是 9 个),然后统计每个区间内的梯度幅值的累加和。这样就得到了一个梯度直方图。

  5. 块归一化:将相邻的若干个单元组成一个块,对每个块内的梯度直方图进行归一化处理。归一化可以降低光照变化对特征的影响,并增强特征的鲁棒性。

  6. 特征向量拼接:将所有块内的归一化梯度直方图按顺序拼接起来,形成最终的 HOG 特征向量。

HOG 特征的优点是能够捕捉图像中物体的边缘和纹理等局部特征,并且对光照变化相对鲁棒。它在行人检测等任务中被广泛使用,通常与支持向量机(SVM)等分类器结合使用,用于目标检测和图像识别。

3、代码实现

评分肯定是先通过正负样本学习,训练出一个特征集合,我们需要先加载这个 xml 文件:

int main() {// 加载车牌图片Mat src = imread("C:/Users/UserName/Desktop/Test/test5.jpg");// 新增加载特征集合LicensePlateRecognizer lpr("C:/Users/UserName/Desktop/Test/svm.xml");// 识别string str_plate = lpr.recognize(src);cout << "车牌号码:" << str_plate << endl;return 0;
}

在 LicensePlateRecognizer 进行识别时,需要调用评分的函数 predict():

/**
* 车牌识别 = 车牌定位 + 车牌检测 + 字符识别
*/
string LicensePlateRecognizer::recognize(Mat src)
{// 传入原图的克隆版本,以防在原图上的绘制影响后续算法定位Mat src_clone = src.clone();// 1.车牌定位,使用 Sobel 算法定位vector<Mat> sobel_plates;sobelLocator->locate(src_clone, sobel_plates);// 使用 HSV 算法定位src_clone = src.clone();vector<Mat> color_plates;colorLocator->locate(src_clone, color_plates);// 将两种车牌合并到一个集合中vector<Mat> plates;plates.insert(plates.end(), sobel_plates.begin(), sobel_plates.end());plates.insert(plates.end(), color_plates.begin(), color_plates.end());// 释放 sobel_plates 和 color_plates 内的 Matfor each (Mat m in sobel_plates){m.release();}for each (Mat m in color_plates){m.release();}// 2.精选车牌定位得到的候选车牌图char windowName[100];for (int i = 0; i < plates.size(); i++){sprintf(windowName, "%zd 候选车牌", i);imshow(windowName, plates[i]);waitKey();}// 评分,将最接近车牌的图片保存到 plate 中,其索引保存在 index 中Mat plate;int index = svmPredictor->predict(plates, plate);src_clone.release();// 暂时还无法识别到车牌号,返回一个测试字符串return string("12345");
}

svmPredictor 就是通过 SVM 进行车牌评分的类,它需要创建一个 SVM 对象,还需要创建一个 HOGDescriptor:

#ifndef SVMPREDICTOR_H
#define SVMPREDICTOR_H#include <opencv2/opencv.hpp>
#include <string>
// 机器学习 Machine Learning
#include <opencv2/ml.hpp>using namespace std;
using namespace cv;
using namespace ml;class SvmPredictor {
public:SvmPredictor(const char* svm_model);~SvmPredictor();virtual int predict(vector<Mat> candi_plates, Mat& dst_plates);
private:// 支持向量机对象Ptr<SVM> svm;// HOG 特征对象HOGDescriptor* svmHog = nullptr;void getHOGFeatures(HOGDescriptor* svmHog, Mat src, Mat& dst);
};#endif // !SVMPREDICTOR_H

我们需要了解 HOGDescriptor 的创建参数:

SvmPredictor::SvmPredictor(const char* svm_model)
{svm = SVM::load(svm_model);svmHog = new HOGDescriptor(Size(128, 64), Size(16, 16), Size(8, 8), Size(8, 8), 3);
}SvmPredictor::~SvmPredictor()
{if (svm){svm->clear();svm.release();}
}

创建 HOGDescriptor 传了 4 个 Size 对象,它们的含义如下:

	/** @overload@param _winSize 使用给定的值设置窗口大小@param _blockSize 使用给定的值设置块大小@param _blockStride 使用给定的值设置滑动增量大小@param _cellSize 使用给定的值设置胞元(CellSize)大小@param _nbins 使用给定的值设置梯度方向*/CV_WRAP HOGDescriptor(Size _winSize, Size _blockSize, Size _blockStride,Size _cellSize, int _nbins, int _derivAperture=1, double _winSigma=-1,HOGDescriptor::HistogramNormType _histogramNormType=HOGDescriptor::L2Hys,double _L2HysThreshold=0.2, bool _gammaCorrection=false,int _nlevels=HOGDescriptor::DEFAULT_NLEVELS, bool _signedGradient=false)

窗口大小设置为 (128, 64) ,作用是扫描图片中指定大小区域的像素,示意图如下:

窗口

一个窗口可以分成若干块,比如我们在代码中指定了块大小为 (16, 16),那么一个 (128, 64) 的窗口就可以在横向放 4 个块,纵向放 8 个块:

块和步

块滑动增量指定一个块在横纵方向上滑动步长为 (8, 8),胞元大小也指定为 (8, 8),那么一个 (16, 16) 的块中就包含 4 个胞元。最后的梯度方向 _nbins 指定为 3,在一个胞元内统计 3 个方向的梯度直方图,每个方向为 180 / 3 = 60°(将水平 180° 进行三等分)。

上面这个检测窗口可以被分为 ((128 - 16) / 8 + 1) * ((64 - 16) / 8 + 1) = 105 个块,一个块有 4 个胞元(Cell),一个胞元的 Hog 描述子向量的长度是 9。设置参数时必须要保证两个乘数内部是可以整除的。

统计梯度直方图特征,就是将梯度方向(0 ~ 360)划分为 x 个区间,将图像化为若干个 16 × 16 的窗口,每个窗口又划分为 x 个 block,每个 block 再化为 4 个 Cell(8 × 8)。对每一个 Cell,算出每一像素点的梯度方向,按梯度方向增加对应 bin 的值,最终综合 N 个 Cell 的梯度直方图组成特征。

简单来说,车牌的边缘与内部文字组成的一组信息(在边缘和角点的梯度值是很大的,边缘和角点包含了很多物体的形状信息),HOG 就是抽取这些信息组成一个直方图。

HOG:梯度方向弱化光照的影响,适合捕获轮廓

LBP:中心像素的 LBP 值反映了该像素周围区域的纹理信息

predict() 参考代码:

int SvmPredictor::predict(vector<Mat> candi_plates, Mat& dst_plate)
{Mat plate;float score;float minScore = FLT_MAX;int minIndex = -1;for (int i = 0; i < candi_plates.size(); i++){plate = candi_plates[i];// 准备获取车牌图片的 HOG 特征,先获取灰度图Mat gray;cvtColor(plate, gray, COLOR_BGR2GRAY);// 二值化(非黑即白,对比更强烈)Mat shold;threshold(gray, shold, 0, 255, THRESH_OTSU + THRESH_BINARY);// 获取特征Mat feature;getHOGFeatures(svmHog, shold, feature);// 获取样本Mat sample = feature.reshape(1, 1);// 获取评分,评分越小越像目标score = svm->predict(sample, noArray(), StatModel::Flags::RAW_OUTPUT);printf("SVM候选车牌%d的评分是:%f\n", i, score);// 记录最小分数的索引if (score<minScore){minScore = score;minIndex = i;}// 释放gray.release();shold.release();feature.release();sample.release();}// 找到了目标图片就把该图片复制给结果参数 dst_plateif (minIndex >= 0){dst_plate = candi_plates[minIndex].clone();imshow("SVM 评测最终车牌", dst_plate);waitKey();}return minIndex;
}

获取特征其实就是通过 HOGDescriptor 计算出特征集合:

void SvmPredictor::getHOGFeatures(HOGDescriptor* svmHog, Mat src, Mat& dst)
{// 归一化处理Mat trainImg = Mat(svmHog->winSize, CV_32S);resize(src, trainImg, svmHog->winSize);// 计算特征vector<float> desc;svmHog->compute(trainImg, desc, svmHog->winSize);// 特征图拷贝给结果 dstMat feature(desc);feature.copyTo(dst);// 释放feature.release();trainImg.release();
}

运行代码,可以看到有 4 个候选车牌,其中最后一个评分最低,是最符合标准的车牌:

2024-4-4.SVM评分选出最终图片

参考资料:

学习Opencv2.4.9(四)—SVM支持向量机

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/831407.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Redis__事务

文章目录 &#x1f60a; 作者&#xff1a;Lion J &#x1f496; 主页&#xff1a; https://blog.csdn.net/weixin_69252724 &#x1f389; 主题&#xff1a;Redis__事务 ⏱️ 创作时间&#xff1a;2024年05月02日 ———————————————— 这里写目录标题 文章目…

SSM+Vue在线OA办公系统

在线办公分三个用户登录&#xff0c;管理员&#xff0c;经理&#xff0c;员工。 SSM架构&#xff0c;maven管理工具&#xff0c;数据库Mysql&#xff0c;系统有文档&#xff0c;可有偿安装调试及讲解&#xff0c;项目保证质量。需要划到 最底 下可以联系到我。 功能如下&am…

蓝桥杯练习系统(算法训练)ALGO-950 逆序数奇偶

资源限制 内存限制&#xff1a;256.0MB C/C时间限制&#xff1a;1.0s Java时间限制&#xff1a;3.0s Python时间限制&#xff1a;5.0s 问题描述 老虎moreD是一个勤于思考的青年&#xff0c;线性代数行列式时&#xff0c;其定义中提到了逆序数这一概念。不过众所周知我们…

nginx--location详细使用和账户认证

在没有使用正则表达式的时候&#xff0c;nginx会先在server中的多个location选取匹配度最高的一个uri&#xff0c;uri是用户请求的字符串&#xff0c;即域名后面的web文件路径&#xff0c;然后使用该location模块中的正则url和字符串串&#xff0c;如果匹配成功就结束搜索&…

C语言----贪吃蛇(补充)

各位看官好&#xff0c;我想大家应该已经看过鄙人的上一篇博客贪吃蛇了吧。鄙人在上一篇博客中只是着重的写了贪吃蛇的实现代码&#xff0c;但是前期的一些知识还没有具体的介绍&#xff0c;比如确认光标位置&#xff0c;句柄等。那么我这一篇博客就来补充上一篇博客所留下来的…

神经网络中的优化方法

一、引入 在传统的梯度下降优化算法中&#xff0c;如果碰到平缓区域&#xff0c;梯度值较小&#xff0c;参数优化变慢 &#xff0c;遇到鞍点&#xff08;是指在某些方向上梯度为零而在其他方向上梯度非零的点。&#xff09;&#xff0c;梯度为 0&#xff0c;参数无法优化&…

数据结构-AVL树

目录 什么是 AVL 树 ASL 度量查找效率 结构体定义 平衡调整 调整类型 左旋和右旋 右旋 左旋 左、右平衡调整 左平衡调整 右平衡调整 插入数据 模拟建立 AVL 树 什么是 AVL 树 二叉排序树的形状取决于数据集&#xff0c;当二叉树的高度越小、结构越合理&#xff0c…

thinkphp家政上门预约服务小程序家政保洁师傅上门服务小程序上门服务在线派单安装教程

介绍 thinkphp家政上门预约服务小程序家政保洁师傅上门服务小程序上门服务在线派单安装教程 上门预约服务派单小程序家政小程序同城预约开源代码独立版安装教程 程序完整&#xff0c;经过安装检测&#xff0c;可放心下载安装。 适合本地的一款上门预约服务小程序&#xff0…

计算机网络——初识网络

一、局域网与广域网 1.局域网&#xff08;LAN&#xff09; 局域网&#xff1a;即Local Area Network&#xff0c;简称LAN。Local即标识了局域⽹是本地&#xff0c;局部组建的⼀种私有⽹络。局域⽹内的主机之间能⽅便的进⾏⽹络通信&#xff0c;⼜称为内⽹&#xff1b;局域⽹和…

A4的PDF按A3打印

先用办公软件打开&#xff0c;比如WPS。 选择打印-属性。 纸张选A3&#xff0c;如果是双面打印&#xff0c;选短边装订&#xff0c;然后在版面-页面排版-每张页数&#xff08;N合1&#xff09;选2。 不同打印机的具体配置可能不一样&#xff0c;但大体都是这个套路。

[NSSCTF]prize_p1

前言 之前做了p5 才知道还有p1到p4 遂来做一下 顺便复习一下反序列化 prize_p1 <META http-equiv"Content-Type" content"text/html; charsetutf-8" /><?phphighlight_file(__FILE__);class getflag{function __destruct(){echo getenv(&qu…

The Role of Subgroup Separability in Group-Fair Medical Image Classification

文章目录 The Role of Subgroup Separability in Group-Fair Medical Image Classification摘要方法实验结果 The Role of Subgroup Separability in Group-Fair Medical Image Classification 摘要 研究人员调查了深度分类器在性能上的差异。他们发现&#xff0c;分类器将个…

基于Springboot的民宿管理平台

基于SpringbootVue的民宿管理平台设计与实现 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringbootMybatis工具&#xff1a;IDEA、Maven、Navicat 系统展示 用户登录 首页 民宿信息 后台登录 后台首页 用户管理 商家管理 民宿信息管理 房间类型管理 …

【正版系统】知识付费系统搭建,系统模板开发完善功能强大,支持快速部署上线

在数字化时代&#xff0c;知识付费已成为一种趋势&#xff0c;为内容创作者和求知者搭建了一个高效的交流平台。今天&#xff0c;我要为大家介绍一款功能强大的知识付费系统。 知识付费系统模板是我们一款经过精心开发、完善的系统&#xff0c;旨在为用户提供一站式的知识付费…

【Docker】如何注册Hub账号并上传镜像到Hub仓库

一、创建Hub账户 浏览器访问&#xff1a;hub.docker.com 点击【Sign up】注册账号 输入【邮箱】【用户名】【密码】 ps&#xff1a;用户名要有字母数字&#xff1b;订阅不用勾选 点击【Sign up】注册即可 点击【Sign in】登录账号 输入【邮箱】【密码】 点击【Continue】登录 二…

Unreal 编辑器工具 批量重命名资源

右键 - Editor Utilities - Editor Utility Blueprint&#xff0c;基类选择 Asset Action Utility 在类默认值内&#xff0c;可以添加筛选器&#xff0c;筛选指定的类型 然后新建一个函数&#xff0c;加上4个输入&#xff1a;ReplaceFrom&#xff0c;ReplaceTo&#xff0c;Add…

大数据学习笔记14-Hive基础2

一、数据字段类型 数据类型 &#xff1a;LanguageManual Types - Apache Hive - Apache Software Foundation 基本数据类型 数值相关类型 整数 tinyint smallint int bigint 小数 float double decimal 精度最高 日期类型 date 日期 timestamps 日期时间 字符串类型 s…

nginx--自定义日志跳转长连接文件缓存状态页

自定义日志服务 [rootlocalhost ~]# cat /apps/nginx/conf/conf.d/pc.conf server {listen 80;server_name www.fxq.com;error_log /data/nginx/logs/fxq-error.log info;access_log /data/nginx/logs/fxq-access.log main;location / {root /data/nginx/html/pc;index index…

使用STM32F103C8T6与蓝牙模块HC-05连接实现手机蓝牙控制LED灯

导言: 在现代智能家居系统中,远程控制设备变得越来越普遍和重要。本文将介绍如何利用STM32F103C8T6单片机和蓝牙模块HC-05实现远程控制LED灯的功能。通过这个简单的项目,可以学会如何将嵌入式系统与蓝牙通信技术相结合,实现远程控制的应用。 目录 导言: 准备工作: 硬…

Java零基础入门到精通_Day 11

1.继承 定义&#xff1a; 继承是面向对象三大特征之一。可以使得子类具有父类的属性和方法&#xff0c;还可以在子类中重新定义&#xff0c;追加属性和方法 格式&#xff1a; public class 子类 extends 父类{} 子类&#xff1a;也叫派生类 父类&#xff1a;基类/超类 继…