之前有看到微信小程序《跳一跳》别人用python实现自动运行,后来看到别人用hash码实现《加减大师》的自动答题领取娃娃,最近一直在研究深度学习,为啥不用机器学习实现呢?不就是一个分类问题吗

如何实现自动答题微信小游戏《加减大师》?

思考:

  • 图像识别吗?
  • 如何建立特征工程?
  • 选用什么算法?

一、图像特征工程

如何获取手机游戏上的图片?

  • 使用adb命令截取手机屏幕;
  • 在PC端和手机端同时运行APowerMirror软件,将手机投屏到电脑上,然后使用Pillow包中的截图方法截取电脑上对应手机屏幕的

    区域。
  • 在PC端和手机端同时运行APowerMirror软件,将手机投屏到电脑上,然后使用Python调用windows的原生API截取电脑上对应手机屏幕的区域。

实验结果: 三种截屏方式花费的时间差异很大,第一种每次截屏需要0.7s左右,第二种0.3s左右,第三种0.04s左右。

当然选择第3种咯,下载地址[https://www.apowersoft.cn/phone-mirror],一个好的软件是成功的关键(够清晰)。

获取训练样本

相关步骤:

1.util.py中的shotByWinAPI函数:首先利用window自带api获取全屏图片,然后自定义config.py的相关参数。

  1. # 从PC端截屏时,截取区域左上角相对桌面的x坐标
  2. 'projection_x': 32,
  3. # 从PC端截屏时,截取区域左上角相对桌面的y坐标
  4. 'projection_y': 278,
  5. # 从PC端截屏时,截取区域的宽度
  6. 'projection_width': 482,
  7. # 从PC端截屏时,截取区域的高度
  8. 'projection_height': 854,

可以用window命令键PrtScSysRq(F12的右边),然后复制到画图中(1920x1080)。


用画图的放大镜放大,图中红色框的小方块位置(32x278)projection_x即32,projection_y即278。


在画图中计算出截图的宽度和高度,即projection_widthprojection_height(482x854)

2.img_tool.py函数介绍:主要是通过all(img, filename)函数进行图片分割

  1. srcImg = cv2.imread(os.path.join("ScreenShotForTrain", f), 0)

上述代码是为了将彩色图片灰度模式加载

  1. def all(img, filename):
  2. """封装对图片的所有操作"""
  3. img = cropImg(img)
  4. img = binaryImg(img)
  5. img1, img2 = cropAgain(img)
  6. imgs = cutImg(img1, filename + '_1') + cutImg(img2, filename + '_2')
  7. return imgs
  8. def cropImg(img):
  9. """裁剪原始截图"""
  10. height = img.shape[0]
  11. img2 = img[int(config.config['exp_area_top_rate'] * height):int(config.config['exp_area_bottom_rate'] * height),:]
  12. #print('裁剪完毕')
  13. return img2

cropImg(img)函数主要是为了裁剪含有数字的区域,通过设置参数

  1. #表达式区域的顶部处于整张图片的位置(307/854=0.359)
  2. 'exp_area_top_rate': 0.36,
  3. #表达式区域的底部处于整张图片的位置(478/854=0.559)
  4. 'exp_area_bottom_rate': 0.56,

如果觉得设置比例太麻烦,可以直接写死位置(img2 = img[int(307):int(478),:])。得到如下图:

  1. def binaryImg(img):
  2. """二值化图片"""
  3. ret, thresh1 = cv2.threshold(img, config.config['binary_threshold'], 255, cv2.THRESH_BINARY)
  4. # ret, thresh1 = cv2.threshold(img, config.config['binary_threshold'], 255, cv2.THRESH_BINARY_INV)
  5. #print('二值化完毕')
  6. return thresh1

binaryImg(img)函数主要是为了将图片二值化,可以参考

Python+OpenCV教程6:阈值分割。得到的图片如下图:


  1. def cropAgain(img):
  2. """再次裁剪"""
  3. height = img.shape[0]
  4. img1 = img[0:int(0.5 * height), :]
  5. img2 = img[int(0.5 * height):height, :]
  6. #print('再次裁剪完毕')
  7. return img1, img2

cropAgain(img)函数主要是为了将图片分成上下两部分




  1. def cutImg(img, filename):
  2. """水平分割图片"""
  3. sb = np.array(img)
  4. print(sb.shape)
  5. sum_list = np.array(img).sum(axis=0)
  6. start_index = -1
  7. res = []
  8. names = []
  9. index = 0
  10. for sum in sum_list:
  11. if sum > 255 * 4:
  12. if start_index == -1:
  13. start_index = index
  14. else:
  15. if start_index != -1:
  16. if config.config['type'] == 0:
  17. sigleCharWidth = config.config['abd_single_char_width']
  18. else:
  19. sigleCharWidth = config.config['pc_single_char_width']
  20. #为了防止字符粘连,需要在此处宽度进行判断
  21. if index - start_index > sigleCharWidth * 2:
  22. res.append((start_index,start_index + (index - start_index) // 2))
  23. res.append((start_index + (index - start_index) // 2, index))
  24. else:
  25. res.append((start_index, index))
  26. start_index = -1
  27. index += 1
  28. imgs = []
  29. count = 0
  30. for single_char in res:
  31. start = single_char[0]
  32. end = single_char[1]
  33. sub_img = img[:, start:end]
  34. sub_img = cv2.resize(sub_img, (120, 240), interpolation=cv2.INTER_CUBIC)
  35. #cv2.imwrite('SingleChar/%s_%d.png' % (filename, count), sub_img)
  36. #names.append('%s_%d.png' % (filename, count))
  37. # cv2.imshow(str(count), sub_img)
  38. imgs.append(sub_img)
  39. count += 1
  40. # cv2.waitKey()
  41. #print('分割,重新设置大小 %s 完毕' %filename)
  42. return imgs

设置pc_single_char_width参数值,得到如下图:


  1. c = 0
  2. def v_cut(img):
  3. global c
  4. """竖直方向切割图片"""
  5. sb1 = np.array(img)
  6. print(sb1.shape)
  7. sum_list = np.array(img).sum(axis=1)
  8. start_index = -1
  9. end = -1
  10. index = 0
  11. for sum in sum_list:
  12. if sum > 255 * 2:
  13. start_index = index
  14. break
  15. index += 1
  16. for i in range(1, len(sum_list) + 1):
  17. if sum_list[-i] > 255 * 2:
  18. end = len(sum_list) + 1 - i
  19. break
  20. img = img[start_index:end, :]
  21. img = cv2.resize(img, (30, 60), interpolation=cv2.INTER_CUBIC)
  22. #cv2.imwrite('SingleChar/%d.png' %c, img)
  23. c += 1
  24. return img

重新固定图片的大小(30x60),得到如下图:


二、训练模型,建立LR分类器

相关代码请看ml.py,这里不过多介绍,直接利用python包from sklearn.linear_model import LogisticRegression

  1. LogisticRegression(class_weight='balanced')

sklearn逻辑回归(Logistic Regression,LR)类库使用小结

三、自动答题模式开启

实现原理

  • 1.截取游戏界面,本项目中提供了三种方案。

    在PC端和手机端同时运行APowerMirror软件,将手机投屏到电脑上,然后使用Python调用windows的原生API截取电脑上对应手机屏幕的区域。

  • 2.提取截屏图片中的表达式区域并进行文字识别,得到表达式字符串。

    由于图片中的表达式区域固定,而且字符规整,因此这一步不是很困难,我仅仅训练了一个简单的逻辑回归模型就得到了非常高的识别正确率。

  • 3.根据第二步得到的表达式,调用Python的eval()函数,得到表达式结果的正误,然后点击手机屏幕的相应区域。当截图使用投屏的方案时,点击手机屏幕通过代码点击

    电脑上手机的对应区域。

首次操作,生成分类器模型

1.借用投屏软件,利用画图工具配置相关参数config.py,可以参考上面的“图像特征工程”

2.对于新的手机(我用的是honor8),必须重新训练模型,设置config.py中的debug参数为True,打开“加减大师”,然后运行main.py,这里必须手动答题,尽可能多答对一些题,目的为了扩充训练样本。

3.步骤2会产生一个SingleCharForTrain文件夹,剔除重复样本和无关样本。

4.运行img_tool.py文件,会生成一个SingleCharForTrain文件夹。

5.将步骤4得到的文件夹中的字符进行人工分类,保存至TrainChar文件夹。

6.运行ml.py文件,生成分类器模型lr.pickle

注意桌面上不要有东西遮挡到手机的投影区域

根据分类器模型自动答题

1.修改config.py中的debug参数为False及其他相关参数。

  1. #使用PC进行截图时点击手机屏幕正确区域的x坐标
  2. 'pc_tap_true_x':117,
  3. #使用PC进行截图时点击手机屏幕错误区域的x坐标
  4. 'pc_tap_false_x':365,
  5. #使用PC进行截图时点击手机屏幕正确和区域的y坐标
  6. 'pc_tap_y':760,

配置正确和错误选择的横纵坐标,横坐标不一样,纵坐标相同(在同一高度)

2.打开加减大师,直接运行main.py即可。

遇到的问题

Q1: 跑到200步左右就停了?

A1: 如果是误判的话,把出错的那张图重新截图,将得到的字符添加到TrainChar文件夹中,重新训练模型

A1: 如果是上一张图和这张图相同,再跑一次呗,不相信你运气会那么差


Q2: 刷到1000分,结果小程序上不了分

A2: 刚开始以为是答题时间没有设置随机的问题,设置main.py

  1. one_tap(res)
  2. # 设置随机睡眠时间,随机性防止微信后台检测
  3. if (count < 100):
  4. time.sleep(0.1 * (random.randint(0, 9)))
  5. elif (count <200):
  6. time.sleep(0.05 * (random.randint(0, 9)))
  7. elif (count <300):
  8. time.sleep(0.01 * (random.randint(0, 9)))
  9. elif (count < 400):
  10. time.sleep(0.01 * (random.randint(0, 9)))
  11. elif (count < 500):
  12. # 可以控制到这一关gg
  13. if (count == 455):
  14. time.sleep(3)

然而并没有软用,估计是后台设置(个人认为,当天的分数不能超过第一名太多),反正是前500都能获得小卡片,你可以尝试设置比第一名多个几分或少几分。

四、源代码地址

记得给哥们的github打♥啊

上代码:https://github.com/Yiutto/WechatGame_jjds

有问题私聊我yiutto@qq.com

最后放出我的娃娃来,手机上显示的是这样的

到手的时候却是这样的(本来以为没戏了,等了将近一个星期)

最后,祝大家都能拿到娃娃!!!

利用机器学习实现微信小程序-加减大师自动答题的更多相关文章

  1. 利用python实现微信小程序游戏跳一跳详细教程

    利用python实现微信小程序游戏跳一跳详细教程 1 先安装python 然后再安装pip <a href="http://newmiracle.cn/wp-content/uploa ...

  2. 利用mpvue开发微信小程序

    最近公司部门负责人提出需求需要开发一款微信小程序,由于本人之前是做前端开发的,对于小程序开发一窍不通,但是很多时候我们都是把不会做变成我会学.于是便在网上寻找小程序开发教程,相比于相生的小程序开发,本 ...

  3. 关于微信小程序爬虫关于token自动更新问题

    现在很多的app都很喜欢在微信或者支付宝的小程序内做开发,毕竟比较方便.安全.有流量.不需要再次下载app,好多人会因为加入你让他下载app他会扭头就走不用你的app,毕竟做类似产品的不是你一家. 之 ...

  4. 微信小程序 加载图片时,先拉长,再恢复正常

    今天在写小程序,发现小程序的图片image如过mode设置为widthFix的话, 加载图片会被先拉伸,后恢复正常 我的处理方法是,给他一个初始的height值,或者就直接 height:auto

  5. 微信小程序加载本地图片方法

    目录结构如下,只要图片按正确的方式放入小程序的开发工具的项目中,即可在wxml文件中用内联样式或者image标签都可以引用本地的图片. 步骤一:微信开发工具 打开项目 步骤二:新建个文件夹(放项目的一 ...

  6. 微信小程序 加载 HTML 标签

    肯定有小伙伴遇到过这个问题:加载的数据是一堆HTML 标签这就尴尬了,因为小程序没有提供 webview 来加载这些 HTML.但是不用慌,小程序不提供我们可以自己造个新轮子,自己造不出新轮子咱们找到 ...

  7. 微信小程序发布新版本时自动提示用户更新

    如图,当小程序发布新的版本后,用户如果之前访问过该小程序,通过已打开的小程序进入(未手动删除),则会弹出这个提示,提醒用户更新新的版本.用户点击确定就可以自动重启更新,点击取消则关闭弹窗,不再更新. ...

  8. 微信小程序实现滚动视频自动播放(未优化)

    先看看大概效果 1.首先需要了解微信API:          wx.createIntersectionObserver(Object component, Object options) 创建并返 ...

  9. 微信小程序------加导航

    效果图如下 这个其实很简单 在app.json上面加点代码 "window":{ "backgroundTextStyle":"light" ...

随机推荐

  1. linux磁盘扩容日志

    //针对ext4文件格式的操作系统(如CentOS6):// umount /dev/vdb e2fsck -f /dev/vdb resize2fs /dev/vdb mount /dev/vdb ...

  2. Oracle VM VirtualBox 无法卸载 更新 和修复

    好久没更新Oracle VM VirtualBox 突然发现不能更新了 提示要某个msi文件,回想起来好像是被某个清理垃圾的软件清理掉了. 于是根据提示的版本号网上搜了种子又把安装包下载回来 在命令行 ...

  3. 线程_synchronized_volatile_ReentranLock

    线程:cpu同时执行多个任务 synchonized   代码块,对象,类 同步方法和非同步方法可以同时执行同步方法可以调用同步方法(重入)脏读:之同步写,不同步读死锁的demo  一个线程先对A加锁 ...

  4. bootstrap轮播图不能显示左右箭头

    引入font文件夹即可 原文 :http://www.imooc.com/qadetail/64277

  5. 软件工程-东北师大站-第十一次作业(PSP)

    PSP 饼状图 2.本周进度条 3.本周累计进度图 代码累计折线图 博文字数累计折线图  

  6. 2018-2019-20172329 《Java软件结构与数据结构》第六周学习总结

    2018-2019-20172329 <Java软件结构与数据结构>第六周学习总结 学无止境,希望自己可以坚持下去,就算自己有太多的事情也不希望自己落下学习,也希望自己可以活成自己想要的样 ...

  7. 什么是REST编程

    参考:什么是REST编程:http://www.ruanyifeng.com/blog/2011/09/restful.html 一.REST是Representational State Trans ...

  8. 《Spring1之第七次站立会议》

    <第七次站立会议> 昨天:我把自己项目工程里的服务器端界面进行了优化和完善. 今天:我查找了关于实现视频功能的相关代码. 遇到的问题:找到的都是基于C#的相关代码,很难找到用java实现的 ...

  9. golang string转json的一些坑

    先带来点冷知识,不知道大家知不知道,反正我刚知道... 大佬们都知道怎么在string中给string类型赋值带双引号的字符串,没错就是用反斜杠,如下: msg := "{\"na ...

  10. Java分布式应用

    分布式计算就是通过计算机网络将计算工作分布到多台主机上,多个主机一起协同完成工作. 我试着列一下相关知识吧. 网络通讯,网络是分布式的基础,对分布式的理解建立在对网络的理解上,包括: OSI模型的7层 ...