微信跳一跳python辅助软件思路及图像识别源码解析
作者:cvMat_ 发布时间:2023-01-10 22:45:57
本文将梳理github上最火的wechat_jump_game的实现思路,并解析其图像处理部分源码
首先废话少说先看效果
核心思想
获取棋子到下一个方块的中心点的距离
计算触摸屏幕的时间
点击屏幕
重要方法
计算棋子到下一个方块中心点的距离
使用 adb shell screencap -p 命令获取手机当前屏幕画面
再通过图像上的信息找出棋子的坐标和下一个方块中心点的坐标
然后通过两点间距离公式计算出距离
计算触摸屏幕的时间
T=A * S
其中S为上步算出的像素距离,T为按压时间(ms),A为一个系数这个系数会随着屏幕分辨率的变化而变化,在1920*1080的屏幕下这个系数为1.35,在2560*1440的屏幕下这个系数为1.475
点击屏幕
adb shell input swipe x y x y time(ms)
这条命令能够点击手机屏幕x,y位置time(ms)
图像处理部分源码解析
图像处理部分代码都在 find_piece_and_board(im) 方法中
通过输入的图像im计算出棋子的坐标点以及下一个方块中心的坐标点
在find_piece_and_board的方法中一进来就是下面的两个嵌套在一起的for循环:
for i in range(int(h / 3), int(h * 2 / 3), 50):
last_pixel = im_pixel[0, i]
for j in range(1, w):
pixel = im_pixel[j, i]
# 不是纯色的线,则记录 scan_start_y 的值,准备跳出循环
if pixel[0] != last_pixel[0] or pixel[1] != last_pixel[1] or pixel[2] != last_pixel[2]:
scan_start_y = i - 50
break
if scan_start_y:
break
这段代码的作用就是从屏幕2/3的位置向下寻找不是纯色的线。并将找到位置的纵坐标-50作为,寻找棋子和方块的起始坐标。这样可以简化以后搜索的工作量,因为在这个横坐标以上是没有东西的。
接下来是查找棋子坐标的代码
# 查找棋子坐标
# piece_x_sum 横坐标总量 piece_x_c 点的个数 piece_y_max 纵坐标最大值
# 从 scan_start_y 开始往下扫描,棋子应位于屏幕上半部分,这里暂定不超过 2/3
for i in range(scan_start_y, int(h * 2 / 3)):
for j in range(scan_x_border, w - scan_x_border): # 横坐标方面也减少了一部分扫描开销
pixel = im_pixel[j, i]
# 根据棋子的最低行的颜色判断,找最后一行那些点的平均值,这个颜色这样应该 OK,暂时不提出来
if (50 < pixel[0] < 60) and (53 < pixel[1] < 63) and (95 < pixel[2] < 110):
piece_x_sum += j
piece_x_c += 1
piece_y_max = max(i, piece_y_max)
if not all((piece_x_sum, piece_x_c)):
return 0, 0, 0, 0
# 平均横坐标
piece_x = int(piece_x_sum / piece_x_c)
# 纵坐标最大值-底座一半的高度
piece_y = piece_y_max - piece_base_height_1_2 # 上移棋子底盘高度的一半
查找棋子的重要依据就是棋子的颜色较为单一并且和方块的颜色有较大差距。如果一个像素点的RGB像素值在B(50, 60), G(53, 63), R(95, 110)范围内那么就认为这个像素点是属于棋子的。根据以上信息就能计算出棋子的平均横坐标,以及最大的纵坐标值。
所以不难计算出棋子坐标(棋子平均横坐标, 棋子最大纵坐标 - 底座一半的高度)其中底座一半的高度因手机分辨率而异。需要提前配置好。
最后是查找下一个方块中心点的坐标的代码
# 寻找最高的棋盘
# 棋盘不会和棋子在同一侧
# 限制棋盘扫描的横坐标,避免音符 bug
if piece_x < w / 2:
board_x_start = piece_x
board_x_end = w
else:
board_x_start = 0
board_x_end = piece_x
for i in range(int(h / 3), int(h * 2 / 3)):
last_pixel = im_pixel[0, i]
if board_x or board_y:
break
board_x_sum = 0
board_x_c = 0
for j in range(int(board_x_start), int(board_x_end)):
pixel = im_pixel[j, i]
# 下一个棋盘紧贴着棋子
# 修掉脑袋比下一个小格子还高的情况的 bug
if abs(j - piece_x) < piece_body_width:
continue
# 修掉圆顶的时候一条线导致的小 bug,这个颜色判断应该 OK,暂时不提出来
if abs(pixel[0] - last_pixel[0]) + abs(pixel[1] - last_pixel[1]) + abs(pixel[2] - last_pixel[2]) > 10:
board_x_sum += j
board_x_c += 1
if board_x_sum:
# 最高棋盘的平均横坐标
board_x = board_x_sum / board_x_c
last_pixel = im_pixel[board_x, i]
代码开头通过棋子所在的屏幕位置限制搜索的宽度,如果棋子在屏幕左边那么就在屏幕右边搜索方块,反之亦然。因为方块和棋子不会在屏幕同一侧。
然后就是自上而下得搜索方块的上顶点。
方块上顶点坐标( 平均横坐标,当前行的纵坐标)
然后再往下纵坐标+247的位置开始向上找颜色与上顶点一样的点,为下顶点。
当然此方法有一点局限性对于纯色的平面效果很好但是对于非纯色的平面。可能会判断出错。
如果上一跳命中中间,则下个目标中心会出现 r245 g245 b245 的点,利用这个属性弥补上一段代码可能存在的判断错误
若上一跳由于某种原因没有跳到正中间,而下一跳恰好有无法正确识别花纹,则有可能游戏失败,由于花纹面积通常比较大,失败概率较低
可改进方案
首先是目前方案对于多分辨率需要多个配置文件来记录不同分辨率下的系数以及棋子底盘一半的高度。随机测试了6台手机其中有两台手机因没有配饰而无法正常运作
首先是系数A,观察方程T=A * S,A就是一个可训练量,利用机器学习框架比如TensorFlow,对这个一元一次方程进行拟合。
观察棋子底盘一半的高度在代码中的作用。不难发现是为了求出棋子底盘中心的纵坐标。而棋子底盘中心的位置恰恰是棋子最宽的地方。所以可以通过找出棋子最宽处的纵坐标的方式找到棋子底盘中心的纵坐标。这样就摆脱了对配置文件的依赖,能让代码在任何手机上正常运行。
其次是对于方块中心坐标位置的判断方法出错率较高,虽然有中心白点可以弥补但是在大量跳跃的过程中还是会出现错误。3太手机不停运行了一下午,最高分只有2009分。
现方法出错率高的原因是使用纯颜色方法判断,但是在实际游戏中颜色丰富的方块也不少。如果想改变就不能依赖颜色方法判断,而应该通过几何图像的形状来计算方块的位置。不难发现游戏中方块只有棱形和圆形两种形状。
首先通过canny或其他轮廓查找算子提取出图像的轮廓,然后通过霍夫变换提取出圆形和棱形的中心坐标。
总结
以上所述是小编给大家介绍的微信跳一跳python辅助软件思路及图像识别源码解析网站的支持!
来源:http://blog.csdn.net/s568974504/article/details/78964377


