ARTICLE DETAIL

资讯详情

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

扑克牌识别数据集:501张原始图与YOLO v11实现99.3%识别率

扑克牌识别数据集:501张原始图与YOLO v11实现99.3%识别率 简介本资源为扑克牌识别数据集面向计算机视觉学习者、目标检测开发者及需要牌面识别方案的工程人员可用于训练模型同时识别扑克牌数字与花色适用于棋牌类应用、自动化发牌、智能娱乐设备等场景。包内共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.yamldata.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_okTrue) # 获取所有图片文件名不含扩展名 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(ftrain: {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_Knames 的顺序必须和标注时的 class_id 一致。我见过有人标注时按花色分组训练时按数字分组结果模型把红桃 2 认成方块 2。检查方法很简单随机抽一张训练图用脚本把标注框画出来看类别名和框是否对应。3.3 训练命令与关键参数解释最小训练命令yolo detect train \ data/home/user/poker_dataset/data.yaml \ modelyolo11n.pt \ epochs200 \ imgsz640 \ batch16 \ lr00.01 \ patience50 \ projectpoker_runs \ nameexp1参数逐个说modelyolo11n.ptn 是 nano 版本参数量小适合扑克牌这种简单场景。如果显存够可以换 s 或 m但 501 张图用 n 就够了。epochs200小数据集需要多跑几轮但配合 patience50如果 50 轮验证集 mAP 不升就早停。imgsz640输入分辨率。扑克牌在画面里占比如果小可以提到 1280但显存翻倍。batch168GB 显存下 640 分辨率跑 yolo11n16 是安全的。如果 OOM降到 8。lr00.01初始学习率。小数据集不要太大0.01 是 ultralytics 的默认值通常不用改。训练过程中看两个指标box_loss 和 mAP50。box_loss 降到 0.5 以下、mAP50 到 0.99 以上基本就到位了。3.4 验证集评估与 99.3% 识别率的复现条件训练完用yolo detect val跑验证集yolo detect val \ modelpoker_runs/exp1/weights/best.pt \ data/home/user/poker_dataset/data.yaml \ imgsz640 \ batch16输出里看 mAP50-95 和 per-class 的 precision、recall。99.3% 这个数字我推测是在 mAP50 或 top-1 分类准确率上得到的。要复现这个水平需要满足几个条件验证集和训练集同分布、光照没有剧烈变化、牌面没有严重遮挡、标注框没有明显偏移。如果实际场景里牌是斜着放的或者有反光识别率会掉。这时候要么补数据要么在推理时做透视校正。4. 扑克牌识别数据集训练避坑5 个血泪踩坑记录4.1 坑一水平翻转增强把数字翻反了现象训练时开了默认增强模型在验证集上把 6 和 9 混淆红桃和方块也偶尔搞混。原因ultralytics 默认开启水平翻转fliplr0.5。扑克牌的数字不是中心对称的6 翻过来像 99 翻过来像 6。花色里红桃和方块翻转后虽然形状不变但和数字的相对位置变了模型学到的特征被破坏。解决在训练命令里加fliplr0.0关掉水平翻转。垂直翻转同理也要关。只保留小角度旋转degrees5和亮度调整hsv_v0.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 很高但推理时远处的牌检测不到。原因训练时 imgsz640牌在画面里占的像素本来就少下采样后特征更弱。模型学到了“大牌”的特征对“小牌”不敏感。解决如果实际场景里牌在画面中占比小于 5%训练时把 imgsz 提到 1280或者用切片推理SAHI。但 imgsz 翻倍显存也翻倍batch 要相应减半。4.5 坑五标注框贴边导致训练不稳定现象loss 震荡mAP 忽高忽低。原因有些标注框的边界正好压在图片边缘归一化后 x_center 或 y_center 接近 0 或 1yolo v11 在计算损失时对边界框的梯度异常。解决检查标注文件把贴边的框往里收 1 到 2 个像素或者把原图裁一下再标。这个坑在 501 张规模下影响不大但如果 loss 曲线像心电图优先查这个。5. 把 99.3% 落到实际牌桌推理加速与误检过滤技巧训练出高 mAP 只是第一步真正放到牌桌上跑还要解决推理速度和误检。我一般用 TensorRT 导出 yolo11n在 Jetson 或桌面 GPU 上做到 5ms 以内一帧。导出命令yolo export modelpoker_runs/exp1/weights/best.pt formatengine halfTrue imgsz640halfTrue 是 FP16 推理速度翻倍精度掉不到 0.1%。导出后在 Python 里加载from ultralytics import YOLO model YOLO(best.engine) results model.predict(sourcetable.jpg, conf0.6, iou0.5, verboseFalse) 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(fclass{model.names[cls_id]}, conf{conf:.3f}, box{xyxy})conf0.6 是置信度阈值。扑克牌场景下我一般设 0.5 到 0.7。设太低会误检把背景纹理认成牌设太高会漏检尤其是牌被手挡住一半的时候。iou0.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 张原始图是起点不是终点。希望帮到你。本文还有配套的精品资源点击获取
返回列表