当前位置:   article > 正文

基于深度学习的车牌检测系统(网页版+YOLOv8/v7/v6/v5代码+训练数据集)

基于深度学习的车牌检测系统(网页版+YOLOv8/v7/v6/v5代码+训练数据集)

摘要:本文深入研究了基于YOLOv8/v7/v6/v5的车牌检测系统,核心采用YOLOv8并整合了YOLOv7YOLOv6YOLOv5算法,进行性能指标对比;详述了国内外研究现状数据集处理算法原理模型构建与训练代码,及基于Streamlit的交互式Web应用界面设计。在Web网页中可以支持图像视频实时摄像头进行车牌检测,可上传不同训练模型(YOLOv8/v7/v6/v5)进行推理预测,界面可方便修改。本文附带了完整的网页设计深度学习模型代码训练数据集的下载链接。

➷点击跳转至文末所有涉及的完整代码文件下载页☇

网页版-基于深度学习的车牌检测系统(YOLOv8/YOLOv7/YOLOv6/YOLOv5+实现代码+训练数据集)


1. 网页功能与效果

        (1)开启摄像头实时检测:本系统允许用户通过网页直接开启摄像头,实现对实时视频流中车牌的检测。系统将自动识别并分析画面中的车牌,并将检测结果实时显示在用户界面上,为用户提供即时的反馈。

在这里插入图片描述

        (2)选择图片检测:用户可以上传本地的图片文件到系统中进行车牌检测。系统会分析上传的图片,识别出图片中的车牌,并在界面上展示带有车牌标签和置信度的检测结果,让用户能够清晰地了解到每个车牌状态。

在这里插入图片描述

        (3)选择视频文件检测:系统支持用户上传视频文件进行车牌检测。上传的视频将被系统逐帧分析,以识别和标记视频中每一帧的车牌。用户可以观看带有车牌检测标记的视频,了解视频中车牌的变化。

在这里插入图片描述

        (4)选择不同训练好的模型文件:系统集成了多个版本的YOLO模型(如YOLOv8/v7/v6/v5),用户可以根据自己的需求选择不同的模型进行车牌检测。这一功能使得用户能够灵活地比较不同模型的表现,以选择最适合当前任务的模型。

在这里插入图片描述

        在我们基于YOLOv8/v7/v6/v5的车牌检测系统中开发的交互式Web应用中,集成了多项功能,旨在为用户提供一个直观、高效且便于操作的界面。首先,实时摄像头车牌检测功能允许用户开启摄像头进行即时的车牌识别,非常适用于需要实时反馈的应用场景。对于静态的图像分析,图片车牌检测功能使用户能够上传图片文件并迅速得到检测结果。此外,视频文件车牌检测功能支持上传视频文件进行分析,系统将逐帧识别车牌,适合处理监控视频等内容。

        为了满足不同用户的需求,我们提供了模型选择功能,用户可以根据自己的需求选择不同版本的YOLO模型进行检测。同时,应用支持检测与原始画面的显示模式,用户可以根据需要选择检测结果的展示方式。通过目标标记与结果展示功能,用户能够专注于对特定车牌的识别和分析,增加了使用的灵活性。

        此外,我们特别设计了界面用于动态展示检测结果,检测结果的动态展示与保存功能让用户能够实时查看车牌识别结果,并将其导出为csv文件进行记录。为了进一步优化检测性能,算法参数调整功能允许用户根据实际情况调整置信度阈值和IOU阈值。最后,检测结果导出功能提供了一种方便的方式,允许用户将标记过的图片、视频以及实时摄像头捕获的场景导出为avi文件,便于保存和分享。

        整体而言,这个Web应用通过整合先进的车牌检测技术和用户友好的操作界面,为各类用户提供了一个功能全面、操作简便的车牌检测平台。


2. 绪论

2.1 研究背景及意义

        随着智能交通系统的迅猛发展,车牌检测技术作为其关键组成部分,已经成为自动化交通管理、违章监控、车辆定位等应用的基础。这项技术能够自动识别车辆的车牌信息,为交通安全、城市管理和道路监控提供支持,显著提高了处理效率和准确性。随着计算机视觉和深度学习技术的进步,基于YOLO(You Only Look Once)系列的车牌检测方法展现出了优异的性能和广阔的应用前景。

        车牌检测不仅仅是识别车牌上字符的过程,它还涉及到从复杂背景中准确地定位车牌的位置,这对算法的准确性和鲁棒性提出了较高的要求。近年来,深度学习技术,特别是卷积神经网络(CNN)在图像识别和处理领域取得了革命性的进展,为解决车牌检测中的难题提供了新的思路和方法。YOLO系列算法因其快速、准确的特性成为了车牌检测研究中的热门方向。自YOLO算法首次提出以来,它的多个版本(YOLOv51、YOLOv62、YOLOv73、YOLOv8)陆续被开发出来,每个版本都在性能上做出了显著的改进。

        然而,尽管这些进展令人鼓舞,车牌检测技术仍面临着一系列挑战,包括在不同光照条件下的检测准确性、在高动态范围场景中的稳定性、以及对于复杂背景和不同车牌类型的适应能力等。为了克服这些挑战,研究人员不断探索更高效的算法改进策略,包括网络结构优化、损失函数调整、数据增强技术等。

        近期的研究成果表明,通过对YOLO网络进行定制化的修改,可以显著提高车牌检测的性能。例如,一些研究通过引入注意力机制来增强模型对车牌特征的识别能力。其他研究则关注于优化算法的速度和准确性,使其能够在实时应用中更加高效。此外,随着数据集的丰富和多样化,模型训练过程中的数据预处理和增强技术也在不断进步,进一步提升了车牌检测系统的鲁棒性和泛化能力。

