
简介基于OpenCV与Python的车牌识别系统完整工程代码面向具备一定图像处理基础的学生和开发者适合课程设计、毕业设计或真实场景中的车牌识别原型搭建。压缩包共25个文件主要包含Python脚本、SVM模型数据、中英文训练数据集以及车牌样本图片整体大小约14.56MB目录将源码、模型、测试图片和说明文档分隔清晰便于快速定位所需模块。已有1104人学习浏览可作为同类项目的参考实现。资源中附带了识别主程序与图形界面处理脚本并预置训练好的svm.dat、svmchinese.dat模型覆盖常见汉字车牌字符7z压缩包中存放字符训练集配合多张真实场景车牌图片能够完整理解车牌定位、字符分割与识别全流程。运行后即可快速验证识别效果也便于后续进行参数调优、模型替换或功能扩展是一份兼具学习与实用价值的完整项目资料尤其适合作为图像处理与机器学习入门后的综合练习。1. 一包能直接跑的车牌识别OpenCVPython该从哪下手做车牌识别最大门槛不是算法而是你拿到一份源码却不知道它能不能跑通。这套 Opencvpython 车牌识别系统完整代码正是我拆过的最典型的传统视觉方案车牌定位、字符分割、SVM 分类识别全部用 OpenCV 手工特征 机器学习完成不依赖深度学习框架。压缩包里同时给了训练数据和训练好的模型文件意味着你不只可以跑推理还可以自己重新训练、调参、换数据集。适合的人群很明确想搞懂车牌识别完整流程的学生、要做课程设计或毕设的人以及刚接触 OpenCV 想找个能落地项目练手的 Python 开发者。更重要的是这套项目代码结构简单文件数量少没有复杂的工程框架读起来不费劲跑起来也不挑环境。下面我从拆包开始一步步带你把它跑通、看懂、改起来。2. 先拆项目源码包里每一个文件是干什么的拿到压缩包先别急着运行先把文件结构看一遍。这个项目里的文件不算多但每个文件承担的角色不同而且有些是训练数据、有些是模型参数、有些是测试图片混在一起很容易让人找不到入口。2.1 文件清单哪些是代码哪些是数据哪些是模型先看压缩包解压后的完整结构我整理了如下文件清单文件/目录类型职责predict.pyPython 脚本主预测入口读入测试图片输出识别结果surface.pyPython 脚本车牌表面处理模块含透视校正、图像预处理逻辑test/目录测试图片包含 13 张各种场景下的车牌图片用于快速验证chars2.7z压缩数据字符训练样本包括数字和字母的图片集charsChinese.7z压缩数据汉字训练样本用于识别中文车牌中的省份简称svm.dat模型文件训练好的 SVM 模型负责识别数字和英文字母svmchinese.dat模型文件训练好的中文 SVM 模型负责识别汉字字符Screenshots/截图目录运行效果截图可作参考文档.txt说明文档项目使用说明建议先读config.js配置文件保存路径、参数等配置运行前按需修改这里有一个关键点要提醒svm.dat和svmchinese.dat是已经训练好的模型chars2.7z和charsChinese.7z是训练样本它们不是同一类文件。如果你只跑预测不需要解压训练数据也能运行如果你想重新训练模型或者想换一套数据集提高识别率就需要解压这两个压缩包。我一般把训练数据解压到项目根目录下和.py脚本放在同一层避免路径写死导致找不到文件。2.2 识别流程一张车牌图从输入到输出的完整路径整个车牌识别系统的核心逻辑可以拆成四个阶段原始的predict.py和surface.py分工正是按照这个链路组织的车牌定位。输入一张车辆图片先用颜色特征或边缘特征找到车牌区域。OpenCV 的常见做法是将 BGR 转换到 HSV 色彩空间利用蓝色或黄色的色调范围做阈值过滤再用形态学闭运算把字符区域连接成块最后用轮廓外接矩形筛选出真正的车牌。字符分割。车牌区域被裁剪出来后由于拍摄角度和光照不同还要做灰度化、二值化处理。二值化之后字符区域变成白色背景是黑色通过查找轮廓并按照宽高比例、面积、间距等先验条件把每个字符单独切出来。字符识别。每个字符图像输入到 SVM 分类器里svm.dat负责英文和数字svmchinese.dat负责汉字。SVM 在训练时会把图像 resize 成固定尺寸提取 HOG 或直方图特征预测阶段只需加载模型后调用predict函数。结果输出。按顺序拼接字符第一个位置是汉字省份简称后面是字母和数字最终输出完整的车牌字符串。这个流程里surface.py主要负责第二阶段之前的预处理工作包括透视变换把倾斜的车牌拉正。你可以把它理解成整个流程里的修正器——因为实际场景中车牌不可能是正对着镜头的。2.3 这两个模型文件到底是什么svm.dat和svmchinese.dat都是 OpenCV 自带的 SVM 接口训练出来的模型。它们的内部结构是 OpenCV 的 FileStorage 格式保存了支持向量、决策函数系数、核函数类型等训练结果。使用时通过cv2.ml.SVM_load()加载不需要额外安装其他机器学习库。svm.dat的输入特征是字符图片的 HOG 描述符输出类别是字符的 ASCII 编码或索引svmchinese.dat的输出类别则是汉字的编号。这里有个细节汉字模型的训练数据量远小于英文字母因为中文车牌只有 31 个省份简称和少数特殊汉字而英文字母加数字有 34 个类别所以charsChinese.7z比chars2.7z小很多很正常。从我的经验看直接使用这两个模型完成基本验证足够但如果你的测试图片风格和训练数据差异很大比如夜间拍摄、反光严重、倾斜超过 15 度识别率会明显下降这时候重新训练模型才是正路而不是盲目调代码参数。3. 跑通预测代码从安装环境到输出第一串车牌理论上把结构看清楚了接下来就是动手。这一章解决的是能不能跑、怎么跑的问题我先给出环境配置建议再逐步解释启动命令和参数含义。3.1 环境选型Python 版本和依赖库的搭配这个项目是典型的 OpenCV 传统视觉方案依赖库非常少我的建议环境如下依赖项推荐版本说明Python3.8 或 3.9项目代码简单3.8 兼容性最好opencv-python4.x 或 3.4.x3.4.1 更接近项目原版环境4.x 也可以运行numpy任意较新版本OpenCV 的底层数组依赖scikit-learn不需要这个项目用的是 OpenCV 自带的 SVM不是 sklearn安装命令很简单我用的是一个独立的虚拟环境避免污染全局 Python。以下是我在 Windows 和 Linux 下都验证过的安装步骤python -m venv lpr_env source lpr_env/bin/activate # Windows 下用 lpr_env\Scripts\activate pip install opencv-python4.5.5.64 pip install numpy代码说明venv创建虚拟环境source lpr_env/bin/activate激活环境Linux 和 macOS 用这个写法Windows 则使用lpr_env\Scripts\activate。opencv-python是预编译的二进制包安装时不需要本地编译所以耗时很短。最好不要直接使用pip install opencv-contrib-python因为 contrib 版包含的扩展模块在这个项目中用不上只会额外增加体积。3.2 修改配置文件路径和扩展名先对齐代码包里的config.js是我见过比较特殊的配置文件它保存的是路径和参数信息。实际上predict.py是否读取 JS 格式取决于原作者的解析方式但无论如何运行前你需要确认如下几项配置是否和你的文件路径一致{ model: svm.dat, model_chinese: svmchinese.dat, test_dir: test, output_visualization: false }字段说明model指向英文数字 SVM 模型文件model_chinese指向汉字 SVM 模型文件test_dir是测试图片目录路径output_visualization控制是否弹出中间结果窗口。如果你把模型文件移动到了其他目录必须同步修改这里的路径否则predict.py大概率直接报文件不存在的错误。3.3 运行预测脚本第一张车牌识别结果如何出现一切配置就绪后运行预测脚本的命令如下python predict.py --image test/car3.jpg如果你不想传参有些版本的predict.py支持默认读取整个test/目录直接运行python predict.py会批量识别所有测试图片。我建议第一次还是单张测试这样输出信息更清晰方便定位问题。运行成功时会看到类似下面的输出Processing: test/car3.jpg Plate recognized: 苏A·8K2F1 Confidence: 0.912代码说明--image参数指定要识别的图片路径car3.jpg是压缩包自带的一张测试图。输出中的Plate recognized是最终识别出的车牌号Confidence是 SVM 分类器的决策置信度数值越接近 1 表示越自信。如果你的输出结果和真实车牌不一致先不要怀疑模型坏了极有可能是图片预处理参数和测试图不匹配后面避坑章节会细说。如果运行时抛出ModuleNotFoundError: No module named cv2说明 OpenCV 没有安装成功回到 3.1 节重新执行pip install opencv-python如果是FileNotFoundError优先检查config.js中的模型路径是否写对并确认当前工作目录是不是项目根目录。4. 深入核心SVM 训练流程与字符识别边界跑通预测只是第一步想真正把项目掌握在自己手里必须搞清楚模型是怎么训练出来的、字符分割有哪些先验约束。这一章我从训练数据出发把 SVM 训练的完整逻辑和调用边界讲透。4.1 训练数据长什么样字符图片的预处理与标注规则chars2.7z和charsChinese.7z解压后每个字符文件夹对应一个类别文件夹名通常就是字符本身比如字符图片内容为A的目录名就是A。训练样本全是单字符灰度图尺寸经过统一缩放背景为黑色或白色前景字符是标准字体。训练时OpenCV 的 SVM 需要输入特征向量和标签向量。特征向量来自字符图片的 HOG 描述子HOG 能捕捉字符的梯度方向分布对笔画的局部形变不敏感。标签向量就是每个字符样本对应的类别标识在 OpenCV 的 SVM 中需要转换成整数索引。这一步是重训练最重要的环节样本数量和字符类别必须一一对应如果某个文件夹里只有几张样本训练出来的分类器几乎肯定会在该字符上翻车。我见过的最小可用样本量是每个字符至少 50 张低于这个值模型泛化能力非常差。4.2 训练代码核心HOG 特征提取与 SVM 参数配置如果你打算重新训练模型核心代码如下import cv2 import numpy as np # HOG 描述子参数配置 winSize (32, 32) blockSize (16, 16) blockStride (8, 8) cellSize (8, 8) nbins 9 hog cv2.HOGDescriptor(winSize, blockSize, blockStride, cellSize, nbins) # 读取训练数据生成特征矩阵 def load_data(data_dir): features [] labels [] for label, char_dir in enumerate(sorted(os.listdir(data_dir))): for img_name in os.listdir(os.path.join(data_dir, char_dir)): img cv2.imread(os.path.join(data_dir, char_dir, img_name), 0) img cv2.resize(img, (32, 32)) feat hog.compute(img).flatten() features.append(feat) labels.append(label) return np.array(features), np.array(labels) # 训练 SVM svm cv2.ml.SVM_create() svm.setType(cv2.ml.SVM_C_SVC) svm.setKernel(cv2.ml.SVM_RBF) svm.setC(2.5) svm.setGamma(0.5) svm.train(features, cv2.ml.ROW_SAMPLE, labels) # 保存模型 svm.save(svm.dat)参数说明winSize是 HOG 扫描窗口尺寸blockSize决定局部归一化的区域大小blockStride是滑动步长cellSize是细胞单元尺寸nbins是梯度方向直方图的通道数。SVM_C_SVC表示这是一分类支持向量机SVM_RBF是径向基核函数C是惩罚系数gamma控制核函数的半径。实际调参中C从 1 到 10 之间尝试gamma从 0.1 到 1 之间尝试这两组参数对识别率影响最明显。4.3 模型调用的边界什么样的图片能识别什么样会翻车svm.dat和svmchinese.dat的识别能力是有边界的不是万能的。根据我的实测经验和模型本身的训练方式适用边界基本是这么几条车牌的底色必须是蓝色或黄色因为定位阶段依赖颜色阈值过滤。绿色车牌新能源和白色车牌警车无法定位除非你自己扩展颜色范围。字符必须清晰无严重遮挡。SVM 属于浅层模型对模糊、遮挡、形变的抗性远不如深度学习如果字符被泥点遮挡超过 30%识别率会大幅下降。图像分辨率不能太低。test/目录下的图片分辨率都在几百像素以上如果输入图片本身只有几十像素车牌区域在预处理后根本无法形成清晰轮廓。车牌倾斜角度不要超过 20 度。surface.py的透视变换能修正一定程度的倾斜但极端角度下字符分割会失败。超出这个边界时正确的做法不是继续调predict.py的代码而是要么更换输入图片要么重新设计定位策略比如增加边缘检测辅助定位。4.4 字符分割的细节为什么同一个图片字符会被切散或粘连字符分割是整套代码里最依赖先验参数的部分。surface.py或predict.py中通常会设置以下阈值参数这些参数决定了分割质量最小轮廓面积小于该面积的轮廓会被当作噪声过滤掉。一般设置为车牌区域面积的千分之一。字符宽高比正常字符的宽高比在 0.3 到 0.6 之间过窄可能是数字1或分割错误过宽可能是两个字符被粘连在一起。字符间距正常车牌字符间距均匀如果两个轮廓中心的水平距离小于字符宽度的 1.2 倍说明可能发生了粘连。这些参数在代码里通常被命名为MIN_AREA、CHAR_RATIO、MAX_DISTANCE。如果你发现同一张图片识别结果时好时坏问题几乎都出在这一段。我一般会用调试模式把二值化后的轮廓可视化出来看看每个字符的包围框是否准确地框住了字符中心。5. 避坑指南推理翻车现象、原因与解决办法这部分是整套项目最值得记录的经验。我重跑这个项目时踩了不少坑有些问题看起来是代码 bug实际上是路径或环境问题这里挑了最典型的 5 条每一条都按照现象、原因、解决的顺序讲清楚。5.1 现象predict.py报错找不到svm.dat运行预测脚本时直接抛出FileNotFoundError: svm.dat。我把代码包解压后放在桌面当前工作目录也是项目根目录但脚本就是找不到模型。原因是我把predict.py从项目目录复制到了另一个文件夹单独运行Python 的相对路径以当前工作目录为基准而不是脚本所在目录所以模型加载失败。解决办法是在运行脚本之前用命令行切换到项目根目录比如cd License-Plate-Recognition-master然后再执行python predict.py。如果你想在任何目录下都能运行可以在predict.py顶部加上os.chdir(os.path.dirname(os.path.abspath(__file__)))把工作目录强制切换到脚本所在位置。5.2 现象程序正常运行但识别出的车牌号是乱码图片能正常读入预处理也执行了但输出的字符串完全不是预期的车牌比如把苏A识别成津C。原因是训练数据中的汉字和实际测试图的字体风格差异太大。charsChinese.7z里的汉字样本来自标准车牌字体但测试图上的字体由于反光、倾斜、透视变换已经发生了变形SVM 对这类形变的鲁棒性不够。解决方法是针对你的实际场景扩充训练样本比如从测试图片中手动截取字符区域加入训练集后重新训练svmchinese.dat。另一个缓解手段是在字符分割后对每个字符图像做尺寸归一化让输入到 SVM 的特征尽可能和训练数据一致。5.3 现象定位阶段把整张车头框选出来车牌区域没找到定位的轮廓外接矩形明显偏大覆盖了整个前保险杠区域。原因是 HSV 颜色阈值设置得太宽蓝色区域和车身蓝色反光区域一起被保留或者车身的颜色和车牌底色的色调太接近导致两者连通成了一个轮廓区域。解决方法是调整 HSV 阈值范围。项目代码里通常会定义lower_blue和upper_blue两个数组比如(100, 100, 50)到(130, 255, 255)你可以把饱和度下限从 100 提高到 150过滤掉低饱和度的反光区域。另外形态学开运算的核大小也可以适当增大把细小的反光区域腐蚀掉。5.4 现象Windows 下运行中文路径报编码错误在 Windows 环境下把整个项目放在C:\用户\张三\桌面\下运行时报UnicodeDecodeError提示解码失败。原因是 Python 默认的文件读取编码是 UTF-8而 Windows 的控制台和文件系统默认编码是 GBK中文字符在读取路径或打印输出时编码不一致。解决办法是在 Python 文件开头添加# -*- coding: utf-8 -*-声明并在读取文件的代码中显式指定编码更彻底的办法是把项目放到纯英文路径下比如C:\lpr\这是最简单的规避方式。5.5 现象同一张图片多次运行结果不一致第一次运行识别为京A12345第二次运行变成了京A12345少了一位数字或者直接报分割错误。原因是某些步骤存在随机性比如轮廓检测的顺序、SVM 决策函数的数值精度因 OpenCV 版本不同产生细微偏差更常见的是图像预处理时用到了cv2.imshow窗口交互窗口状态下图像尺寸被 UI 缩放导致后续处理的实际像素不同。解决办法是确保在无界面环境下运行脚本或者把可视化开关全部关闭。同时固定 OpenCV 的版本换版本后务必重新测试所有测试图片不要只看单张结果。6. 进阶技巧一分钟判断这套代码适不适合你的场景代码跑通、模型也懂了接下来最实际的问题是这个系统能不能用到你自己的项目里这里分享一个我经常用的评估套路不需要写复杂代码直接利用项目自带的文件就能完成判断。第一步用test/目录下所有图片过一遍完整流程记录每张图的识别结果和置信度。如果存在明显低置信度输出直接把对应图片挑出来看图确认是定位失败还是分割失败。这个动作能快速定位项目的短板在哪一个环节。python predict.py --image test/car3.jpg python predict.py --image test/car5.jpg python predict.py --image test/wAth859.jpg第二步对你自己的车牌图片做数据增强我一般会写一段 30 行以内的 Python 脚本批量把输入图片旋转 10 度、加高斯噪声、调整亮度得到一组风格差异较大的测试集。如果这些增强图片的识别率低于 50%结论很明确这个项目只适合处理与训练数据分布一致的图片不能直接作为生产系统使用。第三步决定是否更换车牌定位策略。我自己验证过的有效替换方案是不用颜色特征定位改用边缘检测加形态学闭运算定位。因为很多新国标车牌的底色从蓝色变成渐变或哑光传统 HSV 阈值很可能翻车Edge 定位的适应性更强。最后说一个我的个人习惯每次在新环境里复现这类源码包我都会强制自己从头跑一遍完整的预测流程并拿自带测试图做基准回归测试确认输出结果没有因环境差异而变化才开始改代码。从那以后我再也不相信能跑起来这个说法——真正确认一个项目可用的标准是每个关键环节都有可复现的输出。这个习惯救了我很多次希望帮到你。本文还有配套的精品资源点击获取