☰
基于YOLO v8的汽车充电插口识别数据集与训练实战
2026/10/2 3:43:09 网站建设 项目流程

简介:用于电动汽车充电口识别模型训练的标注数据集,面向目标检测开发者、学员以及充电设施运维人员,共包含1191张实拍充电插口图像,覆盖GB-AC与GB-DC两类主流接口,可直接支持YOLOv8模型训练与验证。压缩包内总计2000个文件,其中1191个txt文件为每张图像对应的YOLO格式标注,808个jpg文件是原始实拍图,另有1个yaml文件用于定义类别、路径和训练/验证集划分,整体仅22.26MB,下载与部署非常轻便。已有272人学习/下载。数据集标注规范、类别清晰,图像包含不同角度与光照条件,能有效提升模型在真实充电场景中的适应性,帮助使用者省去大量数据采集和人工标注成本,可直接用于充电口检测、自动充电引导及智能运维等项目,也可作为目标检测课程的教学案例或算法对比基准。

1. 汽车充电插口识别数据集:1191 张标注图直接喂给 yolo v8

做充电桩巡检或充电车位识别时,最磨人的不是算法选型,而是没有带标注的现场数据。这个数据集就是干这个用的:1191 张真实拍摄的汽车充电插口图片,已经按 YOLO 格式标注完,类别只有 GB-AC 和 GB-DC 两种,对应国标交流慢充和直流快充。拿到手不需要自己开 LabelImg 从零画框,直接按 yolo v8 的目录结构摆好就能训练。适合的目标很明确:你要做充电口类型识别、充电桩运营巡检、或者停车场里区分交流/直流车位,用它当底料跑通第一个可用的检测模型。下面我会从数据格式、训练参数、踩坑记录到验证技巧,完整过一遍。

2. 先看懂数据:GB-AC 与 GB-DC 的标注差异和处理思路

2.1 接口类型判定:充电枪头长什么样才算交流/直流

拿到数据集第一件事不是开训,而是确认两个类别到底在标什么。国标接口里,GB-AC 是交流慢充枪头,常见于家庭桩和目的地桩;GB-DC 是直流快充枪头,常见于高速服务区和城市快充站。两者物理形态上有硬区别:直流枪头是 9 孔,交流枪头是 7 孔,而且直流枪头明显更粗、更重,插座也更宽。标注的时候如果只看整体轮廓,很容易把两者搞混。

我的习惯是先打开十几张图片,对照标注框检查类别语义是否一致。有些标注框会把整个枪头和插座一起框进去,有些只框枪头金属接触部分。这个数据集既然叫“充电插口识别”,框的主体就应该包含枪头或插座能区分类型的关键特征。如果你后续要自己补充标注,建议框住枪头金属端加一部分外壳,不要只框接触孔,不然训练出来的模型对局部特征不敏感。

二分类任务看起来简单,但有一个隐含难点:交流口和直流口在远距离拍摄时,轮廓高度相似,都是圆形带凹槽。真正能区分的是孔位数量和排列。所以数据增强策略里,后面会提到不要随意做水平翻转——直流枪头有防呆设计,孔位排列是有方向性的,翻转后会改变视觉特征含义,这一点在标注规范里就要提前约定。

2.2 数据集目录与 YOLO 标签格式:坐标归一化和类别 ID

YOLO v8 的标准标签格式是每个图片对应一个同名 txt 文件,每行一个目标,五列内容依次是:

  • 类别 ID(从 0 开始)
  • 目标框中心点 x 坐标(归一化后,0~1)
  • 目标框中心点 y 坐标(归一化后,0~1)
  • 目标框宽度 w(归一化后,0~1)
  • 目标框高度 h(归一化后,0~1)

这个数据集已经按上述格式做好。假设类别映射是 0 代表 GB-AC,1 代表 GB-DC,那么一个典型的 label 文件内容大概像这样:

0 0.4825 0.5378 0.2131 0.2842 1 0.7513 0.6104 0.1720 0.2298

第一行表示图中有一个 GB-AC 充电口,它的中心点位于图片横向 48.25%、纵向 53.78% 的位置,宽度占整张图 21.31%,高度占 28.42%。后面的数字也都是相对图片尺寸的比例,不是像素绝对值。这样做的好处是图片尺寸变化时标签不需要重新计算,训练时不管输入 imgsz 设成 640 还是 416,坐标都能直接用。

