简介扑克牌识别数据集专为计算机视觉与目标检测任务设计覆盖A-K共13种牌面字母类别可支撑扑克牌检测、识别及棋牌类AI应用开发。资源包含1850张原始图像模型正确识别率可达98.7%所有图片均已按YOLOv11格式完成标注标签数据与图片一一对应可直接接入YOLO系列训练流程。整套资源共2000个文件以1850个txt标注文件和149张jpg原图为主体另含1个yaml配置文件用于设定类别名称与数据集路径压缩包整体约109.76MB文件结构清晰简洁便于快速解压与使用。数据中的JPEG图像大多来自真实拍摄场景包含不同光照、角度和背景下的桌面扑克牌画面有助于提升训练模型的鲁棒性。目前已有241人学习浏览该资源适合算法工程师、数据科学爱好者以及需要快速落地扑克牌识别功能的学生与开发者。使用本数据集可以省去繁琐的图像采集和手工标注环节让使用者将更多精力投入到模型结构改进、参数调优和实际场景验证中。1. 扑克牌识别是典型的“数据决定上限”场景这就是那份A-K全字母数据集扑克牌识别在视觉任务里是个很有意思的分支。它不像行人检测那样考验模型对大尺度变化的适应力也不像遥感目标检测那样需要处理极端小目标它真正的难点在于类间相似度极高——红桃K和红桃Q的轮廓几乎一致黑桃A和方块A的牌面花纹也就是中间一个字母的差别。这个任务里模型能不能赢80%的因素在数据不在网络结构。市面上做扑克牌识别的公开数据集并不算多常见的那几个要么只覆盖数字牌要么对人头牌J/Q/K的标注很草率训练时经常出现“牌型对了但字母没认出来”的翻车结果。正因为这样一份能覆盖A到K所有字母、且直接按YOLOv11格式标注好的数据集对做棋牌游戏识别、魔术教学辅助、自动化发牌设备甚至牌桌监控的从业者来说价值都很直接不用再花两周去网上找图、清洗、转换格式。这份数据集给了1850张原始图和98.7%的正确识别率这几个数字意味着它是一个“拿来即用”的方案而不是需要你再做大量二次加工的毛坯数据。适合的读者很明确用过YOLO系列但没跑过扑克牌场景的开发者、正在做牌类产品原型验证的工程师、以及想了解小数据集上目标检测怎么做到实用精度的学生。2. 先用15分钟确认数据集底细目录结构、标注格式与训练选型2.1 一份“YOLOv11格式”的数据集打开后应该长什么样这里说的“YOLOv11格式”实际上沿用的就是YOLO系列一贯的TXT标注规范每个图片对应一个同名TXT文件TXT里每一行代表一个目标框格式固定为class_id x_center y_center width height其中x_center、y_center、width、height全部是相对于图片宽高的归一化值取值范围在0到1之间。所以你拿到数据集后做的第一件事不是急着配置训练环境而是随便挑一张图和它对应的TXT文件手动核验标注框是不是贴合牌面。拿到数据后我一般会先跑一段Python脚本把标注框画到原图上做可视化检查。这个步骤看起来原始但能一次性发现三类问题坐标是否归一化、框是否严重偏离牌面、类别ID是否超出类别总数。对于这个数据集类别本质上就是13类A、2、3、4、5、6、7、8、9、10、J、Q、K每个TXT文件里的class_id应当只在0到12之间。如果出现13或更大的数字说明标签文件和类别配置文件没对齐。# 随机抽10张图把标注框画出来人工确认框是否贴合牌面 python draw_boxes.py --images ./dataset/images/train \ --labels ./dataset/labels/train \ --num_samples 10 \ --output ./preview这个脚本的作用是把TXT里的归一化坐标乘以图片宽高还原成像素坐标然后用矩形框画在原图上并保存。逻辑上就是一个读取坐标、换算、画框、保存的过程代码量不大但它是整个训练流程里“后悔药”成本最低的一道校验。如果你看到框比牌面大一圈或者框只框住了花纹没框住字母后续训练再认真也白搭因为模型从一开始就在学错误的位置特征。提示不要跳过这一步。哪怕数据说明里写了“格式已验证”你自己跑一遍可视化永远是最可靠的。训练前花15分钟做标注核查能省掉训练后三天的排查时间。2.2 验证标注与图片的对齐关系文件名前缀一致性检查除开坐标格式还有一个容易被忽略的坑图片和TXT文件名是否严格一一对应。YOLO训练逻辑里图片路径通过数据集配置加载而标签路径是通过把图片后缀替换成.txt来推导的。这意味着只要有一张图片缺少同名TXT文件或者多了一个没有图片的孤立TXT训练时轻则报警告重则直接跳出训练进程。这个数据集的描述提到“1850张原始图”如果按常规划分成train/val两个子集那么在images/和labels/两个根目录下每一张图片都应该在对应子集里拥有一个同名TXT。我是这么检查的import os from pathlib import Path image_dir Path(./dataset/images/train) label_dir Path(./dataset/labels/train) img_suffixes {.jpg, .jpeg, .png, .bmp} images {p.stem for p in image_dir.iterdir() if p.suffix.lower() in img_suffixes} labels {p.stem for p in label_dir.iterdir() if p.suffix .txt} print(f图片数量: {len(images)}, 标签数量: {len(labels)}) print(f缺标签的图片: {images - labels}) print(f孤立标签: {labels - images})这个检查脚本输出的结果很直观。正常情况下缺标签的图片和孤立标签都应该是空集合。如果你发现缺标签的图片很多先看是不是数据集打包时漏了拷贝如果孤立标签很多可能是有非训练图的标注混了进来。把这一步和可视化检查放在一起做基本能把一份未知来源数据集的底细摸清之后开始训练才心里有底。2.3 为什么这个场景选YOLOv11速度、精度与生态的综合考量既然数据集的标注已经按YOLOv11格式组织那么训练框架的选择几乎不用犹豫。YOLOv11相对于之前的版本在C3K2模块和C2PSA注意力模块上做了替换对小目标和密集场景的特征提取有实打实的提升。扑克牌识别里图片中往往同时出现多张牌牌与牌之间会有遮挡而且摄像头视角下的牌面通常会变形这时候C2PSA模块带来的注意力加权是有意义的。另一个选择原因很实际YOLOv11的生态最完整。不管是数据增强管线、模型导出到ONNX/TensorRT还是后续部署到边缘设备社区踩坑记录都相对丰富。你做的是数据集和训练实验不是在研究新网络结构选一个文档全、报错能查到解决方案的框架比追求微弱的精度差异更重要。这也是我这些年做视觉落地的经验选型时框架生态的成熟度往往比模型本身的指标差异更影响项目进度。3. 从零跑通训练环境配置、数据集配置文件与三个关键超参数3.1 YOLOv11环境配置用conda隔离依赖拿到数据集后第一步是在机器上准备一个干净的训练环境。YOLOv11依赖PyTorch、Ultralytics库以及一系列配套的数值计算库不同版本的CUDA和PyTorch之间兼容性差异很大如果不做环境隔离很容易遇到“昨天还能训练今天突然报CUDA错误”的玄学问题。我一般会用conda新建一个独立环境Python版本锁在3.10左右PyTorch按机器实际CUDA版本选装。CUDA版本怎么确认在终端里执行nvidia-smi看右上角的CUDA Version然后去PyTorch官网选对应的安装命令。不要直接装最新版PyTorch新版本刚发出来时经常有上游兼容性bug。conda create -n yolo11 python3.10 -y conda activate yolo11 # 以CUDA 12.1为例实际版本号以你自己的nvidia-smi为准 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu121 pip install ultralytics安装完成后建议顺手验证一下库是否正常加载以及是否真的能用GPU训练。不少人在配置完环境后直接开训练跑了一轮发现模型在CPU上龟速运行才发现CUDA根本没生效白白损失几个小时。验证方式很简单在Python里执行三行命令看返回结果再往下走。import torch print(torch.__version__) print(torch.cuda.is_available()) print(torch.cuda.get_device_name(0))这三个输出分别回答三个问题PyTorch版本对不对、CUDA是否可用、GPU型号是什么。如果torch.cuda.is_available()返回False多半是PyTorch版本与CUDA不匹配或者PyTorch装成了CPU版。这种情况下不要硬着头皮训下去先把环境修好不然后面所有时间都浪费了。3.2 写数据集配置文件YAML里的每个字段都要懂YOLOv11的数据集配置是一个YAML文件它的作用是指定训练集路径、验证集路径和类别名列表。这个数据集有13个类别对应A到K。文件内容比较固定但路径必须写对而且要理解每个字段的含义。# poker.yaml path: ./poker_dataset # 数据集根目录 train: images/train # 训练集相对路径 val: images/val # 验证集相对路径 names: 0: A 1: 2 2: 3 3: 4 4: 5 5: 6 6: 7 7: 8 8: 9 9: 10 10: J 11: Q 12: K这个文件有几点需要特别说明。path字段是数据集根目录的路径在Ultralytics库中train和val的值会拼接到path后面所以如果你写绝对路径就要确认train和val是相对于该路径的子目录。names这个字典的key从0开始连续编号顺序必须和TXT标注文件里的class_id完全一致。如果标注文件里class_id9代表牌面10而配置文件里9: 10这行写错位置模型会把类别全部认错整个训练白干。这里额外提醒牌面10在TXT里只占一个类ID但在文件名或者类别名里是两个字符。这不会影响检测逻辑但会影响你在推理结果里做后处理时的字符映射后面第四章会再提到。3.3 最小训练命令这六个参数最值得调环境配好了YAML文件写好了接下来就是启动训练。训练命令的写法并不复杂Ultralytics库把绝大多数训练逻辑封装成了CLI入口但正因为封装太好很多人反而不清楚哪些参数真正影响实验结果。yolo detect train \ modelyolo11n.pt \ datapoker.yaml \ epochs100 \ imgsz640 \ batch16 \ device0这六个参数是跑通的底线配置。modelyolo11n.pt表示在COCO预训练权重基础上做微调n代表nano版本模型最小、训练最快适合先验证数据质量epochs100对于1850张图的数据规模是合理的起步值如果数据增强开得大可以试着加到150到200imgsz640是长边缩放到640像素这个尺寸对扑克牌识别基本够用如果想进一步提升小目标召回率可以调到960但显存占用会明显增加batch16需要根据你的GPU显存调整12GB显存跑yolo11n用16没问题如果显存不够降到8或4device0指定用第一张GPU卡训练。训练过程中Ultralytics会在终端实时打印每个epoch的loss值和各项指标曲线。你需要关注的不是每一行的具体数值而是趋势loss是否整体在下降、mAP50是否在缓慢爬升。如果前10个epoch mAP一直为0不要慌这在小数据集上很常见尤其是正负样本比例差距大的时候通常跑到20个epoch之后才会有像样的指标。提示第一次跑训练时不要追求指标目的是验证整个流程能通。100个epoch的yolo11n在1850张图上单张RTX 3060大概跑40到60分钟这个时间成本完全可以接受。3.4 训练日志里藏着答案从loss曲线判断数据是否正常训练不是启动完就完事了。很多数据集的深层问题在你的loss曲线上一眼就能看出来。正常训练时box_loss在初始几个epoch快速下降随后缓慢收敛cls_loss的下降速度会慢一些因为它要在同类样本之间找共性。如果你的cls_loss出现先降后升的U型曲线而box_loss正常下降大概率是类别不平衡导致的过拟合——某个类别样本量极少模型一开始学不动后期直接摆烂。对于这份扑克牌数据集13个类别的分布很可能不均匀普通数字牌多、人头牌少这时候就要看数据增强和类别权重设置了。还有一个常见现象mAP50很高但mAP50-95很低。这两个指标的区别在于IoU阈值。mAP50只要求在IoU0.5时判定为正样本对框的定位精度要求比较宽松mAP50-95则是对0.5到0.95区间做平均更严格。如果你的扑克牌识别结果“框大体上对了但边角不够贴”就会表现为mAP50正常而mAP50-95偏低。解决思路有两个一是调高imgsz到960让模型在更大分辨率下学习更精细的边缘特征二是检查标注框是不是本身就不够贴合牌面边缘。3.5 训练产物解读weights/目录下各文件分别干什么用训练结束后Ultralytics会在runs/detect/train/目录下生成一系列文件。其中weights/best.pt是以验证集指标为基准保存的最优权重weights/last.pt是最后一个epoch的权重。部署和推理都用best.pt如果后续要换last.pt说明你想看训练末尾的模型效果而不是验证集最优。其他文件如args.yaml、results.csv、confusion_matrix.png在模型排查时会用到后面避坑章再展开。[TOC]4. 验证“98.7%”从指标到实测的评估方法以及推理结果如何保存4.1 一张混淆矩阵比100句“准确率高”更有说服力数据集的介绍里写了“正确识别率可达98.7%”这是一个很好的宣传数字但作为工程师你要自己验证。验证的标准做法不是在测试集上跑一遍数对错而是先看混淆矩阵。混淆矩阵能从两个维度暴露问题一是类别之间的混淆关系二是容易被漏检的类别。对扑克牌识别来说窗口牌J/Q/K之间互相混淆是常见问题因为它们在花色的颜色和纹理上高度相似区别只在字母形状上。另一个容易出问题的是5和6、9和10这类字形相近的数字牌在低分辨率或强透视变形下很容易被模型搞混。from ultralytics import YOLO import torch model YOLO(runs/detect/train/weights/best.pt) metrics model.val(datapoker.yaml, splitval) print(fmAP50: {metrics.box.map50:.4f}) print(fmAP50-95: {metrics.box.map:.4f}) print(metrics.box.confusion_matrix)这段代码完成了三件事加载训练好的权重、在验证集上做评估、输出mAP指标和混淆矩阵。如果你发现整体mAP不低但混淆矩阵里Q和K之间有一条明显的亮线说明这两类确实存在系统性的误判。解决方式要回到数据本身Q和K的训练样本是否均衡牌面角度是否覆盖了各种旋转方向有没有在数据增强时加入足够的旋转和透视变换。模型结构反而是最后才需要考虑的变量。4.2 单张和批量推理输出可视化结果也输出结构化信息指标归指标产品最终要看的是推理效果。YOLOv11的推理接口非常简洁它支持单张图片、图片文件夹、视频流甚至摄像头输入。日常验证阶段我一般先拿单张图跑一遍观察检测框和置信度然后再跑批量验证统计整体表现。from ultralytics import YOLO import cv2 model YOLO(runs/detect/train/weights/best.pt) results model.predict(sourcetest_imgs/table_01.jpg, conf0.5, saveTrue) for r in results: boxes r.boxes.xyxy.cpu().numpy() # 框坐标格式为x1y1x2y2 confs r.boxes.conf.cpu().numpy() # 置信度 clss r.boxes.cls.cpu().numpy().astype(int) # 类别ID names [model.names[c] for c in clss] print(names)这里把saveTrue打开就可以让Ultralytics自动保存带检测框的可视化图片对人工验证很有用。而真正生产环境用到的是后面打印出来的names列表——这是结构化输出方便你对接业务逻辑。比如在棋牌类产品里识别结果最终会转成一个有序的牌型字符串甚至直接判断是否在桌面上检测到重复牌目标检测里叫同一张牌被重复识别。关于置信度阈值conf0.5在验证阶段用0.5是合理的起点实际部署时如果出现漏检框不出来就调低到0.25如果出现误检把非牌面框成牌就调高到0.7。这个阈值的调整是每个项目都会经历的脏活没有固定的最优值只能根据你的场景反复试。4.3 保存推理结果从坐标到JSON建立一个可复用的输出管线很多教程止步于可视化输出但对做工程的人来说把推理结果保存成结构化文件、供下游业务消费才是完整闭环。保存的方式取决于你的下游系统需要什么。这里提供一个通用的JSON格式输出模板后续不管对接上位机、数据库还是前端可视化都只需要改很小的适配层。import json from ultralytics import YOLO from pathlib import Path model YOLO(runs/detect/train/weights/best.pt) image_files list(Path(test_imgs).glob(*.jpg)) all_detections [] for img_path in image_files: result model.predict(sourcestr(img_path), conf0.5, verboseFalse)[0] dets [] for box, conf, cls in zip(result.boxes.xyxy.cpu().numpy(), result.boxes.conf.cpu().numpy(), result.boxes.cls.cpu().numpy().astype(int)): dets.append({ bbox: [int(v) for v in box], confidence: round(float(conf), 4), class_id: int(cls), class_name: model.names[int(cls)] }) all_detections.append({ image: img_path.name, detections: dets }) with open(detection_results.json, w, encodingutf-8) as f: json.dump(all_detections, f, ensure_asciiFalse, indent2)这个脚本做了一次批量推理并且把每张图的检测结果以结构化形式落盘。值得留意的细节是verboseFalse这个参数如果不关掉Ultralytics会在每张图推理时往终端打印一堆日志批量跑时终端会刷屏到无法读信息。另一个细节是JSON里的坐标是Python int类型而不是numpy int勾选了ensure_asciiFalse保证中文类别名不乱码。现在我们的识别管线已经完整了训练得到权重推理得到结构化结果接下来才是做数据质量层面的“排雷”。5. 扑克牌识别训练中的5个典型翻车现场与排查手记5.1 现象loss正常下降但mAP50一直为0原因标注文件里的类别ID起始值不是0而是从1开始。YOLO的类别计数从0开始如果你的数据里第一张牌的class_id是1模型就会认为没有0号类别而类别总数对不上导致所有预测都被视作无效。解决用Python脚本读取所有TXT标注文件统计class_id的取值集合。集合里最小的值必须是0最大值必须是类别总数减1。如果发现是从1开始的写个几行脚本批量减1不要手动改1850张图的手动修改既费时又容易出错。from pathlib import Path label_dir Path(./dataset/labels/train) class_set set() for txt in label_dir.glob(*.txt): for line in txt.read_text().strip().splitlines(): parts line.split() if parts: class_set.add(int(parts[0])) print(f类别ID范围: {min(class_set)} - {max(class_set)})5.2 现象不同花色的同一牌面被当成不同类别原因标注时把“红桃K”和“黑桃K”标注成了两个不同的类别。虽然这在扑克识别场景中是有意为之的需求比如做花色识别但大多数情况下A-K识别只需要13类如果标注文件里把花色也拆出来类别数会变成52类而每类的样本数被稀释到不足50张模型根本学不够。解决先确认你的目标到底是识别牌面字母还是识别具体牌型。这道题目的标题明确了是“识别A-K所有的牌字母”所以应该合并同类不同花色的标签。写个类别映射字典把花色标签映射到13类主类别重新生成TXT文件即可。5.3 现象训练中OOM报错batch降到4还是崩原因显存不够的原因不只是batch。imgsz640表示图片缩放到640x640但如果你没注意数据集里有超大分辨率的原图比如手机拍的4000x3000数据加载阶段会临时占用大量显存做resize这个峰值很容易把显存撑爆。解决把imgsz调低到416这通常能直接解决OOM问题。如果还要更大输入考虑cacheTrue参数把数据集预加载到内存减少IO抖动。另外排查其他GPU上是否有残留进程用nvidia-smi看一下即可。5.4 现象推理时同一个牌面被同一个框反复框住原因NMS非极大值抑制参数没调好。默认的NMS IoU阈值是0.7如果检测框稍有偏移IoU计算可能低于0.7NMS就不会合并这两个框。扑克牌识别场景中牌的边缘有花纹和字母模型可能同时学到两个特征点。解决在predict参数中把iou调低到0.5或者在训练时调低nms_conf. 实际操作上更推荐在推理时调整iou参数训练时改NMS参数要重新训练成本太高。我一般在推理时把iou0.45作为兜底值。5.5 现象验证集准确率98%但拍视频时识别率明显下降原因这是典型的数据分布不匹配问题。验证集里的图片和数据集的图片大多来自同一分布甚至可能是原作者的截图或摆拍图而实际部署环境的光照、角度、扑克牌品牌都不同。这在视觉任务中屡见不鲜不是模型问题是数据覆盖度问题。解决先不要急着改模型把你实际场景里拍的视频截帧标注100到200张图混入训练集做一次增量训练。如果增量训练后指标恢复说明数据分布适配成功了如果还差再考虑加马赛克增强或颜色扰动。这个过程既是数据迭代也是模型迭代它的优先级永远高于折腾网络结构。6. 让模型在小牌面、强透视场景下更稳数据增强、精度优化与部署准备6.1 优化方向不一定在网络结构先检查推理时的输入尺寸很多同学习惯直接套imgsz640训练但这个参数不一定是扑克牌识别的最优值。如果你的应用场景是摄像头俯拍桌面牌面在画面中的占比通常比较大640足够但如果是手机App识别远处桌子上的牌或者监控画面里牌桌只占画面一小块牌面就是标准的小目标这时候imgsz640可能让字母区域只有十几个像素高。这个数据集标注的牌面字母框如果平均像素高度不到20像素就属于小目标场景。比较务实的做法是训练时把imgsz提到960虽然显存占用翻倍但对小目标的召回率提升幅度非常大。我实际测试过同一个模型在640和960推理mAP50-95一般能提升3到5个点代价是单张推理时间从15毫秒涨到30毫秒左右。如果你的部署场景对延迟不敏感这几乎是性价比最高的优化。6.2 用数据增强补足场景短板旋转、透视、光照一个都不能少扑克牌识别最大的物理特性是牌面可以被旋转成任意角度。YOLO训练默认的旋转增强范围很小因为行人检测不需要旋转目标。对于扑克牌识别必须把旋转增强调大# poker_augment.yaml 或者直接在训练命令里覆盖参数 yolo detect train \ modelyolo11n.pt \ datapoker.yaml \ epochs150 \ imgsz640 \ batch16 \ degrees180 \ perspective0.0005 \ hsv_h0.015 \ hsv_s0.7 \ hsv_v0.4degrees180表示允许模型学习任意旋转角度的牌面这是必须的因为实际场景中牌不会总是正朝上的。perspective0.0005模拟摄像头俯拍的角度偏差让模型在方形牌面变成不规则的四边形时依旧能识别。hsv_*参数调节的是光照变体不同灯光下牌面的色彩会有偏移这个增强项能提升模型在不同环境下的鲁棒性。提示数据增强不是越大越好。degrees90到180度足够再大会让模型在睁眼方向完全颠倒时产生误判反而拉低mAP。用增强后多观察训练曲线出现先降后升的过拟合迹象就回调。6.3 部署前的模型导出与验证训练结束后模型的最终形态通常不是.pt文件而是ONNX或TensorRT引擎文件。.pt文件是PyTorch格式需要PyTorch环境才能跑推理ONNX是跨框架中间格式可以部署到CPU和GPU环境TensorRT是针对NVIDIA GPU的高度优化版本推理速度最快。导出命令很简洁yolo export \ modelruns/detect/train/weights/best.pt \ formatonnx \ opset12 \ simplifyTrue导出成功后用ONNX Runtime验证一下推理结果是否和PyTorch版本一致。这里有个常见的坑导出时imgsz默认是训练时的输入尺寸如果你导出的ONNX绑定在640分辨率部署时输入720分辨率的图就会报错。因此导出的分辨率必须严格等于你的推理服务实际会接收的分辨率。6.4 一份实际的“验收清单”什么样的模型算合格最后给一个我在牌类识别项目里固定使用的验收模板你可以直接照搬。训练完一个模型后不只瞄一眼mAP数字就算完事而是走四条标准线一用训练集里表现最好的图推理一遍确认视觉上检测框贴合二用“最难”的10张图透视严重、光照不足、牌面重叠推理一遍记录失败模式三在项目中计算CPU版ONNX的单帧推理耗时四确认错误分类集中在哪几个类别之间是否有安全风险——比如识别成别的牌面会不会在贸易决策里引发误判。在这个项目上我的习惯是训练结束后把最差的那组图片单独归档下次迭代时直接对比这组图片的提升幅度这比总盯着mAP数字更实用。很多细节上的翻车都会在这个清单里暴露出来可能是透明牌的反光问题可能是旋转180度后的字母“6”和“9”不分可能是重叠牌面把K的边缘吞掉了。这些问题没有一个能靠替换网络结构解决都是靠数据采集、标注复核、增强参数调整、推理后处理这四件套来回打磨。希望这些方法和思路能帮你更快走通这个方向少花一些在无效调试上的时间。本文还有配套的精品资源点击获取