Python + OpenCV >>> 写一个基于图像处理的微信跳一跳全自动脚本

该脚本经过优化后已制作成JumpDevil 软件,无需环境配置,下载即可使用:

参加学校活动时做的关于这个软件的演示视频:
《【高燃】【踩点】防疫期间在家做个微信跳一跳自动软件如何?!》

附下载链接与使用教程

CSDN下载:
JumpDevil-V1.6.zip

或百度网盘下载:
链接:https://pan.baidu.com/s/1DakoknsLvw0xeU_UOKwDMw
提取码:kzny

使用教程:微信跳一跳全自动软件JumpDevil >>> 使用说明

一、前言

在家闲无聊,写个微信跳一跳全自动程序。

因为我的树莓派上面有OpenCV,所以我一开始打算把跳一跳的游戏截图传到树莓派上进行分析计算,但可惜在家里这树莓派的SSH总是不稳定,经常断。无奈之下,只能在Windows安装OpenCV然后直接在Windows上处理,结果发现原来Windows安装OpenCV如此简单~~ 👉 《Windows下安装OpenCV》

首先分析整个项目,我们需要 (获取游戏界面图像)、(分析获取到的游戏图像)、(对屏幕进行点击操作)

经过一番胡思乱想 😐,最终确定的方案为:

  1. :手机和电脑都下载个“傲软投屏”软件,实现手机屏幕在电脑屏幕上的实时显示。然后我们就可以对电脑屏幕进行截图,然后再把其中的手机屏幕截取下来,从而获得实时的游戏界面图像;
  2. :电脑上安装OpenCV并用其对游戏图像进行处理计算;
  3. :“傲软投屏”除了能够实时显示手机界面以外,还能实现电脑的反控操作,也就是鼠标模拟人的触摸操作。

二、开始

1. 必要软件

  1. Python 3.6及以上;
  2. OpenCV;
  3. “傲软投屏”;
  4. Python库——pyautogui

2. 开始获取游戏界面图像

由于我们使用OpenCV非智能化的识别计算,所以我们要确保进行处理的图像越少干扰越好。所以我要获取一个干净的游戏界面图像,其他无关的全都不要。

1)先拿到全屏截图

用pyautogui 库实现全屏截图并保存为文件的操作:

pyautogui.screenshot("C:/User/screenshot.jpg")

2)从截图中找到游戏界面并再次截取

若想了解模板匹配详细情况 > Python + OpenCV 学习笔记(十三)>>> 模板匹配

通过对“傲软投屏”软件界面设计的分析,我们知道这个软件有手机拟物化的上下边栏设计是一定伴随着手机画面一同出现的,就是下面这两个:
在这里插入图片描述
在这里插入图片描述
这就好办了,我们拿上面两个图片用OpenCV 对全屏截图进行模板匹配,分别就得到了这两个图片所在位置,两者中间的图像区域正是手机的画面。

# 匹配顶栏
top = cv.matchTemplate(img, top_tp, cv.TM_CCOEFF_NORMED)
top_min_val, top_max_val, top_min_loc, top_max_loc = cv.minMaxLoc(top)
# 匹配底栏
bottom = cv.matchTemplate(img, bottom_tp, cv.TM_CCOEFF_NORMED)
bottom_min_val, bottom_max_val, bottom_min_loc, bottom_max_loc = cv.minMaxLoc(bottom)
# 游戏界面左上角就是顶栏左下角坐标
game_top_left = (top_max_loc[0], top_max_loc[1]+top_h)
# 游戏界面右下角就是底栏右上角坐标
game_bottom_right = (bottom_max_loc[0]+bottom_w, bottom_max_loc[1])

获取到手机界面的坐标之后,用OpenCV把全屏截图切割一下,就实现了游戏界面的再次截图操作了:

# 获取手机界面的图片
img = img[game_top_left[1]:game_bottom_right[1], game_top_left[0]:game_bottom_right[0]]

效果:
在这里插入图片描述
👇
在这里插入图片描述

3. 计算棋子坐标

这就是那个棋子,我们再用模板匹配从游戏截图中找到这个棋子的位置来:
在这里插入图片描述

# 读取模板图像
tp = cv.imread(tp_path, 0)
w, h = tp.shape[::-1]
# 开始匹配
res = cv.matchTemplate(img, tp, cv.TM_CCOEFF_NORMED)
min_val, max_val, min_loc, max_loc = cv.minMaxLoc(res)
# 左上角坐标
top_left = max_loc
# 右下角坐标
bottom_right = (top_left[0] + w, top_left[1] + h)
# 棋子坐标
Piece_Center = (top_left[0] + (int)(w/2), top_left[1] + h-6)

