
简介这是一份专为目标检测任务设计的扑克牌图像数据集采用YOLOV5标准目录结构适合需要训练检测模型的开发者、研究者以及入门深度学习的目标检测实战。数据集中包含52个类别即四种花色的A至K全部牌型图像尺寸统一为720×720的RGB图片训练集16000张、验证集4000张分别配有对应的txt标注文件可直接用于模型训练与验证无需额外格式转换。资源压缩包共有2000个文件其中1999个为txt标注及类别字典文件1个为可运行的可视化脚本整体大小约947.74MB。内置的Python脚本会随机读取一张图片并绘制边界框运行后自动保存在当前目录方便快速检查标注效果。目前已有134人学习下载适合用于扑克牌识别、棋牌场景目标检测等实际项目的前期数据准备。1. 这个数据集解决的不只是“有没有图”的问题52类别扑克牌检测的硬骨头在哪很多人拿到一个 YOLOv5 格式的目标检测数据集第一反应是“解压、开训、看 mAP”扑克牌这个场景却最容易在这套流程里翻车。一张牌面上同时存在“点数”和“花色”两类信息52 个类别意味着模型既要分清数字 3 和 5又要辨明红心和方块细粒度差异比区分“猫和狗”难得多。再加上牌面经常被旋转、重叠、反光公开的扑克牌检测数据集基本都是 YOLOv5 目录格式正好拿来做迁移学习和超参数调优的练手对象。这篇文章沿着“目录结构 → 标签含义 → 训练命令 → 踩坑 → 盲测验证”这条路把这个数据集从解压到出指标讲透适合准备用 YOLOv5 训练自己数据集、又不想在格式转换上浪费时间的从业者也适合刚入门目标检测、需要一个可控的小型数据集跑通全流程的新手。2. 先拆目录和标签YOLOv5 格式的数据集到底长什么样2.1 目录结构与类别文件先看清楚五个文件夹和一组映射YOLOv5 官方仓库对数据集的目录约定非常固定扑克牌数据集既然声明是 YOLOv5 目录格式解压后你看到的应该是这样的骨架poker_dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ # 可选部分版本只有 train 和 val ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ ├── classes.txt # 52 行每行一个类别名 └── data.yaml # 有的数据集直接给好了有的要自己写这里有个容易被忽略的点YOLOv5 训练时读取的是images/train和labels/train这对目录靠的是“同名不同后缀”来匹配图片和标签。也就是说images/train/A_of_Spades_001.jpg对应的标签文件必须是labels/train/A_of_Spades_001.txt多一个字符、少一个后缀图片就会被当成无标签样本跳过。这个数据集里每张图通常是一张或多张扑克牌的照片一张图对应一个 txttxt 里的行数就是这张图里标注的牌的数量。classes.txt 的排列顺序直接决定标签数值。常见的排列方式是按花色分组黑桃 A、黑桃 2……黑桃 K、红心 A、红心 2……52 行的顺序就是模型训练时类别 ID 的顺序。你训练时用的 data.yaml 里names列表必须和这个文件逐行对应否则会出现模型输出了class_id0你按自己的理解去解析成“黑桃 A”实际标注却指向另一种牌的错位事故。2.2 归一化坐标txt 标签里那五个数每个都不能马虎打开任意一个 labels 下的 txt 文件你会看到类似这样的内容12 0.453125 0.671875 0.240625 0.312500 38 0.781250 0.515625 0.187500 0.250000每行五个数空格分隔含义依次是类别 ID、归一化中心点 x、归一化中心点 y、归一化宽度 w、归一化高度 h。归一化的基准是图片的原始宽高也就是说真实框的像素坐标除以图片宽高后四个数值全部落在 0 到 1 之间。这样做的好处是标签不随输入分辨率变化训练时无论img640还是img1280标签都无需重新计算。我一般拿到数据集后做的第一件事不是直接训练而是写一段脚本把这五个数还原回像素坐标把框画在图上肉眼检查一轮。常见做法是随机抽 20 张训练图叠加画框后看标注是否贴合牌面边缘。扑克牌检测对框的质量极其敏感框画得比牌面大一圈模型学到的特征里就会混入背景框小了角上的点数和花色可能被截掉一半这类误差在网络深层特征里会被放大。2.3 为什么这种格式值得直接训省掉的是转换脚本和坐标系换算的坑目标检测领域里 VOC 格式xml和 COCO 格式json是另两大主流但它们都不能直接喂给 YOLOv5 训练器。VOC 的坐标是绝对的左上右下像素值COCO 的坐标是绝对左上角加宽高而 YOLO 系列统一要求归一化的中心点加宽高。这个数据集直接用 YOLOv5 格式给出等于帮你跳过了最容易被写错的转换环节。自己写过 VOC 转 YOLO 脚本的人都有体会最容易出错的是宽高换算是除以原图尺寸还是除以输入尺寸以及类别索引是从 0 还是从 1 开始。YOLOv5 的类别 ID 严格从 0 开始52 个类别的 ID 范围是 0 到 51classes.txt 第 1 行对应 ID 0第 52 行对应 ID 51。这个数据集既然直接给好了格式你就没有这些转换负担剩下的核心工作就是配置 data.yaml 和调超参数。3. 跑通训练写 data.yaml、摆放数据集、调前三个超参数3.1 最小可用的 data.yaml路径、类别数、names 三件事把数据集放在工程目录下后第一步是配 data.yaml。如果你解压后发现目录里自带了这个文件也要打开检查一遍确认绝对路径或相对路径指向正确。常见的写法是# poker.yaml path: ./poker_dataset # 数据集根目录相对当前工作目录或绝对路径 train: images/train # 训练图片目录相对于 path val: images/val # 验证图片目录相对于 path test: images/test # 测试目录可选没有就注释掉 nc: 52 # 类别数量扑克牌 52 张不含大小王 names: [ A_of_Spades, 2_of_Spades, ..., K_of_Spades, A_of_Hearts, 2_of_Hearts, ..., K_of_Hearts, A_of_Clubs, 2_of_Clubs, ..., K_of_Clubs, A_of_Diamonds, 2_of_Diamonds, ..., K_of_Diamonds ]path字段在 YOLOv5 v7.0 之后的版本里是推荐写法它决定了 train 和 val 是相对谁解析的。这里最容易犯的错是把train写成完整路径又把path也写上结果路径拼接重复导致找不到图片。如果你在跑train.py时报了 Image not found 之类的错误先回来看这三行。nc必须和 names 列表长度一致模型输出层的通道数由它决定。如果数据集实际是 52 类你写成 53训练不会立即报错但最终导出的模型在解析时会出现一个永远没有样本的“幽灵类别”。反过来写成 51训练过程会出现类别 ID 越界的错误因为标签里最大 ID 是 51而模型只分配了 51 个输出通道0 到 50。3.2 训练命令与三个关键超参数img、batch、epochs 怎么定配置好后进入 YOLOv5 仓库目录执行训练。命令本身很简洁但参数怎么定直接关系到这张扑克牌数据集能不能收敛python train.py \ --data poker.yaml \ --weights yolov5s.pt \ --img 640 \ --batch 16 \ --epochs 100 \ --hyp data/hyps/hyp.scratch-low.yaml--img是输入分辨率。扑克牌属于中等尺寸目标牌面细节集中在点数和花色上640 是起点。如果你的图片里牌在画面中占比很小比如桌上摆了一整副牌需要把 img 提到 960 或 1280代价是显存占用和训练时间明显上升。--batch受显存约束16 在 8GB 显存上跑 640 分辨率基本是极限显存小就降到 8但 batch 过小会导致 BN 层的统计量抖动损失曲线会呈现明显的锯齿。--epochs我一般先给 100然后看验证集 mAP 曲线是否在 60 到 80 epoch 之间进入平台期这个数据集的体量和类别数决定了它不需要像 COCO 那样训 300 epoch。--hyp指定超参数文件。YOLOv5 自带hyp.scratch-low.yaml和hyp.scratch-high.yaml区别主要在数据增强强度上。扑克牌场景我建议先用 low 版本因为牌面是平面物体过强的 HSV 扰动会把红色方块和红色红心的色相拉得过于接近反而增加混淆。3.3 验证与指标mAP 之外还要看每一类的 AP训练结束后验证命令单独跑python val.py \ --data poker.yaml \ --weights runs/train/exp/weights/best.pt \ --img 640 \ --save-json --save-txt--save-txt会把每张验证图的预测结果写到 txt 里--save-json在装了 pycocotools 的情况下会额外输出 COCO 格式的评估文件。控制台会打印 mAP0.5 和 mAP0.5:0.95 两个主要指标。对扑克牌来说mAP0.5 达到 0.95 以上不算稀奇因为牌面相对规整真正值得盯的是 52 个类各自的 AP。你大概率会发现红心 A、方块 3 这类“纯红色牌面”的 AP 明显低于黑桃和梅花这不是网络结构的问题而是数据分布和颜色混淆叠加的结果。把results.csv里每类的 AP 拉出来排序底部那几类就是后续补数据或调增强方向的风向标。4. 扑克牌训练避坑从标注翻车到推理失效的五个常见问题4.1 牌面旋转 180 度A 和 8 对称6 和 9 谁是谁现象训练 loss 降得很漂亮验证 mAP 也不错但实测时把一张“红心 6”旋转 180 度喂进去模型死活识别成“红心 9”。原因公开数据集中部分图像里的牌是倒置的标注时按牌面正向语义标了类别但 6 和 9 这类对称翻转后会变成另一张牌的图案旋转增强--hyp里的degrees会把这些写进训练集模型被迫在“6 的正向特征”和“6 旋转后像 9”之间做折中。解决扑克牌场景建议把degrees这个增强参数设成 0或者只保留 90 度的倍数旋转degrees: 90.0。同时检查数据集里是否给同一张牌的正反两面都做了标注如果只标了正向就不要开旋转增强。这类混淆在混淆矩阵热力图上会非常刺眼6 和 9 的交叉格子里会有一片亮色。4.2 类别不平衡边角牌样本少A/K/Q 占了大头现象训练完看每类 APA、K、Q、J 这些牌的 AP 都在 0.95 以上2、3、4、5 这些数字牌普遍掉到 0.88 左右。原因扑克牌数据集的采集天然偏向“展示面”带 A/K/Q 的牌图拍得多数字牌尤其是小点数的牌图数量少。YOLOv5 默认的损失函数对尾部类别没有特殊加权样本少的类别梯度贡献小。解决先统计每类的样本数如果最大类比最小类超过 5 倍就用--cls参数调大分类损失的权重比如从默认的 0.5 提到 1.0。另一个更实用的做法是直接在数据层面动手把样本少的类别做 mosaic 增强时的复制粘贴或者额外找几十张这些牌的单牌图补进训练集。补数据优先于调损失权重因为损失权重只能在现有特征里做权衡补图才能引入新特征。4.3 小目标检测整副牌场景里的小框不稳定现象单张牌的大图检测很准一换成“桌面平铺多张牌”的图片边角处的小牌开始漏检置信度在 0.25 附近抖动。原因牌在整图里占比小经过 YOLOv5 的 stride 32 下采样后小尺寸牌在特征图上的有效像素可能只剩十几个点数和花色的纹理细节基本被池化抹掉了。解决先确认标注框面积占整图的比例。如果大量框的归一化面积小于 0.01考虑把--img提到 960让每张牌在输入图上占据更多像素。同时打开--multi-scale让训练过程随机缩放输入尺寸逼迫模型适应不同尺度。注意 mAP 会因此有小幅下降但对实际场景的泛化能力是提升的。4.4 标注框质量问题贴边框把花色切掉一半现象训练 50 个 epoch 后 loss 降不下去验证集上同一种牌一会儿正一会儿误检损失曲线像心电图。原因扑克牌的标注框如果压得太紧会把左上角的点数和右下角的花色符号切掉一部分如果框得太松又把桌面纹理收进来。同一个数据集里标注尺度不统一模型学到的框回归目标自相矛盾。解决写一个可视化脚本对每个类别随机抽 10 张图叠加真实标注框直接看框边缘和牌面的贴合情况。发现系统性偏差比如所有框都比牌面小一圈用批量脚本统一外扩 3% 到 5%。这类问题不需要重新训练太多轮修正标注后从原权重继续训 30 个 epoch 就够。4.5 过拟合模型背答案而不是认牌现象训练 loss 降到接近 0验证 mAP 也好看但把训练时没见过的牌面照片换个角度、换张桌子喂进去置信度直接崩到 0.5 以下。原因数据集里每张牌的出现次数少且拍摄背景单一——都是同一张桌面、同一光照。模型记住了“黑桃 A 出现的那个角落的纹理”而不是“黑桃 A 本身的图案”。解决观察验证集 mAP 和训练集 mAP 的差值如果超过 5 个百分点就要干预。打开更强的 mosaic 和 mixup 增强或者把背景替换成随机纹理常见做法是用--hyp里的mosaic: 1.0, mixup: 0.2。这一步做完通常训练 loss 会回升一点但验证集上的表现会变得更可信。这个数据集如果本身包含多种场景的照片过拟合风险会低很多如果场景单一务必在增强上做足文章。5. 进阶验证用一批新牌面做盲测别只信 val 指标训练完模型val 集指标再漂亮也只是“见过面的考试”扑克牌这类细粒度任务必须做一次盲测。盲测的做法是从数据集里抽出训练和验证都没出现过的一批牌面照片最好是不同拍摄角度、不同背景的单独建一个目录写一个推理脚本跑一遍输出每张图的预测类别和置信度。实际操作中我会把模型导出成 ONNX用下面这段脚本做快速盲测import cv2 import onnxruntime as ort import numpy as np session ort.InferenceSession(best.onnx) input_name session.get_inputs()[0].name img cv2.imread(blind_test/unknown_poker.jpg) img cv2.resize(img, (640, 640)) img img[:, :, ::-1].transpose(2, 0, 1) # BGR转RGBHWC转CHW img np.ascontiguousarray(img, dtypenp.float32) / 255.0 img np.expand_dims(img, axis0) outputs session.run(None, {input_name: img}) # output[0]: 检测框和置信度output[1]: 52类分类概率这段代码不依赖 YOLOv5 的推理封装直接走 ONNX Runtime适合快速验证导出后的模型行为也方便写进自动化测试流程。盲测时两个指标要同时看一是类别判对没有二是置信度是否在 0.7 以上。如果判对了但置信度只有 0.5说明模型虽然赢了 val 指标但在真实场景里仍然是犹豫的这种牌面应该被加入训练集做增量训练。我的习惯是每训完一版模型就攒 30 张没见过的牌面照片做一次盲测发现哪类牌经常被误判就回去看这类的训练样本数和标注质量。这个迭代闭环比反复调超参数更管用我早期在扑克牌数据集上吃过“val mAP 0.96实拍识别稀烂”的亏后来检查发现是数据增强开太大把红心染成了紫色。多做几轮盲测很多训练时注意不到的隐患会在推理阶段现形。希望这套流程帮你少走几步弯路拿到这个数据集后第一轮训练就能跑到该有的水平。本文还有配套的精品资源点击获取