需要提醒的是,YOLO 标签里所有坐标必须落在 0~1 区间。如果你拿到数据后想自己合并或重新切分,千万不要用整数像素坐标直接硬塞,必须先除图片宽高。常见翻车场景是把 OpenCV 读出来的 x1y1x2y2 像素坐标原样写入 txt,训练时损失直接炸掉或 mAP 一直为零。

2.3 标注质量检查:用脚本统计类别数量和异常框

不管数据集是下载的还是别人给的,我都会先做一轮体检。这里写一个简单的 Python 脚本,统计每个类别的数量,并检查标签坐标是否越界:

import os from pathlib import Path labels_dir = Path("dataset/labels") stats = {0: 0, 1: 0} bad_files = [] for txt in labels_dir.glob("*.txt"): for line in txt.read_text().strip().splitlines(): parts = line.split() if len(parts) != 5: bad_files.append((txt.name, "列数不对")) continue cid = int(parts[0]) x, y, w, h = map(float, parts[1:]) if cid not in stats: stats[cid] = 0 stats[cid] += 1 # 归一化坐标必须落在 0~1,且宽高为正 if not (0 <= x <= 1 and 0 <= y <= 1 and 0 < w <= 1 and 0 < h <= 1): bad_files.append((txt.name, f"越界: {line}")) print("类别统计:", stats) print("异常文件数:", len(bad_files)) for name, reason in bad_files[:20]: print(name, reason)

这段脚本做的事情分三步:先把所有标签文件逐行读出来;再按空格切分,校验列数是否为 5;最后检查归一化坐标是否都在合法范围。跑完之后,你会得到一个直观的数字,比如类别分布是 0 有 900 个、1 有 300 个,那训练时要考虑类别不平衡;如果异常文件数很多,说明标注工具有问题或导出过程损坏,需要先修数据再训模型。

类别不平衡的处理,我一般不会盲目加权重。先看数量差距,如果 GB-DC 只有 GB-AC 的三分之一,可以用 class weights 或简单地对少数类做随机复制(过采样)。yolo v8 在data.yaml里支持直接配置class_weights,但目前版本更推荐在训练参数中通过loss_opt自行调整,或者干脆用 mosaic 增强把少数类图片多参与几次混合。这里建议先跑一版不做特殊处理,看 baseline 的 per-class AP 差多少再决定。

3. 用 yolo v8 训练自己的充电插口识别模型:流程与参数

3.1 数据集划分与目录整理:train/val/test 怎么放

yolo v8 对数据集目录有约定,不是随便一个文件夹就能训。推荐按下面的结构摆放:

dataset/ ├── train/ │ ├── images/ │ │ ├── 001.jpg │ │ └── ... │ └── labels/ │ ├── 001.txt │ └── ... ├── val/ │ ├── images/ │ └── labels/ └── val2/ # 也可以叫 test ├── images/ └── labels/

划分比例我一般取 8:1:1,也就是 1191 张里约 950 张训练、120 张验证、120 张测试。如果原本的图片和标签都在同一个扁平目录里,直接用下面脚本划分:

import random from pathlib import Path import shutil src_imgs = Path("raw/images") src_labels = Path("raw/labels") out_root = Path("dataset") for split, ratio in [("train", 0.8), ("val", 0.1), ("test", 0.1)]: (out_root / split / "images").mkdir(parents=True, exist_ok=True) (out_root / split / "labels").mkdir(parents=True, exist_ok=True) all_files = list(src_imgs.glob("*.jpg")) + list(src_imgs.glob("*.png")) random.shuffle(all_files) n_total = len(all_files) n_train = int(n_total * 0.8) n_val = int(n_total * 0.9) # train + val 合计 90% for i, img_path in enumerate(all_files): label_path = src_labels / (img_path.stem + ".txt") if not label_path.exists(): print("缺少标签:", img_path) continue if i < n_train: split = "train" elif i < n_val: split = "val" else: split = "test" shutil.copy(img_path, out_root / split / "images" / img_path.name) shutil.copy(label_path, out_root / split / "labels" / label_path.name) print("划分完成, 总数:", n_total)

这段脚本的核心是三点:用random.shuffle打乱顺序,防止连续拍摄的相似图片全落在同一分区;按索引比例 8:1:1 切分;复制时检查同名标签是否存在,缺失的直接跳过并打印。要注意的细节是,测试集和验证集必须覆盖两类充电口,不能某个 split 里全是 GB-AC。经验做法是切分前先按类别把文件分组,再每组内均匀抽样,这样能避免极端分布。

