毕业项目推荐:基于yolov8的车牌识别检测系统(Python+卷积神经网络)
概要
随着国家现代化建设的推进和经济的快速增长,居民的生活水平显著提升,机动车的数量也迅速增加,导致交通需求持续上升,加快了智慧交通技术的发展和普及。车牌识别作为智慧交通系统中的一项核心技术,在这一领域中发挥着重要作用。该技术涉及多种方法的结合,如图像处理、目标检测、字符识别等。近年来,深度学习的应用显著提升了车牌识别的准确性,使得系统能够迅速识别车辆及其车牌信息,满足多样化的交通需求,尤其是在紧急情况下更具响应能力。本文的研究基于深度学习,采用卷积神经网络(CNN)技术,针对车牌检测和字符识别进行了深入的算法设计和优化。
关键词:车牌定位;深度学习;车牌识别;LPRNet网络
一、整体资源介绍
项目中所用到的算法模型和数据集等信息如下:
算法模型:
yolov8、yolov8 + SE注意力机制
车牌OCR识别模型:
LPRNet
数据集:
CCPD2019、CCPD2020数据集
以上是本套代码算法的简单说明,添加注意力机制是本套系统的创新点 。
技术要点
- OpenCV:主要用于实现各种图像处理和计算机视觉相关任务。
- Python:采用这种编程语言,因其简洁易学且拥有大量丰富的资源和库支持。
- 数据增强技术: 翻转、噪点、色域变换,mosaic等方式,提高模型的鲁棒性。
功能展示:
部分核心功能如下:
- 功能1: 支持单张图片识别
- 功能2: 支持遍历文件夹识别
- 功能3: 支持识别视频文件
- 功能4: 支持摄像头识别
- 功能5: 支持结果文件导出(xls格式)
- 功能6: 支持切换检测到的目标查看
功能1 支持单张图片识别
系统支持用户选择图片文件进行识别。通过点击图片选择按钮,用户可以选择需要检测的图片,并在界面上查看所有识别结果。该功能的界面展示如下图所示:
功能2 支持遍历文件夹识别
系统支持选择整个文件夹进行批量识别。用户选择文件夹后,系统会自动遍历其中的所有图片文件,并将识别结果实时更新显示在右下角的表格中。该功能的展示效果如下图所示:
功能3 支持识别视频文件
在许多情况下,我们需要识别视频中的车牌。因此,系统设计了视频选择功能。用户点击视频按钮即可选择待检测的视频,系统将自动解析视频并逐帧识别多个车牌,同时将识别结果记录在右下角的表格中。以下是该功能的展示效果:
功能4 支持摄像头识别
在许多场景下,我们需要通过摄像头实时识别车牌。为此,系统提供了摄像头选择功能。用户点击摄像头按钮后,系统将自动调用摄像头并进行实时车牌识别,识别结果会即时记录在右下角的表格中。
功能5 支持结果文件导出(xls格式)
本系统还添加了对识别结果的导出功能,方便后续查看,目前支持导出cvs和xls两种数据格式,功能展示如下:
功能6 支持切换检测到的目标查看
二、数据集
1. 简介
CCPD是一个经过精细标注的大型、多样化的中国城市车牌开源数据集,主要包括CCPD2019和CCPD2020(又称CCPD-Green)两个子数据集。CCPD2019数据集主要包含普通车牌(蓝色车牌),而CCPD2020数据集则专注于新能源车牌(绿色车牌)。在CCPD数据集中,每张图片只包含一张车牌,其中车牌的省份大多为皖。
2. CCPD数据集下载:
(1)百度网盘下载链接(个人上传):
https://pan.baidu.com/s/1ZvbRUsPwpJk_39FujpjObw?pwd=nygt 提取码:nygt
(2)github下载:https://github.com/detectRecog/CCPD,github中包含详细的数据说明介绍
2. 数据集说明
CCPD2019中主要包含以下几个文件夹,
CCPD-Base
:通用车牌图片,共200k
CCPD-FN
:车牌离摄像头拍摄位置相对较近或较远,共20k
CCPD-DB
:车牌区域亮度较亮、较暗或者不均匀,共20k
CCPD-Rotate
:车牌水平倾斜20到50度,竖直倾斜-10到10度,共10k
CCPD-Tilt
:车牌水平倾斜15到45度,竖直倾斜15到45度,共10k
CCPD-Weather
:车牌在雨雪雾天气拍摄得到,共10k
CCPD-Challenge
:在车牌检测识别任务中较有挑战性的图片,共10k
CCPD-Blur
:由于摄像机镜头抖动导致的模糊车牌图片,共5k
CCPD-NP
:没有安装车牌的新车图片,共5k
CCPD2020中的图像被拆分为train/val/test数据集。
4. CCPD数据集标注处理
CCPD数据集没有专门的标注文件,每张图像的文件名就是该图像对应的数据标注。例如图片3061158854166666665-97_100-159&434_586&578-558&578_173&523_159&434_586&474-0_0_3_24_33_32_28_30-64-233.jpg的文件名可以由分割符’-'分为多个部分:
(1)3061158854166666665
:区域(这个值可能有问题,无用);
(2)97_100
:对应车牌的两个倾斜角度-水平倾斜角和垂直倾斜角, 水平倾斜97度, 竖直倾斜100度。水平倾斜度是车牌与水平线之间的夹角。二维旋转后,垂直倾斜角为车牌左边界线与水平线的夹角。
(3)159&434_586&578
:对应边界框左上角和右下角坐标:左上
(159, 434), 右下
(586, 578);
(4)558&578_173&523_159&434_586&474
:对应车牌四个顶点坐标(右下角开始顺时针排列):右下(558, 578),左下(173, 523),左上(159, 434),右上(586, 474);
(5)0_0_3_24_33_32_28_30
:为车牌号码(第一位为省份缩写),在CCPD2019中这个参数为7位,CCPD2020中为8位,有对应的关系表;
(6)64
:为亮度,数值越大车牌越亮(可能不准确,仅供参考);
(7)233
:为模糊度,数值越小车牌越模糊(可能不准确,仅供参考)。
5. CCPD数据集处理相关脚本
(1)CCPD数据集转VOC,xml文件保存
import shutil
import cv2
import os
from lxml import etree
class labelimg_Annotations_xml:
def __init__(self, folder_name, filename, path, database="Unknown"):
self.root = etree.Element("annotation")
child1 = etree.SubElement(self.root, "folder")
child1.text = folder_name
child2 = etree.SubElement(self.root, "filename")
child2.text = filename
# child3 = etree.SubElement(self.root, "path")
# child3.text = path
child4 = etree.SubElement(self.root, "source")
child5 = etree.SubElement(child4, "database")
child5.text = database
def set_size(self, width, height, channel):
size = etree.SubElement(self.root, "size")
widthn = etree.SubElement(size, "width")
widthn.text = str(width)
heightn = etree.SubElement(size, "height")
heightn.text = str(height)
channeln = etree.SubElement(size, "channel")
channeln.text = str(channel)
def set_segmented(self, seg_data=0):
segmented = etree.SubElement(self.root, "segmented")
segmented.text = str(seg_data)
def set_object(self, label, x_min, y_min, x_max, y_max,
pose='Unspecified', truncated=0, difficult=0):
object = etree.SubElement(self.root, "object")
namen = etree.SubElement(object, "name")
namen.text = label
posen = etree.SubElement(object, "pose")
posen.text = pose
truncatedn = etree.SubElement(object, "truncated")
truncatedn.text = str(truncated)
difficultn = etree.SubElement(object, "difficult")
difficultn.text = str(difficult)
bndbox = etree.SubElement(object, "bndbox")
xminn = etree.SubElement(bndbox, "xmin")
xminn.text = str(x_min)
yminn = etree.SubElement(bndbox, "ymin")
yminn.text = str(y_min)
xmaxn = etree.SubElement(bndbox, "xmax")
xmaxn.text = str(x_max)
ymaxn = etree.SubElement(bndbox, "ymax")
ymaxn.text = str(y_max)
def savefile(self, filename):
tree = etree.ElementTree(self.root)
tree.write(filename, pretty_print=True, xml_declaration=False, encoding='utf-8')
def translate(path, save_path):
for filename in os.listdir(path):
print(filename)
list1 = filename.split("-", 3) # 第一次分割,以减号'-'做分割
subname = list1[2]
list2 = filename.split(".", 1)
subname1 = list2[1]
if subname1 == 'txt':
continue
lt, rb = subname.split("_", 1) # 第二次分割,以下划线'_'做分割
lx, ly = lt.split("&", 1)
rx, ry = rb.split("&", 1)
print(lx, ly, rx, ry)
results_xml = [['green', lx, ly, rx, ry]]
img = cv2.imread(os.path.join(path, filename))
if img is None: # 自动删除失效图片(下载过程有的图片会存在无法读取的情况)
# os.remove(os.path.join(path, filename))
continue
height, width, channel = img.shape
save_xml_name = filename.replace('jpg', 'xml')
anno = labelimg_Annotations_xml('folder_name', filename + '.jpg', 'path')
anno.set_size(width, height, channel)
anno.set_segmented()
for data in results_xml:
label, x_min, y_min, x_max, y_max = data
anno.set_object(label, x_min, y_min, x_max, y_max)
anno.savefile(os.path.join(save_path, save_xml_name))
if __name__ == '__main__':
# det图片存储地址
img_path = r"E:\lg\BaiduSyncdisk\project\person_code\chepai_OCR\traindata\CCPD2020\ccpd_green\train"
# det txt存储地址
save_path = r"E:\lg\BaiduSyncdisk\project\person_code\yolox-pytorch\VOCdevkit\VOC2007\Annotations"
translate(img_path, save_path)
class="hljs-button signin active add_def" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
评论记录:
回复评论: