用OpenCV实现的跳一跳外挂
讲道理来说,对于手残人士,跳一跳这个微信小程序是可以将其逼疯的。当你按了半天屏幕,棋子却有自己的意识,义无反顾地跳向方块与方块之间的深渊中,此时只剩下绝望。好了,不扯淡了,主要是最近从零入门OpenCV,刚学了其中的一些函数,之前也了解了一些机器学习的知识,就想练练手,就想到了能否写一个跳一跳的外挂。
简要步骤如下:
- 将手机上的截屏图片下载到电脑的文件夹中
- 识别得到图片中棋子的初始位置
- 用边缘识别的函数对整张图片进行处理,得到其边界轮廓图
- 找到棋子下一步要跳到的品台的目标位置
- 计算初始位置与目标位置的距离
- 根据距离计算需要按压屏幕的时间
- 调用函数对手机屏幕模拟按压对应的时间,实现模拟人机交互
一开始的手机屏幕截图一般是这样的:
得到了这张图像之后,可以使用OpenCV自带的matchTemplate函数使用实现准备好的模板图片,与原图匹配,寻找棋子的初始位置,我用的模板图像是自己手动截的图:
使用OpenCV自带的边缘检测函数canny将原图转化为
根据这个边缘识别后的图像可以很明显发现下一个方块的位置,那么如何去找到目标方块的中心点的位置呢?由于对于整个图像中所有方块平台的倾斜角度是一定的,方块上方的正方形在倾斜角度之后呈现的是一个60°和120°的菱形,我们只需要知道相邻的2个顶点的坐标就可以得到目标方块中心点的坐标了。但是这里存在一个问题:找哪2个点呢?当然是最上边和最右边的2个顶点比较好找,于是截取有效区域(大概上canny图像的上部分1/5到1/2部分),不仅如此,有时棋子的头部会进入这个有效区域内部,会影响顶点的查找,所以也需要把棋子的整体移除(已经知道了棋子的坐标,所以移除之后也没什么影响),具体图像如下:
此时只需要从上到下遍历,从左到右遍历整个图像,去寻找那个像素点值是255即可,由此就得到了目标点的像素坐标。
好咯!我们手上已经有了棋子的初始位置和目标位置,也就是我们知道了棋子要跳动的像素距离,那像素距离和屏幕的按压时间之间存在的是怎样的关系呢,线性关系,二次关系,指数关系,或是其他?由此只能从实验中得到(当然你可以去看跳一跳源码或者科学上网):
所以我们需要按压时间,实际跳转距离这2个未知数的大小,我的做法是首先假设这是一个线性模型,预估其中的正比例参数,使得棋子能跳上平台即可,不要求正好跳到中间。接着我发现在按压结束的0.2秒的那一瞬间,截取手机屏幕可以得到棋子落地瞬间的图像,这时屏幕并未移动,所以可以再次使用cv2.matchtemplate函数去寻找棋子落地点的位置,这样就可以得到实际跳转距离,比如如下图像:
再这样运行了很多次之后,就可以得到一系列按压时间-实际跳转距离的数据,存在文件中画出来的图像大致上为:
图中的直线是我自己手动调参模拟出来的,不过也可以使用Linear Regression使用最小二乘法自动模拟出比较好的参数,从图像中可以很明显看出,这是一个线性模型。由此,所要求得的全部距离和参数都可以得到了,只需最后计算恰当的按压时间就可以交互棋子跳动了。
代码链接:https://github.com/ziniBRC/TiaoYiTiao