3.2 训练命令与关键参数:imgsz、epochs、batch 怎么设

目录准备好后,写一个data.yaml指向数据集位置:

train: /path/to/dataset/train val: /path/to/dataset/val test: /path/to/dataset/test nc: 2 names: 0: GB-AC 1: GB-DC

然后开始训练,基础命令如下:

yolo train \ data=/path/to/data.yaml \ model=yolov8n.pt \ imgsz=640 \ epochs=100 \ batch=16 \ patience=20 \ project=runs/detect \ name=charger

这里几个参数值得展开讲。model=yolov8n.pt用的是 nano 版本,参数量最小,推理速度最快。充电插口目标不算极小但也不是大目标,nano 在 640 分辨率下能跑到 100 FPS 以上,如果部署在边缘盒子(Jetson 或 RK3588)上非常合适。如果你对精度更敏感,可以把yolov8n.pt换成yolov8m.pt或yolov8l.pt,但显存占用会线性上涨,batch 可能要降到 8。

imgsz=640选择原因:1191 张图原始分辨率我没法逐个确认,但充电口一般占画面 1/8 到 1/4,640 能保留足够特征。如果你发现自己的补充图片里充电口特别小,比如只有 30x30 像素,那么建议把 imgsz 提到 800,代价是训练和推理时间增加约 25%。

patience=20是早停参数,表示验证集 mAP 连续 20 个 epoch 不提升就停止训练。设置这个可以防止过拟合,也省时间。如果数据集噪声大,可以调大到 30;如果只是想快速验证流程,设成 10 就行。

3.3 训练结果里看什么:混淆矩阵和 PR 曲线

训练结束后,runs/detect/charger目录下会生成一系列结果文件。我最先看的是这三个:

文件作用重点关注
results.png训练/验证损失曲线box_loss 是否持续下降、是否过拟合
confusion_matrix.png类别混肴情况GB-AC 是否被误判为 GB-DC
PR_curve.png精确率-召回率曲线曲线下面积,整体 AP 水平

注意confusion_matrix_normalized.png才是百分比版本,看起来更直观。如果两类之间出现明显串扰,说明标注时类别边界没定准,或者图片里交流口和直流口同时出现(比如一根桩上挂了两把枪),这种情况在充电站很常见。解决思路是:训练时如果一张图里有两个目标,模型要学会同时输出两个框,不能只输出置信度最高的那个。yolo v8 默认就能输出多目标,所以问题通常出在标注漏标了其中一个。

PR 曲线上如果发现召回率很高但精确率掉得很快,说明模型倾向于把背景当目标;反过来精确率高但召回率低,说明漏检多。这两个趋势对应不同的调参方向,后面避坑章会具体说。

4. 避坑指南:标注、训练和推理阶段的五个常见问题

4.1 标注阶段:类别错标和边界框不统一

现象:训练集标签里 GB-AC 和 GB-DC 的框混在一起,有些框框住整把枪,有些框只框金属触点,导致模型收敛慢、验证 AP 忽高忽低。

原因:充电口在照片里经常被手或线缆遮挡,标注员只能凭局部特征判断,加上交流口和直流口外壳相似,仅看边缘很难区分。如果标注规范只说“框住充电口”,不同人理解的范围差异很大。

解决:重新审定标注规范。框的边界以枪头与插座接触面为准,横向上覆盖枪头主体,纵向上从枪头根部到插入端的可视部分。同时给标注员提供两种枪头的特写参考图,标注前用脚本随机抽 20 张做交叉复核。如果发现某一张图类别可疑,宁可不标也不要硬标——yolo 训练时错误标签的破坏力比漏标更大。

4.2 数据准备:标签坐标越界导致训练直接失败

现象:训练第一个 epoch 时 box_loss 是 nan,或者 loss 数值巨大,终止在几百步。

原因:标签 txt 里的归一化坐标出现大于 1.0 或小于 0 的数值,尤其是目标紧贴图片边缘时,标注工具导出的 x1y1x2y2 计算归一化后容易溢出。

解决:用第 2.3 节的脚本强制检查所有标签,发现越界立即修剪到 0~1 区间,然后重新训练。我还会额外检查标签中是否出现0 0.000 0.000 0.000 0.000这种空框,它通常来自漏标误存,需要手工删除。

4.3 训练阶段:数据集不平衡让少数类直接被忽略

