简介:一套基于OpenCV的车牌识别系统完整源码,面向图像处理初学者、计算机视觉课程学生及智能交通方向开发者,帮助快速掌握车牌定位、字符分割与OCR识别的工程实现。压缩包共23个文件,约14.56MB,包含Python源码、车牌样本图片(jpg/png)、SVM训练数据(dat)、模型压缩包(7z)、使用说明(md)及许可文件等,目录结构清晰,便于按模块查阅。已有1175人学习下载。代码按“图像预处理—车牌定位—字符分割—字符识别”主线组织,涉及灰度化、Canny边缘检测、形态学操作、模板匹配/SVM分类等关键环节;随包提供正负样本和预训练模型,读者可复现实验,也可替换数据或调整参数改进识别效果,非常适合课程设计、毕业设计或智能交通项目预研。通过完整流程演示,能直观理解从图像到文本输出的每个步骤,也可为后续引入深度学习识别打下基础。
1. 拿到基于Opencv的车牌识别系统代码.zip之后,先搞清楚这到底是一套什么方案
拿到一个名为“车牌识别系统代码.zip”的压缩包时,多数人期待的是解压后跑一下就能出结果。但 OpenCV 车牌识别真正的分水岭不在“能不能跑”,而在“换一个场景还能不能跑”。固定机位、车牌端正、光照稳定的条件下,纯 OpenCV 方案识别率做到 90% 以上并不难,CPU 单核就能实时;一旦加入夜间、逆光、新能源绿牌,算法就要重新调参。这套代码解决的是从单张图像到车牌字符串的完整链路——车牌定位、字符分割、字符识别。适合课程设计、毕业设计、停车场道闸这类固定场景,也适合想先看懂传统图像处理流程再上深度学习的入门者。
打开这类 zip 后,第一件事不是直接双击运行,而是先确认依赖:OpenCV 版本、NumPy、图像路径是不是写死。很多“跑不起来”的报错,都出在路径和版本上,与算法本身无关。下面按预处理、定位、分割、识别这条主线,把每一段的原理、命令和参数讲透,最后给出一组排查经验。
2. 先把图像“洗干净”:灰度、高斯滤波与二值化的顺序问题
2.1 为什么从灰度开始:去掉颜色干扰,保留结构信息
车牌识别的第一步几乎都是灰度化,原因很直接:边缘检测和后续的投影分割都在单通道上进行,彩色信息在计算梯度时不仅没有帮助,还会把光照变化放大成噪声。OpenCV 里的转换函数是cv2.cvtColor,参数COLOR_BGR2GRAY表示把蓝绿红三通道按加权公式合并成单通道,这个加权系数是固定的:0.299*R + 0.587*G + 0.114*B。
这里有一个容易被忽略的点:灰度化只服务于边缘检测这条路。车牌定位还有另一条常用路线——基于颜色的 HSV 过滤,它需要的是原始彩色图像,不是灰度图。所以预处理阶段不是“只保留灰度图”,而是两条路线各留一份数据。你会看到实际代码里往往同时保留img和gray两个变量,后面各取所需。
import cv2 import numpy as np # 读取原始图像,BGR 通道顺序,这是 OpenCV 的默认格式 img = cv2.imread("car.jpg") if img is None: raise ValueError("图像路径不对,先确认文件是否存在") # 转灰度:后续 Sobel 边缘检测只需要亮度梯度,不需要颜色 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)这段代码最值得注意的不是cvtColor本身,而是img is None的判断。很多从 zip 里直接跑imread报错的情况,都是因为相对路径写错了,比如脚本在src/目录下,图像在images/目录下,运行时当前工作目录不同就会读到空指针。所以拿到别人的代码包,第一件事就是把图像路径改成绝对路径,或者用os.path.join拼接。
2.2 高斯滤波与 Sobel:先平滑再求导,避免噪声被放大成假边缘
灰度图之后,常见的做法是高斯滤波,而不是直接上Sobel。原因是梯度算子对噪声非常敏感,一个孤立噪点就能产生很强的边缘响应,滤波的作用就是把这种高频噪声压下去。高斯滤波有两个参数:核大小(5, 5)和标准差sigma。
核大小决定平滑范围,5x5 比 3x3 去掉的噪声更多,但也会让真正的地面边缘变粗,定位时矩形轮廓会更“臃肿”。sigma 一般取 1.0 到 1.5 之间的经验值,太小等于没平滑,太大则把车牌字符的笔画边缘都糊掉了。车牌定位关心的是“车牌整块区域”而不是“每个字符”,所以这里选择适度模糊是安全的。
# 高斯滤波:核大小 5x5,sigma=1.0,先平滑再求导 blurred = cv2.GaussianBlur(gray, (5, 5), 1.0) # 对 x 方向求一阶偏导,突出竖直边缘 # 车牌字符笔画、左右边框都有大量竖直边缘,Sobel_x 响应最强 sobel_x = cv2.Sobel(blurred, cv2.CV_64F, 1, 0, ksize=3) # 把负梯度值取绝对值并转回 8 位图,方便后续找阈值 abs_sobel = cv2.convertScaleAbs(sobel_x)这里必须注意cv2.CV_64F这个中间类型。Sobel 求导的结果有正有负,如果直接用 8 位无符号类型接收,负值会被截断成 0,边缘信息直接丢失一半。convertScaleAbs会把负值取绝对并映射到0~255范围。ksize=3是 Sobel 核的最小尺寸,3x3 对细笔画敏感,适合字符边缘;如果设成 5,边缘会更粗,反而会让后续形态学处理把两个相邻字符连在一起。
2.3 二值化:大津法还是固定阈值,取决于光照环境
Sobel 输出的是梯度强度图,接下来要用阈值把它变成黑白二值图。常见的二值化方式有两种:固定阈值和大津法(OTSU)。大津法自动计算阈值,核心思想是让前景和背景的类间方差最大,在光照还算均匀的画面里表现稳定,所以代码包里默认用 OTSU 比较常见。
如果换成固定阈值,比如cv2.threshold(abs_sobel, 100, 255, cv2.THRESH_BINARY),阈值 100 的含义是梯度强度大于 100 的像素判为边缘。固定阈值的问题是:白天强光照下,车身边缘的梯度可能到 200,到了傍晚只有 80,同一个阈值在不同时间点效果完全不同。我一般会把固定阈值留给夜间场景,因为夜间背景简单,固定阈值反而比 OTSU 更稳。
# OTSU 自动选阈值:第二个参数传 0 会被忽略,阈值由算法自己算 ret, binary = cv2.threshold(abs_sobel, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU) # 闭运算:先膨胀后腐蚀,把断续的字符笔画连成一个完整的“白块” kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (17, 5)) closed = cv2.morphologyEx(binary, cv2.MORPH_CLOSE, kernel)闭运算是车牌定位里最关键的形态学操作。二值化之后,字符笔画是一根根碎的边缘线,膨胀会把它们沿上下左右方向“加粗”,让相邻笔画搭在一起,腐蚀再把多余的部分削薄。核选(17, 5)而不是正方形,是因为车牌本身是横向矩形,横向跨度远大于纵向,横长条核能把整排字符连成一块完整的白色区域,同时不把上下两行异物粘连。
这个核的宽度是整套算法里最敏感的参数。太小,比如(7, 5),字符连不成整块,车牌会出现断裂;太大,比如(31, 5),会把车牌附近的保险杠边缘也并进来,定位框直接套住半边车身。实际调参时从 11 开始往上试,每次加 2,观察找出来的轮廓是否完整覆盖七个字符。
3. 车牌定位:Sobel 边缘与 HSV 颜色两条路线怎么选
3.1 定位逻辑:车牌是一块“竖边密集”的横向矩形
预处理之后,图像里所有边缘都被闭运算连成了白色块,接下来要做的是从这些块里找出“最像车牌”的那一个。车牌在图像里的直观特征有三个:横向矩形、面积适中、边缘密集。标准车牌的宽高比是 440:140,约等于 3.14,实际拍摄有透视变形,所以阈值范围要给到 2.5 到 4.5 之间。
cv2.findContours在二值图上找轮廓,RETR_EXTERNAL只取最外层轮廓,避免车牌内部字符产生的子轮廓干扰。然后对每个轮廓调用cv2.minAreaRect,得到一个旋转矩形。这一步比直接取外接矩形要稳,因为车辆停在道闸前时车头可能偏转,车牌在画面里不是笔直的横条,而是一个带角度的平行四边形。
contours, _ = cv2.findContours(closed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) for cnt in contours: rect = cv2.minAreaRect(cnt) # 返回 (中心点, (宽, 高), 角度) w, h = rect[1] # minAreaRect 不保证 w 是长边,先交换到 w >= h if w < h: w, h = h, w ratio = w / h area = w * h # 宽高比按标准车牌的 3.14 留出余量 # 面积下限滤掉远处小噪点,上限滤掉整个车身的大轮廓 if 2.5 < ratio < 4.5 and 500 < area < img.shape[0] * img.shape[1] * 0.3: box = cv2.boxPoints(rect) box = np.int0(box) # box 就是候选车牌的四个角点,后面再决定是否保留minAreaRect返回的角度在 OpenCV 里是 0 到 90 度之间,且角度方向跟 x 轴的夹角定义容易绕晕,所以不要直接用角度做矫正,而是用四个角点去算。面积上限用img.shape[0] * img.shape[1] * 0.3而不是写死数字,是为了让同一套阈值适配不同分辨率的图像。如果你的代码包跑出来一个框把整辆车都套住了,优先检查面积上限是不是没有按分辨率缩放。
3.2 用 HSV 过滤蓝色:光线变化时的救命稻草
Sobel 边缘定位在面对车身颜色与背景相近的场景时会翻车,比如白车停在白色墙前,边缘定位会把整块区域连成一片。这时候颜色是最强的特征:传统蓝牌在 HSV 颜色空间里占据一个非常稳定的区间。OpenCV 的 HSV 转换中,H(色相)范围是 0 到 180,S(饱和度)和 V(明度)范围都是 0 到 255。
蓝色车牌的 H 值大致落在 100 到 124 之间,饱和度下限 80,明度下限 46。这个范围的来源是 OpenCV 教程里的标准值,但不是所有场景都适用:夜间蓝牌的明度会掉到 50 以下,逆光时饱和度会被压低。实际工程里,我会把 S 下限和 V 下限单独拆出来做成配置文件,方便在不同摄像头下微调。
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) # 蓝色车牌的 HSV 范围:OpenCV 的 H 范围是 0-180 lower_blue = np.array([100, 80, 46]) upper_blue = np.array([124, 255, 255]) mask = cv2.inRange(hsv, lower_blue, upper_blue) mask_closed = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, cv2.getStructuringElement(cv2.MORPH_RECT, (17, 5)))inRange输出的是二值掩膜,符合范围的像素为白色,其余为黑色。再走一次闭运算,把车牌上可能因反光产生的蓝色空洞填掉。这套逻辑识别蓝牌非常稳,但它有一个明显盲区:新能源绿牌。绿牌在 HSV 里 H 值大约在 35 到 85 之间,与蓝色区间完全不重合。如果守着一套车牌识别系统,只做蓝牌会漏掉越来越多上路的新能源车。
绿牌的解决办法是再加一个颜色的inRange区间,用cv2.bitwise_or把两个掩膜合并。调参时要注意绿的饱和度不能跟背景的绿色混淆,城市里的绿化带、绿色围挡都会被误检。如果发现绿色掩膜导致误检率上升,宁可把 H 范围收紧到 40 到 70,牺牲一点召回率,保证精度。
提示:HSV 的范围参数强烈建议用滑动条调试,不要靠猜。核心逻辑是先取一个值让蓝牌全亮,再慢慢往下调 S 下限,直到背景里的蓝色不再触发。
3.3 定位框的后处理:透视纠正才是分水岭
定位框拿到之后,最直观的问题是视角倾斜。车牌在画面里通常不是正对摄像头,尤其道闸机安装在侧面时,车牌是一个透视变形后的不规则四边形。字符分割依赖“字符水平排列”的假设,倾斜超过 5 度,垂直投影的波谷就会变浅,分割准确率明显下降。所以定位之后要做透视纠正,把四个角点映射到一个固定的横向矩形上。
def order_points(pts): """按左上、右上、右下、左下排序四个角点""" rect = np.zeros((4, 2), dtype=np.float32) s = pts.sum(axis=1) rect[0] = pts[np.argmin(s)] # 左上角:x+y 最小 rect[2] = pts[np.argmax(s)] # 右下角:x+y 最大 diff = np.diff(pts, axis=1).ravel() rect[1] = pts[np.argmin(diff)] # 右上角:y-x 最小 rect[3] = pts[np.argmax(diff)] # 左下角:y-x 最大 return rect src = order_points(np.float32(box)) dst = np.array([[0, 0], [239, 0], [239, 79], [0, 79]], dtype=np.float32) M = cv2.getPerspectiveTransform(src, dst) plate = cv2.warpPerspective(img, M, (240, 80))这段代码是整个流程里最值得精读的部分。order_points按坐标和差排序,避免四个角点顺序错乱导致图像翻转。目标尺寸选240x80是权衡结构:宽高比正好 3:1,像素数足够后续模板匹配使用,又不至于让计算量变大。如果你用 440x140 这样的标准车牌尺寸,分割和识别会更准,但二值化的光照不均匀问题也会更明显,因为每个像素的明暗差异被放大了。
透视纠正后,车牌区域被单独切出来。到此,定位阶段结束,下一章进入字符分割。这里必须强调:没有做透视纠正的“车牌识别”,在测试集上可能只有六成识别率,而加了一个透视映射后直接到八成。这一步是性价比最高的改进点。
4. 字符分割与识别:垂直投影、连通域和模板匹配
4.1 分割前先清场:去掉边框与铆钉
定位纠正后的车牌图像,除了七个字符外,还有上下边框、左右边框、以及固定车牌的铆钉。这些元素如果不清理,会干扰后续的投影分割。清理的常见做法是对二值化后的车牌图做行投影——统计每一行的白色像素数量,字符所在行白色像素多,边框所在行白色像素也多,但边框线条与字符区域之间存在明显的低谷。
先把车牌图像转灰度、二值化,然后用np.sum按行统计白色像素。找到第一个和最后一个高于阈值的行,把它们之间的区域裁剪出来。这样上下边框就被去掉了。左右边框用同样的方法按列裁剪。阈值通常取最大行像素数的 10% 到 20%,太低会残留边框,太高会把上下边缘笔画较淡的字符剪掉。
gray_plate = cv2.cvtColor(plate, cv2.COLOR_BGR2GRAY) _, binary_plate = cv2.threshold(gray_plate, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU) # 按行统计白色像素,找到上下边缘 row_sum = np.sum(binary_plate, axis=1) / 255 rows = np.where(row_sum > row_sum.max() * 0.1)[0] y_top, y_bottom = rows[0], rows[-1] plate_cropped = binary_plate[y_top:y_bottom + 1, :]这里有个血泪经验:很多代码包在这一步只做上下裁剪,不做左右裁剪。结果车牌左边框残留,垂直投影时左边框被视为一个宽字符,分割出的第一个字符其实是“边框加半个汉字”,后续模板匹配必然出错。左右边框的裁剪方式和行投影完全对称,但要注意车牌左右两侧在透视纠正后可能还带有背景像素,所以左右裁剪的阈值要比上下更严格,取最大值的 30% 左右。
4.2 垂直投影分割字符:阈值的宽窄决定成败
清洗完边框后,字符排列在二值图上,每个字符之间有明显空隙。垂直投影就是对每一列统计白色像素数量,字符所在列数值高,空隙所在列数值低。找阈值的常用做法是取最大列像素数的 15% 到 25%,高于阈值的列视为“字符内”,连续的字符列组成一个分段。
col_sum = np.sum(plate_cropped, axis=0) / 255 col_thresh = col_sum.max() * 0.2 segments = [] in_char = False start = 0 for i, v in enumerate(col_sum): if v > col_thresh and not in_char: start = i in_char = True elif v <= col_thresh and in_char: end = i # 宽度小于 5 像素的分段,基本是噪声、铆钉或分隔圆点 if end - start > 5: segments.append((start, end)) in_char = False # segments 里每个元素就是一个字符的左右边界20% 阈值在理论上是合理的,但实际调试中你会发现字符“1”的笔画最少,它的列像素峰值远低于汉字,按最大值的百分比算,可能低于阈值直接被过滤掉。这是垂直投影法的经典缺陷:窄字符容易被当成分隔噪声。我一般会把宽度判断放在阈值之前:先记录所有投影峰值超过 5% 阈值的连续段,再按宽度过滤,而不是直接用硬阈值切分。
圆点问题也需要在这里处理:车牌第二个字符和第三个字符之间的分隔圆点,直径只有 3 到 4 像素,投影后形成一个尖峰,宽度明显小于正常字符。宽度小于 5 像素的分段直接丢弃,就能把圆点排除。另一个办法是按面积过滤:分割后的字符区域如果小于所有区域平均面积的 30%,视为噪声。两种方式结合,虚检率会大幅下降。
4.3 模板匹配:识别结果与置信度一起返回
字符分割完成后,每个字符是一块二值图。识别环节在传统 OpenCV 方案里最常见的是模板匹配:把字符缩放到固定尺寸,与模板库里每张字符图计算相似度,取最高分作为结果。模板库一般包含省份汉字简称、字母 A-Z、数字 0-9,省份汉字模板通常只有几十张,能量远小于字母数字模板,所以汉字识别率往往是最弱的环节。
模板匹配方法选用TM_CCOEFF_NORMED,它计算的是归一化相关系数,结果范围在 -1 到 1 之间,越接近 1 越相似。它对比的是图像之间的“相对变化模式”,所以对亮度变化不敏感。字符图像必须先缩放到与模板一致,通常是 20x40 或 28x56,缩放时用cv2.INTER_AREA,它对缩小时的抗锯齿效果比线性插值好。
def match_char(cell, template_dict): """cell 是一个字符的二值图,template_dict 是 {字符名: 模板图}""" best_score, best_char = -1, None # 缩放到模板尺寸,二值图用 INTER_AREA 保留笔画结构 cell = cv2.resize(cell, (20, 40), interpolation=cv2.INTER_AREA) # 归一化到 0-255,消除缩放后灰度偏移 cell = cv2.normalize(cell, None, 0, 255, cv2.NORM_MINMAX) for char, template in template_dict.items(): result = cv2.matchTemplate(cell, template, cv2.TM_CCOEFF_NORMED) score = result[0][0] if score > best_score: best_score, best_char = score, char return best_char, best_score plate_str = "" for (start, end) in segments: cell = plate_cropped[:, start:end] ch, conf = match_char(cell, template_dict) if conf > 0.6: plate_str += ch else: plate_str += "?" # 宁可标未知,不要硬识别成错字置信度阈值 0.6 是经验值,实际要根据模板库质量调整:模板图越多、采集越规范,阈值可以提到 0.7;模板不足时,0.6 已经能保证大多数字母数字正确。加一个置信度判断,比直接取最高分可靠得多——在模板库里“最相似的字符”和“真的就是这个字符”是两回事,低置信度情况下返回?,让用户知道这段需要人工确认,好过输出一个错误车牌去比对门禁。
5. 跑不通先别怪算法:5 个高频排查点与避坑记录
5.1 定位框外的黑边导致分割全乱
现象:分割阶段把车牌上下边框也当成字符,七个字符变成了八个或九个区域,模板匹配结果全是乱的。原因:定位后把车牌区域直接送去切割,没有先做边缘裁剪。车牌二值化后,上下边框和字符区域同样有白色像素,垂直投影把边框也算成一个独立的“字符列”。解决:在分割前先做行列投影裁剪,上下裁剪阈值取行投影最大值的 10% 到 20%;左右裁剪阈值取 30% 左右,因为左右边框往往比字符淡且有背景干扰。做完裁剪后,再检查字符区域数量是否为 7 个,如果不是,回看裁剪阈值。
5.2 蓝牌之外还有绿牌:颜色区间只写死了一个
现象:新能源绿牌在 HSV 定位阶段直接被过滤掉,定位框为空。原因:代码里只写了蓝色车牌的inRange区间,H 值 100 到 124 完全覆盖不了绿色。解决:增加一个绿色区间,H 范围先按 35 到 85 设定,S 下限 80、V 下限 46,与蓝色掩膜用cv2.bitwise_or合并。调试时优先用一个绿色车牌样本单独验证,确认绿牌区域被完整点亮,再合入主流程。合并后误检率可能上升,此时收紧 S 下限比收紧 H 范围更有效,因为背景绿色的饱和度通常低于车牌绿色。
5.3 夜间识别率暴跌:V 通道是最大变量
现象:白天好好的系统,晚上同一角度识别率从 90% 掉到 60%。原因:HSV 定位的 V 通道代表明度,夜间车牌区域亮度低,低于 46 的 V 下限时掩膜直接变黑。同时夜间车灯产生的强光晕让 Sobel 边缘图上出现大面积虚假轮廓。解决:两件事同时做。一是对原图先做 CLAHE 直方图均衡,限制对比度增强,把夜间车牌区域的亮度整体抬起来;二是把 V 下限从 46 降到 20,但只对夜间时段生效。如果系统运行在固定场地,建议按时间切两套参数,白天用标准参数,夜间用低 V 阈值加 CLAHE。
5.4 第二个字符后面的圆点被当成一个字符
现象:分割结果出现了 8 段区域,第三段是一个小方块,模板匹配把它误判成数字 1 或字母 I。原因:车牌字符之间的分隔圆点在投影图上产生一个窄峰,宽度大约 3 像素,高于投影阈值后被当成字符。解决:在分割循环里加两个过滤条件——分段宽度小于 5 像素的直接丢弃;分段宽度大于投影总宽度四分之一的是疑似两个字符粘连,也要处理。圆点的尺寸相对于字符来说非常稳定,宽度过滤基本不会误伤真正的窄字符,因为数字 1 即使最窄也有完整笔画,宽度能到 8 像素以上。
5.5 汉字模板匹配全是幻觉:相似字符互相串
现象:字母和数字识别很准,汉字部分要么置信度低于阈值返回?,要么把结构相近的省份简称互相认错。原因:模板匹配的本质是像素级相关,汉字笔画密集,结构相似的两个汉字在归一化相关系数上差距很小。模板库里每个汉字只放一张图,没有覆盖不同摄像头角度下的笔画粗细差异。解决:给每个汉字准备多张模板,比如正常视角一张、轻微左偏一张、轻微右偏一张,识别时取与所有模板比较后的最高分。另一个有效做法是单独训练一个字符分类器,用提取后的 HOG 特征或轮廓特征代替原始像素,几十张样本就能比模板匹配提升明显。
6. 进阶:给识别率做一次“体检”,再决定要不要上深度学习
传统 OpenCV 车牌识别做到最后,瓶颈通常在参数上:闭运算核宽度、投影阈值、置信度阈值,每个参数的合理值都跟着场景变。与其靠手感调参,不如把参数组合成一个网格,在一批标注好的验证集上批量跑,用准确率做排序。这样每次换摄像头、换场地,都能在半小时内找到新环境下最优的参数组合。
from itertools import product # 固定场景下需要重点调的三组参数 param_grid = { "close_w": [13, 17, 21], # 闭运算核宽度 "proj_thresh": [0.15, 0.2, 0.25], # 投影分割阈值比例 "conf_thresh": [0.5, 0.6, 0.7], # 模板匹配置信度 } best_acc, best_params = 0, None for close_w, proj_t, conf_t in product(*param_grid.values()): acc = evaluate(close_w, proj_t, conf_t) # 在标注好的验证集上计算识别准确率 if acc > best_acc: best_acc, best_params = acc, (close_w, proj_t, conf_t) print("best acc:", best_acc, "params:", best_params)evaluate函数需要你准备一批真实场景的车牌照片,每张照片标注好车牌字符串,识别结果的正确性可以按整串匹配判断,也可以按字符级准确率判断。我一般用字符级准确率做排序指标,因为它能反映“到底哪一位最容易错”,比整串正确率更敏感。验证集不用大,每个场景 15 到 30 张足够,覆盖白天、傍晚、夜间和不同行驶角度。
网格搜索的价值不只是找到最优参数,它还能告诉你这个系统的性能上限。如果三个参数组合全部跑不出 85% 以上的准确率,问题大概率不在调参,而在定位或分割逻辑本身,这时候才需要往上走深度学习方案。一大批熟练工程经验是把整套流程先验证到极限,再把算子替换成神经网络。这个“证明传统极限”的步骤,恰恰是深度学习方案落地前最好的参照物。我自己吃过亏:曾经用一张测试图调参调得很漂亮,换到另一个摄像头后全盘崩溃,后来养成了“参数网格搜索加验证集”的习惯,才把这类系统从靠运气变成了可复现的工程。希望帮到你。
本文还有配套的精品资源,点击获取