news 2026/10/24 1:49:50

黄牌车牌检测数据集:json标签校验与YOLO/COCO转换避坑

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
黄牌车牌检测数据集:json标签校验与YOLO/COCO转换避坑

简介:这是一份面向车牌检测与字符识别任务的黄牌图像数据集,适合计算机视觉学习者、算法开发者及课程设计、项目实训使用。数据覆盖多种拍摄角度,标注采用polygon多边形目标框,四个顶点分别对应车牌四角,可更贴合倾斜、透视场景下的车牌轮廓,为检测模型训练与字符识别预处理提供直接可用的标注基础。所有图片经人工逐张筛选,剔除模糊与歧义区域,减少后续清洗成本。压缩包共9324个文件,其中4627张jpg、35张jpeg图像与4662个json标注文件,整体约257.79MB,图像与标签一一对应,便于按目录组织训练集和验证集。已有890人学习下载。对需要矩形框json格式的读者,作者也提供转换支持;无论是做黄牌检测、车牌定位还是字符识别流程验证,都能从中获得较完整的图像与标注素材。

1. 黄牌车牌检测数据集:不是“有框就行”,json标签先决定上限

某开发者拿一批黄牌车牌检测数据集做园区门口抓拍,训练损失降得很顺,推理时却总把黄色广告牌、收费亭反光条框成车牌。翻到数据层才发现,json标签里的框是中心点加宽高,转换脚本却按左上右下读,模型学的是一套偏移框。这个资源就是带json标签的黄牌车牌检测数据集,落在图像识别流程里,负责车牌识别之前的定位环节,适合卡口、停车场、园区门口这类黄牌车较多的场景,也适合想练json转YOLO、COCO标注口径的人。黄牌颜色是先验,不是标签;json字段没读透,训练越久偏得越远。下面从字段校验开始,把能复现的步骤和翻车点拆开。

2. 把json标签读透:字段探测、坐标校验与黄牌样本分布

2.1 先做字段探测,不要上来就硬编码键名

json标签最怕“看起来一样”。同样叫bbox,有的存[x_min, y_min, x_max, y_max],有的存[x, y, w, h],还有的存归一化后的中心点宽高。黄牌车牌检测数据集如果来自不同标注批次,字段名和层级都可能变。我一般不会先写转换脚本,而是先跑一个字段探测,把一份json里所有键路径打印出来,确认图像路径、宽高、标注列表、框字段、类别字段分别在哪一层。

import json from pathlib import Path def walk_keys(obj, prefix=""): """递归打印json键路径,列表只采样前3个元素,避免大文件卡住""" if isinstance(obj, dict): for k, v in obj.items(): yield prefix + k, v yield from walk_keys(v, prefix + k + ".") elif isinstance(obj, list): for i, v in enumerate(obj[:3]): yield from walk_keys(v, prefix + f"[{i}].") json_path = Path("labels/one_sample.json") data = json.loads(json_path.read_text(encoding="utf-8")) for key, value in walk_keys(data): # 只打印键路径和值类型,不打印整段base64或大数组 print(f"{key} -> {type(value).__name__}")

这段代码只做一件事:把嵌套结构摊平。walk_keys对字典逐层拼路径,对列表只取前三个元素,因为标注文件里objects或annotations可能很长,全量递归会拖慢排查。prefix用来保留层级,比如objects.[0].bbox能直接看出框在标注对象里,而不是在顶层。实际使用时先拿一份样本跑,确认键路径后再写批量脚本。

常见字段命名可以对照下表,但不要把它当标准。表里只是排查方向,最终以实际json为准。

信息类型常见键名要确认的点
图像路径imagePath、image_path、file_name是相对路径还是绝对路径,根目录在哪
图像宽高width、height、imageWidth与真实读图尺寸是否一致
标注列表objects、annotations、shapes是列表还是按类别分组的字典
框坐标bbox、points、box是四个数还是两个点,是否归一化
类别label、category、class_name大小写、中英文、是否有空格