现象:训练 100 轮后,confusion_matrix 里 GB-DC 的召回率只有 0.2,大部分都被预测成背景。

原因:1191 张图里如果 GB-DC 标签只占两三成,模型在损失函数优化时会偏向学多数类,因为没有强制对少数类错误施加更大惩罚。

解决:先统计类别比例,比例超过 1:3 就做两件事:一是用yolo的随机过采样,把少数类图片在训练列表里复制 2~3 份;二是开启mosaic=1.0,让少数类目标作为 mosaic 拼图的一部分参与更多迭代。最终验收标准要看 per-class AP,而不是整体 mAP。

4.4 推理阶段:充电口在画面边缘被裁掉

现象:模型对居中充电口识别很好,但实拍时充电口出现在画面边缘,框的位置明显偏移,甚至检测不到。

原因:训练集里很多图片的充电口位于画面中心,因为拍摄时操作者会主动把枪头对准镜头。模型对边缘目标的特征学习不足。

解决:训练时指定hsv_h=0.015, hsv_s=0.7, hsv_v=0.4等增强参数,并启用fliplr=0.5——但注意直流枪头方向性,翻转可能影响真实语义。更稳妥的做法是在推理端先检测整辆车或充电桩,再在局部区域里检测充电口,两阶段定位能避开边缘裁剪问题。

4.5 验证阶段:测试集和训练集存在同源图片

现象:验证 mAP 高达 0.98,但部署到新场景时 AP 骤降到 0.6。

原因:原始数据集可能是连续拍摄的同一辆车、同一个角度,划分时随机打乱后,训练集和验证集里存在相似度极高的帧,导致模型“记住”而非“学懂”。

解决:在切割数据集前,按文件名前缀或拍摄时间分组,确保同一辆车同一场景的图片只进一个 split。如果数据集没有元信息,至少按文件名的数字序号按序划分:前 80% 的文件名序号训练,后 20% 验证,避免随机 shuffle 把相邻帧拆散。

5. 验证与进阶:用混淆矩阵卡阈值,再迁移到其他接口识别

5.1 用 mAP 与置信度阈值找平衡

训练完不是拿起来就部署,先要确定推理置信度阈值。yolo v8 默认conf=0.25,但这个值对充电口场景不一定最合适。我会写一个脚本输出不同阈值下的混淆情况:

from ultralytics import YOLO model = YOLO("runs/detect/charger/weights/best.pt") results = model.predict(source="dataset/test/images", conf=0.5, save_txt=True) for r in results: boxes = r.boxes # 打印每个框的类别和置信度 for box in boxes: cls = int(box.cls[0]) conf = float(box.conf[0]) if cls == 1 and conf < 0.4: print("低置信度 GB-DC:", r.path, conf)

这段代码的核心是用conf=0.5跑一遍测试集,专门挑出少数类且置信度低于 0.4 的样本。如果这类样本多,说明少数类特征学习不到位,需要回上章平衡处理;如果只是个别样本,那么可以把部署阈值降到 0.35 以提升召回率。充电口识别属于安全相关场景,我建议阈值往高调(0.45 以上),宁可漏检人工复核,也不要误检把交流口说成直流口。

5.2 数据增强复用:从 GB 口迁移到 CHADEMO 或 CCS

这个数据集目前只覆盖 GB 口两种类型,但模型结构完全可以迁移到其他接口。把预训练权重换成yolov8n.pt继续训练你的新类别数据,然后冻结模型前 10 层只微调后几层,就能快速适配 CHADEMO、CCS1、CCS2 等接口。建议保留原有输出层,只替换类别数量,因为充电口特征空间是相通的——圆圈结构、孔位分布、枪头阴影都有相似性。

实际部署时,我通常会把模型输出接到一个简单判断逻辑:如果同时检测到 GB-AC 和 GB-DC,且两者框中心距小于 50 像素,说明这张图可能是同一个充电桩上的多把枪,要按面积较大的主目标输出结果。这个逻辑不是模型学的,而是业务规则补位,对小场景特别管用。

从那以后,我每次拿到新数据集都会强制走一遍:先跑标签体检脚本,再随机抽图人工核对类别语义,最后才划分数据集开训。这个流程看着多余,但至少帮我省下过两次“训练两小时后发现标签全错”的返工。数据集的标注质量直接决定模型上限,参数只是帮你接近那个上限而已。希望帮到你。

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询