news 2026/9/15 14:07:14

基于OpenCV的车牌号码识别Python代码:HSV定位与模板匹配实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于OpenCV的车牌号码识别Python代码:HSV定位与模板匹配实战

简介:面向计算机视觉课程设计与期末大作业场景,基于OpenCV的车牌号码识别项目提供了可直接运行的Python源码,适合需要快速搭建完整识别流程的本科学生,也适合作为项目实战练习的入门范例。代码覆盖车牌定位、字符分割、SVM分类识别等关键环节,并附带训练好的svm.dat与svmchinese.dat模型文件,使用者无需自行准备训练数据集,解压后即可直接跑通推理过程。压缩包共25个文件,以py代码为核心,配有jpg/png测试图片、7z数据集分包、dat模型文件、js配置及txt文档说明,整体大小14.56MB,目录结构清晰、模块划分明确。目前已有192人下载学习,predict.py负责推理、surface.py提供可视化界面,test目录下多张真实车牌照片可直接验证效果,便于快速生成课程报告或答辩演示结果。资源内置的chars7z与charsChinese数据集也可供有进阶需求的读者重新训练或优化模型。

1. 为什么“可直接运行”的车牌号码识别Python代码,关键在定位

搜“车牌号码识别”能找到大量教程,但下载后能立刻跑起来的很少。多数人拿到的代码缺图片样张、缺依赖版本说明,或者定位算法本身就没调过参数,一运行就是 ModuleNotFoundError,或者弹个黑窗口什么也不输出。真正能直接运行的 OpenCV 车牌识别 Python 代码,不是把函数抄齐,而是把环境假设和图片假设都缩到最小:只依赖 opencv-python 和 numpy,自带模拟测试图,复制保存后就能看到“定位 → 分割 → 识别”的完整链路。下面这份实现适合第一次接触 OpenCV 图像处理、需要快速验证方案的读者;有五年以上经验的人,也能从 HSV 阈值和形态学核参数里看出真实场景的可调空间。

2. 车牌号码识别流程拆解:HSV 颜色空间与形态学定位原理

2.1 为什么车牌定位优先用 HSV 颜色阈值,而不是 Sobel 边缘

网上最常见的传统方案是灰度化后提取 Sobel 纵向边缘,再做闭运算和轮廓筛选。它依赖边缘密度,可车头的散热格栅、车灯、玻璃倒影都有密集竖边,候选框很容易漂到进气口或前挡风玻璃上。更稳定的先验是颜色——国内蓝底白字车牌有固定色调,HSV 空间下色相不会随光照强度剧烈变化,比 BGR 更接近人对“这是蓝色”的认知。HSV 把颜色拆成 H(色调)、S(饱和度)、V(明度)三个通道,BGR 下蓝值是(255, 0, 0),一旦光线变暗就变成(100, 0, 0),而 HSV 里的 H 基本还在 100 到 130 之间。这是定位环节最值得信耐的一条路径。

2.2 HSV 阈值参数表与不同光照下的调整

OpenCV 的 HSV 取值范围和用户习惯不同,H 是 0 到 179,S 和 V 是 0 到 255。蓝牌对应的常用区间如下。

车牌类型H 范围S 范围V 范围识别场景
蓝色车牌100–13080–25560–255白天正常光照
黄色车牌15–3580–25580–255驾校、教练车
新能源渐变绿40–8080–25580–255绿牌车

提示:调参时先动 H,再动 S。画面偏暗就降低 V 的下界;S 下界设太低会把白色车身反光也放进来。实际项目中我一般先把 mask 用cv2.imshow单独显示出来,确认阈值能看到完整车牌再继续。

2.3 形态学闭运算与开运算的组合:把字符区焊成一块

