
简介面向目标检测入门与扑克牌识别场景的标注数据集适合学习YOLO、SSD等检测模型的初学者也适用于需要自定义扑克牌识别任务的开发者。数据集中图片均来自真实拍摄画面标注类别涵盖queen、ten、nine、king、jack、ace六种常见扑克牌使用LabelImg工具生成VOC格式的XML标签便于直接接入主流检测框架进行训练与验证。整个压缩包共726个文件包括363张JPG原图与363个对应的XML标注文件资源总大小约36.62MB图片与标签一一对应目录结构简洁无需额外整理即可使用。目前已有395人学习下载适合作为目标识别课程作业、算法实验或扑克牌识别项目的前期数据基础。通过该数据集读者可以快速完成数据加载、标签解析、模型训练与精度评估等流程节省自行采集和标注图片的时间成本也可在此数据上进一步扩展更多牌面类别开展更丰富的检测实验。1. 扑克牌目标识别数据集为什么一张牌面的标注比普通物体更难做棋牌 AI 或者牌桌自动化应用时很多人第一次接触扑克牌数据标注会觉得“这不就是框个矩形、贴个名字吗”。真正上手才发现红桃和方块的牌面差异极小黑桃 A 在旋转 180 度后和它本身的区别比猫和狗的距离还近加上反光、遮挡、俯拍角度带来的形变普通目标识别的标注套路在扑克牌上会频繁失效。这个标题要解决的就是为扑克牌目标识别任务准备一套可靠标注数据集的完整路径——从工具选型、类设计、标注规范到难例处理和标注质量验证。它适合正在做棋牌类视觉项目、牌桌机器人、魔术教学识别或自动发牌验证系统的工程师也适合刚接触数据标注、想把自己采集的牌面图像变成能训练 YOLO 或 Detectron2 的标准数据集的人。下面按“先定规范、再动手标、最后验质量”的顺序展开。2. 标注前的准备工具对比、类设计与扑克牌标注规范2.1 选对标注工具CVAT、LabelMe、Roboflow 怎么挑扑克牌标注属于刚性目标识别边界清晰但类别多标准扑克 52 张牌区分花色和点数所以工具选择的优先级跟行人检测那种场景完全不同。我一般建议从三个维度来筛选是否支持多分类标签、导出格式是否覆盖 YOLO/COCO/VOC、是否支持多边形以外的旋转框——因为扑克牌在桌面上经常是倾斜摆放的水平矩形框在斜置牌面上会框进大量背景干扰。工具适用规模旋转框支持多分类标签部署方式LabelMe千张以内单机标注多边形自由绘制支持pip 安装本地运行CVAT中小团队并行标注支持旋转矩形支持可层级组织Docker 部署后浏览器访问Roboflow需要预标注模型协助的团队支持旋转框支持云服务X-AnyLabeling需要半自动 AI 辅助标注支持支持本地运行带推理模型单机个人项目我一般推荐 LabelMe因为它的 JSON 结构透明、二次处理脚本简单。团队协作或者数据量超过两千张时用 CVAT 更合适它能直接在浏览器里分配任务、多人标同一批次图、标的进度可视化而且自带自动标注插件能用预先训练好的模型生成初始框人工只需要调整和改类别。CVAT 用 Docker 起服务的方式比较标准git clone https://github.com/cvat-ai/cvat cd cvat docker compose up -d参数说明默认账号在docker compose logs cvat里看初始密码首次启动需要拉取 PostgreSQL、Redis 和 CVAT 三个镜像占用端口 8080。启动后访问本机 8080 即可打开标注界面。用 CVAT 标注扑克牌时记得在任务设置里把标注模式改成rect加rotation这样拉出来的框能够贴合牌面角度。2.2 类别体系的设计52 类直接标还是花色点数分开标扑克牌目标识别数据集的类别设计从结果上影响模型的收敛难度。常见有两种做法。方案 A直接标 52 个类别。每张牌一个类例如AH表示红桃 AAS表示黑桃 A。标签数量多但每个类在数据集里天然均衡一副牌每种一张模型输出直接是“这张牌是谁”不需要后处理拼装。缺点是如果某张牌的训练图特别少——比如倾斜角度过大的黑桃 5——这个类的 AP 会被拉低。方案 B把点数Rank和花色Suit分开做两个分支。这种在模型结构支持多任务输出时更合理例如点数 13 类、花色 4 类。推理时联合输出“它是 A 且是红桃”。它的好处是类别总数从 52 降到 17小样本问题被缓解但代价是推理链路多了组合步骤错误会传播。YOLOv8 这类单阶段检测器默认不支持多分支分类输出强行改结构性价比不高。实际工程项目里我做的最多的是方案 A 的改良版52 类全量标注但把牌面旋转超过 45 度的难样本单独建一个镜像类——即旋转后的黑桃 A 标成AS_rot。这样模型不需要自己学习跨界角度的判定推理时再做一个几何校正准确率比单纯加大旋转增强稳很多。标注 Directory 结构上原始图像建议按train/ valid/ test/三个目录分好每张图的可视化标注文件跟在原图旁边。2.3 标注规范最小外接框还是紧密贴合扑克牌牌面本身是直角矩形但在照片里由于透视变成任意四边形这引出一个常见的标注争议到底是拉一个水平的矩形框还是用四个顶点拉一个贴合牌面边缘的四边形。我的建议是如果后续只用 YOLO 系列做训练标注水平矩形框加旋转增强足够因为 YOLO 的检测头输出的是轴对齐框你标注旋转框后 loss 反而不好算。但如果用的是 Faster R-CNN 加 RoI Transformer或者后续有做牌面矫正、牌面内容识别的需求那么用四点标注贴合牌面更合适这样后续拿标注点做透视矫正时就省一轮工作量。比较稳妥的做法是扑克牌目标识别用水平框标注但硬性要求矩形框的四个边贴近牌边缘 2 像素以内不允许为了省事框大一圈。原因是扑克牌在识别时边缘的白色边框和圆角本身携带颜色信息框得太大会吞进桌面纹理导致模型学到桌面背景特征。同时要求类别名统一用小写例如ace_of_hearts而不是AceOfHearts这样导出 YOLO 格式时类别索引与data.yaml的映射不容易对错。3. 用 LabelMe 实操标注扑克牌数据集的完整流程3.1 环境搭建安装 LabelMe 与图片整理LabelMe 是当前单人标注场景下最顺手的工具。安装就直接走 pippip install labelme labelme --version参数说明LabelMe 需要 Python 3.8 以上界面基于 PyQt5 实现所以安装时如果提示缺PyQt5直接用 pip 补装即可。运行目录建议做一个images/和labels/的对称结构mkdir -p dataset/images dataset/labels先把采集到的扑克牌图片统一转成 JPG 格式分辨率不要低于 640×640。如果原始照片是 4K 大图先用批量脚本压缩到 1280 或 1920 再标注不然标注界面拖动很卡导出训练时数据加载也慢。这一步容易被忽略标注前统一图像尺寸会比训练时做 resize 更可控因为你在标的时候就能判断小牌面是否清晰可辨。3.2 标注操作步骤从打开图片到保存 JSON打开 LabelMe 后依次操作1. 点击 Open Dir选择 dataset/images 目录 2. 点击 Edit - Create Rectangle在牌面上拉框 3. 弹窗中输入类别名例如 king_of_spades 4. 按下 CtrlS 保存LabelMe 会在图片同名目录下生成 JSON每张图标注完成后检查一下右侧 File List 里对应的 JSON 是否生成。LabelMe 的 JSON 里除了points和label字段外还带有imageWidth和imageHeight这两个参数在转 YOLO 格式时要用于坐标归一化缺了会导致坐标全部错位。提示如果标注过程中发现牌的边缘反光导致看不清花色把图片亮度调低一档再标或者在采集时用偏振镜片消除反光。反光边缘的像素用肉眼看是花色的一部分但模型训练看到的却是白色高光块标注时尽量贴合实际可见的图案边界而非牌面物理边界。3.3 把 JSON 转成 YOLO 格式的脚本与参数说明标注完的 LabelMe JSON 是不能直接丢给 YOLO 训练的必须转成每张图片对应一个.txt文件的格式。下面这个脚本完成扑克牌数据集从 JSON 到 YOLO 的转换import json import os def labelme_to_yolo(json_path, output_dir, class_names): with open(json_path, r, encodingutf-8) as f: data json.load(f) img_w data[imageWidth] img_h data[imageHeight] txt_lines [] for shape in data[shapes]: label shape[label] if label not in class_names: continue class_id class_names.index(label) points shape[points] xs [p[0] for p in points] ys [p[1] for p in points] x_min, x_max min(xs), max(xs) y_min, y_max min(ys), max(ys) center_x (x_min x_max) / 2 / img_w center_y (y_min y_max) / 2 / img_h width (x_max - x_min) / img_w height (y_max - y_min) / img_h txt_lines.append(f{class_id} {center_x:.6f} {center_y:.6f} {width:.6f} {height:.6f}) output_path os.path.join(output_dir, os.path.basename(json_path).replace(.json, .txt)) with open(output_path, w) as f: f.write(\n.join(txt_lines)) class_names [ace_of_hearts, king_of_spades, ...] # 与标注时一致逻辑说明这个脚本取一个标注框的所有顶点坐标计算最小外接矩形的中心点、宽高再分别除以图像宽高完成归一化最终输出 YOLO 格式的一行class_id cx cy w h。参数class_names的顺序对应最终data.yaml里的类别顺序想调整类别索引就在这里改顺序改完后训练配置里要同步改。转换完成后检查一下输出 txt 里的坐标数值全部在 0 到 1 之间才是正常的。如果出现 0 或负数说明原始 JSON 里有的坐标超出了 imageWidth/imageHeight这是因为标注时不小心把标注框拖出画布边界了回到 LabelMe 里修正即可。4. 扑克牌标注里的难例处理与半自动标注4.1 模型最容易犯的错标注时最容易忽略的样本扑克牌目标识别中以下几类样本直接影响最终模型的精度而且都是标注阶段决定成败的一是近邻花色混淆样本。红桃和方块在不看颜色时非常像尤其是低分辨率下。标注这类牌面时颜色通道如果是灰色、灯光偏黄肉眼看不清必须放大到 300% 再确认花色。我一般要求标注员在拿不准时直接看牌局部放大图判花色而不是靠经验猜。二是旋转角度刁钻的样本。一张黑桃 A 如果旋转 90 度它和没旋转的样本差很多。按 2.2 节的方案超过 45 度的旋转样本单独设置类别或做镜像标记否则模型在推理时会误判点数的上下方向使得 A 和倒着的 A 变成两个特征。三是遮挡牌面。叠牌场景里下面一张牌露出 60% 的情况很常见。标注这类样本时必须坚持“看不见完整牌面的牌不标”但露出面积超过 50% 且能明确辨别类别时要标——这个比例阈值就是标注规范里最核心的参数通常定在 50%。低于 50% 的牌标注进数据集模型会学着猜而不是学着看导致真实场景下误检率升高。四是桌面反光和手指遮挡。数据集里没有手指的样本训练出来的模型在真实场景中有手入镜时容易把手指尖当成牌角。解决方法是标注时把手和牌的交界处统一处理成被遮挡牌不标。大原则是宁可漏标不可错标。难例场景标注策略期望的增强效果红桃 vs 方块放大确认花色降低近邻花色误检旋转 90 度独立旋转镜像类避免点数方向误判遮挡低于 50%不标注该牌减少无法检出的噪声手指/物体遮挡只标可见部分不补全牌面提升遮挡场景鲁棒性模糊/运动拖影不标注或移到 hard 集防止模型学到模糊特征4.2 用预标注模型加速扑克牌标注当待标注图片超过一千张时纯人工标注一张平均要 30 秒加上休息和复查一天最多处理 800 张。这时候做半自动预标注是效率最高的做法。CVAT 里可以直接集成预训练的目标检测模型做自动标注也可以本地用 YOLOv8 跑一遍推理生成初步框再导入 LabelMe 人工纠错。以本地的方式为例用 YOLOv8 生成预标注结果并转成 LabelMe JSONyolo predict modelbest_ckpt.pt sourcedataset/images/ save_txtTrue save_confTrue参数说明save_txtTrue会输出每张图的 YOLO 格式 txtsave_confTrue同时输出置信度。生成的 txt 里每行是class_id cx cy w h conf我们可以写一个反向转换脚本把带置信度的 txt 合并成 LabelMe JSON然后再用 LabelMe 打开逐一纠错。这个流程能减少 60% 以上的拉框时间因为预标注模型对常见牌面的定位已经比较准人工只需要改类别错误和调整边界。注意预标注的置信度阈值不要拉太高否则漏框很多反而省不了时间一般设到 0.25 比较合适宁可多出几个需要删掉的假框也不要漏掉难检的牌面。提示半监督学习方法在扑克牌场景同样可以用。第一次用少量人工标注样本比如 200 张训练一个粗模型然后让它去给未标注的图片做伪标注人工只修正低置信度的样本再把新样本加入训练集迭代。这种“从弱到强”的方式在扑克牌固定类别场景下能明显降低标注工作量。5. 验证标注质量并快速接入 YOLOv8 训练5.1 标注质量抽检类别分布与框面积的异常检测标注完成后训练之前必须先做一次数据体检。最容易出问题的几个点某个牌面类别样本数明显少于其他类、标注框面积占比异常通常不会超过整图的 60%、坐标数值越界。下面用脚本统计类别分布和框尺寸import os label_dirs [labels/train, labels/valid] cls_count {} box_area_ratios [] for label_dir in label_dirs: for txt_file in os.listdir(label_dir): with open(os.path.join(label_dir, txt_file), r) as f: for line in f.readlines(): parts line.strip().split() cls_id int(parts[0]) cls_count[cls_id] cls_count.get(cls_id, 0) 1 w float(parts[3]) h float(parts[4]) box_area_ratios.append(w * h) print(类别分布:, cls_count) print(框面积占比均值:, sum(box_area_ratios) / len(box_area_ratios))逻辑说明类别分布用字典统计每个class_id出现的次数如果某类数量低于平均数的三分之一说明该牌面的训练样本不足需要针对性补采或增加该类的旋转增强。框面积占比均值在 5% 到 20% 之间比较正常如果超过 40%可能是标注时把桌面背景都框进去了这将导致模型学習到大量背景特征。5.2 用 YOLOv8 验证数据集的可训练性数据体检通过后直接拉起一个最小训练验证数据集质量。用 YOLOv8 训练自己的数据集命令如下yolo detect train datadataset/data.yaml modelyolov8s.pt epochs50 imgsz640 batch16参数说明data.yaml里要写清楚train和val的图片路径及类别列表modelyolov8s.pt表示用 YOLOv8s 的预训练权重做迁移学习。epochs50对扑克牌数据集来说够用了因为牌面差异相比自然图像更小模型收敛快如果 50 轮后 mAP 还在明显上升再调大。训练完成后查看runs/detect/train/下的results.png重点看mAP50和mAP50-95两条曲线的增长坡度如果mAP50在 20 轮内没超过 0.9大概率是标注数据里有错误标签——最常见的错误是红桃和方块标混。最终记住一个验证技巧训练完成后用最佳权重对训练集做一次全量回测找出所有置信度低于 0.3 的检测结果并打印原始标注与之对比。这些低分样本就是标注质量最差的区域逐张修正后重新训练扑克牌识别准确率会有一次明显跃升。本文还有配套的精品资源点击获取