2.2 国内外研究现状

        在当前的研究现状中,车牌检测技术正经历着前所未有的发展,尤其是在深度学习和计算机视觉领域。最新的研究聚焦于提升车牌检测的准确性、速度以及在复杂环境下的鲁棒性。随着YOLO4系列算法的不断进化,它们在车牌检测任务中表现出了显著的优势,但同时也面临着挑战。研究人员正致力于通过算法优化、数据增强以及网络架构创新来解决这些问题。

        近期,YOLOv5因其轻量级和高效性能在实时车牌检测方面受到广泛关注。一项研究通过对YOLOv5进行微调,显著提高了在复杂背景下的检测准确率。YOLOv6和YOLOv7引入了新的特征提取和融合策略,进一步优化了检测流程,实现了更快的处理速度和更高的准确性。YOLOv85,通过深度优化网络结构和训练策略,展示了在多种车牌检测基准上的优异性能。

        除了YOLO系列之外,还有研究探索了结合其他深度学习技术以强化车牌检测系统的性能。例如,一些研究通过融合注意力机制,有效提升了模型对车牌特征的识别能力,尤其是在光照变化和遮挡条件下。另外,利用生成对抗网络(GANs)生成的合成数据进行训练,也被证明能够增强模型的泛化能力和鲁棒性。

在这里插入图片描述

        视觉变换器(ViT)和基于注意力机制的模型在处理车牌检测的任务时展现了独特的优势。ViT通过将图像分割成序列化的图块并利用自注意力机制处理,展现了在复杂场景下对细节的敏感性和更好的泛化能力。注意力机制通过赋予模型对图像特定部分更高的权重,能够更精确地定位并识别车牌,尤其是在背景复杂或车牌部分遮挡的情况下。

        RetinaNet和Faster R-CNN作为经典的目标检测框架,在车牌检测领域也有广泛的应用。RetinaNet通过其独特的Focal Loss解决了类别不平衡问题,提高了小目标如车牌的检测准确率。Faster R-CNN通过引入区域建议网络(RPN),大幅提升了检测速度和准确性,尤其是在需要精确定位目标的场景中表现优异。

        DETR(Detection Transformer)作为一种结合了自注意力和全局推理的目标检测方法,在车牌检测中也显示了其潜力。通过直接预测目标的方式,DETR避免了传统检测算法中复杂的预处理步骤和后处理步骤,展现了更简洁和有效的检测流程。

        另一方面,针对特定的应用场景和需求,一些研究提出了基于YOLO的改进版本,如Glod-YOLO,它通过优化模型结构和训练策略,旨在提高在特定领域,如车牌检测的性能。同时,开源项目MMDetection为目标检测研究提供了一个强大的工具,支持多种算法和模型的快速实验,加速了目标检测技术的发展和应用。

2.3 要解决的问题及其方案

2.3.1 要解决的问题

        在开发基于YOLOv8/v7/v6/v5的车牌检测系统中,我们面对的主要问题和挑战集中在以下几个方面:

  1. 车牌检测的准确性和速度

        车牌检测的核心挑战在于如何在多变的道路环境中实现对车牌的高准确度识别与实时处理。车牌在不同国家和地区有着多样的格式和设计,加之车辆在行驶过程中的速度快、角度多变、可能的部分遮挡和不同光照条件,均对识别系统的准确性和处理速度提出了极高的要求。我们通过对YOLOv5至YOLOv8不同版本的综合测试和优化,调整模型参数和网络结构,使用高质量的数据集进行训练,以确保模型能够在各种情况下都保持高性能。

  1. 环境适应性和模型泛化能力

        变化的光照条件、复杂的背景以及不同天气状况对车牌检测均构成了挑战。为了提升系统的环境适应性和模型泛化能力,我们采用了数据增强技术,如随机光照变化、背景噪声添加和天气模拟等,以此来模拟真实世界中的各种复杂情况,从而训练出更为鲁棒的模型。

  1. 用户交互界面的直观性和功能性

        为了确保用户能够有效且轻松地使用车牌检测系统,我们在基于Streamlit的网页应用中投入了大量的设计和开发工作。通过简洁直观的界面设计和合理的功能布局,用户可以轻松上传图片或视频文件,进行实时摄像头检测,切换不同的模型文件,以及查看和导出检测结果。此外,我们还通过CSS进行了界面美化,提升了整体的用户体验。

  1. 数据处理能力和存储效率

        考虑到系统将处理大量图像和视频数据,我们优化了数据处理流程和存储机制。通过引入高效的数据压缩和缓存技术,降低了数据传输和存储的负担,同时保证了检测的实时性。此外,对于数据的安全性和隐私保护,我们采取了加密存储和访问控制等措施,确保用户数据的安全。

  1. 系统的可扩展性和维护性

        为了应对未来可能的需求变化和技术升级,我们在系统设计时充分考虑了其可扩展性和维护性。系统采用模块化设计,方便集成新的模型或功能。同时,通过持续集成和自动化测试流程,确保了系统的稳定性和可靠性,简化了日常的维护和升级工作。

        总之,通过综合考虑车牌检测任务面临的挑战,并采取一系列针对性的解决方案,我们的系统在保证高准确性和实时性的同时,也提供了良好的用户体验和高效的数据处理能力,满足了现代智能交通和车辆管理需求。

2.3.2 解决方案

        针对基于YOLOv8/v7/v6/v5的车牌检测系统,我们计划采取以下解决方案来应对提出的挑战,确保系统的高性能和良好用户体验:

  1. 深度学习模型的选择和优化
  • 模型架构:我们选择了YOLOv5至YOLOv8这一系列模型作为我们系统的核心,根据各自的特点进行了精细的选择和优化。YOLOv8以其最新的架构优化和性能提升作为首选模型,用于处理最复杂的场景。同时,提供YOLOv5至YOLOv7作为备选,以适应不同硬件条件和实时性要求。
  • 数据增强:为了提升模型的泛化能力,特别是在复杂光照、不同角度和遮挡情况下的表现,我们采用了一系列数据增强技术。这包括但不限于随机裁剪、旋转、缩放、色彩调整等,以此模拟真实世界中车牌可能遇到的各种情况。
  • 迁移学习:通过在大规模通用数据集上预训练的模型作为基础,使用迁移学习技术针对车牌检测任务进行微调。这一策略加速了模型训练过程,同时提高了在特定车牌检测任务上的准确性。
  1. 技术框架和开发工具
  • PyTorch框架:我们采用PyTorch作为深度学习的核心框架,利用其灵活性和强大的GPU加速能力,以支持快速迭代和开发高效的深度学习模型。
  • Streamlit网页应用:选择Streamlit作为构建用户交互界面的工具,它允许我们以最少的代码快速搭建出一个功能丰富且美观的Web应用。通过简洁的API和直观的设计,Streamlit极大地简化了数据呈现和模型部署的工作。
  • PyCharm IDE:使用PyCharm作为主要的集成开发环境(IDE),它提供了代码编辑、调试、版本控制等一系列强大功能,有效提升了开发效率和项目管理的便利性。
  1. 功能实现和系统设计
  • 多输入源支持:系统设计以支持图像、视频和实时摄像头捕获等多种输入源,以适应不同用户的需求。这一特性使得系统能够灵活应用于各种场景,如停车场管理、交通监控等。
  • 模型切换功能:实现了一个用户友好的界面,允许用户根据实际需求和硬件条件灵活选择不同的检测模型。这不仅提升了系统的适用性,也使得用户能够在精确度和速度之间根据需要做出最佳平衡。
  • 用户界面设计:借助Streamlit和CSS,我们开发了一个既直观又功能丰富的Web界面,用户可以在此轻松上传数据、选择模型、查看检测结果,并进行相关设置调整。
  1. 数据处理
  • 高效数据处理:利用PyTorch强大的数据加载和预处理能力,实现了一个高效流畅的数据处理流程。