颜色阈值得到的 mask 里,字符笔画之间是断开的,需要形态学处理把它连成完整矩形。闭运算用cv2.MORPH_CLOSE先膨胀后腐蚀,能把字符间隙填平;开运算是先腐蚀后膨胀,负责去掉面积小的噪点。核的选择很关键:宽 15、高 5 的矩形核,宽度略大于单个字符笔画间距,高度接近车牌字符高度,才能既填住缝隙又不把周围区域涂黑。对小尺寸车牌,核太宽会把旁边色块也并进来;核太窄则缝隙合不上。先闭后开是车牌定位最常用的组合,顺序不要调反。

2.4 候选框筛选:面积与宽高比双条件

形态学处理后的轮廓还包含干扰色块,必须用车牌几何先验过滤。车牌长宽比通常在 1.8 到 6.0 之间,小于 1.8 的是方块色块,大于 6.0 的可能是路牌或横幅。简单做法是遍历所有轮廓,先用cv2.boundingRect拿到外接矩形,再对面积和比例打分:满足比例区间的候选给高权重,最终取分数最高的那个,而不是contours[0],因为轮廓列表的先后顺序和面积无关。

for cnt in contours: x, y, w, h = cv2.boundingRect(cnt) if w < 60 or h < 20: continue area = w * h ratio = w / h score = area * (1.0 if 2.0 <= ratio <= 5.5 else 0.2)

3. 基于 OpenCV 的车牌号码识别 Python 代码:定位、分割与模板匹配

3.1 完整可运行脚本

下面是整份代码,保存为plate_recognition.py,运行python plate_recognition.py即可。没有测试图时会自动生成一张模拟场景图,保证首次运行也能看到完整流程。

import cv2 import numpy as np import string TEMPLATE_CHARS = string.digits + string.ascii_uppercase def make_demo_image(): """生成一张包含蓝色车牌的模拟场景图,用于在没有真实照片时跑通流程""" bg = np.random.randint(80, 120, size=(360, 640, 3), dtype=np.uint8) plate = np.zeros((80, 260, 3), dtype=np.uint8) plate[:] = (255, 0, 0) # BGR 蓝色 cv2.putText(plate, "SU 12345", (14, 52), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (255, 255, 255), 2) bg[120:200, 190:450] = plate noise = np.random.normal(0, 8, bg.shape) bg = np.clip(bg.astype(np.int16) + noise, 0, 255).astype(np.uint8) return bg def locate_plate(img): """通过 HSV 颜色阈值 + 形态学处理 + 轮廓筛选定位车牌区域""" hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) mask = cv2.inRange(hsv, (100, 80, 60), (130, 255, 255)) kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (15, 5)) mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel) mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel) contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) best, best_score = None, 0 for cnt in contours: x, y, w, h = cv2.boundingRect(cnt) if w < 60 or h < 20: continue area = w * h ratio = w / h score = area * (1.0 if 2.0 <= ratio <= 5.5 else 0.2) if score > best_score: best_score = score best = (x, y, w, h) if best is None: return None, None x, y, w, h = best return img[y:y + h, x:x + w], (x, y, w, h) def split_chars(plate): """对定位到的车牌区域做二值化,用连通域切出单个字符""" gray = cv2.cvtColor(plate, cv2.COLOR_BGR2GRAY) blur = cv2.GaussianBlur(gray, (3, 3), 0) _, thresh = cv2.threshold(blur, 127, 255, cv2.THRESH_BINARY_INV) contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) chars = [] for cnt in contours: x, y, w, h = cv2.boundingRect(cnt) if h > plate.shape[0] * 0.3 and w > 2 and w / h < 0.8: chars.append((x, y, w, h, thresh[y:y + h, x:x + w])) chars.sort(key=lambda c: c[0]) return chars def generate_templates(): """用 OpenCV 自带字体生成数字与字母模板""" templates = {} for ch in TEMPLATE_CHARS: img = np.zeros((60, 40), dtype=np.uint8) cv2.putText(img, ch, (5, 44), cv2.FONT_HERSHEY_SIMPLEX, 1.2, 255, 2) templates[ch] = img return templates def match_char(cell, templates): """将待识别字符与每个模板求绝对差,取均值最小的作为结果""" cell = cv2.resize(cell, (40, 60)) best_char, best_score = '?', float('inf') for ch, tpl in templates.items(): tpl = cv2.resize(tpl, (40, 60)) diff = cv2.absdiff(cell, tpl).mean() if diff < best_score: best_score = diff best_char = ch return best_char if __name__ == "__main__": img = cv2.imread("car.jpg") if img is None: print("[提示] 未找到 car.jpg,使用内置模拟图跑通流程") img = make_demo_image() plate, rect = locate_plate(img) if plate is None: print("未定位到车牌,请检查 HSV 阈值") else: templates = generate_templates() chars = split_chars(plate) plate_no = "".join(match_char(cell, templates) for _, _, _, _, cell in chars) print(f"定位坐标: {rect}") print(f"分割字符数: {len(chars)}") print(f"识别结果: {plate_no}") cv2.rectangle(img, (rect[0], rect[1]), (rect[0] + rect[2], rect[1] + rect[3]), (0, 0, 255), 2) cv2.imshow("result", img) cv2.imshow("plate", cv2.resize(plate, (plate.shape[1] * 2, plate.shape[0] * 2))) cv2.waitKey(0) cv2.destroyAllWindows()

