扑克牌识别一直是计算机视觉领域一个极具挑战性的任务。52张标准扑克牌在视觉上具有高度相似性,特别是同花色的牌面图案几乎一致,仅靠数字或字母区分。传统图像处理方法在这个问题上往往捉襟见肘,而深度学习技术特别是目标检测算法YOLO系列的出现,为这个问题提供了全新的解决方案。
我最近基于最新的YOLOv10算法开发了一套完整的扑克牌识别系统,经过反复测试和优化,最终实现了对52种标准扑克牌(13个点数×4种花色)的高精度识别。这个系统不仅能准确识别单张扑克牌,还能处理多张牌重叠、部分遮挡等复杂场景,平均识别准确率达到98.7%,单帧处理速度在RTX 3060显卡上可达45FPS。
选择YOLOv10作为基础算法主要基于以下几个关键考量:
实时性需求:相比两阶段检测器(如Faster R-CNN),YOLO系列的单阶段特性更符合实时检测需求。YOLOv10在保持YOLO系列实时性的基础上,进一步优化了精度和速度的平衡。
小目标检测:扑克牌在图像中往往只占较小区域(特别是远距离拍摄场景),YOLOv10改进的特征金字塔网络(FPN)和自适应特征融合机制对小目标检测更为友好。
部署便利性:YOLOv10提供了完善的Python接口和模型导出功能,支持ONNX、TensorRT等多种格式,便于后续集成到各类应用场景。
整个系统采用模块化设计,主要包含以下核心组件:
数据采集与标注模块:负责扑克牌图像的采集、清洗和标注工作,输出符合YOLO格式的标准数据集。
模型训练与优化模块:基于YOLOv10进行模型训练、验证和超参数调优,输出最优模型权重。
推理检测模块:加载训练好的模型,实现图片、视频和实时摄像头的扑克牌检测功能。
用户交互界面:采用PyQt5开发的图形界面,提供直观的操作体验和结果展示。
构建高质量的数据集是模型成功的基础。我们采用了多维度采集策略:
设备多样性:使用10种不同型号的手机和相机(iPhone 12/13、华为Mate40、佳能EOS R等)进行拍摄,确保图像传感器特性的多样性。
场景覆盖:
样本平衡:确保每类扑克牌的样本数量基本均衡,避免模型出现类别偏见。
标注质量直接影响模型性能,我们制定了严格的标注规范:
标注工具:使用LabelImg进行人工标注,标注文件保存为YOLO格式(归一化坐标)。
标注要求:
质量保障:每张图像由3人分别标注后进行交叉验证,标注不一致的样本由专家仲裁。
为提高模型泛化能力,我们实施了全面的数据增强策略:
python复制# 数据增强配置示例(YOLOv10训练配置文件)
augmentations:
# 空间变换
hsv_h: 0.015 # 色调调整幅度
hsv_s: 0.7 # 饱和度调整幅度
hsv_v: 0.4 # 明度调整幅度
translate: 0.1 # 平移幅度
scale: 0.5 # 缩放幅度
shear: 0.0 # 剪切幅度
perspective: 0.0001 # 透视变换幅度
flipud: 0.0 # 上下翻转概率
fliplr: 0.5 # 左右翻转概率
mosaic: 1.0 # mosaic增强概率
mixup: 0.0 # mixup增强概率
我们使用以下硬件和软件环境进行模型训练:
硬件配置:
软件环境:
环境配置步骤:
bash复制# 创建conda环境
conda create -n yolov10 python=3.9
conda activate yolov10
# 安装PyTorch
pip install torch==1.12.1+cu113 torchvision==0.13.1+cu113 --extra-index-url https://download.pytorch.org/whl/cu113
# 安装YOLOv10
pip install ultralytics
YOLOv10提供了多种预训练模型尺寸,我们根据实际需求选择了适当的模型:
| 模型类型 | 参数量 | 适用场景 | 推理速度(FPS) | mAP@0.5 |
|---|---|---|---|---|
| YOLOv10n | 2.3M | 嵌入式设备 | 145 | 0.82 |
| YOLOv10s | 7.2M | 实时应用 | 98 | 0.86 |
| YOLOv10m | 21.2M | 平衡型 | 62 | 0.89 |
| YOLOv10b | 36.7M | 服务器端 | 45 | 0.91 |
| YOLOv10l | 52.9M | 高精度 | 32 | 0.92 |
我们最终选择YOLOv10b作为基础模型,在精度和速度之间取得了良好平衡。训练参数配置如下:
python复制from ultralytics import YOLOv10
# 初始化模型
model = YOLOv10('yolov10b.pt')
# 训练配置
results = model.train(
data='poker.yaml',
epochs=500,
batch=64,
imgsz=640,
device='0',
workers=8,
optimizer='AdamW',
lr0=0.001,
weight_decay=0.05,
warmup_epochs=3,
box=7.5, # box loss增益
cls=0.5, # cls loss增益
fl_gamma=1.5 # focal loss gamma
)
训练过程中我们密切监控以下关键指标:
损失函数变化:
评估指标:
硬件利用率:
我们使用TensorBoard进行训练过程可视化,便于及时发现和解决问题。
在训练过程中,我们应用了以下优化技巧提升模型性能:
自适应锚框计算:基于我们的数据集重新计算了锚框尺寸,更贴合扑克牌的实际比例。
类别平衡采样:对样本较少的类别(如某些花色的A、K、Q、J)适当增加采样权重。
困难样本挖掘:在训练中后期,重点关注模型预测错误的样本,加大这些样本的训练权重。
学习率调度:采用余弦退火学习率策略,配合warmup阶段,使训练更加稳定。
系统的核心检测流程如下:
图像预处理:
模型推理:
后处理:
关键代码实现:
python复制def detect_poker(image, model, conf_thresh=0.5, iou_thresh=0.45):
"""
扑克牌检测核心函数
:param image: 输入图像(numpy数组)
:param model: 加载的YOLOv10模型
:param conf_thresh: 置信度阈值
:param iou_thresh: NMS的IoU阈值
:return: 检测结果列表,每个元素为[class_name, confidence, [x, y, w, h]]
"""
# 图像预处理
img = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
img = letterbox(img, new_shape=640)[0] # 保持长宽比的resize
img = img.transpose(2, 0, 1) # HWC to CHW
img = np.ascontiguousarray(img)
img = torch.from_numpy(img).to(model.device)
img = img.float() / 255.0 # 归一化
# 模型推理
with torch.no_grad():
pred = model(img[None]) # 增加batch维度
# 应用NMS
pred = non_max_suppression(pred, conf_thresh, iou_thresh)
# 后处理
results = []
for det in pred[0]: # 第一个batch的结果
if det is not None and len(det):
for *xyxy, conf, cls in det:
x1, y1, x2, y2 = xyxy
w, h = x2 - x1, y2 - y1
class_name = model.names[int(cls)]
results.append([class_name, float(conf), [float(x1), float(y1), float(w), float(h)]])
return results
我们使用PyQt5开发了直观的用户界面,主要功能包括:
界面布局采用经典的左右分栏设计:
为实现实时检测,我们实施了以下性能优化措施:
异步检测线程:将检测逻辑放在独立线程中运行,避免阻塞UI主线程。
帧采样策略:对于视频输入,当处理速度跟不上帧率时,自动跳过中间帧,确保实时性。
GPU加速:使用CUDA加速所有图像处理和张量运算。
内存管理:及时释放不再使用的图像内存,避免内存泄漏。
模型量化:将训练好的FP32模型量化为INT8,在几乎不损失精度的情况下提升推理速度。
我们在测试集(1,010张图像)上对系统进行了全面评估,主要指标如下:
| 指标名称 | 数值 | 说明 |
|---|---|---|
| mAP@0.5 | 0.987 | IoU阈值0.5时的平均精度 |
| mAP@0.5:0.95 | 0.842 | 不同IoU阈值下的平均精度 |
| 精确率 | 0.992 | 检测为正样本中真正正样本比例 |
| 召回率 | 0.983 | 真正正样本中被检出的比例 |
| 推理速度(FPS) | 45 | RTX 3060显卡上的处理速度 |
| 模型大小 | 36.7MB | YOLOv10b模型文件大小 |
系统在不同场景下的表现有所差异:
理想条件(良好光照、正视角、单张牌):
挑战性条件:
特殊场景:
分析模型预测错误的案例,主要错误类型包括:
相似类别混淆:
定位误差:
漏检:
针对这些错误,我们计划在后续版本中通过以下方式改进:
将本系统集成到赌场监控系统中,可以实现:
集成方案通常包括:
在线上扑克平台或实体娱乐场所,本系统可用于:
对于扑克魔术爱好者和研究者,本系统可以提供:
在扑克牌生产流水线上,本系统可以用于:
场景覆盖:尽可能覆盖所有可能的应用场景,包括不同的光照条件、背景环境和摆放方式。
设备多样性:使用多种拍摄设备采集数据,避免模型对特定摄像头特性产生依赖。
标注一致性:制定详细的标注规范,确保不同标注人员的工作结果一致。
数据平衡:定期检查各类别的样本数量,对样本不足的类别进行针对性补充。
学习率设置:初始学习率不宜过大,建议使用学习率预热(warmup)策略。
早停机制:监控验证集指标,当指标不再提升时提前终止训练,避免过拟合。
模型检查点:定期保存模型权重,便于回溯和选择最佳模型。
混合精度训练:使用AMP(自动混合精度)技术可以显著减少显存占用并提升训练速度。
模型量化:将FP32模型量化为INT8,可以大幅提升推理速度,适合边缘设备部署。
TensorRT加速:对于NVIDIA平台,使用TensorRT可以进一步优化模型推理性能。
批处理优化:对于视频流处理,适当增大批处理尺寸可以提高GPU利用率。
内存池:预先分配图像处理所需的内存空间,避免频繁的内存申请释放操作。
CUDA内存不足:
过拟合:
类别不平衡:
推理速度慢:
完整项目源码包含以下主要目录和文件:
code复制poker-detection-yolov10/
├── data/ # 数据集相关
│ ├── images/ # 图像文件
│ │ ├── train/ # 训练集图像
│ │ ├── val/ # 验证集图像
│ │ └── test/ # 测试集图像
│ └── labels/ # 标注文件
│ ├── train/ # 训练集标注
│ ├── val/ # 验证集标注
│ └── test/ # 测试集标注
├── models/ # 模型相关
│ ├── yolov10b.pt # 预训练权重
│ └── poker_best.pt # 训练得到的最佳权重
├── utils/ # 工具函数
│ ├── datasets.py # 数据集加载
│ ├── general.py # 通用函数
│ └── plots.py # 绘图函数
├── detect.py # 检测脚本
├── train.py # 训练脚本
├── ui.py # 用户界面
├── requirements.txt # 依赖库列表
└── poker.yaml # 数据集配置文件
模型轻量化:探索知识蒸馏、剪枝等技术,进一步减小模型尺寸,适应边缘设备部署。
3D姿态估计:增加对扑克牌三维姿态的估计能力,更好处理重叠和遮挡情况。
多模态融合:结合RFID等其他传感技术,提升在极端条件下的识别鲁棒性。
领域自适应:开发自适应算法,使模型能够快速适应新的扑克牌设计和拍摄环境。
行为分析:扩展系统功能,不仅识别牌面,还能分析玩家的拿牌、出牌等行为模式。