2.4 博文贡献与组织结构

        本文的核心贡献在于综合性地探讨了基于YOLOv8/v7/v6/v5等深度学习模型的车牌检测系统的开发与实现,涵盖了从文献综述、数据集处理,到算法选择与优化,再到实际应用开发的完整流程。我们的贡献可以从以下几个方面具体概述:

  1. 详细的任务相关文献综述:我们提供了一个全面的文献回顾,涉及到车牌检测领域内的各种深度学习模型,特别是YOLO系列的发展历程及其在车牌检测任务中的应用。这为理解当前研究热点和技术难点奠定了坚实的基础。

  2. 数据集的处理:文章详细介绍了如何收集、预处理和增强用于训练和验证车牌检测模型的数据集。我们展示了一系列数据处理技巧,旨在提高模型的泛化能力和在复杂环境下的表现。

  3. 算法选择与优化:本文不仅对比了YOLOv7/v6/v5等算法的性能,还详细探讨了为什么最终选择YOLOv8作为核心算法,并且如何对其进行优化以适应车牌检测的特定需求。

  4. Streamlit网页设计:我们采用Streamlit框架设计了一个美观友好的网页应用,使用户能够轻松上传图像或视频进行车牌检测,实时查看结果,并支持切换不同的模型进行检测。这部分不仅展示了系统的前端设计和用户交互功能,也说明了后端模型与前端界面的整合方法。

  5. 实验结果与分析:通过大量的实验,我们对比了YOLOv7、v6、v5等不同版本的性能,包括检测准确率、处理速度等关键指标,为读者提供了清晰的性能评估。

  6. 资源共享:本文提供了完整的数据集和代码资源包下载链接,包括预处理脚本、训练和测试代码,以及预训练模型。这些资源的共享旨在帮助读者更好地理解和复现我们的研究成果,同时也促进了技术的开放交流。

        后续章节的组织结构如下: 绪论:介绍研究背景、目的和本文的主要贡献;算法原理:详细介绍YOLOv8/v7/v6/v5等算法的工作原理及其在车牌检测中的应用;数据集处理:讨论使用的数据集及其预处理、增强方法。代码介绍:提供模型训练和预测的详细代码说明,包括环境搭建、参数配置和执行步骤。实验结果与分析:展示不同模型在车牌检测任务上的实验结果,并进行比较分析。系统设计与实现:介绍基于Streamlit的车牌检测系统的设计与实现细节。结论与未来工作:总结本文的研究成果,并讨论未来的研究方向和潜在的改进空间。


3. 数据集处理

        在构建一个基于深度学习的车牌检测系统时,数据集的质量和构成是实现高准确率和鲁棒性的关键。我们的项目采用了一个精心策划和丰富的数据集,包含了5555张图像,这些图像经过细致的挑选和预处理,以确保训练过程的有效性和模型最终的性能。数据集分为5102张训练图像、432张验证图像以及21张测试图像,这种分布策略旨在最大化模型训练时的信息量,并确保在独立的数据上评估其性能和泛化能力。博主使用的类别如下:

Chinese_name = {
    "License_Plate": "车牌", "cars": "汽车", "motorcyle": "摩托车", "truck": "卡车"
}
  • 1
  • 2
  • 3

        每一张图像都经过了自动的方向校正,保证了数据的一致性,这一步骤通过去除EXIF方向信息来完成,确保所有图像的方向都是正确的,以便于模型处理。此外,所有图像都被统一地调整为416x416像素的大小,这样的统一化处理不仅适应了我们模型输入的需求,也减少了模型训练过程中可能遇到的变形问题。虽然这一调整过程涉及到拉伸,可能导致一些比例上的失真,但经过多次实验验证,模型已经能够很好地适应这些变化,保持了检测的准确性。

在这里插入图片描述

        进一步的数据集分析显示,绝大部分的图像标签集中在“车牌”类别,这一现象强调了我们对车牌检测任务的专注。同时,标注的车牌在图像中的大小和位置也展示了一定的规律性。大部分车牌在图像中的占比相对集中,意味着模型能够更专注地学习到适中尺寸的车牌特征。而车牌中心点多数分布在图像中心,这样的特性对于模型来说既是一个优势也是一个挑战。它说明我们的模型在训练时可能自然而然地更关注图像中心的对象,而忽略边缘位置的车牌。

在这里插入图片描述

        针对这些分析结果,我们采取了一系列措施以优化训练过程并提高模型的泛化能力。数据增强策略的引入旨在模拟车牌在不同位置和大小下的出现,通过随机缩放、色彩抖动、随机裁剪和旋转等手段扩展了训练数据的多样性。此外,为了弥补数据集中车牌位置分布的偏差,我们特意加入了对非中心区域的车牌进行强化的数据增强技术,确保模型在边缘区域也具有较高的识别精度。

        总而言之,我们的数据集是专门为车牌检测任务设计的,其细致的准备工作和后续的处理策略,使其成为训练高效准确的YOLO模型的理想选择。在未来的工作中,我们将继续探索更多的数据增强和预处理技术,以不断提升系统的性能,确保在各种环境和情境下都能表现出色。


