十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Python+OpenCV车牌识别实战:从环境配置到识别率优化

Python+OpenCV车牌识别实战:从环境配置到识别率优化 简介基于 Python 与 OpenCV 实现的车牌识别系统毕业设计源码包面向高校毕业设计、课程项目及图像识别初学者。除基础车牌的搜索、对比与数据库认证外还支持本地文件、网络图片地址、实时截图及摄像头拍照等多种识别入口并集成 HyperLPR 提升识别率图片自适应窗口、前端交互等模块也一并包含能够覆盖从数据采集、识别到验证展示的完整流程。资源共 119 个文件含 Python 源码18 个 py、说明文档md/txt、模型权重dat及大量 jpg/png 测试图与 GIF 演示压缩包约 22.37MB目录结构清晰运行说明与 Dockerfile 便于快速搭建环境。目前已有 411 人学习下载适合需要完整参考实现与可直接运行验证的毕业设计场景。1. 车牌识别项目的真实难度与技术主线答辩时最容易翻车的一块不是模型而是车牌定位定位框偏了、字符粘连、蓝色车牌在强光下发白识别结果就从“京A12345”变成一串乱码。PythonOpenCV做车牌识别的技术主线是图像预处理、车牌定位、字符分割、字符识别每一步都有参数要根据实际图片去调。这篇文章针对项目包里“源码项目运行说明”最常见的需求讲清楚拿到包之后怎么装环境、怎么读代码、怎么调参以及怎么把识别率从“偶尔对”拉到“稳定可用”。适合正在准备毕业设计、或把车牌识别当CV入门项目的读者。以下内容围绕PythonOpenCV的车牌识别流程展开代码可以直接改到自己的main.py里跑通。2. 基于OpenCV的车牌识别系统构成与图像处理流程2.1 车牌识别在PythonOpenCV下的整体架构车牌识别表面上是一个文字识别问题实际上是一条由图像处理算子串联起来的流水线。选OpenCV而不是直接上深度学习不是因为深度学习不好而是因为毕设场景里需要可解释、可调试、可快速改参数。每一步中间结果都能用imshow或imwrite列出来答辩时讲原理比甩一个黑盒模型更有说服力。典型流程是读图、统一缩放、灰度化、去噪、边缘检测、二值化、形态学闭运算、轮廓提取、按宽高比和面积筛出车牌区域、字符分割、字符识别。整条链路涉及的OpenCV模块不多但每个算子的参数会直接影响后续结果。下面用表格概括各模块的输入、输出和主要函数。模块输入输出主要OpenCV函数车牌定位原图车牌区域坐标cvtColor、GaussianBlur、Sobel、morphologyEx、findContours车牌矫正倾斜车牌图像水平矩形图minAreaRect、getPerspectiveTransform、warpPerspective字符分割车牌灰度图单字符图像列表threshold、findContours、boundingRect字符识别字符图像最终字符串matchTemplate / pytesseract需要明确的是车牌识别项目里的“核心”不是最后的识别模型而是定位和分割。字符识别哪怕用最简单的模板匹配只要前面两步干净准确率也能到可用水平。所以后面的调试重点都应该放在能看见图像中间结果的环节上而不是反复换识别算法。2.2 车牌定位灰度化、边缘检测与轮廓筛选国内绝大多数车牌是蓝底白字字符本身是白色竖笔画密集区域。从图像处理角度看车牌区域最明显的特征是“垂直边缘密集”。常见做法是用Sobel算子计算x方向梯度而不是用Canny因为Canny会把车灯、落叶、路面纹理也当成边界导致候选区域爆炸。先看一段定位预处理的通用代码很多毕设源码里都能看到相似写法。import cv2 import numpy as np def preprocess_plate(img): # 转为灰度图减少颜色干扰 gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 高斯模糊去掉传感器噪声核越大越平滑但也会抹掉字符边缘 gray cv2.GaussianBlur(gray, (5, 5), 0) # Sobel只做x方向捕捉字符的垂直边缘 sobel_x cv2.Sobel(gray, cv2.CV_16S, 1, 0, ksize3) sobel_x cv2.convertScaleAbs(sobel_x) # 二值化阈值偏低会引入大量背景噪声偏高会丢掉字符边缘 _, thresh cv2.threshold(sobel_x, 80, 255, cv2.THRESH_BINARY) # 闭运算把分散的竖边连成矩形块核的宽度决定“连多远” kernel cv2.getStructuringElement(cv2.MORPH_RECT, (17, 5)) close cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel) return close def find_plate_candidates(preprocessed): # 只取外轮廓避免车牌内部字符轮廓干扰 contours, _ cv2.findContours(preprocessed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) candidates [] for cnt in contours: x, y, w, h cv2.boundingRect(cnt) area w * h ratio w / h # 车牌宽高比约3.1实际拍摄会有透视形变放宽到2.5~5.5 if 2000 area 50000 and 2.0 ratio 5.5 and h 20: candidates.append((x, y, w, h)) return candidates这段代码做了三件事先用高斯模糊让边缘更连续再用Sobel突出字符竖边最后用闭运算把所有竖边拼成车牌形状的块。findContours返回的轮廓经过boundingRect转成矩形宽高比和面积就是第一道筛选条件。参数说明GaussianBlur的核(5, 5)适合800×600左右的图如果输入是4K大图最好先压缩到800宽再处理Sobel的ksize3是经验值再大边缘会变粗闭运算更容易把两个相邻区域连到一起阈值80不是固定的晚上拍的图可能需要降到50晴天强光下可能提到120。后面第6章会讲怎么用HSV颜色再做一次先验筛选这里不展开。2.3 图像处理管线参数对车牌定位的影响很多毕设源码把定位参数写死在函数里换一张图就失效。原因是分辨率变了、拍摄角度变了、光照变了同一组阈值不可能通吃。比较实用的办法是先定基准分辨率再调其他参数。我一般会把输入图片统一缩放到宽度800这样后续轮廓筛选的面积阈值、宽高比范围都相对稳定。参数常见取值范围过小的影响过大的影响GaussianBlur核大小(5,5) ~ (7,7)噪声多边缘不连续字符边缘模糊定位框偏大Sobel ksize3边缘较细闭运算后可能断边缘粗易与周围物体粘连二值化阈值50 ~ 120背景噪声被当成车牌边缘车牌字符边缘丢失闭运算核宽度15 ~ 25字符竖边连不成整块多个目标连成一个轮廓框变大宽高比筛选2.5 ~ 5.5新能源和倾斜车牌被滤掉容易把广告牌、护栏框进来面积阈值2000 ~ 50000远处小目标丢失近处大目标直接选错调参时不要一次性改多个参数。先固定宽高比和面积用imshow看close图像里车牌区域是否被闭运算连成一个完整白块如果白块碎了把闭运算核宽度从17加到23如果背景里出现了大片白块缩小闭运算核宽度或者调高二值化阈值。提示把灰度图、Sobel结果、闭运算结果横向拼成一张调试图可以快速定位“是哪一步把车牌弄丢了”。这个习惯在毕设调参阶段比调什么参数都重要。3. PythonOpenCV环境准备安装、目录结构与依赖清单3.1 Python与OpenCV安装教程最小可运行的版本组合拿到项目压缩包后先别急着跑main.py先确认环境能正确导入cv2。推荐Python 3.10或3.1164位版本OpenCV选4.5.x或4.6.x都比较稳。opencv-python和opencv-contrib-python二选一即可但有些源码里用了SIFT等contrib模块直接装contrib版本能省掉后面的“找不到模块”问题。python -m venv venv # Windows激活命令 venv\Scripts\activate # Linux/macOS激活命令 source venv/bin/activate pip install --upgrade pip pip install opencv-python4.5.2.52 opencv-contrib-python4.5.2.52 numpy如果下载速度慢可以加清华镜像源参数这在校园网环境下很常见。pip install opencv-python4.5.2.52 -i https://pypi.tuna.tsinghua.edu.cn/simple安装后做一次最小验证确认解释器里能正常导入import cv2 print(cv2.__version__) print(cv2.getBuildInformation())getBuildInformation()输出的编译信息很长不需要逐行看只要确认能打印出4.5.2之类的版本号即可。常见问题是pip装到了系统Python而VSCode里选的解释器是conda环境导致import失败。运行前用which python或where python检查当前解释器路径能少踩很多坑。3.2 项目运行说明里的常见目录结构与依赖清单毕设zip包里的目录结构没有统一标准但大部分项目会按“数据、源码、模板、说明文档”四类组织。常见做法是car_plate_recognition/ ├── data/ │ └── test_images/ ├── src/ │ ├── main.py │ ├── detect_plate.py │ └── recognize_plate.py ├── templates/ │ ├── 京.png │ ├── A.png │ └── ... ├── requirements.txt └── README.mdrequirements.txt通常长这样opencv-python4.5.2.52 opencv-contrib-python4.5.2.52 numpy1.23.5 pytesseract0.3.10 Pillow9.2.0参数说明如果源码没有使用Tesseract OCR把pytesseract和Pillow两行删掉能减少安装失败概率如果源码里用了SIFT或xfeatures2d必须保留opencv-contrib-python。opencv-python和opencv-contrib-python同时存在时有时能运行有时会因为符号冲突出现诡异报错。更稳妥的做法是只保留opencv-contrib-python一行因为contrib包本身也包含主模块的全部功能。3.3 运行前的最小验证读图、显示、调试开关环境装好后用一张测试图片验证读图和显示链路是否正常。注意cv2.imread不能正确处理中文路径这是毕设项目里最常见的“代码没问题但图片读取失败”原因。如果图片路径或项目路径含中文imread会安静地返回None后续所有操作都会报错。import cv2 import numpy as np def imread_unicode(path): # 用二进制方式打开文件再用imdecode解码路径含中文也能读取 stream open(path, rb).read() return cv2.imdecode(np.frombuffer(stream, np.uint8), cv2.IMREAD_COLOR) img imread_unicode(data/test_images/蓝牌测试.jpg) if img is None: raise FileNotFoundError(图片读取失败请检查文件路径) # 统一缩放宽度到800避免高分辨率图片导致后续阈值全部失效 h, w img.shape[:2] img cv2.resize(img, (800, int(h * 800 / w))) cv2.imshow(origin, img) cv2.waitKey(0) cv2.destroyAllWindows()这段代码的核心不是resize本身而是“用imdecode代替imread”这一条。很多项目的data目录下图片名是“鲁A12345.jpg”这种中文命名imread返回None后main.py会直接崩掉。把imread_unicode作为工具函数放进公共模块能省掉后续所有中文路径问题。waitKey(0)表示等待按键后才关闭窗口调试阶段不要改成waitKey(1)否则窗口一闪而过。4. 车牌识别核心源码实现定位、分割与字符识别4.1 车牌定位源码基于轮廓的车牌区域提取前文已经给了预处理函数这里补一个完整的locate_plate。它返回所有候选区域坐标并按面积降序排列方便让调用方优先处理最大、最可信的那个区域。实际项目里经常把“面积最大的候选框”直接当作车牌因为绝大多数场景下车牌是画面中面积最大的矩形纹理区域。def locate_plate(img, min_area2000, max_area50000): # 统一缩放宽度到800让后续面积和宽高比阈值保持稳定 h, w img.shape[:2] scale 800 / w if scale ! 1.0: img cv2.resize(img, (800, int(h * scale))) # 注意如果返回框坐标给原图使用需要把坐标按1/scale还原 gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) gray cv2.GaussianBlur(gray, (5, 5), 0) sobel cv2.Sobel(gray, cv2.CV_16S, 1, 0, ksize3) sobel cv2.convertScaleAbs(sobel) _, binary cv2.threshold(sobel, 90, 255, cv2.THRESH_BINARY) kernel cv2.getStructuringElement(cv2.MORPH_RECT, (17, 5)) close cv2.morphologyEx(binary, cv2.MORPH_CLOSE, kernel, iterations2) contours, _ cv2.findContours(close, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) boxes [] for cnt in contours: x, y, w, h cv2.boundingRect(cnt) area w * h ratio w / h if min_area area max_area and 2.5 ratio 5.5 and h 20: boxes.append((x, y, w, h)) # 面积大的候选框排前面后面只取第一个即可 boxes.sort(keylambda b: (b[2] * b[3]), reverseTrue) return boxes逻辑说明先缩放图片再做灰度化和高斯模糊Sobel只保留x方向梯度这是“字符竖边”这个特征的直接表达。闭运算执行两次是为了确保在车牌稍有倾斜时也能把字符边缘连成一个完整块。findContours的RETR_EXTERNAL模式只找最外层轮廓避免把车牌的7个字符分别当成独立轮廓。参数说明min_area和max_area是针对800宽图片设置的。800×600的图像里车牌通常占2000~10000像素面积上限留到50000是为了兼容近距离拍摄的大车牌。h 20限制最小高度目的是过滤掉远处栏杆、地面文字的细窄轮廓。如果候选框数量太多说明闭运算把别的区域也连成了块优先调大二值化阈值而不是改宽高比。4.2 字符分割二值化与外接矩形排序定位到车牌区域后把原图对应区域单独裁出来。很多毕设代码会省略“车牌倾斜矫正”这一步直接在原区域上做二值化和轮廓提取。这不影响竖直拍摄的照片但斜拍时字符上下边缘不齐分割出来全是歪的。稳妥的做法是先用minAreaRect判断车牌外接矩形角度角度大于5度时用getPerspectiveTransform矫正。字符分割阶段最常用的策略是“二值化 外接矩形 按x排序”。蓝底白字车牌在灰度图里通常表现为蓝底偏暗、白字偏亮大津法OTSU可以自适应算阈值不需要手动调。def split_characters(plate_img): gray cv2.cvtColor(plate_img, cv2.COLOR_BGR2GRAY) # 统一缩放到440x140方便后续模板匹配的尺寸对齐 gray cv2.resize(gray, (440, 140)) _, binary cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY cv2.THRESH_OTSU) # 蓝底白字时白字为255黄底黑字时反转 binary cv2.bitwise_not(binary) # 开运算去除边缘毛刺和铆钉噪声核不宜太大 kernel cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3)) binary cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel) contours, _ cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) boxes [] for cnt in contours: x, y, w, h cv2.boundingRect(cnt) if h 40 and w 10 and w 80: boxes.append((x, y, w, h)) boxes.sort(keylambda b: b[0]) return boxes, binary参数说明resize(440, 140)是以国内蓝牌440mm×140mm的标称尺寸为基准这一步让后续所有分割阈值都建立在统一尺度上而不是依赖原始拍摄分辨率。THRESH_OTSU会忽略手动阈值所以threshold第一个参数传0。h 40是过滤字符下方可能残留的牌照边框线w 10过滤细小噪声w 80防止车牌左右两侧装牌螺丝被当成字符。字符分割最常见的坑是“京”这类左右结构的汉字被拆成多个框比如“京”可能被拆成“亠”和“口”两部分。解决办法是做一个横向合并如果两个相邻框的水平间距小于5~8像素就把它们合并成一个框。具体实现可以参考merge_close_boxes函数def merge_close_boxes(boxes, gap6): merged [] for x, y, w, h in sorted(boxes, keylambda b: b[0]): if merged and x - (merged[-1][0] merged[-1][2]) gap: mx, my, mw, mh merged[-1] nx min(mx, x) ny min(my, y) nw max(mx mw, x w) - nx nh max(my mh, y h) - ny merged[-1] (nx, ny, nw, nh) else: merged.append((x, y, w, h)) return merged逻辑说明按x坐标排序后逐个判断当前框的左边界与上一个框的右边界之间的距离。小于gap就合并成一个更大的矩形否则作为新框加入。合并后还要重新按x排序一次确保识别顺序从左到右。这个函数在毕设代码中非常重要因为汉字分割错误会直接导致整串识别结果少一位或多一位。4.3 字符识别模板匹配与OCR引擎融合字符识别这层最简单、也最容易让识别率崩掉。模板匹配速度快、无需训练但要求字符图像和模板的字体、大小、粗细基本一致。OCR引擎对自然场景文字泛化能力更强但车牌字体不是常规印刷体Tesseract直接跑经常把“0”和“O”、”1“和“I”搞混。常见做法是先用模板匹配识别分数低于阈值时再用OCR兜底。import os def match_char(char_img, template_dirtemplates): # 统一字符尺寸为20x40模板也按同样尺寸准备 char_img cv2.resize(char_img, (20, 40)) best_label ? best_score -1 for name in os.listdir(template_dir): label os.path.splitext(name)[0] tmpl cv2.imread(os.path.join(template_dir, name), cv2.IMREAD_GRAYSCALE) tmpl cv2.resize(tmpl, (20, 40)) res cv2.matchTemplate(char_img, tmpl, cv2.TM_CCOEFF_NORMED) _, max_val, _, _ cv2.minMaxLoc(res) if max_val best_score: best_score max_val best_label label return best_label, best_score逻辑说明TM_CCOEFF_NORMED会把图像均值归一化对光照变化不那么敏感所以模板和字符都只需要做灰度化和resize不需要再做二值化。模板文件名直接用作标签比如京.png对应“京”A.png对应“A”。返回best_score能帮助上层判断识别置信度低于0.6可以认为字符被切坏了。方案优势劣势建议用途模板匹配速度快、可解释、无需训练数据对字体、倾斜、模糊敏感干净的车牌图片、答辩演示Tesseract OCR通用性强、能读印刷体车牌字体识别率不稳定、需额外安装数字和字母混合的兜底CNN分类准确率高、抗干扰强需要标注数据和训练流程数据量大、想写进论文对比模板匹配的模板数量不需要覆盖所有中文汉字毕设一般只准备常见省份简称即可。实际识别流程可以这样组合第一个字符用模板匹配后面的数字和字母先用模板匹配得分低于0.6再交给OCR。这样既保留速度又给“不完美的字符”留了一条退路。5. 项目运行说明启动命令、入口参数与高频报错排查5.1 基于图片与基于摄像头的运行入口设计毕业设计答辩时演示方式通常有三种单张图片、视频文件和摄像头实时画面。很多源码只写了图片模式对视频场景支持不完整。给main.py加一套统一的命令行参数能同时覆盖这三种情况演示时切换非常方便。python main.py --image data/test_images/blue.jpg python main.py --video data/test_videos/road.mp4 python main.py --camera 0对应的参数解析代码import argparse def parse_args(): parser argparse.ArgumentParser(descriptionPythonOpenCV车牌识别系统) parser.add_argument(--image, typestr, defaultNone, help输入单张图片路径) parser.add_argument(--video, typestr, defaultNone, help输入视频文件路径) parser.add_argument(--camera, typeint, defaultNone, help摄像头设备编号默认0) parser.add_argument(--debug, actionstore_true, help显示灰度、边缘、闭运算等中间结果) parser.add_argument(--save, typestr, defaultNone, help识别结果保存路径支持.jpg和.mp4) return parser.parse_args()视频循环的写法有固定模板。每帧读取后调用定位函数如果找到候选框就取面积最大的框绘制矩形和识别文字。waitKey(1)控制视频播放速度改成waitKey(30)相当于约30fpsCPU不够时可以调大。def process_video(video_path): cap cv2.VideoCapture(video_path) while True: ret, frame cap.read() if not ret: break boxes locate_plate(frame) if boxes: x, y, w, h boxes[0] plate frame[y:yh, x:xw] text, _ recognize_and_split(plate) cv2.rectangle(frame, (x, y), (xw, yh), (0, 255, 0), 2) cv2.putText(frame, text, (x, y-10), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0), 2) cv2.imshow(plate_recognition, frame) if cv2.waitKey(1) 0xFF ord(q): break cap.release() cv2.destroyAllWindows()逻辑说明先读视频帧再定位、识别、画框。boxes[0]取的是面积最大的候选框如果连续多帧都识别失败可在debug模式下把候选框数量打印出来观察是不是背景被误判成了车牌。cv2.putText不支持中文显示“京A12345”时汉字部分会变成问号答辩前最好用PIL在图像上画中文或者只显示数字字母部分。5.2 高频报错排查从ModuleNotFoundError到识别结果为空毕设项目运行不起来的报错绝大多数集中在环境缺失和图像路径两类。下面这张表可以直接当排查手册用。报错信息或现象常见原因解决办法ModuleNotFoundError: No module named cv2当前解释器没安装OpenCV激活venv后执行pip install opencv-pythonAttributeError: ... has no attribute SIFTSIFT只在contrib包中安装opencv-contrib-python删除普通opencv-pythonTesseractNotFoundError系统没安装Tesseract-OCR安装Tesseract并设置pytesseract.pytesseract.tesseract_cmdimread返回Nonecv2.error:(-215)路径不存在或路径含中文用imread_unicode函数替代imread定位框把整张图框进去闭运算核过大或面积阈值过大缩小核宽度调低max_area字符识别多一位或少一位汉字被拆开或两个字符粘连合并相邻框调整w和h的上下限识别结果全是问号模板不匹配或字符尺寸不对检查模板目录、模板resize尺寸是否与代码一致TesseractNotFoundError的细节值得单独说。pytesseract只是Python客户端实际识别引擎是独立的Tesseract-OCR程序。Windows下安装后需要把安装路径写进代码import pytesseract pytesseract.pytesseract.tesseract_cmd rC:\Program Files\Tesseract-OCR\tesseract.exe如果不设置这行pip装得再干净也会报找不到引擎。Linux环境则用apt install tesseract-ocr安装后同样需要确认tesseract命令在PATH里。5.3 项目运行说明里值得保留的调试技巧调试车牌识别项目有一个很实用的习惯把中间结果批量导出成图片而不是只在屏幕上imshow。屏幕显示只能看当前一张批量导出可以一次性对比20张图的定位问题。做法是保存灰度图、Sobel图、闭运算图、最终画框图到debug_out目录def save_debug_image(img_list, labels, out_pathdebug/debug.jpg): items [] for img, label in zip(img_list, labels): if img.ndim 2: img cv2.cvtColor(img, cv2.COLOR_GRAY2BGR) items.append(img) result np.hstack(items) cv2.imwrite(out_path, result)调用方式把原图、闭运算结果、画框结果横向拼接后保存。这样跑一次测试集就能看到“哪张图在哪个阶段失败”。调整参数时不要只盯着识别结果而是看闭运算这一步车牌是否成形。中间结果对了最终字符串大概率能对。6. 进阶优化HSV颜色定位与识别率验证方法6.1 用HSV颜色做先验区域提升复杂背景下的定位成功率纯轮廓定位在干净道路上效果不错但背景里有树影、车身拉花、路边广告牌时很容易选出错误区域。常见做法是增加HSV颜色先验蓝底车牌在HSV色域里集中在固定的H分量范围先找出所有蓝色像素再做连通域筛选能绕过大量非蓝色干扰。def locate_by_hsv(img): hsv cv2.cvtColor(img, cv2.COLOR_BGR2HSV) # 蓝色车牌常见HSV范围S和V都设下限避免把暗色噪声算进来 mask cv2.inRange(hsv, (100, 100, 100), (124, 255, 255)) mask cv2.morphologyEx(mask, cv2.MORPH_CLOSE, np.ones((15, 15), np.uint8)) contours, _ cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) boxes [] for cnt in contours: x, y, w, h cv2.boundingRect(cnt) if 2.5 w / h 5.5 and 1000 w * h 50000: boxes.append((x, y, w, h)) return boxesHSV阈值需要根据车牌类型微调常备一组测试值即可应对大部分工况。车牌类型H范围S范围V范围蓝色车牌100~124100~255100~255黄色车牌15~34100~255100~255绿色新能源车牌35~8080~25580~255逻辑说明HSV色域把色调和亮度分开蓝色在自然光下变化时H值相对稳定S和V的下限用于排除偏黑、偏灰的误检。形态学闭运算把断裂的蓝色区域连通再用宽高比和面积筛选出车牌矩形。HSV定位的缺点是强阳光下蓝色容易发白H值不变但S值下降遇到这类图可以把S下限从100改到60。6.2 识别率验证三档统计口径优化不能只看“感觉变好了”要做量化验证。准备20~50张带标注的测试图片按三个口径统计定位成功率、分割成功率和整串识别率。定位成功可以定义为预测框与真实车牌区域的交并比大于0.5分割成功定义为每个字符的外接框数量与真实车牌字符数一致整串识别成功要求输出的车牌号与标注完全一致。def evaluate(results): loc_ok sum(r[loc_iou] 0.5 for r in results) / len(results) seg_ok sum(r[seg_correct] for r in results) / len(results) full_ok sum(r[text] r[label] for r in results) / len(results) return {定位: loc_ok, 分割: seg_ok, 整串: full_ok}先看定位成功率如果低于80%问题基本出在轮廓筛选或HSV阈值上没必要去改字符识别模块。定位框稳定后再看分割成功率汉字被拆开就去调合并间隙参数。最后才看整串识别率。字符识别率低时优先检查定位框是否紧贴车牌边缘、字符区域是否带进边框杂物逐张调完一张demo图后再批量跑10张验证避免只对单张测试图过拟合。本文还有配套的精品资源点击获取
返回列表