☰
扑克牌识别数据集:501张原始图与YOLO v11实现99.3%识别率
2026/9/24 23:08:33 网站建设 项目流程

简介:本资源为扑克牌识别数据集,面向计算机视觉学习者、目标检测开发者及需要牌面识别方案的工程人员,可用于训练模型同时识别扑克牌数字与花色,适用于棋牌类应用、自动化发牌、智能娱乐设备等场景。包内共1003个文件,包含501张jpg原始图像、501个txt标注文件及1个yaml配置文件,压缩包约11.82MB;图像覆盖多种牌面与拍摄条件,标注采用YOLO v11格式,可直接接入主流检测框架训练,yaml文件用于定义数据集路径与类别信息。据描述,该数据集训练后正确识别率可达99.3%,数字与花色均能稳定检出,适合作为课程设计、竞赛项目或产品原型的训练数据。目前已有762人学习下载,具备一定社区验证基础。读者可据此快速搭建扑克牌检测流程,省去从零采集与标注的成本,并参考标注格式与类别组织方式迁移到其他卡牌识别任务。

1. 扑克牌识别数据集:501 张原始图如何撑起 99.3% 的识别率

做牌桌视觉项目的工程师多半遇到过这个场景:摄像头架好了,光照也调了,可模型就是分不清红桃和方块,更别提梅花和黑桃的细微差别。问题往往不在网络结构,而在数据。扑克牌识别数据集要解决的核心矛盾很具体——花色之间的类间差异极小,数字和花色的组合又要求模型同时完成分类与定位。501 张原始图听起来不多,但如果标注质量到位、增强策略合理,配合 yolo v11 格式的标注文件,正确识别率做到 99.3% 是可信的。这个数据集适合三类人:做棋牌类机器人视觉的、做实时牌面检测原型的、以及想拿一个干净的小规模数据集练手 yolo v11 训练流程的从业者。它不解决通用目标检测问题,但在扑克牌这个封闭域里,够用且好用。

2. 从 501 张原始图到 yolo v11 标注:数据集的构成与选型逻辑

2.1 为什么是 501 张,而不是 5000 张

扑克牌识别是一个强约束场景。一副牌 54 张,去掉大小王后 52 张,每张牌的花色和数字组合是固定的。这意味着模型不需要学习无限多样的外观变化,只需要在有限类别上做到高精度。501 张原始图覆盖了 52 个类别,平均每个类别约 9.6 张。这个数量在常规目标检测任务里偏少,但在扑克牌场景下,因为类内差异小、背景可控,反而能避免模型过拟合到无关特征。

我一般会这样判断:如果任务的目标类别是封闭集合,且每个类别的外观变化主要来自光照和角度,那么每类 8 到 12 张原始图配合在线增强,就足以让 yolo v11 收敛到一个可用的 mAP。501 张这个数字,大概率是经过实际拍摄和筛选后留下的有效帧,而不是随便截取的。

2.2 yolo v11 格式标注的字段含义与目录结构

yolo v11 沿用 ultralytics 系列的标注规范,每张图片对应一个同名 txt 文件,每行表示一个目标框,格式为:

<class_id> <x_center> <y_center> <width> <height>

其中坐标和宽高都是相对于图片宽高的归一化值,范围 0 到 1。class_id 从 0 开始,按类别列表顺序编号。扑克牌数据集通常有两种编号方式:一种是 52 类直接编号,0 到 51;另一种是先分花色再分数字,用两级标签。yolo v11 只支持单级标签,所以常见做法是把花色和数字组合成一个类别,比如红桃 A 是 class 0,黑桃 K 是 class 51。

目录结构一般长这样:

dataset/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── data.yaml

data.yaml 里写清楚 train、val 路径和 nc、names。nc 是类别数,names 是类别名列表。这里有个容易翻车的地方:names 的顺序必须和标注文件里的 class_id 严格对应,否则训练出来的模型会把红桃认成方块。

2.3 标注工具选型:labelImg、CVAT 还是 X-AnyLabeling

热词里出现了不少标注工具,labelImg、CVAT、LabelStudio、X-AnyLabeling 都在列。针对扑克牌这个任务,我的选型逻辑是这样的:

工具适合场景扑克牌任务下的注意点
labelImg小规模、单机、矩形框快,但无自动标注,501 张纯手标约 2 到 3 小时
CVAT多人协作、视频抽帧功能全,部署重,适合团队
X-AnyLabeling自动标注、预标注可先用小模型预标,再人工修正,效率最高
LabelStudio多模态、分类+检测配置复杂,纯检测任务有点杀鸡用牛刀

如果只有 501 张,我一般会先用 X-AnyLabeling 加载一个通用检测模型做预标注,然后人工过一遍。扑克牌的矩形框边界清晰,预标注的召回率通常不错,人工主要修的是类别错标和漏标。

2.4 从原始图到训练集:划分与增强的最小命令

