基于OpenCV的微信跳一跳外挂实现


前些日子,微信进行了一次更新,加入了一个小游戏跳一跳,发布之后这个游戏迅速走红并且在朋友圈刷屏,游戏的规则很简单,就是控制一个小矮子再各个墩子上跳来跳去。规则说起来容易但是想玩高分还是有一定难度的。这个游戏出现之后各路程序员也没闲着,外挂横飞,甚至产生了各种物理外挂。今天这篇文章就来讲述一下我来使用OpenCV实现的思路。


首先来说一下外挂的通常思路,外挂会通过Android手机的ADB来截取屏幕,然后通过对截图进行分析,算出来玩家与下一个落脚点的距离,然后通过距离算出来需要按压多长时间的屏幕,之后再通过发送ADB指令来模拟按下屏幕达到自动刷分的目的。也就是说,这个外挂的核心就是取得玩家与下一个落脚点的距离,有了距离之后,一切都好说了。



这篇文章主要讲的就是来确定这两个点的编程思路。我们将会用到Python与OpenCV来进行操作。


OpenCV熟悉编程的人一定知道,是一个著名的开源计算机视觉库,实现了图像处理和计算机视觉方面的很多通用算法。要想在Python上运行OpenCV只需要使用pip安装就好,在Terminal中执行pip install opencv-python即可。


注意,使用OpenCV时一般是用于分析图片灰度图,因为我这里需要画框划线进行标记,所以为了方便就直接读RGB彩图了,这样因为一个像素三个通道所以会慢一点,之后投入使用直接分析灰度图就好。


1 玩家位置识别


首先需要做的就是识别玩家的位置,玩家的形状不变,是一个紫色的棋子,那么可以使用OpenCV带有的图像模板匹配来找出玩家的位置。


首先需要一张小矮子的图片,就像这样,保存为player.png



然后就可以使用Python读取了,对于游戏场景,我使用下图,名字为1.png:



1.1 图像模板匹配


模板匹配是一项在一幅图像中寻找与另一幅模板图像最匹配(相似)部分的技术。再OpenCV中调用matchTemplate函数即可实现模板匹配。


1.2 代码实现


import cv2 as cv

img = cv.imread("1.png")
player_template = cv.imread('player.png')
player = cv.matchTemplate(img, player_template, cv.TM_CCOEFF_NORMED)

min_val, max_val, min_loc, max_loc = cv.minMaxLoc(player)


通过调用上面的代码即可进行模板匹配,最后一行的max_loc则是匹配出来的位置,因为玩家是一个宽度50高度150像素的图形(在我的iPhone 6s上)。所以再添加以下代码来框出玩家位置。并且画出了玩家的点。


corner_loc = (max_loc[0] + 50, max_loc[1] + 150)
player_spot = (max_loc[0] + 25, max_loc[1] + 150)
cv.circle(img, player_spot, 10, (0, 255, 255), -1)
cv.rectangle(img, max_loc, corner_loc, (0, 0, 255), 5)
cv.namedWindow('img', cv.WINDOW_KEEPRATIO)
cv.imshow("img", img)
cv.waitKey(0)


之后再运行,这时会打开一张片,可以看见玩家的位置已经被识别出来了:



在上图中蓝色的点即为玩家的位置。

 

2 落脚点识别


接下来就要识别落脚点了,但是蹲蹲千变万化,有方形的,有圆形的。所以刚才的模板识别就用不上了,即使使用的话成功率也很低,这个时候就需要用到边缘检测了。


2.1 Canny边缘检测



OpenCV带有Canny算法的实现来帮助我们得到图形的边缘。在做边缘检测之前首先需要对图片进行高斯模糊处理,高斯模糊主要作用就是去除噪声。因为噪声也集中于高频信号,很容易被识别为边缘。高斯模糊可以降低伪边缘的识别。但是由于图像边缘信息也是高频信号,高斯模糊的半径选择很重要,过大的半径很容易让一些弱边缘检测不到。


