OpenCV 入门(三)—— 车牌筛选

OpenCV 入门系列:

OpenCV 入门(一)—— OpenCV 基础
OpenCV 入门(二)—— 车牌定位
OpenCV 入门(三)—— 车牌筛选
OpenCV 入门(四)—— 车牌号识别
OpenCV 入门(五)—— 人脸识别模型训练与 Windows 下的人脸识别
OpenCV 入门(六)—— Android 下的人脸识别
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://xiahunao.cn/news/3016290.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

批量将GOID转成GO term名并添加BP,MF,CC分类信息

基因本体论&#xff08;Gene Ontology&#xff0c;GO&#xff0c;https://www.geneontology.org&#xff09;是一个广泛应用于生物信息学领域的知识库&#xff0c;它提供了一套标准化的词汇和分类体系&#xff0c;用于描述基因功能、细胞组分和生物过程。GO旨在统一科研人员对基…

LeetCode刷题记(五):121~150题

121. 买卖股票的最佳时机 给定一个数组 prices &#xff0c;它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票&#xff0c;并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。 返回你可以从…

代码审计之某高校通用系统getRequsetURI函数的三次鉴权绕过

前言&#xff1a; 写个随笔&#xff0c;写个代码审计的漏洞案例&#xff0c;该系统为大量高校使用的一个系统。 三次绕过。 正文&#xff1a; 如图所见&#xff0c;系统厂商采用的是利用过滤器的写法进行鉴权 第一次的校验代码&#xff1a; 即requestURI转为小写后&#x…

SpringBoot中HandlerInterceptor拦截器的构建详细教程

作用范围&#xff1a;拦截器主要作用于Spring MVC的DispatcherServlet处理流程中&#xff0c;针对进入Controller层的请求进行拦截处理。它基于Java的反射机制&#xff0c;通过AOP&#xff08;面向切面编程&#xff09;的思想实现&#xff0c;因此它能够访问Spring容器中的Bean…

机器学习笔记-22

终章 至此吴恩达老师的机器学习课程已经完成啦&#xff0c;总结一下&#xff1a; 1.监督学习的算法&#xff1a;线性回归、逻辑回归、神经网络和向量机 2.无监督学习的算法&#xff1a;K-Means、PCA、异常检测 3.推荐系统、大规模数据处理、正则化、如何评估算法 4.上限分析、…

贪吃蛇大作战(C语言--实战项目)

朋友们&#xff01;好久不见。经过一段时间的沉淀&#xff0c;我这篇文章来和大家分享贪吃蛇大作战这个游戏是怎么实现的。 &#xff08;一&#xff09;.贪吃蛇背景了解及效果展示 首先相信贪吃蛇游戏绝对称的上是我们00后的童年&#xff0c;不仅是贪吃蛇还有俄罗斯⽅块&…

红外与可见光图像融合评价指标(cddfusion中的代码Evaluator.py)

一、Evaluator.py全部代码&#xff08;可正常调用&#xff09; import numpy as np import cv2 import sklearn.metrics as skm from scipy.signal import convolve2d import math from skimage.metrics import structural_similarity as ssimdef image_read_cv2(path, modeRGB…

晶振负载对系统有什么影响?

电子系统中&#xff0c;晶振&#xff08;晶体振荡器&#xff09;是确保系统各部分同步工作的关键组件。然而&#xff0c;晶振的性能受到其负载电容大小的显著影响。本文将详细探讨晶振负载电容对系统性能的影响&#xff0c;并给出相应的解决方案。 一、晶振负载电容的作用 晶…

使用 GPT-4-turbo+Streamlit+wiki+calculator构建Math Agents应用【Step by Step】

&#x1f496; Brief&#xff1a;大家好&#xff0c;我是Zeeland。Tags: 大模型创业、LangChain Top Contributor、算法工程师、Promptulate founder、Python开发者。&#x1f4dd; CSDN主页&#xff1a;Zeeland&#x1f525;&#x1f4e3; 个人说明书&#xff1a;Zeeland&…

Linux高级学习(前置 在vmware安装centos7.4)