拿到 501 张原始图和对应标注后,第一步是划分训练集和验证集。常见比例是 8:2 或 9:1。因为总量少,我倾向于 9:1,验证集约 50 张,保证每个类别在验证集里至少出现一次。

import os import random import shutil # 原始图片和标注路径 img_dir = "raw/images" lbl_dir = "raw/labels" # 输出路径 out_img_train = "dataset/images/train" out_img_val = "dataset/images/val" out_lbl_train = "dataset/labels/train" out_lbl_val = "dataset/labels/val" for p in [out_img_train, out_img_val, out_lbl_train, out_lbl_val]: os.makedirs(p, exist_ok=True) # 获取所有图片文件名(不含扩展名) names = [os.path.splitext(f)[0] for f in os.listdir(img_dir) if f.endswith(".jpg")] random.seed(42) random.shuffle(names) split = int(len(names) * 0.9) train_names = names[:split] val_names = names[split:] def copy_pair(name_list, img_out, lbl_out): for n in name_list: shutil.copy(os.path.join(img_dir, n + ".jpg"), os.path.join(img_out, n + ".jpg")) shutil.copy(os.path.join(lbl_dir, n + ".txt"), os.path.join(lbl_out, n + ".txt")) copy_pair(train_names, out_img_train, out_lbl_train) copy_pair(val_names, out_img_val, out_lbl_val) print(f"train: {len(train_names)}, val: {len(val_names)}")

这段脚本做三件事:读取原始文件名、固定随机种子打乱、按 9:1 复制到对应目录。random.seed(42) 是为了让划分可复现,避免每次跑出来验证集不一样。copy_pair 函数同时复制图片和标注,保证一一对应。

划分完之后,增强策略要跟上。yolo v11 训练时自带 mosaic、mixup、随机翻转等增强,但对于扑克牌,翻转要小心:水平翻转会把红桃变成对称图形,但数字会反,所以一般只开小角度的随机旋转和亮度调整,不开水平翻转。这个细节后面避坑章节会展开。

3. 用 yolo v11 训练扑克牌检测模型:参数配置与训练命令

3.1 环境准备与 ultralytics 安装

yolo v11 通过 ultralytics 包调用。我一般用 Python 3.10 以上,PyTorch 2.1 以上,CUDA 11.8 或 12.1。安装命令:

pip install ultralytics pip install torch torchvision --index-url https://download.pytorch.org/whl/cu121

装完之后用yolo checks确认环境和 GPU 是否识别正常。如果显存小于 8GB,训练时 batch 要调小,后面参数表里会写。

3.2 data.yaml 的写法与类别名映射

data.yaml 是训练入口,内容如下:

path: /home/user/poker_dataset train: images/train val: images/val nc: 52 names: 0: hearts_A 1: hearts_2 ... 51: spades_K

names 的顺序必须和标注时的 class_id 一致。我见过有人标注时按花色分组,训练时按数字分组,结果模型把红桃 2 认成方块 2。检查方法很简单:随机抽一张训练图,用脚本把标注框画出来,看类别名和框是否对应。

3.3 训练命令与关键参数解释

最小训练命令:

yolo detect train \ data=/home/user/poker_dataset/data.yaml \ model=yolo11n.pt \ epochs=200 \ imgsz=640 \ batch=16 \ lr0=0.01 \ patience=50 \ project=poker_runs \ name=exp1

参数逐个说:

  • model=yolo11n.pt:n 是 nano 版本,参数量小,适合扑克牌这种简单场景。如果显存够,可以换 s 或 m,但 501 张图用 n 就够了。
  • epochs=200:小数据集需要多跑几轮,但配合 patience=50,如果 50 轮验证集 mAP 不升就早停。
  • imgsz=640:输入分辨率。扑克牌在画面里占比如果小,可以提到 1280,但显存翻倍。
  • batch=16:8GB 显存下 640 分辨率跑 yolo11n,16 是安全的。如果 OOM,降到 8。
  • lr0=0.01:初始学习率。小数据集不要太大,0.01 是 ultralytics 的默认值,通常不用改。

训练过程中看两个指标:box_loss 和 mAP50。box_loss 降到 0.5 以下、mAP50 到 0.99 以上,基本就到位了。

3.4 验证集评估与 99.3% 识别率的复现条件

训练完用yolo detect val跑验证集:

yolo detect val \ model=poker_runs/exp1/weights/best.pt \ data=/home/user/poker_dataset/data.yaml \ imgsz=640 \ batch=16

输出里看 mAP50-95 和 per-class 的 precision、recall。99.3% 这个数字,我推测是在 mAP50 或 top-1 分类准确率上得到的。要复现这个水平,需要满足几个条件:验证集和训练集同分布、光照没有剧烈变化、牌面没有严重遮挡、标注框没有明显偏移。如果实际场景里牌是斜着放的,或者有反光,识别率会掉。这时候要么补数据,要么在推理时做透视校正。