提示:字段探测阶段不要急着改json,先把原始键路径和值类型记录下来。后面转换脚本报错时,这份记录就是后悔药。

2.2 坐标口径与越界检查:四个必须落库的校验

确认字段后,下一步不是直接转YOLO,而是做坐标校验。黄牌车牌在图像里通常偏小,框偏移几个像素肉眼看不出来,但归一化之后会被放大。我一般要求四个校验必须落库:坐标数值有限、右下大于左上、框不越界、json宽高与真实读图尺寸一致。前三个决定框能不能用,第四个决定归一化分母对不对。

import math from PIL import Image def to_xyxy(bbox, fmt, w, h): """把不同口径的框统一成绝对像素xyxy""" if fmt == "xyxy": x1, y1, x2, y2 = bbox elif fmt == "xywh": x, y, bw, bh = bbox x1, y1, x2, y2 = x, y, x + bw, y + bh elif fmt == "cxcywh": cx, cy, bw, bh = bbox x1, y1, x2, y2 = cx - bw / 2, cy - bh / 2, cx + bw / 2, cy + bh / 2 elif fmt == "norm_xyxy": x1, y1, x2, y2 = bbox[0] * w, bbox[1] * h, bbox[2] * w, bbox[3] * h elif fmt == "norm_cxcywh": cx, cy, bw, bh = bbox x1, y1 = (cx - bw / 2) * w, (cy - bh / 2) * h x2, y2 = (cx + bw / 2) * w, (cy + bh / 2) * h else: raise ValueError(f"未知坐标口径: {fmt}") return x1, y1, x2, y2 def check_bbox(bbox, fmt, img_path, tol=2.0): img = Image.open(img_path) w, h = img.size x1, y1, x2, y2 = to_xyxy(bbox, fmt, w, h) if not all(math.isfinite(v) for v in (x1, y1, x2, y2)): return "non_finite" if x2 <= x1 or y2 <= y1: return "invalid_wh" # 允许少量越界,超过tol像素就记为异常,不要静默裁剪 if x1 < -tol or y1 < -tol or x2 > w + tol or y2 > h + tol: return "out_of_bound" return "ok"

to_xyxy把五种常见口径统一成绝对像素左上右下。fmt必须由字段探测确认,不能猜。check_bbox里tol=2.0是容忍少量像素越界,因为标注工具缩放时可能产生1到2像素误差;超过这个范围就记异常,而不是直接裁剪。裁剪会把错误藏起来,后面评估时看不出问题。实际落地时建议把原始框、统一后的框、异常类型一起写进检查表,方便回查。

如果json里有width和height,还要和Image.open(img_path).size比对。差异超过1像素就要查原因:是图像被重新缩放后没更新json,还是手机拍摄的EXIF方向导致读图尺寸旋转。EXIF问题可以用ImageOps.exif_transpose在读图时统一方向,再以旋转后的尺寸为准。

2.3 用统计和可视化找“黄牌偏科”

黄牌车牌检测数据集容易“偏科”:白天多、夜间少,近景多、小目标少,干净车牌多、泥污遮挡少。只看总框数没意义,要看每图框数、框面积占比、宽高比和黄色像素比例的分布。框面积占比能判断小目标比例,宽高比能发现异常扁框,黄色像素比例能辅助看颜色先验是否稳定,但它不是标签,不能拿来当训练目标。

import numpy as np from PIL import Image from pathlib import Path def yellow_ratio(img_path): """粗略统计黄色像素比例,只用于分布检查,不参与训练标签""" img = Image.open(img_path).convert("RGB") arr = np.asarray(img).astype(np.float32) / 255.0 r, g, b = arr[..., 0], arr[..., 1], arr[..., 2] # 黄色大致满足:红绿高、蓝低;阈值只用于观察,不作为硬规则 mask = (r > 0.45) & (g > 0.35) & (b < 0.45) & (r > b + 0.12) & (g > b + 0.08) return float(mask.mean()) def bbox_area_ratio(bbox, fmt, w, h): x1, y1, x2, y2 = to_xyxy(bbox, fmt, w, h) return max(0.0, (x2 - x1) * (y2 - y1)) / (w * h)

