基于SVM的车牌识别算法

news2024/11/18 3:32:18

基于SVM的车牌识别系统(Python代码实现)

车牌识别系统是智能交通系统的重要组成部分,有着广泛的应用。车牌识别系统主要有车牌定位、字符分割和字符识别三部分组成,本文的研究重点是车牌字符识别这部分,本文提出了一种基于OpenCVSVM的车牌识别方法。首先通过Soble边缘检测算法与形态学算法相结合来确定大致的车牌轮廓,结合车牌的外接矩形的面积与长宽比来筛选出符合车牌特征的候选区域,然后使用投影法将车牌中的字符分割出来,最后使用SVM分类器来对分割出的字符进行识别,输出识别结果。经过验证,该车牌识别系统能够适用于比较复杂的环境,识别准确率相对较高。为了提升该系统的可操作性,本文使用PyQt5设计了GUI界面,提升了系统的可操作性,同时使界面更加美观。

一、算法流程

一个完整的车牌号识别系统要完成从图像采集到字符识别输出,过程相当复杂,基本可以分成硬件部分跟软件部分,硬件部分包括系统触发、图像采集,软件部分包括图像预处理车牌定位字符分割字符识别四大部分,一个车牌识别系统的基本结构如图:

在这里插入图片描述

二、图像预处理

获取蓝色和绿色通道:

    hsv = cv2.cvtColor(src, cv2.COLOR_BGR2HSV)  # 将RGB图像转换为HSV图像
    h, s, v = cv2.split(hsv)  # 分离H,S,V
    lower = np.array([100, 90, 40])
    upper = np.array([124, 255, 255])  # 设置阈值
    mask = cv2.inRange(hsv, lower, upper)  # 获取图像蒙版
    img = cv2.bitwise_and(s, s, mask=mask)  # 在图像蒙版上使用“按位与”运算符吗,分离绿色和蓝色通道
    

处理结果:在这里插入图片描述

直方图均衡化:

    img = cv2.equalizeHist(img)  # 直方图均衡化,增强对比度:将已知灰度概率密度分布的图像经过变换,使其称为一个均匀灰度概率密度分布的新图像
    img = cv2.GaussianBlur(img, (3, 3), 0, 0, cv2.BORDER_DEFAULT)  # 高斯滤波

处理结果:
在这里插入图片描述
检测图像中的纹理:

    flipped = cv2.flip(img, 1)  # 图像翻转,1:水平翻转
    sobel1 = cv2.Sobel(img, cv2.CV_8U, 1, 0, ksize=3)  # 图像边缘检测,Sobel算子,对x轴方向求导
    sobel2 = cv2.flip(cv2.Sobel(flipped, cv2.CV_8U, 1, 0, ksize=3), 1)  # 先平滑图像边缘,再翻转
    img = sobel1 / 2 + sobel2 / 2
    img = img.astype('uint8')  # 强制类型转换

处理结果:
在这里插入图片描述
灰度图转为二进制图像:

    th = (np.mean(img) + (np.max(img) - np.mean(img)) * 0.6)
    ret, img = cv2.threshold(img, th, 255, cv2.THRESH_BINARY)  # 简单阈值函数,从灰度图像中获取二进制图像

处理结果:
在这里插入图片描述
形态学闭合操作:

img = close_op(img, 36)

处理结果:
在这里插入图片描述

三、车牌定位

    for contour in contours:
        area = cv2.contourArea(contour)  # 计算图像轮廓面积
        if area < 200 or area > 50000:  # 判断车牌轮廓区域
            continue

        rect = cv2.minAreaRect(contour)  # 求出点集contour的最小矩形面积,返回值rec[0]为矩形的中心点,rec[1]为矩形的长和宽,rec[2]矩形的旋转角度
        if rect[1][0] * rect[1][1] < 666 or area < rect[1][0] * rect[1][1] * 0.6:
            continue

        dy, dx = contour.flatten().reshape(contour.shape[0], -1).T.ptp(1)
        cwb = rect[1][1] / rect[1][0] if rect[1][1] > rect[1][0] else rect[1][0] / rect[1][1]
        if dy < dx or cwb < 2.5 or cwb > 6:
            continue

        if not check_plate(src, rect):
            continue

        plate = extract_plate(src, rect)  # src为原始图像,rect为车牌区域坐标

处理结果:
在这里插入图片描述

四、车牌字符分割