4. 扑克牌识别数据集训练避坑:5 个血泪踩坑记录

4.1 坑一:水平翻转增强把数字翻反了

现象:训练时开了默认增强,模型在验证集上把 6 和 9 混淆,红桃和方块也偶尔搞混。

原因:ultralytics 默认开启水平翻转(fliplr=0.5)。扑克牌的数字不是中心对称的,6 翻过来像 9,9 翻过来像 6。花色里红桃和方块翻转后虽然形状不变,但和数字的相对位置变了,模型学到的特征被破坏。

解决:在训练命令里加fliplr=0.0,关掉水平翻转。垂直翻转同理,也要关。只保留小角度旋转(degrees=5)和亮度调整(hsv_v=0.3)。

4.2 坑二:类别编号顺序和 names 不一致

现象:训练 loss 正常下降,但验证时 per-class 指标里某些类别 precision 极低,模型把 A 认成 K。

原因:标注时 class_id 是按花色排的,data.yaml 里 names 是按数字排的。yolo v11 不检查 names 和标注的语义对应,只按数字索引,导致标签错位。

解决:写一个校验脚本,读一张图的标注,按 class_id 取 names 里的名字,画到图上,人工看一眼。确认无误再开训。这个检查花 2 分钟,省 2 小时返工。

4.3 坑三:验证集里某些类别一张图都没有

现象:训练完 mAP 看着不错,但实际用的时候发现黑桃 Q 从来没被正确识别过。

原因:501 张图按 9:1 随机划分,某些稀有类别(比如某张牌只拍了 3 次)可能全被分到训练集,验证集里没有。模型在验证集上没机会暴露这个类别的弱点。

解决:划分时用分层抽样,保证每个类别在验证集里至少有一张。如果某个类别总数少于 5 张,考虑补拍或从训练集里匀一张到验证集。

4.4 坑四:imgsz 设太大导致小目标漏检

现象:训练时 mAP 很高,但推理时远处的牌检测不到。

原因:训练时 imgsz=640,牌在画面里占的像素本来就少,下采样后特征更弱。模型学到了“大牌”的特征,对“小牌”不敏感。

解决:如果实际场景里牌在画面中占比小于 5%,训练时把 imgsz 提到 1280,或者用切片推理(SAHI)。但 imgsz 翻倍显存也翻倍,batch 要相应减半。

4.5 坑五:标注框贴边导致训练不稳定

现象:loss 震荡,mAP 忽高忽低。

原因:有些标注框的边界正好压在图片边缘,归一化后 x_center 或 y_center 接近 0 或 1,yolo v11 在计算损失时对边界框的梯度异常。

解决:检查标注文件,把贴边的框往里收 1 到 2 个像素,或者把原图裁一下再标。这个坑在 501 张规模下影响不大,但如果 loss 曲线像心电图,优先查这个。

5. 把 99.3% 落到实际牌桌:推理加速与误检过滤技巧

训练出高 mAP 只是第一步,真正放到牌桌上跑,还要解决推理速度和误检。我一般用 TensorRT 导出 yolo11n,在 Jetson 或桌面 GPU 上做到 5ms 以内一帧。导出命令:

yolo export model=poker_runs/exp1/weights/best.pt format=engine half=True imgsz=640

half=True 是 FP16 推理,速度翻倍,精度掉不到 0.1%。导出后在 Python 里加载:

from ultralytics import YOLO model = YOLO("best.engine") results = model.predict(source="table.jpg", conf=0.6, iou=0.5, verbose=False) for r in results: for box in r.boxes: cls_id = int(box.cls[0]) conf = float(box.conf[0]) xyxy = box.xyxy[0].tolist() print(f"class={model.names[cls_id]}, conf={conf:.3f}, box={xyxy}")

conf=0.6 是置信度阈值。扑克牌场景下,我一般设 0.5 到 0.7。设太低会误检,把背景纹理认成牌;设太高会漏检,尤其是牌被手挡住一半的时候。iou=0.5 是 NMS 的阈值,扑克牌之间重叠少,0.5 够用。

误检过滤还有一个技巧:利用牌面的长宽比。扑克牌的标准长宽比约 1.4:1,如果检测框的长宽比偏离这个范围超过 30%,大概率是误检,可以直接丢掉。这个规则用几行代码就能加:

w = xyxy[2] - xyxy[0] h = xyxy[3] - xyxy[1] ratio = max(w, h) / min(w, h) if ratio < 1.1 or ratio > 1.8: continue # 跳过异常长宽比的框

这个过滤在背景杂乱的牌桌上特别管用,能把误检率再压一截。

最后说一个我自己的习惯:每次换新牌桌或新光照,先拍 20 张图跑一遍推理,看误检和漏检的分布。如果某个花色在特定光照下总是错,就补拍那个花色的图,用增量训练微调 10 个 epoch。501 张原始图是起点,不是终点。希望帮到你。

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

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

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

立即咨询