猜你喜欢
- 说在最前不知道小伙伴们在写代码的时候有没有区分开numpy.abs和abs函数,别小看这两个函数,如果在写程序的时候正确区分使用这两个函数可
- 爬虫中scrapy.Request的更多参数scrapy.Request的参数scrapy.Request(url[,callback,me
- async / await是ES7的重要特性之一,也是目前社区里公认的优秀异步解决方案。目前,async / await这个特性已经是sta
- 目录一、简介1、优势2、劣势二、安装三、locust的库和方法介绍1、from locust import task2、from locus
- python怎么查看数据类型?第一步我们首先需要知道在python中查看变量数据类型是使用type()函数,type函数的用法如下图所示:第
- 摘要:本文主要是在pandas中如何对字符串进行切分。我们考虑一下下面的应用场景。这个是我们的数据集(data),可以看到,数据集中某一列(
- 如果用户输入的是直接插入到一个SQL语句中的查询,应用程序会很容易受到SQL注入,例如下面的例子:$unsafe_variable = $_
- 服务器之间的http数据传输直接使用python内置的http服务:python -m SimpleHTTPServer 8000此时,输入
- 以XML格式查看查询结果通过使用传统—xml 选项调用MySQL命令行客户程序,你可以以XML格式(而不是传统的列表形式
- 1. 前言文章主要围绕着以下三个问题:group by的作用where与having的区别表的连接分为哪些,分别是什么作用2. 表的设计在创
- 如果把通过函数或方法调用,明确的将某种类型转换成另一种类型称为显示转换 ,相反则称为隐式类型转换 。google和 * 中没有找到“显示类
- SocketServer简化了网络服务器的编写。它有4个类:TCPServer,UDPServer,UnixStreamServer,Uni
- 本文实例讲述了Python unittest模块用法。分享给大家供大家参考,具体如下:python的unittest模块提供了一个测试框架,
- transforms按住Ctrl查看transforms的源码可以知道,transforms就是一个python文件,里面定义了很多类,每一
- 索引并不是时时都会生效的,比如以下几种情况,将导致索引失效:如果条件中有or,即使其中有条件带索引也不会使用(这也是为什么尽量少用or的原因
- 本文在前面文章基础上介绍tkinter添加图片和文本,在这之前,我们需要安装一个图片库,叫Pillow,这个需要下载exe文件,根据下面图片
- 一、图片验证码django-simple-captcha配置1.在pycharm中,File====》Settings====》Projec
- 前言:在开发中经常会与时间打交道,如:获取事件戳,时间戳的格式化等,这里简要记录一下python操作时间的方法。python中常见的处理时间
- 在使用flask部署Keras,tensorflow等框架时候,经常出现FailedPreconditionError: Attemptin
- 如果出现 automation服务器不能创建对象 解决方法:1、如果是Scripting.FileSystemObje