yellow_ratio用RGB近似黄色,阈值写成比例而不是固定0到255,方便不同曝光图像比较。bbox_area_ratio算框面积占全图比例,输出分位数比看均值可靠。实际排查时把面积占比分成<0.1%、0.1%到1%、>1%三档,看验证集和训练集比例是否接近。如果训练集小目标多、验证集近景多,mAP会虚高,业务现场却掉点。

注意:黄色像素比例只适合做分布观察。夜间暖光、泥污、反光条都会让黄色比例失真,把它当过滤条件会埋下漏检。

2.4 划分训练验证集:按场景分组,别按文件随机

黄牌车牌检测数据集常见连拍:同一辆车在同一个门口连续几张,文件名只差序号。按文件随机划分,训练集和验证集会同时出现同一辆车的相邻帧,指标看起来很好,换场景就崩。我一般按场景分组:目录名、文件名前缀、拍摄点位、时间段,任选一个能代表“场景”的键,保证同一组只进一个split。

from collections import defaultdict from pathlib import Path import random def group_key(json_path: Path): # 按父目录名分组;如果文件名前缀更能代表场景,可改成 json_path.stem.split("_")[0] return json_path.parent.name json_files = sorted(Path("labels").rglob("*.json")) groups = defaultdict(list) for p in json_files: groups[group_key(p)].append(p) keys = list(groups.keys()) random.Random(42).shuffle(keys) train, val, test = [], [], [] for i, k in enumerate(keys): # 7:2:1 按组划分,组内文件整体进入同一个split if i % 10 < 7: train.extend(groups[k]) elif i % 10 < 9: val.extend(groups[k]) else: test.extend(groups[k])

group_key是划分的核心。父目录名通常对应一个拍摄批次或一个场景,比文件名随机稳。random.Random(42)固定种子,方便复现。i % 10实现7:2:1,组数少时可以改成按组大小分层,避免某个split没有小目标。划分完要再跑一次统计,确认训练集和验证集的框面积分位数、黄色比例分位数没有明显断层。断层太大就先调分组键,不要急着训练。

3. 从json转到YOLO与COCO:转换脚本、参数口径和回读自检

3.1 选YOLO还是COCO:看训练框架和后续标注回流

json标签转格式,先定目标格式。YOLO的txt适合单阶段检测训练,每行类别 id cx cy w h,全部归一化到0到1;COCO的json适合多工具协作和标注回流,bbox是绝对像素[x, y, w, h],area是面积,category_id从1开始更常见。黄牌车牌检测数据集如果只做单类plate,YOLO txt最轻;如果团队还要用标注平台复标、做数据版本管理,COCO json更稳。

维度YOLO txtCOCO json
坐标口径归一化中心点宽高绝对像素左上宽高
类别 id通常从0开始通常从1开始
空标签生成空txt表示负样本没有annotation也要有image记录
适合场景快速训练、单类检测多工具协作、标注回流
易错点归一化分母、类别顺序image_id、category_id、area

选型不是技术高低,是流程匹配。单类黄牌车牌检测,YOLO txt足够;如果后续要加颜色分类、车型分类,COCO json的扩展字段更从容。转换前把class_map固定下来,比如{"plate": 0},不要在不同脚本里各写一套。

3.2 写一个可复用的json转YOLO脚本

转换脚本要处理三件事:找到标注列表、统一框口径、把类别名映射成id。未知类别必须报错,不能静默跳过,否则训练时类别数对不上。空标注也要生成空txt,YOLO训练需要负样本。