4. 原理与代码介绍

4.1 YOLOv8算法原理

        在目标检测的世界中,YOLOv8代表了技术的最新进展。它是在YOLO(You Only Look Once)系列算法发展中的又一重要里程碑。作为一个高效的目标检测模型,YOLOv8继承了YOLO系列算法的核心思想,即在单次前向传播中同时预测多个目标的类别和位置,实现了检测的实时性和准确性的平衡。

        YOLOv8的架构包含了三个主要部分:Backbone、Neck和Head。Backbone是模型的主干网络,负责提取图像的特征。YOLOv8的Backbone在结构上进行了重要的优化,比如引入了CSP(Cross Stage Partial networks)设计,它通过部分连接多个网络阶段,减少了计算量的同时保持了特征的丰富性。此外,YOLOv8的Backbone可能还整合了SPP(Spatial Pyramid Pooling)和C2F(Coarse-to-Fine)结构,使模型能够捕获从粗到细的多尺度特征。

在这里插入图片描述

        Neck部分的作用是连接Backbone和Head,它在特征传递过程中起到增强和过滤的作用。YOLOv8可能采用了PANet(Path Aggregation Network)或者BiFPN(Bidirectional Feature Pyramid Network)这样的结构,以促进不同尺度的特征图之间的信息流动,强化了检测器对于不同尺寸目标的检测能力。

        Head部分是模型的预测器,负责最终的目标检测任务。它通常包含多个并行的卷积层,用于预测边界框的位置、尺寸和目标的类别。YOLOv8的Head可能通过改进的anchor机制来预测边界框,该机制能够更精准地匹配目标的形状和大小,从而提高了检测的精度。

        除了架构上的创新,YOLOv8在算法的训练和优化方面也做了诸多改进。例如,利用AutoML技术自动调整网络结构,或者采用了更先进的损失函数来优化模型的性能。这些技术的应用,使得YOLOv8在各种复杂场景下的水下目标检测任务中都表现出色,无论是在精确度、速度还是鲁棒性方面。

        YOLOv8还采用了最新的训练技巧,例如自适应标签分配(adaptive label assignment),这使得模型在训练过程中能够更智能地分配标签,以适应不同目标的特性。此外,YOLOv8还引入了一种新的损失函数,用于平衡检测任务中的多个目标,如定位精度和类别准确性,这有助于模型在多个评价指标上都取得良好表现。

        总的来说,YOLOv8在继承了YOLO系列算法速度与准确度优势的基础上,通过架构和算法的创新,进一步提升了目标检测性能,尤其在水下目标检测等需要高精度和快速响应的应用场景中,表现出了非凡的能力。

4.2 模型构建

        在“代码介绍”部分,我们将详细讨论构建高效车牌检测模型的核心代码。这一代码片段展示了如何利用深度学习框架和计算机视觉库来创建一个车牌检测系统,它使用了YOLO算法的最新版本,旨在通过实时分析视频或图像来检测车牌。

        我们使用cv2,即OpenCV库,它是一个开源的计算机视觉和机器学习软件库,主要用于图像处理。torch是PyTorch的核心库,一个开源的机器学习框架,广泛应用于深度学习项目中。QtFusion.models中的Detector类是一个用于所有检测器模型的抽象基类,我们将根据此类创建我们的车牌检测模型类。datasets.label_name中的Chinese_name是一个字典,它将类别标签映射到中文名称。ultralytics的YOLO类和select_device函数则专门用于加载YOLO模型并选择计算设备(如CPU或GPU)。

import cv2
import torch
from QtFusion.models import Detector
from datasets.label_name import Chinese_name
from ultralytics import YOLO
from ultralytics.utils.torch_utils import select_device
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

        设备选择逻辑检测到是否有可用的CUDA环境,优先使用GPU进行加速,如果没有则回退到CPU。初始参数ini_params被设置来定义模型预测时的一些关键参数,如置信度阈值和IOU阈值。这些参数对于控制检测精度和过滤结果至关重要。IOU阈值用于非极大抑制,这是一个在目标检测中常用的技术,用于去除多余的检测框,从而确保每个目标只被检测一次。

