ARTICLE DETAIL

资讯详情

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

CRPD车牌检测数据集精读:标注规范、训练评测与踩坑复盘

CRPD车牌检测数据集精读:标注规范、训练评测与踩坑复盘 1. 我为什么把CRPD单独拎出来读车牌检测这个方向外面看着像是被做烂了——随便找个开源仓库塞个YOLO进去几张图就能出框好像没啥可研究的。但真做过落地项目的人都知道能框出来和框得稳是两回事。卡口那种正对、补光足、车速可控的场景早就不是技术难题了难的是路侧、斜拍、远距离、逆光、雨雪天、广告牌上的假车牌、车身贴纸上的车牌图案这些东西一旦进了真实数据流模型的虚警率会飙得让人怀疑人生。CRPD这个数据集我关注它的原因很简单它瞄准的就是这一类不那么干净的检测场景而且它是一篇有配套论文、有明确标注规范和评测协议的大型车牌检测数据集不是网上随手打包的那种几千张图加一堆乱标框的资源。我把这篇论文当成一次完整的数据集设计复盘来读因为它解决的几个问题——采集怎么选、标注边界怎么定、划分怎么避免泄漏——是每一个想自己攒数据集的人都会撞上的墙。这篇笔记写给两类人一类是想在车牌检测这个窄领域快速上手、需要一个靠谱公开数据集做baseline的同学另一类是手上已经有业务数据、但不确定标注规范和评测口径该怎么定想找一份参照的算法工程师。不管你是哪一类读完至少能少走两三个月的弯路。1.1 车牌检测这道题难点早就不在能不能框出来先把问题拆开。车牌检测本质上是一个单类别、高长宽比、小目标、密集程度不高的目标检测任务。单看字面这几乎是目标检测里最好啃的骨头类别只有一个不用处理类间混淆车牌通常横向排布长宽比集中在2.5到5之间不像行人那样姿态千变万化一张图里的车牌数量普遍在个位数不存在人群那种极端密集场景。但实际情况是这四个看起来简单的特点每一个都是坑。单类别意味着没有类间差异带来的特征多样性模型很容易过拟合到背景纹理上——车牌周围总有一块固定的车身区域网络偷懒记这块区域比记车牌本身容易得多换个车身颜色就崩。固定长宽比意味着anchor或者先验框的设计空间被压缩一旦遇到俯拍角度导致的极端纵横比斜45度看过去车牌可能接近正方形先验框覆盖率骤降。小目标是最要命的一张1080p的路侧监控图车牌像素宽可能只有60到120像素缩到网络输入尺寸640之后只剩三四十像素经过五次下采样就只剩不到两个像素特征图上的响应基本糊成一团。非密集则意味着正样本数量少训练时正负样本极度不平衡损失函数很容易被背景主导。所以车牌检测的核心矛盾从来不是能不能检出而是在低虚警前提下保持高召回尤其要把车牌图案、广告牌文字、反光条这些长得像但又不是的东西排掉。1.2 CRPD在整个车牌数据集谱系里的位置我把手上接触过的车牌数据集捋了一遍大致能分出三类。第一类是卡口抓拍型图像正对、光照稳定、车牌占据画面比例大适合做识别训练但拿来测检测泛化性基本没参考价值。第二类是城市停车型典型代表是CCPD那一系数量大、倾斜角度丰富但标注偏粗很多时候只有框没有更细的几何信息。第三类就是真实路侧型CRPD属于这一类图像来源更接近路侧监控或车载前视的实际视角光照和天气分布更杂视角变化更剧烈。CRPD在谱系里的差异化价值我看下来主要落在两点。一是标注维度比常规检测数据集多除了车牌的位置框还带了车牌角点或者更细的几何信息不同版本和衍生版本在这块有差异具体字段要以你实际拿到的标注文件为准这为后面做透视校正、字符级识别提供了条件。二是采集和划分的控制更严格论文在去重、避免同车同场景跨集出现这些细节上花了篇幅这在很多自建数据集里是直接被忽略的环节。至于规模我印象中CRPD属于数千张图像的量级不算大但对车牌检测这个窄任务来说足够撑起一个可用的baseline——具体数字建议直接翻论文里的数据表我不在这里复述以免记串。1.3 这份笔记适合谁看如果你已经在别的检测任务上跑通过完整流程想切到车牌这个场景那么CRPD最大的作用是给你一个干净的起点标注规范相对统一评测口径明确你踩的坑基本都能归因到模型或训练策略上而不是归因到数据脏。如果你是完全的新手只有yolov8训练自己的数据集那种经验那这份笔记能帮你建立一个关键认知——数据集的质量上限决定了模型的上限标注边界的几像素差异会让你的mAP上下浮动好几个点而这几个点在你调参调到吐的时候是永远追不回来的。还有一种情况我也想专门提一下如果你手上正在做的是占道经营检测、桥墩病害检测、齿轮箱故障诊断这类看起来完全不相关的任务这篇笔记里关于标注一致性检查、训练集测试集泄漏排查、小目标评测口径的讨论同样适用。数据集这件事的底层逻辑是跨领域通用的换的是图像内容不换的是流程。2. 论文的数据集设计思路拆解读数据集论文我一般不从头读方法部分而是先看它怎么回答三个问题数据从哪来、标注怎么定、怎么证明这个数据集有意义。这三个问题回答得清楚这篇论文的贡献就站得住回答得含糊那这个数据集大概率只能当玩具用。CRPD在这三点上的处理我觉得是有借鉴价值的下面按我的理解顺序拆。2.1 采集端为什么路侧场景比卡口更值得做论文选择路侧视角而不是卡口正拍这个决定背后有一个很现实的判断卡口场景的模型已经够用了继续优化边际收益极低而路侧场景的需求在快速增长但公开数据极度稀缺。想想实际落地时的场景——园区出入口的斜向抓拍、路边停车位的俯视监控、车载行车记录仪的前视画面这些视角下的车牌跟卡口那张正面大特写完全是两个分布。采集环节我读下来比较认同的几个取舍是覆盖不同时段和天气因为逆光和夜间补光噪点是车牌检测虚警的主要来源覆盖不同拍摄高度和俯仰角因为俯仰角直接改变车牌在图像里的纵横比这是先验框设计的核心依据刻意保留了一定比例的模糊和遮挡样本而不是只挑清晰图。最后这一点很多自建数据集会做反——清洗的时候把模糊图全删了结果模型上线后对运动模糊帧完全没有鲁棒性。我的经验是模糊样本要留但要标记出来单独统计训练时正常用评测时按模糊/清晰分组看指标这样你才知道模型到底是被哪一类样本拖了后腿。还有一个容易被忽略的细节是去重。论文里提到了对连续帧和近似重复图像的过滤。这件事的重要性怎么强调都不过分路侧监控是连续录像抽帧的如果不做去重同一辆车在相邻两帧里的画面会同时出现在训练集和测试集测试指标会虚高十几个点等上线发现完全对不上回头查才发现是数据泄漏。我自己的做法是抽帧时强制保证同一个片段内至少间隔N帧才取一张然后用感知哈希或者特征相似度再跑一遍全局去重阈值我一般取在相似度0.9以上宁可多删不可漏删。2.2 标注规范一个框的四条边到底压在哪数据集论文里最容易被跳过、但实际影响最大的部分就是标注规范。一个车牌的检测框左边界压在外框还是压在字符边缘上下边界是贴紧牌照实体还是包含一点点边距这些差异会直接变成模型学到的目标定义。如果训练集里有的图框贴得紧、有的图留了五像素边距模型就得同时拟合这两种定义最后学出一个折中的、两边都不准的边界。我读论文时特别留意了几条规则也结合我自己的标注经验补几句。第一框的边界应与车牌物理外框对齐而不是与最外侧字符对齐因为物理外框是稳定的几何参考字符位置会随排版变化。第二部分遮挡的处理要统一要么统一标注可见部分的包围盒要么统一按几何外推补全这两条路都能走但绝不能混着来。我倾向于前者因为外推补全会引入标注者的主观估计不同人标出来的框能差出十来个像素。第三模糊到看不清字符的车牌仍然要标因为检测任务只关心是不是车牌不关心上面写了什么只要人眼能判断出这是车牌区域就应该进正样本。第四如果标注里包含角点信息角的顺序必须全局一致一般按左上、右上、右下、左下顺时针排顺序错位会让后面的透视校正直接算出扭曲结果而且这种错误在可视化检查时很难一眼看出来。提示接手任何车牌数据集第一件事是抽50张图做可视化把框画上去然后问自己一个问题——如果让我重新标我会不会画得跟它一样。答案如果是不会那这个数据集的标注规范你就得重新评估或者干脆按自己的规范重标一遍。2.3 划分与评测协议怎么让数字不难看又不虚高划分这件事表面上是按比例切一刀实际上的坑全在怎么切。随机切分是最省事但最危险的做法尤其在路侧连续录像抽帧的场景下随机切分几乎必然导致泄漏。正确的切分粒度应该是场景级或车辆级同一个摄像头点位、同一个时间段、同一辆车的图像只能整体落进训练集或测试集其中一边。论文里的评测协议我看了下用的是车牌检测领域比较通行的口径单类别以IoU阈值0.5判定命中报告AP和Recall。为什么不用0.75因为车牌的检测框受标注边界歧义影响比一般目标更大框的宽度可能就是几十像素差三个像素IoU就掉一大截用0.75会大量惩罚框得对但边界略有出入的正确检测指标噪声太大。这里有个实操上的建议主指标用AP0.5但一定要额外报告一个IoU 0.5到0.75之间的分布统计因为你的下游如果是字符识别框的精度直接决定识别率只看AP0.5会把框得勉强够用的模型误判成好模型。另外我强烈建议在评测时做按目标尺寸分组统计。车牌是小目标任务整体AP可能被少数大车牌拉高而真正难的小车牌指标其实很差。分组看大小目标的AP差距往往能直接定位到你该不该换更大的输入分辨率或者该不该调小anchor尺寸比盲目调学习率有效得多。3. 标注结构与数据组织实操论文读完落到工程上就是一件事把标注文件读进来变成一个能喂给训练框架的格式。这部分我讲得具体一点因为这是最容易被论文写得好、代码跑不通卡住的地方。3.1 目录结构与我拿到文件时的第一反应我拿到任何数据集包第一步不是写代码是先看目录树和文件命名规律。典型的组织方式无非两种一种是图像和标注分开放在两个目录文件名一一对应另一种是图像和同名标注文件放在一起靠扩展名区分。CRPD这类数据集一般会给出明确的训练/测试划分子目录标注以json、xml或者txt的形式提供。我习惯用下面这条命令先摸清楚结构比在图形界面里一层层点快得多# 看目录层级和文件数量分布 find ./CRPD -maxdepth 3 -type d | head -50 find ./CRPD -type f -name *.jpg | wc -l find ./CRPD -type f -name *.json | wc -l find ./CRPD -type f -name *.xml | wc -l # 抽查几个样本确认命名是否一一对应 ls ./CRPD/train/images | head -5 ls ./CRPD/train/annotations | head -5看到数量对不上或者命名规律有例外比如个别图是png后缀、个别标注少了几个文件不要急着写脚本先把这些异常样本单独挑出来看。常见情况是几张图损坏、几张图被人工剔除但标注忘了删。这些残留文件如果不处理会在训练跑到第N个epoch的时候突然抛一个FileNotFoundError然后你花半小时才定位到问题。3.2 标注字段逐项解析假设你拿到的标注是json格式这是比较常见的形态逐项看的话一般包含这几类信息图像文件名或图像id、图像的宽高、该图内所有车牌实例的列表。每个实例里面至少有一个位置字段可能叫bbox、points、box或者polygon另外可能有车牌类型标签、是否模糊、是否有遮挡之类的小字段。位置字段的形式决定了你后面的处理方式这里必须分清楚三种情况位置字段形态数据结构后续处理方式适用场景水平矩形框[x, y, w, h]或[x1, y1, x2, y2]直接归一化成YOLO格式常规检测训练四边形角点[[x1,y1],[x2,y2],[x3,y3],[x4,y4]]取外接矩形或保留角点做校正需要透视变换多边形掩膜任意数量顶点转成RLE或位图实例分割训练我拿到四边形角点的时候不会直接丢掉角点信息只留外接矩形因为角点在做车牌矫正时价值极大——把倾斜车牌先透视变换成正视图再送去识别识别率能提升一大截。稳妥的做法是训练时用外接矩形当检测目标同时把角点信息单独存一份等检测框出来之后再回头查对应的角点做校正。这里顺便说一个坐标系的坑有的数据集给的是绝对像素坐标有的给的是0到1归一化坐标还有的给的是中心点加宽高而不是左上角加宽高。这三种如果不确认清楚训练时loss会直接从几点几飙到几百点几。判断方法很简单随便打开一个标注文件看看数值范围和图像尺寸的关系如果数值都小于1那是归一化的如果远大于图像宽高那可能是中心点偏移或者多个坐标拼接错了。3.3 转成YOLO和COCO格式的两段脚本下面这两段转换脚本是我自己常用的模板字段名按你实际拿到的标注文件对应改一下就行。第一段转YOLO格式import json import os from pathlib import Path def crpd_to_yolo(ann_file, img_dir, out_dir, class_id0): 把json标注转成YOLO的txt格式 每行: class_id cx cy w h (全部归一化到0-1) os.makedirs(out_dir, exist_okTrue) with open(ann_file, r, encodingutf-8) as f: data json.load(f) # 兼容两种常见组织方式list 或 dict里有images/annotations if isinstance(data, dict): images data.get(images, []) anns data.get(annotations, []) img_info {im[id]: im for im in images} else: img_info None anns data print(f总共 {len(anns)} 条标注待处理) for item in anns: if img_info is not None: im img_info[item[image_id]] fname im[file_name] iw, ih im[width], im[height] else: fname item[image_name] iw, ih item[image_width], item[image_height] # 位置字段这里按实际名称改bbox / points / box box item.get(bbox) or item.get(box) if box is None: print(f跳过无位置字段的标注: {fname}) continue # 如果是四边形角点取外接矩形 if isinstance(box[0], (list, tuple)): xs [p[0] for p in box] ys [p[1] for p in box] x1, y1, x2, y2 min(xs), min(ys), max(xs), max(ys) else: # 判断是 x1y1x2y2 还是 xywh x1, y1, a, b box if a x1 and b y1 and a iw and b ih: x2, y2 a, b # 形式为 x1y1x2y2 else: x2, y2 x1 a, y1 b # 形式为 xywh # 边界裁剪防止越界产生异常loss x1, y1 max(0, x1), max(0, y1) x2, y2 min(iw, x2), min(ih, y2) w, h x2 - x1, y2 - y1 if w 1 or h 1: print(f异常框跳过: {fname} - {w}x{h}) continue cx (x1 x2) / 2.0 / iw cy (y1 y2) / 2.0 / ih nw w / iw nh h / ih txt_path Path(out_dir) / (Path(fname).stem .txt) with open(txt_path, a, encodingutf-8) as fo: fo.write(f{class_id} {cx:.6f} {cy:.6f} {nw:.6f} {nh:.6f}\n) print(转换完成)第二段是转COCO格式主要为了用pycocotools算标准APimport json from pathlib import Path def build_coco_anno(ann_list, out_json): ann_list: 每项为 dict(file_name, width, height, boxes) boxes 为 [[x1,y1,x2,y2], ...] 绝对像素坐标 coco { images: [], annotations: [], categories: [{id: 1, name: plate}] } ann_id 1 for img_id, item in enumerate(ann_list, start1): coco[images].append({ id: img_id, file_name: item[file_name], width: item[width], height: item[height] }) for box in item[boxes]: x1, y1, x2, y2 box w, h x2 - x1, y2 - y1 coco[annotations].append({ id: ann_id, image_id: img_id, category_id: 1, bbox: [x1, y1, w, h], area: w * h, iscrowd: 0 }) ann_id 1 with open(out_json, w, encodingutf-8) as f: json.dump(coco, f, ensure_asciiFalse) print(f写入 {out_json}共 {len(coco[annotations])} 个实例)注意转换脚本写完不要直接开训一定要随机抽十张图把转换后的框画回原图看一眼。我见过太多次因为坐标系搞反而导致模型完全学不动的情况而这种错误在loss曲线上表现得跟学习率太大几乎一模一样误判代价极高。4. 用CRPD把一次车牌检测训练跑通数据准备好了接下来是把训练跑通。这块我按实际操作的顺序讲包括体检、配置、评测三步。4.1 训练前的数据体检清单我现在的习惯是任何数据集在开训前必须跑一遍体检脚本输出一份统计报告。这份报告能省掉后面无数次的为什么效果不好的猜谜游戏。要统计的东西我列一下框的宽高比分布。车牌的正常比例集中在2.5到5如果统计出来有大量比例接近1的框要么是俯拍极端视角要么是标注标到了整块车身后者必须人工复核。框的绝对像素尺寸分布。按宽高分成小、中、大三档看看小车牌占比多少。小车牌占比超过三成输入分辨率就得往上提或者改用带小目标增强的结构。框的位置热力图。把所有框的中心点叠在一张图上如果全挤在画面中间一小块说明裁剪时尺度统一过头了模型会缺乏尺度多样性。重复图像检测。用感知哈希跑一遍全量图像相似度超过阈值的输出成组人工过一遍。这一步是防泄漏的最后一道闸。标注文件与图像文件的一一对应检查。有标注没图、有图没标注的情况必须清零。体检脚本不用写得多漂亮能输出上面的数字和几张可视化图就够。我一般还会顺手统计一下每图像的车牌数量分布如果绝大多数图只有1个车牌那针对多车牌场景的NMS参数就得单独调别指望默认阈值能兼顾。4.2 训练配置输入尺寸、anchor与增广参数配置这块我按车牌任务的特点来调跟通用检测不一样的地方我逐条说明理由。输入尺寸。通用检测常用640但车牌是小目标我建议从768或者960起步如果显存扛得住就上1280。这里的计算逻辑很直接假设原图车牌宽100像素原图宽1920缩到640后车牌宽只剩33像素网络总下采样32倍后特征图上不到1个像素缩到1280后车牌宽67像素下采样后还有2个像素的响应这在检测头能区分的边缘上。代价是显存和推理耗时实测下来960到1280是车牌任务比较舒服的区间。anchor或者先验框。车牌长宽比集中如果框架支持自定义anchor直接把宽高比调到2到5这个区间用k-means在自己的训练集上聚类一遍最稳。用anchor-free的框架就省掉这一步但要注意中心点采样的半径设置车牌宽度小半径设大了会把大量背景点算成正样本。数据增广这块坑最多我单独说。马赛克增强要慎用因为车牌是有明确语义边界的刚性矩形马赛克拼接会大量产生半个车牌和被裁断的车牌模型会学出一堆切边响应虚警率明显上升。如果非要用把拼接后的目标面积过滤阈值调高把小于原始面积一定比例的目标直接丢弃。HSV色彩抖动要收窄车牌底色的颜色本身就是强特征蓝色、黄色、绿色对应的车型类别不同H通道抖过头会让蓝牌变绿牌模型学到的颜色先验就乱了我的经验是H通道控制在正负10度以内S和V可以放宽到正负30%。随机缩放和随机裁剪可以做但要保证裁剪后车牌不被切掉这个在实现上一般通过检查框的完整性来过滤。旋转增强要控制在小角度车牌在大角度旋转下会变成不自然的形状而且真实场景里车牌相对地面基本是水平或小幅倾斜的。学习率和训练轮次。数据集规模不大我一般用预训练权重初始化学习率设在1e-3到1e-4之间配合warmup和余弦退火。轮次不用太多几十到一百多轮基本就收敛了跑太多只会过拟合。判断过拟合的信号很直接训练loss继续降但验证集的AP开始原地踏步甚至下滑。4.3 评测与结果解读别只看mAP评测阶段我最想强调的一点是mAP是个被平均过的数字它会藏起你最需要知道的信息。我通常会把评测结果拆成四张表来看。第一张是按IoU阈值展开的AP曲线。AP0.5、AP0.6、AP0.75三个数字放在一起看如果0.5很高但0.75掉得厉害说明模型能大概找到但框不准这对下游识别是致命的。这种情况的解法通常是提升标注质量、增加回归分支的loss权重、或者加入角点回归辅助。第二张是按目标尺寸分组的AP。小、中、大三组的差距如果超过十几个点说明尺度问题没有解决好该调输入分辨率或者FPN结构。第三张是不同场景条件下的AP。如果数据集带了天气、时段这类元信息一定要分组统计。我见过整体AP很高但夜间AP惨不忍睹的模型这种模型在真实部署里几乎不可用。如果数据集没有这些元信息可以自己用图像亮度、对比度做近似分组。第四张是虚警和漏检的可视化样本。AP是数字但真正让你知道该怎么改的是那些画了框的错图。我一般按置信度排序把FP里置信度最高的二十张和FN里最典型的二十张导出来看。高置信度虚警基本能一眼看出规律车牌图案、广告牌、反光条、其他车辆的尾灯组合。漏检样本也有规律极端小目标、严重遮挡、和背景颜色接近的车牌。提示评测集一定要和训练集严格隔离不要为了指标好看反复在测试集上调参。我自己的做法是测试集跑一次记下数字之后所有的调参都在验证集上做只有最终定版才碰测试集。5. 踩坑记录与排查技巧这部分是我觉得最有价值的地方因为论文不会写文档也不会写只有真跑过才知道。5.1 数据层面的五个坑第一个坑是坐标越界。标注里偶尔会出现x2超过图像宽度、或者坐标是负数的框。这种框在转格式的时候如果不做裁剪归一化之后会大于1或者小于0在某些框架里会直接导致loss变成NaN。我的做法是在转换脚本里强制裁剪并且把被裁剪超过一定比例的框打上标记人工复核。第二个坑是极扁或极细的框。有人标车牌的时候手抖画出一条高度只有两三个像素的框或者宽度是整个图像宽度但高度只有十像素。这类框在统计里一眼能看出但如果不体检它们会一直混在训练集里污染回归分支。第三个坑是同图重复标注。同一张图里的同一个车牌被标了两次两个框轻微错位。这会让NMS在训练标签分配阶段产生两个正样本互相竞争模型学出来的框会落在两者中间。检测方法是按IOU做组内自比较IOU超过0.85的框对就该人工看一眼。第四个坑是图像和标注的通道顺序不一致。有的图是BGR存的有的是RGB有的带alpha通道。这个坑在训练时表现得很隐蔽模型不是完全学不动而是学得比预期差一截颜色相关的特征全部错位。稳妥做法是读图后统一转成RGB三通道用cv2读的话记得加一步cvtColor。第五个坑是训练测试集泄漏前面反复提过这里再强调一次具体检查方法抽取测试集每张图的感知哈希去训练集里查最近的几个相似度排名前列的逐张人工确认。宁可多花两小时检查也不要带着虚高的指标上线。5.2 训练层面的四个坑第一个坑是正样本太少导致loss震荡。车牌小、每图数量少正样本可能只占总样本的千分之几直接训练会出现loss在前几十轮里不断爆掉的情况。解法一般是用预训练权重、加warmup、或者对正样本做loss加权。我实际用下来warmup加上分类loss的focal变体基本能稳住。第二个坑是NMS阈值照抄通用配置。通用检测的NMS阈值常在0.45到0.5但车牌场景下同一辆车很少出现两个真实车牌重叠所以阈值可以调低一点来压虚警比如0.4。但如果画面里有前后车牌在透视下产生较大重叠阈值太低又会把真车牌误删这个得看你的实际场景实测。第三个坑是过多依赖颜色特征。如果你发现模型在换了颜色的测试集上掉点明显说明它学的主要是颜色不是形状。解法是在增广里加入灰度化、颜色通道随机交换这类操作逼模型去学结构特征。这个技巧在处理各种颜色的车牌时特别有效。第四个坑是导出部署时的预处理不一致。训练时用了letterbox填充、归一化参数是某个均值方差推理时忘了对齐结果线下指标很好线上完全不对。我建议在训练脚本里就把预处理封装成一个函数导出模型时把这个函数的参数一起存下来避免手写推理代码时凭记忆填错。5.3 常见问题速查表我把上面这些内容整理成一张表方便对着查现象最可能的原因优先排查动作loss从第一轮就是NaN坐标越界或归一化错误检查转换后坐标是否全在0到1之间loss能降但mAP不涨标注边界不一致或存在重复标注抽样可视化做IOU自比较去重训练集指标极高验证集很差数据泄漏或过拟合做感知哈希查重加增广减轮次夜间或逆光场景AP骤降训练集光照分布偏窄分组统计补充困难样本高置信度虚警集中在广告牌负样本挖掘不足收集难负样本加入训练小目标几乎全漏输入分辨率不够或anchor不匹配提升输入尺寸重新聚类anchor框能检出但明显偏移回归分支权重低或标注有系统偏差加大回归loss权重复核标注边界同一目标出现多个框NMS阈值过高适当下调NMS阈值并实测换车色后效果明显下降过度依赖颜色特征加灰度化与颜色扰动增广6. 从CRPD往后还能做什么数据集跑通只是起点车牌这个方向的完整链路是检测加识别而且识别部分的数据需求跟检测完全不同。6.1 检测框到字符识别的衔接检测和识别之间有一个经常被低估的环节几何校正。检测出来的车牌往往是倾斜的尤其是路侧视角下倾斜角度可能到二三十度。直接把斜框裁出来送进识别网络识别率会明显下降因为字符的排列在图像里变成了斜线序列识别模型的对齐机制会被干扰。如果数据集带角点标注这一步就非常好办用四点透视变换把车牌拉成正视图即可。实现上就是标准的getPerspectiveTransform加warpPerspective目标尺寸按车牌的宽高比设成固定值比如94乘24或者120乘40。如果只有水平框退而求其次可以用最小外接矩形加旋转校正但效果会差一些。还有一点容易被忽略检测框的宽松程度要针对识别任务重新调。检测阶段为了提升泛化性框可能会稍微宽松一点但识别网络对边界很敏感多出来的一圈背景会引入噪声。我一般的做法是在检测框的基础上按固定比例收缩或者干脆训练一个专门针对识别任务微调的小检测头。6.2 数据合成与域自适应真实车牌数据标注成本高尤其是带字符标注的。合成数据是一条很实用的路用字体渲染车牌文本贴到各种背景上再加入真实的光照、模糊、噪声扰动。这条路的坑在于合成与真实的域差异直接用合成数据训出来的模型到真实场景上会掉得很厉害。比较有效的缓解手段是在合成数据上做更强的域随机化——背景从真实无车牌图像里随机抠光照和噪声参数范围开得比真实分布更宽模糊核用多种类型混合。另一个手段是用少量真实数据做微调哪怕只有几百张也能把域差异拉近很多。我自己试过的组合是大量合成加少量真实效果比纯真实小样本训出来的稳不少。至于数据集本身的扩展方向我建议是在自己的业务场景里持续采集困难样本尤其是那些模型判错的帧。CRPD给的是一个通用的起点但真正决定上线效果的永远是你自己场景里那些长得特别的车牌。我个人的习惯是每周把线上推理的错例捞出来人工确认后补进训练集几个月下来积累的困难样本比任何公开数据集都管用。最后分享一个我在数据标注上一直坚持的小习惯标注规范一定要写成文档而且带正反例图。文字描述框要贴紧车牌外框和给出一张画好的示意图标注员的产出质量能差出一倍。这件事在你只有自己一个人的时候显得多余但只要涉及到第二个人参与标注这份文档就是数据质量的生命线。
返回列表