import json from pathlib import Path from PIL import Image CLASS_MAP = {"plate": 0} # 黄牌数据集单类时固定为0;多类时在这里统一顺序 def iter_objects(data): """兼容 objects / annotations / shapes 三种常见标注列表""" for key in ("objects", "annotations", "shapes"): value = data.get(key) if isinstance(value, list): return value return [] def pick_bbox(obj): for key in ("bbox", "box", "points"): if key in obj: return obj[key] raise KeyError(f"找不到框字段: {obj.keys()}") def pick_label(obj): for key in ("label", "category", "class_name", "name"): if key in obj: return str(obj[key]).strip() raise KeyError(f"找不到类别字段: {obj.keys()}") def convert_one(json_path, img_path, out_txt, fmt="xyxy"): data = json.loads(Path(json_path).read_text(encoding="utf-8")) w, h = Image.open(img_path).size lines = [] for obj in iter_objects(data): label = pick_label(obj) if label not in CLASS_MAP: raise ValueError(f"未知类别 {label},先补 CLASS_MAP") x1, y1, x2, y2 = to_xyxy(pick_bbox(obj), fmt, w, h) # 归一化并保留6位小数,减少txt体积 cx = (x1 + x2) / 2 / w cy = (y1 + y2) / 2 / h bw = (x2 - x1) / w bh = (y2 - y1) / h lines.append(f"{CLASS_MAP[label]} {cx:.6f} {cy:.6f} {bw:.6f} {bh:.6f}") Path(out_txt).write_text("\n".join(lines), encoding="utf-8")

iter_objects按常见键名找标注列表,找到第一个列表就返回,避免同一份json里多个字段重复。pick_bbox和pick_label把字段差异收敛到两个函数,后面换数据集只改这里。CLASS_MAP必须显式定义,未知类别直接抛错,这是血泪经验:静默跳过会让某类样本在训练集里消失,评估时才发现召回上不去。fmt要和字段探测结果一致,传错就是框整体偏移。空标注时lines为空,仍然写出空txt,负样本才有记录。

提示:转换前先用一份样本打印前5个框的原始值和转换后的归一化值,肉眼确认中心点落在车牌上,再跑批量。

3.3 转COCO时最容易错的两个字段

COCO json有两个字段最容易翻车:image_id和category_id。image_id是图像记录的唯一整数,annotation里的image_id必须和images里的id一致;category_id通常从1开始,YOLO习惯从0开始,直接混用会让类别错位。bbox写绝对像素[x, y, w, h],area写w * h,不要写归一化值。