def plate_cut_text(img):
    '''
    车牌字符分割,将分割好的车牌区域进行字符分割
    '''
    sum = np.sum(img, 1)
    limit = np.mean(sum) * 0.2
    bound = []
    start = 0
    for i in range(len(sum) - 1):
        if sum[i] < limit and sum[i + 1] >= limit:
            start = i
        elif sum[i] >= limit and sum[i + 1] < limit:
            bound.append([start, i])
            start = 0
    if start != 0:
        bound.append([start, len(sum - 1)])
    up, down = 0, 0
    for b in bound:
        if b[1] - b[0] > down - up:
            up = b[0]
            down = b[1]

    return img[up: down + 1, :]

五、基于SVM的车牌字符识别

reader = SVM_ocr.Reader()
def plate_recognition(plate):  #字符识别代码
    '''
    车牌识别核心代码,使用SVM对分割的车牌字符进行识别,并将识别结果返回
    '''
    img = cv2.cvtColor(plate, cv2.COLOR_BGR2GRAY)
    th = (np.mean(img) + (np.max(img) - np.mean(img)) * 0.2)
    _, img = cv2.threshold(img, th, 255, cv2.THRESH_BINARY) #阈值函数
    img = plate_cut_text(img)
    display('plate th', img, 360)
    bound = plate_split(img) #调用plate_split函数,对车牌字符进行拆分,返回一个列表,列表每个值记录车牌每个字符起始位置
    print('拆分出来的各个字符起始位置:',bound)
    plate_res = []
    for i, b in enumerate(bound):
        display('character_'+str(i), img[:,b[0]:b[1]], 50)
        if b[1] - b[0] > 5 and b[1] - b[0] < 28: #判断每个分割出来的字符宽度是否正常
            if len(plate_res) == 0:
                ch = reader.recognize_chinese(adjust_vision(img[:, b[0]:b[1]+1]))[0] #识别车牌汉字
            else:
                ch = reader.recognize_alnum(adjust_vision(img[:, b[0]:b[1]+1]))[0] #识别车牌字符
            plate_res.append(ch) #将识别结果添加到变量ch中
    return plate_res #返回车牌识别结果

六、使用Qtdesigner进行UI界面设计

在这里插入图片描述

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

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

相关文章

每日一练 | 华为认证真题练习Day134

1、开启标准STP协议的交换机可能存在哪些端口状态&#xff1f;&#xff08;多选&#xff09; A. Discarding B. Listening C. Disabled D. Forwarding 2、下列路由协议中优先级最高的是&#xff1f; A. Direct B. RIP C. OSPF D. Static 3、参考如图所示的输出结果&…

Linux驱动开发笔记(四):设备驱动介绍、熟悉杂项设备驱动和ubuntu开发杂项设备Demo

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/134533533 红胖子网络科技博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬…

基于JAVA+SSM+VUE+微信小程序的前后端分离的生活日用品交易平台的设计与实现

✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取项目下载方式&#x1f345; 一、项目背景介绍&#xff1a; 随着互联网的快速发展…

Qt应用开发(进阶篇)——线程 QThread

一、前言 QThread类继承于QObject基类&#xff0c;是Qt经典基础工具类&#xff0c;QThread类提供了一种独立于平台的方式来管理线程&#xff0c;让开发者能够快速的完成多线程的创建和使用。 正常情况下&#xff0c;一个PC程序使用到多线程的概率是非常高的&#xff0c;在不同方…

C#使用MaxMind.GeoIP2数据库查询当前ip地址

GeoLite2-City.mmdb下载 因为比较简单&#xff0c;直接上代码&#xff0c;代码展示获取ip地址的国家和城市信息 using MaxMind.GeoIP2; using MaxMind.GeoIP2.Model; using System; using System.Collections; using System.Collections.Generic; using System.Linq; using Sy…

利用 Gem5 模拟器创建一个简单的配置脚本——翻译自官网

文章目录 创建简单的配置脚本gem5 配置脚本关于模拟对象的插话 创建配置文件全系统与系统调用模拟 运行Gem5 创建简单的配置脚本 本章教程将指导你如何为 gem5 设置一个简单的模拟脚本&#xff0c;并首次运行 gem5。我们假定你已完成本教程第一章的学习&#xff0c;并已成功创…

DITTEL控制器维修SENSITRON6-2AE

DITTEL工控产品维修包括&#xff1a;德国DITTEL平衡测试仪维修,DITTEL模块&#xff0c;过程监控模块&#xff0c;DITTEL控制器&#xff0c;平衡头&#xff0c;机电平衡头&#xff0c;显示器&#xff0c;平衡系统等产品。 DITTEL过程控制模块维修 DM6000是一个过程控制模块&…

第1关:图的邻接表存储及求邻接点操作

任务要求参考答案评论2 任务描述相关知识编程要求测试说明 任务描述 本关任务&#xff1a;要求从文件输入顶点和边数据&#xff0c;包括顶点信息、边、权值等&#xff0c;编写程序实现以下功能。 1&#xff09;构造图G的邻接表和顶点集&#xff0c;即图的存储结构为邻接表。 …