【小白入门 通俗易懂】2021韩顺平 一周学会Linux 此文章包含第006p-第p007的内容 操作 在安装好的vmware下进行安装 这里使用的是vmware15&#xff08;win10下&#xff09;&#xff0c;win11可能无法使用15&#xff08;有几率蓝屏&#xff09;&#xff0c;换成16就行了 用迅雷…

ogv转mp4怎么转?只需3个步骤~

OGV&#xff08;Ogg Video&#xff09;是一种开源的视频文件格式&#xff0c;起源于对数字媒体领域的开放标准的需求。作为Ogg多媒体容器的一部分&#xff0c;OGV的设计初衷是提供一种自由、高质量的视频编码方案&#xff0c;以满足多样化的应用需求。 支持打开MP4文件格式的软…

[蓝桥杯]真题讲解:班级活动(贪心)

[蓝桥杯]真题讲解&#xff1a;班级活动&#xff08;贪心&#xff09; 一、视频讲解二、正解代码1、C2、python33、Java 一、视频讲解 [蓝桥杯]真题讲解&#xff1a;班级活动&#xff08;贪心&#xff09; 二、正解代码 1、C #include<bits/stdc.h> using namespace st…

欢迎参展GASITC2024成都国际城市燃气智能应用技术展

GASITC2024中国&#xff08;成都&#xff09;国际城市燃气智能应用技术展览会 2024China City Gas Intelligent Application Technology Exhibition 同期召开&#xff1a;第十五届&#xff08;成都&#xff09;国际化工技术及装备展览会 展出地点&#xff1a;成都世纪城新国…

软件实施方案Word原件2024(全套软件资料包)

1.概述 2.项目介绍 3.项目实施 4.实施计划 5.人员培训 6.项目验收 7.售后服务 8.项目保障措施 软件资料清单列表部分文档&#xff08;全套可获取&#xff09;&#xff1a; 工作安排任务书&#xff0c;可行性分析报告&#xff0c;立项申请审批表&#xff0c;产品需求规格说明书…

SolidWorks进行热力学有限元分析一、模型建立

1.话不多说按照我的操作来 2.这一步鼠标移到中心点直接拉就行 3.这里选单位&#xff0c;继续按照操作来 4.选中这个边&#xff0c;直接拉&#xff0c;输入尺寸后确定&#xff0c;其他边同理 5.鼠标右键设置厚度 6.右键零件&#xff0c;然后编辑材料&#xff0c;给他赋予你需要的…

MySQL之聚合函数与应用

1. 前言 上文我们讲到了单行函数.实际上SQL还有一类叫做聚合函数, 它是对一组数组进行汇总的函数, 输入的是一组数据的集合, 输出的是单个值. 2. 聚合函数 用于处理一组数据, 并对一组数据返回一个值. 有如下几种聚合函数 : AVG(), SUM(), MAX(), MIN(), COUNT(). 3. AVG(…

(三)JSP教程——JSP动作标签

JSP动作标签 用户可以使用JSP动作标签向当前输出流输出数据&#xff0c;进行页面定向&#xff0c;也可以通过动作标签使用、修改和创建对象。 <jsp:include>标签 <jsp:include>标签将同一个Web应用中静态或动态资源包含到当前页面中。资源可以是HTML、JSP页面和文…

B端UX/UI设计面试作品集分层源文件figmasketch模板

当您考虑找工作时&#xff0c;是否曾质疑过项目复盘作品集的重要性&#xff1f;实际上&#xff0c;一份精心准备的项目复盘作品集对于求职者来说具有无可估量的价值&#xff0c;特别是对于设计师这一职业领域。 以下所述或许对您而言已非陌生。您的作品集应当成为您专业技能与…

Stable Diffusion:AI绘画的新纪元

摘要&#xff1a; Stable Diffusion&#xff08;SD&#xff09;作为AI绘画领域的新星&#xff0c;以其开源免费、强大的生成能力和高度的自定义性&#xff0c;正在引领一场艺术与技术的革命。本文旨在为读者提供Stable Diffusion的全面介绍&#xff0c;包括其原理、核心组件、安…