coco = { "images": [], "annotations": [], "categories": [{"id": 1, "name": "plate"}], } ann_id = 1 for image_id, (json_path, img_path) in enumerate(pairs, start=1): w, h = Image.open(img_path).size coco["images"].append({"id": image_id, "file_name": str(img_path), "width": w, "height": h}) data = json.loads(Path(json_path).read_text(encoding="utf-8")) for obj in iter_objects(data): x1, y1, x2, y2 = to_xyxy(pick_bbox(obj), fmt, w, h) bw, bh = x2 - x1, y2 - y1 coco["annotations"].append({ "id": ann_id, "image_id": image_id, # 必须等于 images 里的 id "category_id": 1, # 与 categories 里的 id 对齐 "bbox": [x1, y1, bw, bh], # 绝对像素,不是归一化 "area": bw * bh, "iscrowd": 0, }) ann_id += 1

这段代码里image_id用enumerate生成,保证唯一;category_id固定1,和categories一致。bbox是[x1, y1, bw, bh],不是[x1, y1, x2, y2],这是COCO和YOLO最大的口径差。area用于评估时区分小中大目标,黄牌车牌大多落在小目标区间,area写错会影响分层指标。iscrowd=0表示普通实例,黄牌检测一般不用crowd标注。

3.4 转换后回读自检:三类断言

转换脚本跑完不等于正确。我一般做三类断言:每张图有对应txt、每行五列且类别id在集合内、反算像素框与原始json框的IoU大于0.999。IoU断言能抓住中心点宽高和左上右下混用的问题,比肉眼看几张图可靠。

def yolo_to_xyxy(line, w, h): cls_id, cx, cy, bw, bh = line.split() cx, cy, bw, bh = map(float, (cx, cy, bw, bh)) x1 = (cx - bw / 2) * w y1 = (cy - bh / 2) * h x2 = (cx + bw / 2) * w y2 = (cy + bh / 2) * h return int(cls_id), x1, y1, x2, y2 def iou(a, b): ax1, ay1, ax2, ay2 = a bx1, by1, bx2, by2 = b ix1, iy1 = max(ax1, bx1), max(ay1, by1) ix2, iy2 = min(ax2, bx2), min(ay2, by2) iw, ih = max(0.0, ix2 - ix1), max(0.0, iy2 - iy1) inter = iw * ih union = (ax2 - ax1) * (ay2 - ay1) + (bx2 - bx1) * (by2 - by1) - inter return inter / union if union > 0 else 0.0

回读时对每张图读原始json框和txt反算框,逐框算IoU。阈值设0.999,因为只差浮点舍入;低于这个值就打印原始框、反算框和fmt,十有八九是口径传错。类别id也要断言在set(CLASS_MAP.values())里,防止把plate写成Plate后映射失败。空txt要允许存在,但要在检查表里标记为负样本,不要当成转换失败。

4. 黄牌检测训练:基线配置、增强边界与误检分析

4.1 单类检测还是多类检测:先定标签语义

黄牌车牌检测数据集先定标签语义。如果json里只有plate,就做单类检测,输出一个框,颜色信息交给后处理或单独分类器。如果json里明确分了yellow_plate、blue_plate,可以保留多类,但类别顺序必须和CLASS_MAP一致。不要因为图像是黄牌就把颜色塞进类别名,除非标注本身这么定义。单类的好处是减少类间混淆,黄牌颜色先验在推理阶段做二次校验更灵活。

单类训练时names只写0: plate,评估只看一类AP。多类训练时每个类别都要有足够样本,否则小类别会把整体mAP拉低。黄牌场景里如果混入少量蓝牌负样本,可以把蓝牌车牌标成背景不框,或者单独加一类,取决于业务要不要拒绝蓝牌。标签语义定不下来,后面转换、训练、评估都会反复。

4.2 基线训练配置与黄牌小目标参数

基线配置先跑通,不要一上来堆增强。黄牌车牌在卡口图里往往只占几十像素,imgsz比模型大小更关键。我一般从960起步,显存不够再降;batch按显存调,lr0用常规值,patience留早停。数据配置文件只写路径和类别,不写花哨参数。

path: /data/plate_yellow train: images/train val: images/val names: 0: plate
yolo detect train \ data=data.yaml \ model=<预训练权重> \ imgsz=960 \ epochs=100 \ batch=16 \ lr0=0.01 \ patience=20 \ workers=8 \ project=runs/plate \ name=yellow_baseline

path是数据集根目录,train和val写相对路径,避免换机器后失效。imgsz=960是为了保住小目标细节,黄牌车牌在640下可能只剩十几个像素。batch=16不是固定值,显存不够就降到8,同时按比例调lr0。patience=20表示验证指标20轮不升就停,省时间。workers=8按CPU核数调,太高反而拖慢数据加载。第一次训练先关掉强增强,确认loss正常下降,再加。

增强参数要克制。马赛克增强会把多张图拼在一起,小目标可能被切碎;黄牌颜色对HSV增强敏感,色相扰动过大可能把黄色推到橙色。常见做法是先把马赛克关小或关掉,随机缩放范围不要压得太狠,HSV的饱和度和明度扰动保留,色相扰动调低。具体值看验证集,不要照搬。

参数基线建议调整理由
imgsz960起黄牌车牌小,分辨率比模型深度更直接
batch显存允许的最大值小目标梯度噪声大,batch太小不稳定
lr00.01附近预训练权重微调,过大容易震荡
mosaic先低后高小目标被切碎后反而学不到完整车牌
hsv_h调低黄色色相范围窄,扰动过大改变颜色语义
patience20到30小目标指标波动大,早停太早会误杀

注意:验证集指标不升不一定是模型不行,先回看标注框是否偏移、验证集是否和训练集同场景。数据层的问题,调参救不回来。

4.3 评估指标怎么看:mAP之外还要看召回分层

评估命令把置信度阈值压低,先看PR曲线全貌,再定业务阈值。黄牌检测不能只看mAP50,小目标多的时候mAP50-95会明显低,这是正常现象。要看召回按框面积分层:小框召回够不够,夜间子集召回掉多少,误检集中在什么背景。

yolo detect val \ model=runs/plate/yellow_baseline/weights/best.pt \ data=data.yaml \ imgsz=960 \ conf=0.001 \ iou=0.6

conf=0.001是为了让PR曲线覆盖低置信度区间,评估阶段不怕框多,怕漏。iou=0.6是NMS和匹配的常用值,黄牌车牌框比较规整,0.5到0.6都可以试。看结果时先看召回,再看精确率。业务现场漏检比误检更麻烦,阈值可以偏低,误检交给二次校验。

指标关注点异常信号
mAP50框大致重合时的综合表现高但现场漏检,查验证集泄漏
mAP50-95高IoU下的定位精度明显低,查小目标和框偏移
Precision误检比例低,查黄色广告牌、反光条
Recall漏检比例低,查夜间、遮挡、小目标
分层AP按面积/场景拆开小框AP远低于大框,调imgsz和增强

评估完不要只看一个总分。把验证集按白天/夜间、近景/远景、干净/遮挡拆开,分别跑一遍。黄牌车牌检测数据集如果夜间样本少,整体mAP会被白天拉高,夜间召回可能很难看。拆开看才知道下一步是补数据还是调增强。

4.4 误检分析:黄色先验不能当硬规则

黄牌检测的误检经常来自黄色物体:广告牌、反光条、收费亭、工程车车身。颜色先验可以做二次校验,但不能在检测前硬过滤。硬过滤会把夜间暖光下的黄牌、泥污车牌、偏色图像直接删掉,漏检比误检更难补。我一般把检测框裁出来,统计框内黄色像素比例,看误检和真检的分布是否可分,再决定阈值。

import numpy as np from PIL import Image def crop_yellow_ratio(img_path, xyxy): img = Image.open(img_path).convert("RGB") x1, y1, x2, y2 = map(int, xyxy) crop = np.asarray(img.crop((x1, y1, x2, y2))).astype(np.float32) / 255.0 if crop.size == 0: return 0.0 r, g, b = crop[..., 0], crop[..., 1], crop[..., 2] mask = (r > 0.45) & (g > 0.35) & (b < 0.45) & (r > b + 0.12) & (g > b + 0.08) return float(mask.mean())

这个函数只做统计,不直接过滤。把真检和误检的黄色比例分别画分布,如果真检集中在高分段、误检集中在低分段,可以设一个保守阈值做二次排序,而不是一刀切。阈值取分位数,比如保留真检95%召回对应的下限,再看误检能压掉多少。夜间和逆光样本要单独看,否则阈值会被白天样本带偏。

5. 避坑与排查:json标签落地时最容易翻车的五件事

5.1 框整体偏移:中心宽高与左上右下混用

现象很典型:训练loss正常下降,验证集mAP也有零点几,但推理框整体往左上或右下偏,车牌只框到一半。原因是json里存的是中心点宽高cx, cy, bw, bh,转换脚本按左上右下x1, y1, x2, y2读,中心点被当成左上角,框整体偏移半个宽高。黄牌车牌框本来就小,偏一点就掉出车牌。

解决不靠肉眼抽查,靠回读断言。转换后把txt反算成像素框,和原始json框算IoU,低于0.999就报错。to_xyxy里把fmt作为必填参数,不允许默认值,逼着调用方确认口径。批量转换前先拿一份样本打印原始框和反算框,确认中心点落在车牌中心。字段探测阶段看到bbox是四个数还不够,要看数值范围:如果数值都小于1,可能是归一化;如果宽高明显小于坐标,可能是宽高格式。

5.2 图像尺寸字段与实际读图不一致

现象是归一化后的框整体缩放错位,或者同一批数据里部分图正常、部分图偏移。原因是json里的width、height是标注时的尺寸,图像后来被重新缩放、裁剪,或者手机EXIF方向导致读图尺寸旋转,json没同步更新。用json尺寸做归一化分母,就会把错误放大到所有框。

解决是以真实读图尺寸为准,不用json宽高做分母。读图时先做EXIF方向校正,再取size。如果json宽高和读图尺寸差异超过1像素,记录下来,抽样看是缩放还是旋转。批量脚本里不要把json宽高当唯一真值,它只能做交叉校验。遇到旋转图,先把图像转正再标注或转换,不要一边转一边用旧尺寸。

from PIL import Image, ImageOps def read_size(img_path): img = Image.open(img_path) img = ImageOps.exif_transpose(img) # 先按EXIF转正 return img.size

ImageOps.exif_transpose返回转正后的图像,size才是视觉上的宽高。黄牌车牌如果横竖方向不一致,框的宽高比会异常,统计时很容易发现。

5.3 训练验证集连拍泄漏导致指标虚高

现象是验证集mAP很高,换一个门口或换一天就掉得厉害。原因是同一辆车、同一个场景的连拍图被随机分到训练集和验证集,模型记住了背景和车牌字符,不是学会定位。黄牌车牌检测数据集如果按文件随机划分,相邻帧几乎一模一样,指标虚高是必然的。

解决是按场景分组划分。用目录名、文件名前缀、拍摄点位、时间段做group_key,保证同一组只进一个split。划分后检查训练集和验证集的框面积分位数、黄色比例分位数,差异大就换分组键。连拍图还可以用感知哈希或文件大小近似去重,但不要只靠文件名序号,序号可能跨场景重复。

5.4 类别名大小写与中英文不一致

现象是转换时报未知类别,或者训练时类别数对不上,评估混淆矩阵里出现空类。原因是json里同一类写成plate、Plate、车牌、车牌,CLASS_MAP只写了一个键。静默跳过未知类别会让样本悄悄消失,训练集里某类样本变少,召回上不去。

解决是先统计所有类别名,再定映射表。统计时用strip()去空格,但不要自动转小写,先把原始值列出来,人工确认哪些是同一类。CLASS_MAP里未知类别必须抛错,不能continue。映射表单独存一份json或csv,转换脚本和评估脚本共用,避免两处各写一套。

from collections import Counter counter = Counter() for obj in all_objects: counter[pick_label(obj).strip()] += 1 print(counter)

Counter输出原始类别名和出现次数,先看有没有大小写变体、中英文混写、尾部空格。确认后再写映射,比如{"plate": 0, "Plate": 0, "车牌": 0},但训练时只输出一个id。映射表要版本化,后面加类别时先改表再转格式。

5.5 颜色阈值硬过滤造成漏检

现象是白天效果不错,夜间、逆光、泥污车牌漏检明显。原因是在检测前用固定HSV阈值过滤黄色区域,夜间暖光把黄牌照成橙色,泥污把饱和度拉低,阈值一卡就没了。黄牌颜色先验有用,但它是统计特征,不是硬门禁。

解决是把颜色放到检测后做二次校验,用分位数定阈值,不用固定值。先统计真检框的黄色比例分布,取保留95%真检的下限,再看误检能压掉多少。夜间样本单独统计,阈值可以放宽。检测器主输出仍然保留,颜色只做排序或复核,不直接删除框。这样即使颜色判断错了,还有检测框兜底。

6. 进阶用法:把黄牌检测接进业务流程的三个技巧

6.1 切片推理处理小目标

黄牌车牌在广角卡口图里可能只占几十像素,整图缩放到960再推理,小目标只剩几个像素。我一般用切片推理:把原图按重叠窗口切成若干块,分别推理后再把框映射回原图坐标,做一次NMS。切片大小和重叠率要看车牌像素分布,太小会增加误检,太大起不到放大作用。常见做法是切片边长取原图短边的三分之一到二分之一,重叠20%左右,先在一批验证图上比较整图推理和切片推理的小框召回,再定参数。切片推理耗时高,适合离线复核或重点点位,不适合所有帧全量跑。

6.2 颜色先验做二次校验而不是硬门禁

颜色先验放在检测后,用法是给每个框算黄色比例,再结合置信度做排序或复核。不要设一个固定阈值直接删框,而是看真检和误检的分布重叠区。重叠区大的样本送人工复核,重叠区小的按置信度处理。夜间、逆光、泥污单独分组统计,阈值分组设置。这样颜色是加分项,不是一票否决。黄牌车牌检测数据集的黄牌比例高,颜色特征确实有用,但业务现场的偏色和遮挡会让固定阈值翻车。

6.3 用json回写做人工复核闭环

模型跑完不要只保存txt,把检测结果回写成和原始json同结构的文件,带上图像路径、框、置信度、颜色比例,人工复核时直接看json和裁图。复核确认的框再回流到训练集,形成闭环。回写时保留原始image_id或文件名,不要打乱顺序;置信度低和颜色比例处于重叠区的样本优先送审。这样每次复核都在补数据,而不是一次性验收。

从那以后我每次拿到带json标签的数据集,都先把字段探测、坐标校验、回读断言跑一遍,再谈训练。黄牌车牌检测数据集的价值不在图像多,而在标签口径能不能复现。需要拿这份资源练手时,按资源页的获取方式取原始包,先跑字段校验和转换自检,再开训练,别急着上大模型。希望帮到你。

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

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

Windows 安卓应用安装指南:APK Installer 快速上手

Windows 安卓应用安装指南:APK Installer 快速上手 【免费下载链接】APK-Installer An Android Application Installer for Windows 项目地址: https://gitcode.com/GitHub_Trending/ap/APK-Installer Windows 上装安卓应用,电脑里并不会多出一台虚拟手机。APK Installe…

作者头像 李华
网站建设 2026/10/24 1:45:41

BYTEX命令行工具完全指南:一条CLI跑通回测、实盘节点与数据管理

【免费下载链接】bytex 项目地址&#xff1a; https://gitcode.com/gh_mirrors/byt/bytex 点击查看 免费下载 BYTEX 命令行工具&#xff08;bytex CLI&#xff09;是 .NET 交易引擎 BYTEX 的统一操作入口&#xff1a;一条命令即可运行历史回测、启动沙箱或实盘交易节点、管理 …

作者头像 李华
网站建设 2026/10/24 1:44:48

zapret-discord-youtube 深度解析:Windows平台网络优化技术实战指南

zapret-discord-youtube 深度解析&#xff1a;Windows平台网络优化技术实战指南 引言&#xff1a;网络环境优化之道 在当今互联网环境中&#xff0c;许多网络服务可能会遇到连接不稳定或访问受限的情况。zapret-discord-youtube项目应运而生&#xff0c;为Windows用户提供了一套…

作者头像 李华
网站建设 2026/10/24 1:44:44

KICAD规则优先级问题

kicad9.0在做PCB设计的时候&#xff0c;经常遇到小的封装和大的封装设计规则不兼容&#xff0c;最常见的就是BGA封装的设计规则和其他封装不兼容。今天遇到同样的问题&#xff0c;查找了网上的资料&#xff0c;尝试自定义设计规则、尝试重写封装的间距&#xff0c;每次设置完之…

作者头像 李华
网站建设 2026/10/24 1:44:42

用街霸 3 实时对战评估 LLM:llm-colosseum 快速上手

用街霸 3 实时对战评估 LLM&#xff1a;llm-colosseum 快速上手 【免费下载链接】llm-colosseum Benchmark LLMs by fighting in Street Fighter 3! The new way to evaluate the quality of an LLM 项目地址: https://gitcode.com/GitHub_Trending/ll/llm-colosseum be…

作者头像 李华
网站建设 2026/10/24 1:44:40

四步把 Reachy Mini 应用搭建并部署到 Hugging Face

四步把 Reachy Mini 应用搭建并部署到 Hugging Face 【免费下载链接】reachy_mini Reachy Minis SDK 项目地址: https://gitcode.com/GitHub_Trending/re/reachy_mini Reachy Mini 是一款开源桌面机器人&#xff0c;它的 Python SDK 让你可以为它编写"应用"&a…

作者头像 李华