diff --git a/分组实验报告.doc b/分组实验报告.doc new file mode 100644 index 0000000..a45ded2 --- /dev/null +++ b/分组实验报告.doc @@ -0,0 +1,422 @@ + + + + + + Python分组实验报告 + + + 题目 车牌识别与分类 + + + + + + + + + 院 系 计算机与控制工程学院 + 专 业 软件工程 + 班 级 计237-2 + 姓 名 王昱博 + 学 号 202358507208 + 同组同学 刘钰廷、冯雅君、冯昌盛、潘浩宇、戴晓齐、焦雅雯 + + + 指导教师 李瑞旭 + + + + 2023年 12月 10日 + + 教师批改意见 +|序号|评价 |评分标准 |评分 | | +| |指标 | | | | +|1 |软件 |主要指标5项,各6分,满分30分。 |30 | | +| |情况 |(1)技术先进性3-6之间 | | | +| | |(2)功能齐全2-6之间 | | | +| | |(3)软件设计合理性3-6之间 | | | +| | |(4)工作量饱满3-6之间 | | | +| | |(5)安全性3-6之间 | | | +|2 |验收情况|(1)根据自述,对软件和设计整体掌|20 | | +| | |握程度0-10之间 | | | +| | |(2)回答问题正确程度0-10之间 | | | +|3 |报告结构|根据报告完整性情况,在5-10之间打 |10 | | +| |完整情况|分 | | | +|4 |图文 |根据图文规范性,在1-10分打分 |10 | | +| |规范 | | | | +|5 |报告论 |根据报告条理清晰、表达准确、要素 |30 | | +| |述情况 |齐全、论述充分等,在10-30之间打分| | | +| |合计 |满分100 |100 | | +|其它| | | +|意见| | | +| | | | +| | | | +| |批改教师: | | +| |年 月 日 | | + + + + 目录 + + + 1项目简介 1 + 2 需求分析 1 + 3 概要设计和详细设计 2 + 4 关键技术和系统实现 3 + 5 系统测试 4 + 6 综合设计总结 5 + 参考文献 6 + 源代码摘录(部分) 7 + + + + + + +1项目简介 + + 本项目是基于计算机视觉、卷积神经网络和OCR技术对符合中华人民共和国交通部标 +准的车牌进行识别和分类的程序。程序使用计算机视觉技术将车牌从图像中取出,使用 +OCR(光学字符识别)技术对车牌中的文字,即车牌号进行识别处理,并使用训练好的神 +经网络图像分类模型对车牌进行分类。 + +2 需求分析 + + 1. 需求概述 + 本项目需要实现以下功能: + +输入与预处理:接收包含车牌的图片,找出图片中车牌所在的具体位置并将其切分为独 +立图像。 + +基于OCR的车牌识别:接收预处理过程完成后的图片,识别图片中车牌的车牌号,并对识 +别结果进行修正。 + 车牌分类:使用图像分类模型对车牌的种类进行分类,输出分类的结果。 + -- +分类模型的训练:使用一个已妥善分类的车牌训练集对预训练的ResNet34模型进行进一 +步训练调整,使其能高效准确地完成车牌分类任务。 + 2. 功能需求 + 2.1 输入与预处理 + 接收图片文件作为输入,支持jpg/jpeg/png等多种格式。 + 对输入图像进行预处理,包括图像增强、去噪等操作。 + 定位图片中车牌具体位置,将车牌切分为独立图像 + 2.2 车牌识别 + 使用OCR技术对车牌号进行识别。 + 按照中华人民共和国交通部相关标准对识别结果进行纠错。 + 2.3 车牌分类 + 根据OCR识别结果按照中华人民共和国交通部相关标准进行推测。 + 使用经过训练地神经网络模型对车牌类型进行识别。 + 2.4 训练识别模型 + + 使用指定的训练数据集对预训练的图像分类模型进行微调,使其适用于针对车牌 + 的分类。 + 3. 非功能需求 + 系统应能对各种状态下的车牌进行识别 + 系统应提供用户友好的输出 + 系统应具有一定的容错能力 + +3 概要设计和详细设计 + + 本系统的概要设计包括以下模块: + 输入和预处理模块:负责接收输入图像数据,并进行预处理。提供图像增强和去 + 噪的功能。 + 车牌检测模块:用于检测输入图像中的车牌区域,并对其进行定位。 + 字符识别模块:对定位到的车牌区域进行字符识别,转换为文本格式。 + 车牌分类模块:使用AI模型对车牌进行分类。 + 输入和预处理模块详细设计 + 数据结构:接收和存储输入图像数据。 + 输入处理函数:实现图像预处理算法,如图像增强、去噪等。 + 车牌检测模块详细设计 + 数据结构:接收预处理后的图像作为输入,保存车牌区域的位置信息。 + 车牌检测函数:实现车牌区域检测算法。可以使用基于边缘检测和特征匹配的方 + 法来定位车牌。 + 字符识别模块详细设计 + 数据结构:接收车牌图像作为输入,保存字符识别的文本结果。 + 字符识别函数:使用深度学习模型进行OCR识别。 + 车牌分类模块详细设计 + 数据结构:接收车牌图像作为输入,保存车牌的分类信息。 + 车牌分类函数:使用预训练的模型对车牌进行分类。 + + + +4 关键技术和系统实现 + + 1. 车牌定位 + 中华人民共和国交通部对车牌的形式、大小、长宽比、底色和背景色等参数做 + 出了严格的规定。这部分规定就可以成为从图像中提取车牌的依据。 + + 考虑到照片拍摄过程中可能会存在的色差、畸变等问题,我们决定从车牌的形状 + (矩形)和长宽比作为突破点进行处理。 + + 通过使用功能完善且开源的计算机视觉库OpenCV,我们实现了对图像中符合特定 + 特征矩形的选取,该矩形的位置即为车牌的位置。 + 2. OCR识别车牌号 + OCR,即光学字符识别技术是最常用的从图像中提取文字信息的技术手段,一 + 般采用卷积神经网络的方式实现。一个优秀的OCR模型可以识别多种语言且拥有较 + 高的准确率。 + 训练一个OCR模型要求大量的文字数据集和长时间的反复调整,以及一定的技 + 术积累,这种从零开始的路线并不适合我们的开发过程。因此我们选用经过检验 + 的通用OCR库——EasyOCR作为识别使用的库文件。 + 经过反复的测试我们发现,通用OCR库对车牌识别的准确率有限。由于车牌面 + 积小、文字密度大、排列方式多样的特点导致通用OCR库的优势无法完全发挥,因 + 此我们引入了专用于车牌的HyperLPR库作为车牌号识别的主力,而EasyOCR作为补 + 充。通过二者配合,我们获得了不错的识别率。 + 3. 车牌分类 + 由中华人民共和国交通部的规范文件可知,不同种类的车牌的底色和背景色由 + 明显的区别,这一点可以作为对车牌进行分类的依据。 + 尽管我们可以使用传统的计算机视觉方案比对色彩进行分类,但这样的方案代 + 码复杂且准确率低,因此我们选择了更高效的方案——图像分类AI。 + 但是正如上文所述,从零开始构建神经网络模型的方案并不理想,因此我们使 + 用了经过预训练的模型ResNet34,并在它的基础上进行进一步微调,使它更适用 + 于对车牌的分类工作。 + 实际测试表明我们的选择是正确的,预训练模型减轻了我们准备训练集的工作 + 压力,也允许了我们在GPU性能较低的情况下完成多次反复的AI训练工作。最终我 + 们将最低识别错误率降至6.25%,平均错误率降至12.5%以下。 + +5 系统测试 + + 在开发过程中,我们对每个模块都进行了独立的测试工作,在确认模块运行正常后我 +们将它们整合在一起,并对整合后的代码进行了新的测试。 + 对于图像预处理部分,我们使用Pillow库的显示功能将图片处理过程可视化,根据处 +理的中间结果进一步调整代码: + # plt显示彩色图片 + def plt_show0(img): + b, g, r = cv2.split(img) + img = cv2.merge([r, g, b]) + plt.imshow(img) + plt.show() + + + # plt显示灰度图片,排除颜色对识别的干扰 + def plt_show(img): + plt.imshow(img, cmap='gray') + plt.show() + 对于OCR识别和矫正的部分,我们编写了一个主函数,通过传入不同的图片来测试不 +同的情况下算法的表现: + def main(): + image_path = "src/image3.jpg" + license_plate, car_type = recognize_license_plate(image_path) + if license_plate: + license_plate = swap_chars(license_plate) + print("number:", license_plate) + print("car_type:", car_type) + else: + print("ERROR!") + 对于训练出的图像分类AI,我们采取于OCR类似的测试方案: + image_path = 'E:\\VLPR\\Images\\SmallCar\\川A8K059.jpg' + pred_class, confidence = predict_image(image_path) + print(f"图片类别: {pred_class}, 置信度: {confidence}") + +6 综合设计总结 + + + + +在程序整合完成之后,我们准备了测试集对系统进行测试。经过测试发现程序对水平的 +车牌识别准确率高,而对倾斜、倒置等情况的车牌识别率偏低,猜测可能为切分程序对 +长宽比的筛选所致。而分类AI的表现则非常优秀,只要可以完成切分就可以准确的识别 +出车牌的类型,即使车牌倾斜或者不清晰,识别准确率也能在95%以上。以我们项目的开 +发周期而言已经远超过了我们的预期结果。 + 学习心得: + +在整个实训过程中,我们通过分工合作完成了代码的各个模块,并进行了最终的整合过 +程。实际表明了适当分工可以有效的提升开发效率,降低开发压力。各位组员对项目都 +做出了自己的贡献,才有了现在的项目。 + ——王昱博 + +在实训中,愈发了解使用图像分类AI对车牌种类进行区分的处理过程。深刻认识到使用 +收集到的数据对模型进行训练时,需要根据实际情况不断调整模型参数,这样才能使模 +型能够更好地拟合数据,提高识别准确率。 + ——刘钰廷 + +车牌识别系统可以实现自动化管理,减少了人工成本,降低了管理难度。虽然车牌识别 +技术已经取得了很大的进步,但仍然存在一定的误识别率 + ——冯雅君 + +Python是一门简洁易学的编程语言,相较于其他编程语言更加容易上手。学习过程中, +需要多动手实践,多看官方文档和优秀的代码,不断提高自己的编程能力。 + ——戴晓齐 + +该项目使用的python库有opencv、panda、easyocr等,通过对车牌图片进行剪裁去噪等 +处理,再到easyocr进行图片文字到识别,并进一步对识别后对结果进行分类。在使用e +asyocr识别文字的时候,easyocr识别准确率低可能是由于文字不规范所导致的。通过该 +项目,让我更加了解了python库的强大,相对于其他编程语言,python提供了大量的内 +置函数和库,使得编程变得简单高效。 + ——焦雅雯 + +通过这次python项目,让我懂得了open CV图像识别的功能,通过分辨颜色,形状和质地 +,用于检测图像中的各种特征,更加方便广泛的应用到我们的生活中,让我学习到了很 +多知识。 + ——潘浩宇 + Python作为一门编程语言,还是有着不同的优缺点。但是,Python无疑是一门值得学 +习的编程语言,它为我们提供了丰富的工具和框架来解决实际问题。相信在未来的学习 +和实践中,我也会对Python有更深入的认识和应用。 + ——金小杰 + 通过这次的Python项目,让我充分体会到了Python语言的优势——拥有各种各样可以使 +编程变得简单的内置函数和库,像项目中使用到的opencv,easyocr,fastai等库,都简化 +了很多的代码量。 + ——冯昌盛 + +参考文献 + + EasyOCR项目文档 https://github.com/JaidedAI/EasyOCR + OpenCV-Python官方文档 +https://docs.opencv.org/3.4/d6/d00/tutorial_py_root.html + HyperLPR3官方文档 https://github.com/szad670401/HyperLPR + FastAI项目 https://github.com/fastai/fastai + FasiAI官方教程 https://course.fast.ai/Lessons/lesson1.html + PyTorch官方网站 https://pytorch.org/ + 项目协作支持: + Gitee https://gitee.com/ + U.N.S. Git Server http://git.unknownnetworkservice.com:8013/ + 文件分发支持: + U.N.S. PFS http://www.unknownnetworkservice.com:40000/ + U.N.S. Cloud http://cloud.unknownnetworkservice.com:8020/ + + + + + + + +源代码摘录(部分) + + 图像预处理和切分: + @classmethod + def ImagePreProcess(cls, image_path: str) -> tuple: + # 复制一张图片,在复制图上进行图像操作,保留原图 + origin_image = cv2.imread(image_path) + # 图像去噪灰度处理 + image = origin_image.copy() + # x方向上的边缘检测(增强边缘信息) + gray_image = cls.gray_guss(image) + Sobel_x = cv2.Sobel(gray_image, cv2.CV_16S, 1, 0) + absX = cv2.convertScaleAbs(Sobel_x) + image = absX + # +图像阈值化操作——获得二值化图,将像素置为0或者255。将灰度转成黑白 + ret, image = cv2.threshold(image, 0, 255, cv2.THRESH_OTSU) + # +形态学(从图像中提取对表达和描绘区域形状有意义的图像分量)——闭操作 + # +使用形状为(30,10)的矩形kernelX对图像进行偏X方向的闭运算,将图像进行X方向融 +合找出车牌区域。 + kernelX = cv2.getStructuringElement(cv2.MORPH_RECT, (30, 10)) + image = cv2.morphologyEx(image, cv2.MORPH_CLOSE, kernelX, +iterations=1) + return origin_image, image + + + @classmethod + def CutPlateRect(cls, origin_image: cv2.Mat, image: cv2.Mat) -> +cv2.Mat: + # 去除细小的边缘 + # 腐蚀(erode)和膨胀(dilate) + kernelX = cv2.getStructuringElement(cv2.MORPH_RECT, (50, 1)) + kernelY = cv2.getStructuringElement(cv2.MORPH_RECT, (1, 20)) + # x方向进行闭操作(抑制暗细节) + image = cv2.dilate(image, kernelX) + image = cv2.erode(image, kernelX) + # y方向的开操作 + image = cv2.erode(image, kernelY) + image = cv2.dilate(image, kernelY) + # 中值滤波(去噪)将边缘平滑 + image = cv2.medianBlur(image, 21) + # 获得轮廓 RETR_EXTERNAL矩形的外边缘 + contours, hierarchy = cv2.findContours(image, cv2.RETR_EXTERNAL, +cv2.CHAIN_APPROX_SIMPLE) + # 筛选 + for item in contours: + rect = cv2.boundingRect(item) + x = rect[0] + y = rect[1] + weight = rect[2] + height = rect[3] + # 根据轮廓的形状特点,确定车牌的轮廓位置并截取图像 + if (weight > (height * 3.5)) and (weight < (height * 4)): # +对长宽比例进行确定 + _image = origin_image[y:y + height, x:x + weight] # +对图片进行裁剪 + return cv2.Mat(_image) + return origin_image + + + 图像分类AI的训练: + @classmethod + def TrainAI(cls, data_set_path: str, export_path: str) -> None: + blocks = (ImageBlock, CategoryBlock) + batch_size = 32 + dls = DataBlock( + blocks=blocks, + get_items=get_image_files, + splitter=RandomSplitter(), + get_y=parent_label, + item_tfms=Resize(460), + batch_tfms=[*aug_transforms(size=224, min_scale=0.75), +Normalize.from_stats(*imagenet_stats)] + ).dataloaders(data_set_path, num_workers=0, bs=batch_size) + model = vision_learner(dls, resnet34, metrics=error_rate) + model.fine_tune(5, freeze_epochs=3) # 5 - 训练的轮次, 3 - +冻结的轮次 + model.export(Path(export_path) / 'model.pkl') + + + + + OCR识别于基于OCR的车牌类型推测: + @classmethod + def RecognizeLicensePlate(cls, image: cv2.Mat, lpr_text: str) -> +tuple: + reader = easyocr.Reader(['ch_sim', 'en'], +model_storage_directory='./easyocr_model') + result = reader.readtext(image) + license_plate = "" + for res in result: + license_plate += res[-2] # +如果车牌号码是两行的,按行识别出来再拼接起来 + license_plate = cls.SwapChars(license_plate) + if lpr_text is not None: + license_plate = lpr_text + if '\u8b66' in license_plate: + car_type = '警用车辆' + elif '\u573a\u5185' in license_plate: + car_type = '场内车辆' + elif '\u6302' in license_plate: + car_type = '挂车/半挂车' + elif len(license_plate) > 7: + car_type = '新能源车辆' + else: + car_type = '小型轿车' + return license_plate, car_type + + + + + + + 带有功能选择的主程序: + if __name__ == '__main__': + result = input('请选择运行模式(训练(t)/识别(r)): ') + if result == 't' or result == 'T': + data_path = input('输入训练集路径: ') + export_path = input('输入模型保存路径: ') + try: + train(data_path, export_path) + except Exception as e: + print(f'训练过程中发生错误: {e}') + else: + print('模型已成功训练') + finally: + print('训练结束') + elif result == 'r' or result == 'R': + model_index = input('选择使用的识别模型(1/2/3): ') + image_path = input('输入图片路径: ') + if (not model_index.isdigit()) or (int(model_index) < 1) or +(int(model_index) > 3): + print('输入有误') + else: + main(int(model_index), image_path) + else: + print('输入有误') +----------------------- + 1