在这里插入图片描述

4. 计算落点坐标前先处理一下图片

先不要急着计算落点坐标,否则会发现干扰因素太多了,我们需要先对图像做简单的处理,让它变得更加容易分析计算。

1)高斯模糊

对游戏界面图像进行高斯模糊:

# 高斯模糊,去除干扰噪点
blurred = cv.GaussianBlur(img, (7,7), 0)

2)边缘提取

若想了解边缘提取详细情况 > Python + OpenCV 学习笔记(十二)>>> Canny 边缘提取

高斯模糊后进行边缘提取:

# 边缘提取后图像
edge_output = cv.Canny(blurred, 2, 10)  # 利用x,y 轴梯度对图像进行边缘提取

在这里插入图片描述

3)棋子像素处理

为了避免有时棋子离下一个方块太近而干扰后续的落点计算,我们把棋子的像素处理一下:

# 把棋子的全部像素变成背景色(黑)
for x in range(top_left[0], top_left[0]+w):
    for y in range(top_left[1], top_left[1]+h):
        edge_output[y][x] = 0

在这里插入图片描述

4. 计算落点坐标

1)确定分析区域

通过分析我们知道,接下来的落点总是处于游戏画面的1/4到1/2之间区域:
在这里插入图片描述
注意:看到这里或许有的朋友第一反应就是:“那就再用OpenCV裁剪一下呗!”
不可以,不可以,不可以!重要的事情说三遍

当我们获取到游戏界面图像之后,不能再对图像做任何的裁剪操作。裁剪完的图像各点坐标都会变化,而我们必须保证棋子坐标的计算和落点坐标的计算这两者的环境一致性。只有这样,两次计算得到的坐标才是基于同一个坐标轴的,方便后续计算距离。

2)确定分析方法

分析得到“落点处于游戏画面的1/4到1/2之间区域”这一结论之后,我们还可以知道,要想计算出落点坐标,只需要得到A点坐标和B点坐标即可 👇:
在这里插入图片描述
在这里插入图片描述

3)构建算法

由于我这边当时时间有限,所以没有想出更好的算法,在这里就拿我的算法抛砖引玉一下:

先找A点,假定遇到的第一个白点就是A点。但是这里要注意一下,若后续要跳跃到的平台是圆台的话,一开始就会遇到一连串的白点,此时A点就不是第一个白点,而是连续白点的中间那个。所以要是后续没有遇到相同Y轴坐标的白点,就可以认为这不是圆台,第一个白点就是A点。否则计算圆台的连续白点坐标中值获得A点。
确定好A点之后,再寻找B点。我们可以分析得到,B点一般是在分析区域当中所有白点中X轴坐标最大的那个点,那我们就一行一行找,找到X轴大的点,就默认为B点,直到所有白点都遍历完。

for y in range((int)(H/4), (int)(H/2)):
    for x in range(0, W):
        if img[y][x]==255:
            Pixel_Counter = Pixel_Counter+1
            # 先假定第一个像素点就是A点
            if Pixel_Counter==1:
                A_Y = y
                A_X = x
            elif x>A_X:
                if A_Stable==False:
                    # 若A后像素点连续
                    if y==A_Y:
                        Constant_Pixel_Counter = Constant_Pixel_Counter+1
                    else:
                        A_Stable = True
                        A_X = A_X+(int)(Constant_Pixel_Counter/2)
                        Constant_Pixel_Counter = 0
                # 在A点右侧图像寻找B点
                else:
                    if x>Previous_B_X:
                        Previous_B_X = x
                        B_Y = y
                        B_X = x
                    else:
                        break

最后也就得到了落脚点坐标 (A_X, B_Y)

5. 计算跳跃距离 > 估算需要按压时间

def Cal_JumpDistance(p1, p2):
    return pow((pow((p2[0]-p1[0]),2)+pow((p2[1]-p1[1]),2)), 0.5)

# 计算得到最终需要跳跃的像素点数量
Jump_Distance = Cal_JumpDistance(Piece_Center, Final_coordinate)
Press_time = Jump_Distance/K

注意:K为时间参数,大家根据自己的实际情况取。我取的是420,最后得出的就是按压的时间,单位为秒。

6. 按压屏幕

这里我们用Python来模拟鼠标的按压操作:

# 把鼠标移动到电脑屏幕的手机界面区域当中
pag.moveTo(X, Y)
pyautogui.mouseDown()
time.sleep(Press_time)
pyautogui.mouseUp()

三、最终效果

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

诺亚方包

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值