使用wxPython和PyMuPDF合并PDF文档并自动复制到剪贴板

导语&#xff1a;处理大量的PDF文档可能会变得复杂和耗时。但是&#xff0c;使用Python编程和一些强大的库&#xff0c;如wxPython和PyMuPDF&#xff0c;可以使这个任务变得简单而高效。本文将详细解释一个示例代码&#xff0c;展示如何使用这些库来创建一个可以选择文件夹中的…

STM32 -Bin/Hex文件格式解析

文章目录 1. 概述2. Hex文件2.1 格式解析2.2 数据类型2.3 举例解析2.4 合并两个Hex文件方法 3 总结&#xff08;未完待续&#xff09; 1. 概述 Hex文件&#xff1a;它是单片机和嵌入式工程编译输出的一种常见的目标文件格式&#xff08;比如keil就能编译输出hex文件&#xff0…

Kubernetes容器状态探测的艺术

在Kubernetes集群中维护容器状态更像是一种艺术&#xff0c;而不是科学。原文: The Art and Science of Probing a Kubernetes Container[1] 在Kubernetes集群中维护容器状态更像是一种艺术&#xff0c;而不是科学。 本文将带你深入理解容器探测[2]&#xff0c;并特别关注相对较…

SQL常见函数整理 —— LAG() 向上偏移

1. 用法 窗口函数&#xff0c;用于访问窗口中当前行之前的行的数据。该函数可以根据需要计算当前行之前的值&#xff0c;使我们能够轻松地比较不同行之间的差异和变化。 2. 基本语法 LAG(column, offset, default_value) OVER (ORDER BY column)column&#xff1a;代表在返回…

代码随想录刷题】Day15 二叉树02------延伸题目练习

文章目录 1.【100】相同的树1.1 题目描述1.2 java代码实现 2.【572】另一棵树的子树2.1 题目描述2.2 java代码实现 【100】相同的树 【572】另一棵树的子树 1.【100】相同的树 1.1 题目描述 给你两棵二叉树的根节点 p 和 q &#xff0c;编写一个函数来检验这两棵树是否相同。…

“轻松管理你的文件库:按大小归类保存,高效整理!“

亲爱的朋友们&#xff0c;你是否曾经为了整理电脑中杂乱无章的文件而感到烦恼&#xff1f;文件大小不一&#xff0c;无法快速找到所需内容&#xff0c;实在让人感到心力交瘁。但现在&#xff0c;我们为你带来一种全新的解决方案&#xff0c;让你的文件管理更轻松&#xff0c;更…

算法设计与分析复习--回溯(一)

文章目录 上一篇回溯法性质子集和问题装载问题0-1背包问题下一篇 上一篇 算法设计与分析复习–贪心&#xff08;二&#xff09; 回溯法性质 类似穷举的搜索尝试过程&#xff0c;在搜索尝试过程中寻找问题的解&#xff0c;组织得井井有条&#xff08;避免遗漏&#xff09;&am…

工业领域的设备“监测”和“检测”有何区别?

在工业领域中&#xff0c;设备的监测和检测是关键的运维活动&#xff0c;它们在保障设备可靠性和生产效率方面发挥着重要作用。尽管这两个术语经常被人们混为一谈&#xff0c;但它们在含义和应用上存在一些关键区别。 "监测"与"检测"的概念 1. 监测&#…

PHP手动为第三方类添加composer自动加载

有时候我们要使用的第三方的类库&#xff08;SDK&#xff09;没用用composer封装好&#xff0c;无法用composer进行安装&#xff0c;怎么办呢&#xff1f;&#xff1f;&#xff1f; 步骤如下&#xff1a; 第一步、下载你需要的SDK文件包&#xff0c;把它放在vendor目录下 第二…

【Python】学习Python面向对象编程的疑问

&#xff08;Java菜鸟来学Python了&#xff09; &#x1f914; 1. 静态方法与类方法什么区别&#xff1f; 实例方法只能被实例对象调用(Python3 中&#xff0c;如果类调用实例方法&#xff0c;需要显示的传self, 也就是实例对象自己)&#xff0c;静态方法(由staticmethod装饰…

【MATLAB源码-第84期】基于matlab的802.11a标准的OFDM系统误码仿真对比QPSK,16QAM。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 基于802.11a标准的OFDM&#xff08;正交频分复用&#xff09;系统是一种高效的无线通信技术&#xff0c;特点如下&#xff1a; 频带与信道&#xff1a; 802.11a工作在5 GHz频段&#xff0c;这个频段相对于2.4 GHz&#xff08…