简介:扑克牌识别数据集专注于A-K全字母牌面检测,面向计算机视觉入门及目标检测实战人群,可直接用于YOLOv11模型训练与验证。资源共2000个文件,包括1850个txt格式的标注文件、149张jpg原始图像及1个yaml配置文件,压缩包大小109.76MB。txt文件对应每张图片的目标框与类别标签,yaml文件定义了数据集路径与类别名称,整体结构规范,能够帮助使用者跳过数据清洗与格式转换环节,快速开展扑克牌识别模型的训练与验证。该数据集包含多角度、多样环境下的真实照片,标注精度较高,在测试条件下正确识别率可达98.7%,适合构建棋牌识别、发牌检测、牌局自动化记录等应用;可用于课程设计、毕业设计或实际项目开发,省去大量数据准备时间。目前已有241人学习浏览,对有类似识别需求的研究者或开发者来说是一份可直接上手的实用资源。
1. 扑克牌识别数据集在YOLO v11里怎么用
做棋牌类AR应用或扑克牌自动计分系统时,“识别A-K所有牌字母”是常见的第一步。这个标题的数据集给出1850张原始图,标注文件是YOLO v11可直接读取的txt格式,训练难度不高,正确识别率做到98.7%并不意外:13个类别、牌面图形相对固定、背景干扰可控。适合刚接触yolo训练自己数据集的工程师,也适合需要一个干净基线来验证数据增强和部署方案的熟手。相比满网保存的COCO 2017或车牌数据集,这种小而专属于桌面场景的数据集,反而能让你把一套“数据→训练→评估→部署”的流程完整走通。下面我按自己训练牌类识别模型时的做法,从标注格式、训练闭环、精度边界到验证手段逐层展开。
2. YOLO v11格式的扑克牌数据集:图片、txt与类别映射
2.1 一张扑克牌图对应的标注长什么样
YOLO格式不保存像素坐标,保存的是归一化坐标。对每个目标,标注文件的一行是“类别ID + 中心点x + 中心点y + 宽度 + 高度”,全部是相对图片宽高的比例,取值范围在0到1之间。
拿一张640x480的红桃A举例,牌面右上角字母A的像素框是x_min=120, y_min=170, x_max=210, y_max=260,则:
- 中心点x = (120+210)/2 / 640 = 0.2578
- 中心点y = (170+260)/2 / 480 = 0.4479
- 宽度 = (210-120)/640 = 0.1406
- 高度 = (260-170)/480 = 0.1875
最终txt文件里对应行就是0 0.2578 0.4479 0.1406 0.1875。这个数据集把A到K映射成连续类别ID,花色不参与分类,所以类别数固定为13。
| 牌面字母 | 类别ID | 备注 |
|---|---|---|
| A | 0 | Ace |
| 2 | 1 | Two |
| 3 | 2 | Three |
| 4 | 3 | Four |
| 5 | 4 | Five |
| 6 | 5 | Six |
| 7 | 6 | Seven |
| 8 | 7 | Eight |
| 9 | 8 | Nine |
| 10 | 9 | Ten |
| J | 10 | Jack |
| Q | 11 | Queen |
| K | 12 | King |
2.1.1 数据集目录结构与data.yaml
拿到这类数据集后,第一步是把它整理成ultralytics默认识别的目录树。我一般会按下面的结构摆放:
cards_dataset/ ├── data.yaml ├── train/ │ ├── images/ │ └── labels/ └── val/ ├── images/ └── labels/data.yaml是这个数据集和YOLO v11之间的接口文件,内容如下:
train: ./train/images val: ./val/images nc: 13 names: ['A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K']nc必须与names列表长度一致,顺序一旦确定就不要在训练中途改。如果原始数据集的标注文件里出现了“红桃A”“黑桃K”这类带花色的标签名,需要先过滤或统一映射,否则LabelError会在训练启动阶段直接报出来,错误信息会告诉你“Label class X exceeds nc=13”。
2.1.2 批量转换标注时我用的Python脚本
很多公开数据集不会直接给你YOLO txt,而是给JSON或XML。以下是我把JSON转成YOLO格式的常用脚本,可以直接套用到手头数据集:
import json from pathlib import Path from PIL import Image def convert_annotation(json_path: Path, output_dir: Path): """ 把JSON标注(像素坐标)转成YOLO txt。 假设JSON结构为: { "image": "img_0001.jpg", "boxes": [ {"label": "A", "x1": 120, "y1": 170, "x2": 210, "y2": 260} ] } """ label_to_id = {'A': 0, '2': 1, '3': 2, '4': 3, '5': 4, '6': 5, '7': 6, '8': 7, '9': 8, '10': 9, 'J': 10, 'Q': 11, 'K': 12} with open(json_path, 'r', encoding='utf-8') as f: data = json.load(f) img = Image.open(json_path.parent / data['image']) w, h = img.size lines = [] for b in data['boxes']: cls_id = label_to_id.get(b['label']) if cls_id is None: continue # 跳过非A-K的花色标记 x_center = (b['x1'] + b['x2']) / 2 / w y_center = (b['y1'] + b['y2']) / 2 / h box_w = (b['x2'] - b['x1']) / w box_h = (b['y2'] - b['y1']) / h lines.append(f"{cls_id} {x_center:.6f} {y_center:.6f} {box_w:.6f} {box_h:.6f}") output_dir.mkdir(parents=True, exist_ok=True) (output_dir / (data['image'][:-4] + '.txt')).write_text('\n'.join(lines), encoding='utf-8')这个脚本先读原图尺寸,再把像素框换算成归一化坐标。关键点在于cls_id的映射表,如果你手里的数据集把“10”放在“9”和“J”之间,ID顺序要保持一致。另外,输出的小数位保留6位就够,YOLO读取时对第7位之后的多余精度不敏感,但少于4位会明显掉边框精度。
2.1.3 标注质量检查:把框画回图上
数据集标注“看着能用”和“真的能用”是两件事。我拿到1850张牌的标注后,不会直接开训,而是先把txt画回图片上做一遍人工抽查,这一步能迅速发现坐标归一化错误、文件错位、框体偏移到牌面外等问题。
import cv2 def check_label(img_path: str, label_path: str): img = cv2.imread(img_path) h, w = img.shape[:2] with open(label_path, 'r') as f: for line in f: cls, xc, yc, bw, bh = map(float, line.split()) x1 = int((xc - bw / 2) * w) y1 = int((yc - bh / 2) * h) x2 = int((xc + bw / 2) * w) y2 = int((yc + bh / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(img, str(int(cls)), (x1, max(0, y1 - 8)), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0), 2) cv2.imwrite('check.jpg', img)对扑克牌这类高对比度目标,如果框中心落在牌面纹理而非字母上,模型的分类头会学到错误特征。边框最好框住整个牌面或单独框住角落字母,两者不能混用,否则同类别的正样本外观差异过大,训练时要花更多epoch才能收敛。
2.2 小数据集下如何划分train/val
1850张图不算多,我一般按85%训练、15%验证来切,也就是大约1572张训练、278张验证。不要按整副牌来分,要按图片切,防止同一张图里的多张牌同时出现在训练集和验证集。具体切分可以直接用ultralytics的val参数指定目录,不需要额外写脚本。如果验证集里出现某一张牌面在训练时已经见过,验证指标会被明显高估,最终上线时正确识别率会掉5个百分点以上。
3. 用YOLO v11把扑克牌数据集跑成可识别模型
3.1 训练命令与参数选择
目录就绪后,训练只需要一条命令:
yolo train data=cards_dataset/data.yaml model=yolo11n.pt epochs=100 imgsz=640 batch=16 device=0这里model=yolo11n.pt用的是YOLO v11的nano预训练权重,COCO预训练权重能加速收敛,比随机初始化更容易在小数据集上稳定。imgsz=640与数据集原始分辨率匹配,多数牌面图本身就在640附近,不需要强行放大到1280。
| 参数 | 推荐值 | 说明 |
|---|---|---|
| model | yolo11n.pt | 13类小任务,nano足够 |
| imgsz | 640 | 与图片分辨率一致 |
| epochs | 100~150 | 1850张图为基准,100轮后可看曲线 |
| batch | 16或32 | 显存不够就降为8 |
| workers | 8 | 数据加载线程数,按CPU核数调 |
| cache | True | 小数据集直接预加载到内存,显著降训练时间 |
我一般会加cache=True,1850张图完整缓存到内存也就一两GB,读取速度提升明显。batch在单卡16G显存下设为16比较稳。device=0指定单GPU训练,没有GPU时改为device=cpu,但12类小任务也会慢好几倍,建议先用Google Colab或租卡跑通。
3.1.1 为什么从yolo11n.pt而不是yolo11s.pt开始
扑克牌识别不属于细粒度分类,不需要大模型容量来区分相似物种。A到K之间虽然有易混淆对,但整体特征差异足够大,nano模型已经能把mAP50推到0.98以上。大模型在这个数据量下更容易过拟合,训练日志里会出现train loss继续降、val loss抬头的典型曲线。如果你手里的显卡有余量,可以先跑一版nano作baseline,再用model=yolo11m.pt对比,但不要指望精度有质变。
3.2 训练过程中的Loss与指标怎么看
训练启动后,ultralytics会在runs/detect/train/下生成results.csv和results.png。你需要盯着四个指标:train/box_loss、train/cls_loss、metrics/mAP50和metrics/mAP50-95。
对扑克牌识别,box_loss会在前20个epoch快速下降,30轮后进入平台期。cls_loss是重点,A和4、J和1这类易混淆字母会让它降得比其他任务慢。mAP50如果稳定在0.98以上,说明检测头已经能准确定位牌面;mAP50-95在0.9附近就算健康,因为牌面框和真实框重叠度很高,框精度对识别率影响不大。
训练结束后,验证集评测命令是:
yolo val model=runs/detect/train/weights/best.pt data=cards_dataset/data.yaml split=val输出结果里重点看Class列精度。真正决定“正确识别率98.7%”这个数字的,不是总体mAP,而是每个字母类别的加权准确率,所以必须看到A、K、Q这些单类的precision值。
3.2.1 训练500轮不如先检查数据
有人看到数据集小就盲目加epochs,从100加到300甚至500。实际上扑克牌识别跑到150轮后,val指标基本不再变化,继续训练只会增加过拟合风险。我遇到这类数据集,更倾向于在训练前把数据增强参数调好,再决定epoch数。数据增强对牌面识别的影响,下一章详细展开。
4. 把98.7%正确识别率做实:牌面字母的边界与增强
4.1 “牌字母识别”和“纸牌检测”是两回事
标题里写的是“可识别A-K所有的牌字母”,不是“识别整副牌的类别”。两者的标注粒度不同:如果是检测整张牌,一个图里一张牌只有一个框;如果是识别字母,一张牌上通常有多个字母(左上角和右下角各一个),且字母框比牌面框小得多。
如果数据集提供的是整牌框标注,模型学到的是“整张牌长什么样”,换个背景或牌面角度就掉点。我一般处理扑克牌数据集会优先采用字母级标注,至少也要让训练框覆盖到牌面中央的大字母。标题里这个数据集标注的是牌字母,说明原始设计者已经帮你把粒度控住了。
4.2 A-K字母识别的三个典型坑
4.2.1 A与4在反光下的混淆
红桃A和红桃4都有明显的三角和竖线结构,当牌面有反光、阴影或拍摄角度倾斜时,A的内部横线会被高光吃掉,模型就会给出4的预测。解法不是换更大模型,而是在训练时加入轻微旋转和亮度扰动。
# 推荐的增强参数组合 yolo train data=cards_dataset/data.yaml model=yolo11n.pt epochs=100 imgsz=640 \ hsv_h=0.02 hsv_s=0.5 hsv_v=0.3 fliplr=0.5 flipud=0.5 scale=0.3hsv_v=0.3模拟光照变化,scale=0.3让模型适应牌在不同距离下的大小变化。flipud=0.5很关键:扑克牌上下旋转180度后仍然是有效的牌面,如果训练时不允许上下翻转,推理时遇到倒置牌就会漏检或错检。
4.2.2 J、Q、K这类带人像的牌占用更多像素
J、Q、K在牌面中央有人像,角落字母只占全图很小比例。如果标注目标是“牌字母”,边框过小会导致下采样后语义信息丢失,模型经常把J检出但把角落的J字母漏掉。我常用的做法是让标注框适度外扩,比如在原始字母框基础上扩展20%像素,保留一点背景上下文,分类准确率反而更高。
4.2.3 倒置牌与flip增强的关系
这里有个容易踩的坑:YOLO的fliplr和flipud会同时翻转标注框的坐标,ultralytics会自动处理,不需要你手动镜像数据。但如果你用了真值增强,比如自己写离线翻转脚本,就必须同步翻转坐标,否则训练时会报“box size out of bounds”或更隐蔽的错位框。
4.3 训练集只有1850张,过拟合怎么压
1850张图对13类识别不算富裕,尤其是Q和K这类样本数量天然偏少的牌。我一般用两种手段压制过拟合:一是mixup=0.2让模型看到牌面之间的混合图像,二是把close_mosaic设为10,让mosaic增强在最后10个epoch关掉,避免增强分布和真实分布差距过大导致val波动。
yolo train ... mosaic=1.0 mixup=0.2 close_mosaic=10在小数据集上,这两个参数的收益比调任何网络结构都明显。训练完成后用yolo val输出混淆矩阵,runs/detect/train/confusion_matrix.png能直接告诉你谁和谁互相打结。
5. 验证98.7%识别率的两个硬指标与一个部署技巧
5.1 用每个字母的准确率而不是只看mAP
mAP是检测任务的标准指标,但它混合了定位和分类的误差。拿标题里的98.7%来说,用户想知道的是“图里出现一张牌,模型有没有读对上面的字母”,这更接近classification accuracy。我在验证阶段会把val集的预测结果和人工标注做逐框匹配,IoU>=0.5且类别一致才算一个TP,然后单独统计每个字母的precision、recall和F1。
from ultralytics import YOLO model = YOLO('runs/detect/train/weights/best.pt') results = model.predict(source='cards_dataset/val/images', save_txt=True, conf=0.25) # 解析results,按类别统计 from collections import defaultdict stats = defaultdict(lambda: {'tp': 0, 'fp': 0, 'fn': 0}) for r in results: for box in r.boxes: cls = int(box.cls[0]) conf = float(box.conf[0]) # 假设计数逻辑:这里需要结合GT做匹配,完整脚本略 if conf >= 0.25: stats[cls]['tp'] += 1 # 实际需与GT比对实际统计时,我会把每个预测框和真值框做IoU匹配,避免光靠置信度自欺欺人。脚本不长,但能输出一张表格:每个字母的precision、recall、F1,再把13个类别的准确率按样本数加权平均,得到和标题里的98.7%可对比的数字。
5.2 导出ONNX后在部署端设双阈值
验证通过后,把best.pt导出为部署格式:
yolo export model=runs/detect/train/weights/best.pt format=onnx opset=12ONNX在部署端的推理速度比PyTorch快不少,而且可以脱离训练框架运行。导出后建议在推理代码里做双阈值判断:置信度大于0.9的预测直接采用,0.5到0.9之间的预测进入二次确认。二次确认可以是对同一张牌裁出区域再做一次字母分类,也可以是简单的“连续两帧结果一致才生效”。这个技巧尤其适合实时视频流场景,能明显压制A与4、J与1这类偶尔闪烁的误判。
5.3 牌面角度修正:把78.6%的旋转牌拉回到正确轴线
最后说一个实拍场景里最影响识别率的点:牌不会端端正正放在桌上。桌面摄像头拍到的牌经常带45度、90度甚至任意角度旋转,模型虽然对旋转有一定鲁棒性,但超出30度后字母形变严重,漏检率上升。我的做法是在检测结果上加一个角度修正步骤:
- 先用YOLO定位整张牌的粗略位置,拿到四个角点;
- 用最小外接矩形求旋转角;
- 以牌中心为轴做仿射变换,把牌转正;
- 转正后的小图再送入模型做字母分类。
这一步代码量不多,但能直接把摄像头俯拍场景下的正确识别率推高两到三个点。配合上面第5.2节的双阈值,整体识别流程已经接近标题所描述的98.7%水平。如果试完发现某些特定字体或特殊牌背仍然误判,优先去检查对应类别的数据增强参数,而不是立刻换更大的模型。
本文还有配套的精品资源,点击获取