尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

用YOLOv5打造AI斗地主:目标检测识别牌面,规则引擎决策出牌

用YOLOv5打造AI斗地主:目标检测识别牌面,规则引擎决策出牌 简介基于YOLOv5的AI斗地主项目将目标检测算法与强化学习结合利用YOLOv5的高速度与高准确度对实时牌面图像进行检测识别并辅助AI完成出牌决策面向对AI游戏、深度学习应用感兴趣的开发者或学生。资源内包含Python推理脚本、模型权重best.pt、数据集处理与模型工具模块以及ncnn-android部署工程可实现从牌面图像识别、定位矫正到出牌策略模拟的完整工作流同时涵盖训练、验证、Android集成等关键环节。压缩包共39个文件以.py、.cpp、.java源码和.xml、.gradle配置文件为主附带README说明、效果截图及运行脚本整体仅14.42MB目录结构清晰整体结构合理便于按需查阅。目前已有128人学习下载适合用于学习YOLOv5在真实场景的目标检测应用、强化学习训练流程以及将模型移植到Android端的技术实践。 我第一次看到基于yolov5的ai斗地主.zip这个文件名第一反应是作者在整活一个目标检测模型怎么能打斗地主但等我拆开项目才明白这个命名其实很诚实——它不打算用强化学习去统治牌桌而是让yolov5当整个系统的眼睛先看清楚屏幕上有什么牌再把状态交给策略逻辑去决定怎么出。这个定位让整件事变得合理多了斗地主的决策部分可以用规则搞定而视觉识别部分才是yolov5的主场。整个项目做下来我发现它特别适合三类人想学目标检测工程落地的同学、需要毕设或作品集项目的开发者以及纯粹想搞个能跑通的AI小玩具的玩家。1. 用目标检测当斗地主的眼睛项目定位与整体架构1.1 识别先行、决策后置的拆解思路斗地主的对局流程看起来很复杂但把它按信息流拆开本质只有三步看清牌面、分析局势、做出出牌动作。yolov5能解决的恰好是第一步里最核心的部分——识别画面中的每一张扑克牌是什么。至于第二步第三步其实不需要深度学习也能做到能用规则引擎加简单评分就够了。我搭的整体数据流是这样的屏幕截图 → ROI区域裁剪 → yolov5推理 → 检测框清洗与合并 → 结构化牌型状态 → 策略引擎 → 模拟点击出牌这套架构最大的好处是解耦识别部分只负责输出当前画面中手牌区有红桃3、方块3、黑桃K……策略部分只负责接收这串状态并返回出红桃3两边的修改互不影响。比如你想把策略从规则换成DQN识别模块一行不用改反过来你想换更高精度的模型策略端也不用动。1.2 模型选型先v5s起步再谈压缩很多新手一上来就纠结用yolov5s还是yolov5n我的建议是先别纠结直接上yolov5s跑通流程。等后面发现帧率不够、显存紧张再换小模型也不迟。我实际测下来不同模型在这里的表现差距很明显模型参数量桌面截图推理耗时(1080p输入)树莓派5是否可用综合建议yolov5n约1.9M15-25ms可用可作后期优化目标yolov5s约7.2M30-50ms勉强可用前期开发首选yolov5m约21.2M60-90ms不建议精度高但没必要斗地主牌面识别不是细粒度分类任务牌面点数区域占的像素又不小v5s的容量完全够用。我第一版用的是v5m精度没有明显优势推理耗时倒是涨了一大截后来果断降回v5s。如果你的对局环境很复杂比如桌面背景乱、牌堆遮挡多可以保留v5s慢慢调数据优先保证识别率比追求模型大小务实得多。1.3 先跑通最小闭环再谈自动化做这类项目最容易翻车的地方是一上来就想全自动打完一整局。我建议分三步走第一步只做识别。固定一个游戏画面截屏后把识别结果打印到控制台确认手牌区的牌都能被正确识别、排序、合并。第二步手动出牌。识别状态稳定之后自己根据控制台输出的牌信息去点击出牌验证整条链路里除了决策以外的所有环节是否可靠。第三步接上自动出牌。最后这一步反而是最简单的因为决策模块输入输出都定义好了剩下的就是调用模拟点击把动作发出去。这套渐进式打法的核心思路是让每个环节的错误在最小范围内暴露。如果识别就乱了后面策略再强也是白搭。2. 牌面数据采集与标注整活项目最磨人的一关2.1 数据从哪来三种来源的取舍这项目看起来是AI项目实际上花时间最多的是数据准备。牌面数据来源我试过三种第一种是自己截图最直接。打开斗地主对局等到发牌后截几张不同阶段的画面覆盖不同牌背、按钮状态、明暗环境再写个小脚本把每张牌裁出来。缺点是量少而且视角单一基本都来自同一个游戏界面。第二种是使用公开的扑克牌数据集。网上能搜到不少比如各类扑克牌检测数据集优点是类别全、数量多缺点是很多图片是俯拍真牌或渲染牌和你实际要检测的游戏画面风格差异大直接拿过来用效果不一定好。第三种是合成数据。用PIL把抠好的牌面贴到随机背景上再做随机旋转缩放能快速扩充数量。合成数据适合让模型学会牌的普遍长相真实截图则负责教会模型这个游戏界面的特殊风格两者结合效果最好。2.2 类别体系的两套方案一张一类别 vs 点数花色分离这是整个项目最值得想清楚的设计决策。扑克牌识别有两种类别设计思路方案A每张牌一个类别红桃A、黑桃K、方块10这样单独建类一共54类加大小王。优点是逻辑直观检测结果直接就是这张牌是什么缺点是类别多、样本需求大遇到新牌面或新字体要重新训练。方案B点数13类加花色4类分开检测检测两个目标再用位置关系组合成最终牌。比如同一张牌的位置附近同时检测到7和梅花就能确定是梅花7。优点在于类别少、误检率低后续还能复用模型识别其他牌的扩展场景缺点是需要额外写组合逻辑处理点数框和花色框的匹配关系。我最终选了方案B。实践下来的好处非常明显数据标注少一个量级训练时间短而且两个小模型合起来的精度比一个大而全的模型还好。花色的分类边界比点数模糊得多单独训练可以针对花色的混淆做特殊数据增强。至于组合逻辑其实就几十行代码的事。2.3 标注与清洗小数据集也要讲究质量标注用的工具是LabelImg框选的是牌面左上角的点数和花色区域而不是整张牌。这样做的原因是手牌经常互相遮挡整张牌的轮廓并不完整但左上角的点数区域通常露在外面。标注目标越小模型学到的特征越集中误检反而更少。我总共标了约1800张图每张图片里包含2到8张不等的牌面合计牌目标约8000个。对一个小项目来说这个量级够用但前提是覆盖度要够不同分辨率、不同亮度、牌与牌重叠、明牌和半遮挡都要有。有几张图反光严重到人眼都难分辨我一开始犹豫要不要删后来试着放进去发现模型会把反光区域学成带纹理干扰的特征于是果断把这类图从训练集里挑出来单独做图像增强而不是直接清洗掉效果改善很明显。2.4 数据增强mosaic在这类任务上要慎用yolov5自带的增强参数里mosaic增强在目标检测里通常很香但在扑克牌识别上却是个坑。mosaic会把四张图拼在一起再随机缩放很容易把一张牌切成两半或者让牌面点数区域变得极小这对后续的合并逻辑非常不友好。我的做法是把mosaic概率调低到0.2左右同时增加亮度、对比度、透视变换的增强力度。透视变换特别重要因为实际截图中牌经常是倾斜的如果不增强模型对倾斜牌面的泛化能力会很差。还有一个细节不要开随机旋转180度增强否则训练数据里会出现倒置的牌面检测器会同时输出正向和倒向两个框反而增加后处理负担。3. 从检测框到能看懂的牌后处理的几个关键细节3.1 检测框清洗置信度过滤与聚类去重模型输出的raw检测结果不能直接用。我踩得最深的坑是同一张牌经常被重复框出来两三次尤其是当牌面上既有大点数又有小花色图标时模型会把它们分别当作目标。虽然NMS已经去了一批高度重叠的框但仍有不少框中心点接近却IoU不够高的情况。我的清洗流程分三步先按置信度过滤阈值设在0.3到0.4之间再按检测框中心点距离做聚类两张框中心距离小于20像素就认为是同一张牌最后按类别合并保留置信度最高的那个框。这样处理之后重复检测基本消失。注意聚类阈值要根据你对局的牌面大小调整如果手牌区域特别宽牌与牌之间距离本来就大阈值可以适当放宽。3.2 倒牌检测一个容易被忽略的问题玩过斗地主的都知道手牌虽然是正面朝向玩家的但出牌区里的牌可能歪着、倒着。如果训练数据里没有倒置样本模型勉强能识别但置信度会很低如果训练数据里有倒置样本模型能识别出来但你没法从检测框得知这张牌是正向还是倒向的。我第一版就栽在这识别出一堆红桃7但实际是倒过来的方块7。现在的应对方案是给花色检测单独加一个二分类分支判断该张牌是正向还是倒置。实现上并不复杂就是给花色检测头多加一个输出维度。如果嫌麻烦更取巧的做法是只检测正向牌在数据增强里关闭旋转出牌区识别不到就降低它的优先级反正自动出牌时最关键的信息是手牌区手牌区里的牌一定是正向的。3.3 区域归属用ROI减轻识别压力斗地主界面布局很固定手牌在屏幕底部底牌在顶部出牌区在中间。我建议在送进模型之前就按ROI把截图裁开分别检测。这样做有两个好处一是大幅减少背景干扰二是三个区域用不同的置信度阈值手牌区要求严格出牌区可以放松一点。ROI的坐标需要针对不同分辨率做一次适配我直接写了个配置函数按当前屏幕分优先读取预设的1920x1080布局其他分辨率按比例缩放。实际测试下来ROI裁剪后识别准确率从92%提升到了97%左右提升非常可观。3.4 截屏库选型与推理性能提速的隐藏战场很多人忽略截屏本身的开销。我一开始用PIL的ImageGrab截一帧大约80到120毫秒直接把整个流程拖慢到每秒6帧推理再快也没用。后来换成mss库同样的截屏操作降到20到30毫秒帧率直接翻倍。mss是纯Python库pip安装就能用代码也不复杂强烈建议替换。如果你需要部署到树莓派5这类低算力设备yolov5n配合TensorRT做FP16推理一次推理大约20到30毫秒加上截屏和后处理整体可以做到每秒10帧以上。树莓派上的坑主要是内存带宽和散热实测跑半小时后温度上去会掉帧最好加个散热片或者限制帧率这属于工程优化里很实际的问题。4. 策略引擎yolov5不管的那部分决策4.1 牌型判定先把牌整理成机器能理解的结构拿到手牌区的牌型列表之后第一件事是把它们整理成计数器结构。我用的是Python的collections.Counter键是点数、值是数量。斗地主核心牌型就十种左右单张、对子、三张、三带一、三带二、顺子、连对、飞机、炸弹、王炸。判断我出的牌能不能管住上家的逻辑核心就是先解析上家出的牌型再从我手中枚举同型且更大的组合。我贴一下顺子判断的核心思路from collections import Counter def parse_sequence(cards): # cards: [3,4,5,6,7] # 返回 (牌型, 起始点数, 长度) 或 None counts Counter(cards) if len(counts) ! len(cards): return None # 有重复点数不是顺子 pts sorted(int(c) for c in counts) if len(pts) 5 or pts[-1] 14: # 2和大小王不能进顺子 return None if pts[-1] - pts[0] len(pts) - 1: return (顺子, pts[0], len(pts)) return None这个模块是整个决策部分的地基牌型解析错了后面策略全错。所以我当时专门写了一组单元测试把各种边界情况都覆盖了比如23456不合法、10JQKA合法、A2345不合法这类细节。4.2 一个托管级别的出牌策略够用且不依赖炼丹很多人以为AI斗地主一定要用强化学习其实一个规则加评分的小系统就足够打赢简单托管。我的策略核心是四件事第一先出手数少的牌型比如连对、顺子、三带一一口气多出几张能快速减少手牌数量。第二单张小牌优先出比如3、4、5这类保留大牌和炸弹做控制牌。第三拆牌能不动就不动。比如手里已经凑出了3到7的顺子就不要为了出一张3先把顺子拆散。拆牌前先模拟一下拆完之后的剩余手数亏不亏一目了然。第四炸弹和王炸尽量留着。一般来说在自己快跑完的时候或者对手只剩一两张牌时炸弹才值得交出去。无脑炸是最常见的败因。这套策略用优先级打分实现每种候选出法算一个分数出牌后剩余手数越少分越高拆的牌越少分越高出掉的牌越小分越高选最高分执行。实测对战简单托管级别可以稳定赢对中级稍微吃点亏主要还是记不住牌。4.3 升级路线把决策模块换成强化学习如果你想在这个项目基础上做更深的毕设或者作品集决策模块是可以独立升级的。常见的做法是把牌面状态编码成一个15维向量3到2、大小王、手牌数量、上家出牌类型或者直接摊平成54维one-hot再配合合法性mask限制动作空间用DQN或者PPO去训练。这正好体现了解耦架构的好处yolov5识别模块已经提供了完全结构化、干净的状态输入强化学习代理可以直接拿这个状态做训练完全不需要处理图像训练效率高很多。视觉和决策两个模块分开讲写文档、做答辩都能理得很顺。5. 实测翻车现场、性能数字与工程化补完5.1 最容易翻车的三个场景第一个是背景误检。游戏界面里经常有扑克牌花色的装饰元素或者桌面壁纸本身带扑克图案模型很容易在背景区域误检出一堆黑桃红桃。我们用ROI裁剪能挡住大部分但手牌区附近的装饰元素仍会漏进来。解决方法是提高置信度阈值同时在候选框过滤时增加目标必须在牌面区域的约束。第二个是牌面重叠。手牌叠在一起时只露出左上角的点数区模型通常能正确识别最上面的牌但偶尔会把底下那张牌的点数也当成一个检测目标产生幽灵牌。我最后是靠手牌区检测出的牌数应该等于实际手牌数这个约束来兜底的数量对不上就把低置信度结果丢弃并重新截图识别。第三个是反光与暗光。深色背景下黑色牌面几乎隐身亮度归一化处理只能缓解一部分。最有效的办法是在数据增强里加入模拟反光的光斑效果让模型见过这些模式。这三个场景的共性问题是模型会自信地出错单纯调置信度阈值解决不了只有从数据和后处理两个方向同时堵。5.2 长稳运行显存泄漏与推理稳定性自动打牌一挂就可能挂好几个小时PyTorch推理在循环里如果不注意显存会缓慢增长。我第一版跑了一个晚上显存占用从2G涨到5G最后直接把进程卡死。排查后发现根因有两处一是每次推理都创建新的临时张量没有释放二是动态输入尺寸导致CUDA缓存不断重新分配。解决办法很简单固定用batch1、固定输入尺寸推理前关闭梯度计算推理后手动调用torch.cuda.empty_cache()。另外我加了个简单的看门狗脚本每30分钟检查一次显存占用超过阈值就自动重启进程。实测稳定挂机4小时显存占用曲线非常平。5.3 合规与风险提示这个项目能做什么、不能做什么我在这里必须把话说清楚这类自动出牌程序不要用于任何在线对战平台去刷分、代打或者牟利。自动化操作本质上违反多数游戏的使用协议一旦被检测到封号是小事更麻烦的是可能影响其他玩家体验。尤其注意如果斗地主涉及真实金钱输赢那就不是休闲棋牌而是赌博范畴了属于法律禁止的行为。所以这个项目最合适的使用场景就是单机练习、技术学习、算法研究和作品展示不要在真实对局环境里跑自动出牌。这也是我把项目做成识别为主、决策为辅这个定位的原因之一它是一个很好的计算机视觉落地案例而不是一个作弊工具。5.4 关于zip的发布建议让项目能跑起来才是真的既然项目的最终形态是xxx.zip那么别人下载下来能不能跑起来直接决定了这个项目的传播价值。我踩过的坑是压缩包里只有训练代码和权重没有任何运行说明结果自己换了一台机器都折腾了半天环境。后来我整理了一个规范的发布结构weights/存放训练好的权重文件和对应的yaml配置scripts/推理脚本、后处理脚本、决策脚本分离data/标注好的数据集和数据集划分文件README.md写清楚Python版本、依赖库版本、推理入口、常见问题requirements.txt固定关键依赖版本尤其是torch和yolov5分支版本还有一个小细节yolov5的官方仓库经常更新不同分支的接口可能不兼容所以README里一定要写明用的是哪个commit或哪个release版本否则用户clone最新代码很可能跑不起来。打包之前把依赖装一遍、按README走一遍确认能跑再压缩这是对下载者最基本的尊重。整套项目断断续续做了一周多中间最崩溃的不是训练模型而是后处理。我一开始天真地把检测结果直接当成牌型结果发现手牌排序乱七八糟、重复检测一大堆。后来老老实实按ROI裁剪加聚类去重才把状态输出稳定下来。这个过程让我意识到很多AI整活项目真正花时间的地方其实在模型之外的工程细节。如果你也想做类似的毕设或者练手项目我的建议是先确定一个清晰的小目标——只要能看清牌、会按规则出牌就好不要一上来就追求完胜人类。等视觉链路稳定了决策部分你想上什么策略都行甚至将来接大模型做牌局解说也不是不可能。yolov5在里面的角色更像是一个给人打工的眼睛眼睛够亮后面才好干活。本文还有配套的精品资源点击获取
返回列表