执行如下代码:


img_blur = cv.GaussianBlur(img, (5, 5), 0) #高斯模糊
canny_img = cv.Canny(img_blur, 1, 10) #边缘检测
cv.namedWindow('img', cv.WINDOW_KEEPRATIO)
cv.imshow("img", canny_img)


然后图片就会被边缘识别,这个图是灰度图,每一个像素是 0-255之间任意一个值,黑色为0白色为255.



2.2 图片切片


其实现在我们已经可以开始分析边缘来找到下一个落脚点了,但是图片中边缘实在是太多,可以通过裁切图片来,首先要知道,下一个落脚点肯定是在整个界面的上1/2。也就是说,图片的下半段可以不要,而且,上面的记分牌也没有任何用处。


执行以下代码来切除上面的300像素的高度加下半部分图片:


height, width = canny_img.shape
crop_img = canny_img[300:int(height/2), 0:width]
cv.namedWindow('img', cv.WINDOW_KEEPRATIO)
cv.imshow("img", crop_img)


运行后,发现图片被成功的裁掉了,留下了我们需要的部分。



2.3 消除玩家


但是有一点还是很烦,上图的左下角还有一部分玩家的头部,有时候如果玩家需要向左上角跳,这个头的存在可能会造成一定的干扰,所以需要写代码消除它,因为我们已经知道了玩家的坐标了,所以把那个范围的像素全设成0就好了。


for y in range(max_loc[1], max_loc[1]+150):
    for x in range(max_loc[0], max_loc[0]+50):
        canny_img[y][x] = 0


然后再运行代码,发现头部已经被取出掉了



2.4 落脚点判断


现在只剩下敦敦的边缘了,现在需要得到他的中心点,仔细观察这个图形,发现他是一个菱形,并且有两个点是很容易通过遍历像素点然后分析得到的:



A点B点是很容易得到的,通过由上到下,由坐到右遍历全部像素,A点应该是便利顺序的像素中第一个值为255的点,B点是便利顺序中第一次横坐标最大的点。


得到了A,B点的坐标,整个形状的中点 (X3, Y3)其实就是 (X1,Y2)。


可以通过如下代码来判断中心点:


crop_h, crop_w = crop_img.shape
center_x, center_y = 0, 0

max_x = 0

for y in range(crop_h):
    for x in range(crop_w):
        if crop_img[y, x] == 255:
            if center_x == 0:
                center_x = x
            if x > max_x:
                center_y = y
                max_x = x
                
cv.circle(crop_img, (center_x, center_y), 10, 255, -1)

cv.namedWindow('img', cv.WINDOW_KEEPRATIO)
cv.imshow("img", crop_img)
cv.waitKey(0)


重新执行代码,发现程序已经标出了中心点:



然后两个点都找到了,可就可以通过两点间距离公式算出距离,从而得出需要多少按压时间了。


看下最终效果:


 


可以看到敦敦是圆形的情况下中心点有点向左偏,是因为那个椭圆形的顶点是一排纵坐标相同的点,所以之后可以优化下取中间点就好


这就是OpenCV实现的大概思路,其实判断落脚点也可以使用findContours(http://docs.opencv.org/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html?highlight=findcontours#findcontours)函数来实现,这里因为实在太容易直接判断出来我就没有用。


过两天还有一场数学考试。。所以就先说到这吧。。。


代码


所有代码我上传到了我的GitHub上:
https://github.com/Yigang0622/OpenCV_Wechat_jump


出处:https://miketech.it/opencv_wechat_jump/


版权申明:内容来源网络,版权归原创者所有。除非无法确认,我们都会标明作者及出处,如有侵权烦请告知,我们会立即删除并表示歉意。谢谢。



架构文摘

ID:ArchDigest

互联网应用架构丨架构技术丨大型网站丨大数据丨机器学习

更多精彩文章,请点击下方:阅读原文

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值