3.2 定位函数的筛选参数说明

参数当前取值作用调参建议
w < 6060 像素过滤宽度太小的噪点图像小就降到 40
h < 2020 像素过滤高度太小的色块车牌在画面中占比较小时重点调这里
宽高比区间2.0–5.5匹配车牌长宽比新能源车牌比例更大,可放宽到 6.0
形态学核(15, 5)横向填平字符缝隙核宽约为图像中车牌宽度的 1/20

3.3 模板匹配识别的工作原理与局限

代码先把分割出的字符统一resize成 40×60,再用cv2.putText生成 0-9、A-Z 的模板,逐对计算cv2.absdiff的均值,差值最小就是识别结果。这个方法不依赖第三方 OCR 库,所以能“直接运行”。但要认清边界:模拟图的字符和模板都出自同一个FONT_HERSHEY_SIMPLEX,识别率自然高;真实车牌使用专用印刷字体,笔画粗细和模板差异明显,模板匹配的准确率会明显下降。所以这份代码的意义在于把定位和分割的关键步骤跑通,字符识别部分到真实场景再替换为 OCR 或深度模型。

4. 运行这份车牌识别 Python 代码:环境准备、测试图片与常见报错排查

4.1 最小环境安装命令

需要 Python 3.7 及以上版本,然后安装两个依赖包。opencv-python提供cv2模块,numpy负责数组操作,模板匹配里大量用到np.zerosnp.absdiff的底层计算,这两个缺一不可。

pip install opencv-python numpy

安装速度慢时,可以临时指定国内镜像源。装完用一条命令确认版本,能打印出 4.x 就说明环境正常。

python -c "import cv2; print(cv2.__version__)"

4.2 首次运行的三种场景

把代码保存为plate_recognition.py,当前目录下放一张清晰的车辆前脸照片并命名为car.jpg,直接运行python plate_recognition.py。如果目录里没有这张图,程序会自动生成模拟场景图继续执行,这是这份代码能做到“直接运行”的关键设计。运行后终端会依次输出定位坐标、分割字符数和识别结果,屏幕上会弹出两个窗口:一个画了红色矩形框的整图,一个放大的车牌区域。按任意键关闭窗口,程序正常退出。

4.3 常见报错与排查思路

现象原因处理方式
ModuleNotFoundError: No module named 'cv2'依赖没装,或 pip 装到了另一个 Python 环境重新执行pip install opencv-python,用pip -V检查当前环境路径
输出“未定位到车牌”HSV 阈值不匹配,或被测图不是蓝牌单独显示mask中间结果,观察蓝色区域是否完整
分割字符数超过 8 个铆钉、边框、车牌汉字被切碎收紧split_charsh > plate.shape[0] * 0.3的高度条件
窗口弹出但按键没反应终端焦点不在图像窗口上先点击图像窗口再按键;或改用cv2.imwrite保存结果代替窗口显示