device = "cuda:0" if torch.cuda.is_available() else "cpu"
ini_params = {
    'device': device,
    'conf': 0.25,
    'iou': 0.5,
    'classes': None,
    'verbose': False
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

        count_classes函数是一个实用工具,它可以统计检测结果中每个类别的实例数量。这对于理解模型在不同类别上的表现非常有用,可以帮助我们调整类别的权重或对数据进行重采样,以解决类别不平衡的问题。

def count_classes(det_info, class_names):
    count_dict = {name: 0 for name in class_names}
    for info in det_info:
        class_name = info['class_name']
        if class_name in count_dict:
            count_dict[class_name] += 1
    count_list = [count_dict[name] for name in class_names]
    return count_list
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

        在定义了车牌检测模型类YOLOv8v5Detector后,我们看到这个类继承了Detector,这是一个抽象基类。继承自该类意味着YOLOv8v5Detector需要实现特定的方法,如load_model、preprocess、predict和postprocess。这种面向对象的设计允许代码更好地模块化和重用。load_model方法负责加载预训练的YOLO模型。模型路径是作为参数传入的,这增加了灵活性,允许我们在需要时轻松更换不同的模型文件。在preprocess方法中,虽然当前的实现比较直接(仅保存并返回图像),但这里提供了预处理图像数据的可能性,比如调整大小、归一化或数据增强等。

class YOLOv8v5Detector(Detector):
    def __init__(self, params=None):
        super().__init__(params)
        self.model = None
        self.img = None
        self.names = list(Chinese_name.values())
        self.params = params if params else ini_params
	def load_model(self, model_path):
	    self.device = select_device(self.params['device'])
	    self.model = YOLO(model_path)
	    names_dict = self.model.names
	    self.names = [Chinese_name[v] if v in Chinese_name else v for v in names_dict.values()]
	    self.model(torch.zeros(1, 3, *[self.imgsz] * 2).to(self.device).type_as(next(self.model.model.parameters())))
	def preprocess(self, img):
	    self.img = img
	    return img
	
	def predict(self, img):
	    results = self.model(img, **ini_params)
	    return results
	
	def postprocess(self, pred):
	    results = []
	    for res in pred[0].boxes:
	        for box in res:
	            class_id = int(box.cls.cpu())
	            bbox = box.xyxy.cpu().squeeze().tolist()
	            bbox = [int(coord) for coord in bbox]
	            result = {
	                "class_name": self.names[class_id],
	                "bbox": bbox,
	                "score": box.conf.cpu().squeeze().item(),
	                "class_id": class_id,
	            }
	            results.append(result)
	    return results
	    
    def set_param(self, params):
        self.params.update(params)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

        predict方法是模型的核心,它使用加载的模型对输入图像进行预测。这一步是实时车牌检测流程中最关键的部分,因为它直接影响到检测结果的质量和速度。postprocess方法处理模型的预测结果,并转换为一个包含类别名称、边界框、置信度和类别ID的结果列表。后处理是从原始模型输出中提取实用信息的重要步骤,为后续的分析或实时反馈提供了便利。最后,set_param方法允许动态更新模型的参数,这对于在不同的运行时环境中调整模型表现至关重要。

        通过这个类的实例,我们可以轻松地加载模型、进行预测,并处理预测结果,从而有效地将复杂的模型操作封装起来,便于维护和迭代。

4.3 训练代码

        在这个“模型训练”部分的博客,我们将逐步解析车牌检测系统中的模型训练代码,揭示其构建块以及它们是如何协同工作的。以下表格详细介绍了YOLOv8模型训练中使用的一些重要超参数及其设置:

超参数设置说明
学习率(lr00.01决定了模型权重调整的步长大小,在训练初期有助于快速收敛。
学习率衰减(lrf0.01控制训练过程中学习率的降低速度,有助于模型在训练后期细致调整。
动量(momentum0.937加速模型在正确方向上的学习,并减少震荡,加快收敛速度。
权重衰减(weight_decay0.0005防止过拟合,通过在损失函数中添加正则项减少模型复杂度。
热身训练周期(warmup_epochs3.0初始几个周期内以较低的学习率开始训练,逐渐增加到预定学习率。
批量大小(batch16每次迭代训练中输入模型的样本数,影响GPU内存使用和模型性能。
输入图像大小(imgsz640模型接受的输入图像的尺寸,影响模型的识别能力和计算负担。

        环境设置与模型加载:这段代码的开始是标准的导入语句块,引入了必需的模块和函数。torch是PyTorch框架的核心,它为模型训练提供支持。yaml用于解析YAML格式的配置文件,这种格式的文件通常用于存储模型训练时的配置信息。ultralytics库中的YOLO类是我们模型训练的基石,它提供了YOLO模型的功能。QtFusion.path中的abs_path函数用于获取文件的绝对路径,这在确保路径正确性方面非常有用。

import os
import torch
import yaml
from ultralytics import YOLO  # 用于加载YOLO模型
from QtFusion.path import abs_path  # 用于获取文件的绝对路径
  • 1
  • 2
  • 3
  • 4
  • 5

        这行代码检查是否有可用的GPU,并据此设置device变量。如果CUDA可用,device将设置为字符串"0",表示使用编号为0的GPU。如果CUDA不可用,device将回退到CPU。这是非常重要的一步,因为它直接关系到模型训练的速度和效率。

device = "0" if torch.cuda.is_available() else "cpu"
  • 1

        数据集准备:这里的workers指定了数据加载时使用的进程数。在多核CPU上,增加工作进程数可以加快数据的加载速度,但也需要更多的内存。batch是指训练过程中每批次的图像数量,它是内存消耗和训练速度的关键参数。data_name是数据集的名称,用于构造数据集配置文件的路径。abs_path函数被用来找到这个配置文件的绝对路径,确保无论当前工作目录在哪里,路径都是正确的。这行代码将路径转换为UNIX风格的路径,这在某些情况下是必要的,比如在使用某些依赖于特定路径风格的工具时。

workers = 1  # 工作进程数
batch = 8  # 每批处理的图像数量
data_name = "VehicleLicense"
data_path = abs_path(f'datasets/{data_name}/{data_name}.yaml', path_type='current')
unix_style_path = data_path.replace(os.sep, '/')
  • 1
  • 2
  • 3
  • 4
  • 5

        这里,我们读取了数据集配置文件。YAML文件通常包含了有关数据集路径、类别、批次大小等信息的配置。

directory_path = os.path.dirname(unix_style_path)
with open(data_path, 'r') as file:
    data = yaml.load(file, Loader=yaml.FullLoader)

if 'path' in data:
    data['path'] = directory_path
    with open(data_path, 'w') as file:
        yaml.safe_dump(data, file, sort_keys=False)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

        训练模型:在处理路径和YAML配置之后,我们加载了预训练的YOLO模型。最终,我们调用train方法开始训练过程。在这一步中,我们将数据集的配置、计算设备、工作进程数、输入图像的大小、训练周期数和每批次大小等关键参数传递给模型。通过这些精心调整的参数,我们设置了模型训练的舞台,并启动了模型对数据的学习过程。

model = YOLO(abs_path('./weights/yolov5nu.pt', path_type='current'), task='detect')  # 加载预训练的YOLOv8模型
# model = YOLO('./weights/yolov5.yaml', task='detect').load('./weights/yolov5nu.pt')  # 加载预训练的YOLOv8模型
# Training.
results = model.train(  # 开始训练模型
    data=data_path,  # 指定训练数据的配置文件路径
    device=device,  # 自动选择进行训练
    workers=workers,  # 指定使用2个工作进程加载数据
    imgsz=640,  # 指定输入图像的大小为640x640
    epochs=120,  # 指定训练100个epoch
    batch=batch,  # 指定每个批次的大小为8
    name='train_v5_' + data_name  # 指定训练任务的名称
)
model = YOLO(abs_path('./weights/yolov8n.pt'), task='detect')  # 加载预训练的YOLOv8模型
results2 = model.train(  # 开始训练模型
    data=data_path,  # 指定训练数据的配置文件路径
    device=device,  # 自动选择进行训练
    workers=workers,  # 指定使用2个工作进程加载数据
    imgsz=640,  # 指定输入图像的大小为640x640
    epochs=120,  # 指定训练100个epoch
    batch=batch,  # 指定每个批次的大小为8
    name='train_v8_' + data_name  # 指定训练任务的名称
)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

        这段代码集中表述了车型识别模型训练的完整流程。通过细节的描述,读者可以清晰理解每一步的作用以及如何利用现代深度学习工具来训练一个强大的车辆检测模型。从数据准备到模型初始化,再到训练过程的细粒度控制,每个步骤都被详细阐释。


5. 实验结果与分析

5.1 训练曲线

        训练过程中损失函数的变化是衡量模型学习质量的关键指标之一。图中的“train/box_loss”、“train/cls_loss”和“train/obj_loss”分别代表训练过程中的边界框损失、分类损失和目标损失。这三者的损失值随着训练周期(epoch)的增加而逐渐下降,显示了模型在识别物体位置、分类以及检测目标物体方面的学习能力正在增强。损失曲线的平滑版本,显示了损失下降的趋势,有助于我们观察到真实的趋势,排除了训练过程中的随机波动。

在这里插入图片描述

        在验证集上,我们观察到了类似的趋势。“val/box_loss”、"val/cls_loss"和"val/obj_loss"的图表显示了在训练期间模型在未见过的数据上的性能。这些损失函数的下降证明了模型不仅在训练集上表现良好,而且在泛化到新数据上时也能保持其性能。尤其是在开始的几个epoch,损失下降得非常快,这表明模型迅速从数据中学习。

        当我们分析精度(precision)和召回率(recall)曲线时,可以看到在训练过程中它们存在一定的波动,但整体呈上升趋势。这种波动可能是由于训练过程中的批次间变异性所引起的,或者是因为模型在尝试学习数据中的更复杂模式。尽管存在波动,模型的精度和召回率最终都达到了相对较高的水平,这表明模型在定位和分类方面都取得了不错的结果。

        最后,评估指标mAP(mean Average Precision)衡量了模型在一系列不同的IoU(Intersection over Union)阈值下的平均精度。这是目标检测模型性能的标准度量。从图表中可以看到,“metrics/mAP50”和“metrics/mAP50-95”随着训练周期的增加而稳步上升。mAP50仅考虑IoU阈值为0.5的情况,而mAP50-95计算了从0.5到0.95的IoU阈值下的平均精度。mAP50-95的上升轨迹显示了模型在检测不同尺寸和形状的物体时的鲁棒性。最终达到的mAP值表明了模型具有较好的识别能力,并能准确定位检测对象。

        总体来看,损失函数和评估指标图表向我们展示了模型训练的良好进展。损失的逐步下降以及精度和召回率的提高,以及mAP的稳定提升,共同指向了模型性能的整体提升。这些结果表明模型不仅在训练集上学习得很好,而且在验证集上也具有很好的泛化能力。

5.2 PR曲线图

        理想的PR曲线紧贴左上角,表示模型具有高精度(Precision)和高召回率(Recall)。从图中我们可以观察到,“License_Plate”和“motorcycle”两个类别的AP值非常高,分别为0.995,显示了模型在这些类别上的卓越性能。这可能是由于车牌和摩托车的特征相对明显,或者是训练数据在这些类别上特别充足和多样化。

在这里插入图片描述

        对于“cars”类别,AP值为0.872,仍然是一个非常好的结果,但与“License_Plate”和“motorcycle”类别相比稍低。这表明车辆检测也相当准确,但可能由于车辆类型和尺寸的多样性,使得检测任务变得相对复杂。对于“truck”类别,AP值为0.811,是四个类别中最低的,这可能是因为卡车在数据集中出现较少,或者它们的特征对于模型来说不如其他类别那么容易学习。

        综合考虑所有类别,模型的平均精度(mAP)达到了0.918(在IoU=0.5的情况下),这是一个非常高的性能指标,显示了模型在综合所有类别的目标检测任务上具有很高的准确性。在实际应用中,这意味着模型能够以很高的概率正确地识别和定位图像中的目标,同时保持较低的误检率。

        从曲线的形状可以看出,对于每个类别,随着召回率的增加,精度有所下降,这是正常现象。因为随着召回率提高,模型尝试检测更多的正样本,从而可能引入更多的误检。然而,在本模型中,这种下降是平缓的,这表明模型能够在提高召回率的同时仍保持相对较高的精度。

        PR曲线的分析向我们展示了模型在不同类别上的强项和弱点。对于那些具有非常高AP值的类别,我们可以有信心地将模型部署到实际应用中。对于AP值相对较低的类别,我们可能需要进一步调查原因,并在可能的情况下,通过增加样本多样性、进行更细粒度的特征工程或调整模型结构来提高性能。

5.3 YOLOv8/v7/v6/v5对比实验

(1)实验设计
        本实验旨在评估和比较YOLOv5、YOLOv6、YOLOv7和YOLOv8几种模型在车牌目标检测任务上的性能。为了实现这一目标,博主分别使用使用相同的数据集训练和测试了这四个模型,从而可以进行直接的性能比较。该数据集包含车牌的图像。本文将比较分析四种模型,旨在揭示每种模型的优缺点,探讨它们在工业环境中实际应用的场景选择。

模型图像大小 (像素)mAPval 50-95CPU ONNX 速度 (毫秒)A100 TensorRT 速度 (毫秒)参数数量 (百万)FLOPs (十亿)
YOLOv5nu64034.373.61.062.67.7
YOLOv8n64037.380.40.993.28.7
YOLOv6N64037.5--4.711.4
YOLOv7-tiny64037.4--6.0113.1

(2)度量指标

  • F1-Score:F1-Score 作为衡量模型性能的重要指标,尤其在处理类别分布不均的数据集时显得尤为关键。它通过结合精确率与召回率,提供了一个单一的度量标准,能够全面评价模型的效能。精确率衡量的是模型在所有被标记为正例中真正属于正例的比例,而召回率则关注于模型能够识别出的真正正例占所有实际正例的比例。F1-Score通过两者的调和平均,确保了只有当精确率和召回率同时高时,模型的性能评估才会高,从而确保了模型对于正例的预测既准确又完整。
  • mAP(Mean Average Precision):在目标检测任务中,Mean Average Precision(mAP)是评估模型性能的重要标准。它不仅反映了模型对单个类别的识别精度,而且还考虑了所有类别的平均表现,因此提供了一个全局的性能度量。在计算mAP时,模型对于每个类别的预测被单独考虑,然后计算每个类别的平均精度(AP),最后这些AP值的平均数形成了mAP。
名称YOLOv5nuYOLOv6nYOLOv7-tinyYOLOv8n
mAP0.8680.9450.8480.91
F1-Score0.860.930.850.88

(3)实验结果分析

       在评估和比较YOLOv5nu、YOLOv6n、YOLOv7-tiny以及YOLOv8n四个版本的性能时,我们采用了两个核心指标:mAP(平均精度均值)和F1-Score。这两个指标共同衡量了模型检测准确性的两个方面:模型检测出的真正例占所有真实正例的比例,以及检测出的真正例占所有被检测为正例的比例。

       通过数据我们可以看出,YOLOv6n在这两个指标上都呈现出领先的性能,其mAP达到了0.945,F1-Score为0.93。这说明YOLOv6n在准确检测物体位置及分类方面具有很高的准确率和召回率,很可能是因为YOLOv6的架构或训练策略在这些方面进行了有效的优化。可能的优化方面包括了更深或更复杂的网络结构,更有效的特征提取方式,或者是更高级的训练技巧,如注意力机制的使用或是更精细的标签分配策略。

       YOLOv5nu和YOLOv7-tiny的表现略低于YOLOv6n,但也展现出相对较高的性能。YOLOv5nu的mAP为0.868,F1-Score为0.86,而YOLOv7-tiny的mAP为0.848,F1-Score为0.85。尽管这两个版本在性能上稍逊于YOLOv6n,但仍表现出良好的检测能力。这些模型版本可能在网络结构简化或是针对特定任务的优化上做得较为充分,但在处理更复杂的场景或是更多样的数据集时可能略显不足。

       YOLOv8n作为四个模型中最新的版本,其性能介于YOLOv6n和其他两个模型之间,mAP为0.91,F1-Score为0.88。这可能意味着YOLOv8n在保持了YOLO系列模型一贯的高性能的同时,还进一步提高了模型的泛化能力或者是在处理具体任务上做出了新的改进。比如,YOLOv8n可能加入了新的训练策略,或者在模型结构上做了调整,以适应更多样化的数据和更复杂的检测任务。

在这里插入图片描述

       总体而言,不同版本的YOLO模型在性能上的差异反映了不同的设计哲学和技术演进。随着深度学习技术的不断发展,我们可以预见未来的YOLO模型将在性能上继续提升,尤其是在处理更加复杂多变的真实世界任务时。对于实际应用场景的选择而言,我们需要综合考量模型的性能指标和任务需求,选择最合适的模型版本进行部署。


6. 系统设计与实现

6.1 系统架构概览

        在设计基于YOLOv8/v7/v6/v5的车牌检测系统时,我们采取了一种模块化、易于扩展的系统架构。本系统架构不仅关注于算法的效率和精度,还充分考虑了用户交互和实际应用场景的需求。以下是系统主要组成部分的详细介绍:

在这里插入图片描述

  1. 模型加载与初始化(YOLOv8v5Detector)

        系统首先通过YOLOv8v5Detector类负责加载预训练的YOLO模型。这一步是车牌检测系统的基础,确保了模型的正确加载及其后续的正常运行。该类封装了模型的加载、预处理和预测等功能,为系统提供了一个强大且灵活的目标检测能力。

  1. 图像处理与检测(Detection_UI)

        在Detection_UI类中,系统集成了用户界面和检测逻辑,使用户能够通过图形界面上传图像或视频文件,并展示检测结果。该类负责管理用户交互、文件上传、检测参数设置(如置信度阈值conf_threshold和IOU阈值iou_threshold)以及视觉展示等功能。

  1. 实时检测与日志记录(process_camera_or_file、LogTable)

        为了实现实时检测,Detection_UI中的process_camera_or_file方法通过整合OpenCV库实现了从摄像头实时捕获图像并进行检测的功能。同时,利用LogTable类记录检测过程中的详细信息,如检测位置、置信度等,便于后续的分析和优化。

  1. 结果展示与交互(setupMainWindow、frame_process)

        系统通过setupMainWindow方法设置主窗口的布局和样式,利用Streamlit库创建直观的用户界面。在frame_process方法中,对捕获的图像帧进行预处理、调用模型进行预测,并处理预测结果,最后将检测结果以图形形式展示给用户,提高了系统的交互性和用户体验。

  1. 系统配置与优化(setup_sidebar)

        通过setup_sidebar方法,系统提供了侧边栏配置面板,允许用户自定义模型设置(如选择不同的YOLO版本)、调整检测参数和选择输入源。这种设计使得系统更加灵活,可以根据不同的应用场景和用户需求进行快速调整。

        本系统通过细致的模块划分和接口设计,实现了一个高效、准确且用户友好的车牌检测系统。通过对YOLO系列算法的有效利用,结合Streamlit和OpenCV等技术,系统不仅在技术层面上达到了先进水平,也在实用性和可扩展性上具有很好的表现。在未来,系统可以根据新的需求和技术进展进行进一步的优化和扩展,以满足更广泛的应用场景。

6.2 系统流程

        在本节中,我们将详细介绍基于YOLOv8/v7/v6/v5的车牌检测系统的工作流程。为了更加形象地呈现系统如何运作,以下是以程序流程图的形式展开的步骤介绍:

在这里插入图片描述

  1. 初始化系统(Detection_UI构造函数)

    • 系统启动时,首先初始化Detection_UI类的实例。这一步骤包括加载类别标签、设置页面标题、初始化检测相关的配置参数(如模型类型、置信度阈值和IOU阈值)、初始化相机和文件相关的变量,以及UI显示相关的变量。
  2. 配置页面和侧边栏(setup_pagesetup_sidebar方法)

    • 通过setup_page方法设置页面布局,如页面标题和图标。
    • 通过setup_sidebar方法配置侧边栏,包括模型设置、摄像头配置和识别项目设置等。用户可以在这里选择模型类型、设置置信度和IOU阈值、选择摄像头或上传文件。
  3. 加载模型(YOLOv8v5Detector实例化)

    • 如果系统尚未加载模型,将创建YOLOv8v5Detector的实例并加载预训练的YOLO模型。这个步骤确保了系统具备进行目标检测的能力。
  4. 处理输入(process_camera_or_file方法)

    • 根据用户在侧边栏的选择,系统可以处理来自摄像头的实时视频流或用户上传的图片/视频文件。
    • 对于摄像头输入,系统实时捕获图像帧并进行检测。
    • 对于文件上传,系统读取文件内容,处理并显示检测结果。
  5. 图像帧处理(frame_process方法)

    • 对于每个捕获或上传的图像帧,系统首先进行预处理,然后使用加载的YOLO模型进行目标检测。
    • 检测完成后,应用非极大值抑制(NMS)等后处理步骤,过滤掉重叠的检测结果,保留最佳的检测框。
  6. 结果展示(setupMainWindow方法)

    • 检测结果将在主窗口中展示,包括检测到的车牌的边界框、置信度等信息。用户可以通过设置显示模式,选择是单画面显示还是双画面显示(原始画面和识别画面)。
  7. 日志记录与导出(LogTable类)

    • 系统通过LogTable类记录每次检测的详细信息,如检测时间、位置、置信度等,并支持将日志数据保存为CSV文件,方便用户进行分析和记录。
  8. 用户交互

    • 用户可以通过侧边栏进行实时的配置更改,如修改置信度阈值、选择不同的摄像头或上传新的文件进行检测。
    • 系统根据用户的交互实时更新检测结果和展示内容。

        通过以上步骤,我们的车牌检测系统不仅能够高效地处理实时视频流和文件上传,还能提供灵活的用户交互和配置选项,满足不同用户在不同场景下的需求。此流程确保了系统的高性能和良好的用户体验,为车牌检测任务提供了一个强大的解决方案。


代码下载链接

        如果您希望获取博客中提及的完整资源包,包含测试图片、视频、Python文件(*.py)、网页配置文件、训练数据集、代码及界面设计等,可访问博主在面包多平台的上传内容。相关的博客和视频资料提供了所有必要文件的下载链接,以便一键运行。完整资源的预览如下图所示:

在这里插入图片描述

        资源包中涵盖了你需要的训练测试数据集、训练测试代码、UI界面代码等完整资源,完整项目文件的下载链接可在下面的视频简介中找到➷➷➷

演示及项目介绍视频:https://www.bilibili.com/video/BV1Jx421U7h2/

在这里插入图片描述

完整安装运行教程:

        这个项目的运行需要用到Anaconda和Pycharm两个软件,下载到资源代码后,您可以按照以下链接提供的详细安装教程操作即可运行成功,如仍有运行问题可私信博主解决:

  1. Pycharm和Anaconda的安装教程https://deepcode.blog.csdn.net/article/details/136639378

        软件安装好后需要为本项目新建Python环境、安装依赖库,并在Pycharm中设置环境,这几步采用下面的教程可选在线安装(pip install直接在线下载包)或离线依赖包(博主提供的离线包直接装)安装两种方式之一:

  1. Python环境配置教程https://deepcode.blog.csdn.net/article/details/136639396(2,3方法可选一种);
  2. 离线依赖包的安装指南https://deepcode.blog.csdn.net/article/details/136650641(2,3方法可选一种);

        如使用离线包方式安装,请下载离线依赖库,下载地址:https://pan.baidu.com/s/1uHbU9YzSqN0YP_dTHBgpFw?pwd=mt8u (提取码:mt8u)。


7. 结论与未来工作

        在本项目中,我们通过实现基于YOLOv8/v7/v6/v5的车牌检测系统,深入探讨了YOLO系列算法在车牌检测任务中的应用。借助高效的目标检测模型,我们成功地解决了复杂背景、不同光照条件以及车牌遮挡等一系列挑战,展示了YOLO算法在实时车牌识别方面的强大能力。系统架构的设计充分考虑了模型的效率和准确性,采用的技术和方法在实际应用中表现出了高度的适用性和稳定性。

        我们的系统不仅仅是对YOLO算法的一次应用,更是对目标检测技术在交通领域应用的一次深入探索。通过不断的测试和优化,系统已经能够在多种复杂环境下稳定运行,为车辆管理、交通监控等领域提供了有效的技术支持。此外,我们的实验也证明了通过适当的参数调整和模型优化,可以进一步提升检测的准确率和速度。

未来工作的方向将主要集中在以下几个方面

  • 模型优化:探索更深层次的网络结构优化,利用最新的研究成果进一步提升模型的检测精度和速度。
  • 数据增强:开发更高级的数据增强技术,以提高模型对不同环境条件下车牌的识别能力。
  • 算法融合:尝试将YOLO算法与其他机器学习或深度学习技术结合,以解决更复杂的车牌检测问题。
  • 实际应用扩展:将车牌检测技术应用到更广泛的场景中,如无人驾驶、智能交通系统等,并解决实际应用中的具体问题。

        通过不断的努力和探索,我们相信车牌检测技术将更加成熟,为智能交通和车辆管理领域带来更大的贡献。我们期待着在未来工作中取得更多的突破,为智能交通的发展贡献自己的力量。


  1. Yusof, Najiha‘Izzaty Mohd, et al. “Assessing the performance of YOLOv5, YOLOv6, and YOLOv7 in road defect detection and classification: a comparative study.” Bulletin of Electrical Engineering and Informatics 13.1 (2024): 350-360. ↩︎

  2. Goel, Lavika, and Pankaj Patel. “Improving YOLOv6 using advanced PSO optimizer for weight selection in lung cancer detection and classification.” Multimedia Tools and Applications (2024): 1-34. ↩︎

  3. Zhao, Dewei, et al. “A Small Object Detection Method for Drone-Captured Images Based on Improved YOLOv7.” Remote Sensing 16.6 (2024): 1002. ↩︎

  4. Flores-Calero, Marco, et al. “Traffic Sign Detection and Recognition Using YOLO Object Detection Algorithm: A Systematic Review.” Mathematics 12.2 (2024): 297. ↩︎

  5. Qiu, Shi, et al. “Automated detection of railway defective fasteners based on YOLOv8-FAM and synthetic data using style transfer.” Automation in Construction 162 (2024): 105363. ↩︎

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/356487
推荐阅读
相关标签
  

闽ICP备14008679号