注意:cv2.waitKey(0)会无限等待按键,这是 OpenCV 程序“看起来卡住”的最常见原因。调试阶段建议改为cv2.waitKey(2000),让窗口自动关闭。

5. 从模拟图到真实车牌:三个立马上手的扩展方向

5.1 老牌的扩展:黄色车牌与新能源绿牌

蓝色阈值只能覆盖蓝牌,真实停车场里还有黄色和新能源绿色车牌。做法是把cv2.inRange执行两次,分别用黄色区间(15, 80, 80)-(35, 255, 255)和绿色区间(40, 80, 80)-(80, 255, 255),最后把两个 mask 用cv2.bitwise_or合并。注意黄牌是黑字黄底,二值化时不能直接套THRESH_BINARY_INV,需要先判断车牌主色,黑字场景改用THRESH_BINARY,否则字符区域会反白,模板匹配全盘失效。

5.2 中文省份字的处理:模板匹配的边界

国内车牌第一位是省份简称汉字,第二位是发牌机关字母,后面五位是数字和字母。模板匹配不擅长处理汉字,因为字模库要覆盖几十个省份简称,工作量成倍增长。常见做法是做一套省份汉字模板,利用“第一位必是省份”的位置先验,把匹配范围限制在 31 个汉字里,而不是全部字符集。更省力的方案是只保留 OpenCV 定位与分割,识别部分换成 PaddleOCR 或 Tesseract,由 OCR 直接吃字符序列,这一步替换后准确率会有一个明显跃升。

5.3 实时视频流:先缩图再跳帧

要处理摄像头视频,把主流程包进VideoCapture循环即可,但要注意性能。常见做法是先把每一帧缩到 640 宽度再送入定位函数,这会显著减少 HSV 转换和形态学计算量;定位到车牌后再把裁剪区域放大做字符分割,等于把算力集中在 ROI 上。识别帧率不需要拉满,每 5 帧做一次完整识别已经足够覆盖大多数车辆通行场景。这样组合下来,普通笔记本 CPU 也能跑到 10 帧以上的处理速度,并且省下的算力还能留出一部分给后续的追踪模块。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/15 14:07:07

Vue3工业MQTT实时监控系统设计与实践

简介&#xff1a;本资源是一个面向工业物联网场景的前端管理系统实战项目&#xff0c;专为中高级前端开发者及IoT系统工程师设计&#xff0c;解决工业设备实时监控、多源数据可视化与MQTT协议集成等核心问题。压缩包共262个文件&#xff0c;主体为96个Vue3单文件组件与140个Typ…

作者头像 李华
网站建设 2026/9/15 14:06:46

kubeasz 集群 DNS 部署实战:CoreDNS 与 NodeLocal DNSCache 架构解析

kubeasz 集群 DNS 部署实战&#xff1a;CoreDNS 与 NodeLocal DNSCache 架构解析 【免费下载链接】kubeasz 使用Ansible脚本安装K8S集群&#xff0c;介绍组件交互原理&#xff0c;方便直接&#xff0c;不受国内网络环境影响 项目地址: https://gitcode.com/GitHub_Trending/k…

作者头像 李华
网站建设 2026/9/15 14:06:06

基于uniapp+Vue3的露营App开发实践:多端适配、地图定位与弱网优化

简介&#xff1a;基于uniapp与Vue框架开发的《露营》App完整项目&#xff0c;面向希望学习跨端应用开发及前后台系统设计的开发者与学生&#xff0c;也非常适合作为课程设计或毕业设计的参考方案。项目基于HBuilder X平台构建&#xff0c;用户端实现了首页、露营信息、露营教程…

作者头像 李华