python-游戏自动化(三)(实战-豆腐女孩)

前提准备

特别注意:
        本节教程所演示的模拟器分辨率设置为 720x1080(手机版),电脑分辨率设置大720x1080并且没有设置放大。

        今天的课程开始之前我们来回顾一下昨天所学的知识内容,因为今天要学的内容和昨天内容有着紧密的联系。昨天的课程主要讲解了计算机的图像相关基础知识,图像坐标系,图像灰度化,图像二值化,使用OpenCV进行图像匹配、图像切割,还尝试了对图像进行轮廓处理。

        在前面的学习中,我们已经掌握了使用OpenCV进行图片处理的相关知识,之所以做了那么多的铺垫,目的就是为这节课服务的。
        写出这个游戏的自动化脚本中,图像的处理占了超过一半的工作量,这也是模拟类自动化脚本的常见情况。
        图像处理的目的是什么? 是把图像识别成简单的数据类型或数据结构,以便于使用算法来解决问题。
        大家来想一想,在这个 豆腐女孩 的游戏中,规则很简单,开始后,只要不断识别游戏画面,看到有豆腐过来,就判断豆腐离女孩的距离,如果距离在某个数值范围内,点击鼠标起跳就可以了。

        通过观察游戏界面,豆腐出现的区域是不变的,所以我们只需要关注中间那一块区域就了,通过坐标把这一块区域裁剪出来,一方面可以减少图像处理的计算量,另一方面可以减少不必要的干扰,简化处理的逻辑。

        接下来对这块目标区域的图像进行处理,先装成灰度图,再找出一个合适的阈值,变成二值化图像:

        对于这样背景和前景分明的图像,就可以非常轻松的找出轮廓了,但不是所有的轮廓都是符合条件的,我们只需要找到面积最大的轮廓的边框,就可以确认豆腐的位置。

        上图中的绿色线条方框就是找出来的豆腐的位置,而小女孩是居中显示的,所以得到豆腐的边,再计算两个物体的距离,然后根据豆腐的移动速度,就可以算出起跳前的等待时间。

        通过OpenCV这个强大的图像处理库,就可以真正从目标识别的角度去编写逻辑,跟那些基于找图找色的按键精灵、易语言写的那些脚本不一样,这是基于图像识别的方法,使用分层思想来设计模型,帮助大家真正提高从底层逻辑去建立起解决问题的思维,这在大家以后不光是学编程,写python,做脚本时非常有用,对于生活中、学习中、工作中的复杂问题的解决,同样可以有很大的帮助。
        人跟人的本质区别,在于思维的层次差别。

        有了上面整理出来的思路,接下来老师就带领同学们来一步步来实现我们的思路。 

        抽离出一个模拟器的模块,负责对窗口的基本操作,比如激活、点击、截图等功能,到时作为模块导入,可以很方便的调用这里面的功能,从而简化逻辑,并且达到高内聚,低耦合的设计目标。

模拟器模块

import time
import win32api
import win32con
import win32gui
import win32ui
import numpy as np
import cv2 as cvdef activate_window():hwnd = win32gui.FindWindow(None, '雷电模拟器')  # 注意引号使用英文if hwnd == 0:print('未找到游戏窗口')return 0tup = win32gui.GetWindowPlacement(hwnd)  # 获取窗口布局if tup[1] != win32con.SW_SHOWNORMAL:  # 非正常尺寸(已最小化或最大化)win32gui.SendMessage(hwnd, win32con.WM_SYSCOMMAND, win32con.SC_RESTORE, 0)# 恢复窗口大小time.sleep(0.1)if win32gui.GetForegroundWindow() != hwnd:win32gui.SetForegroundWindow(hwnd)  # 窗口前置time.sleep(0.3)return hwnddef click(window_coords):#:param window_coords: 元组(x, y) x为横坐标,y为纵坐标#:return: 返回点击执行结果window_handle = activate_window() #得到窗口句柄if window_handle == 0:print('模拟器窗口不存在,点击失败')return Falsedesktop_coords = win32gui.ClientToScreen(window_handle, window_coords)  # 窗口坐标换算成桌面坐标win32api.SetCursorPos(desktop_coords)  # 设置鼠标位置win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0)  # 鼠标按下win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP, 0, 0, 0, 0)  # 鼠标弹起return Truedef _capture_window(hwnd):desktop = win32gui.GetDesktopWindow()dc = win32gui.GetWindowDC(desktop)mfc_dc = win32ui.CreateDCFromHandle(dc)save_dc = mfc_dc.CreateCompatibleDC()save_bit_map = win32ui.CreateBitmap()left, top, right, bottom = win32gui.GetWindowRect(hwnd)w, h = right - left, bottom - topsave_bit_map.CreateCompatibleBitmap(mfc_dc, w, h)save_dc.SelectObject(save_bit_map)save_dc.BitBlt((0, 0), (w, h), mfc_dc, (left, top), win32con.SRCCOPY)signed_ints_array = save_bit_map.GetBitmapBits(True)im_opencv = np.frombuffer(signed_ints_array, dtype='uint8')im_opencv.shape = (h, w, 4)save_dc.DeleteDC()win32gui.DeleteObject(save_bit_map.GetHandle())win32gui.ReleaseDC(hwnd, dc)  # 修正此行return im_opencvdef screenshot():window_handle = activate_window()if window_handle == 0:print('模拟器窗口不存在,截图失败')return Nonereturn _capture_window(window_handle)if __name__ == '__main__':activate_window()time.sleep(0.5)start = time.time()img = screenshot()end = time.time()print('花费', end - start, '秒')if img is not None:cv.imwrite(r'E:\home.bmp', img)h, w = img.shape[:2]detection_result = '检测通过!' if w == 762 and h == 1316 else '检测未通过!请修改模拟器分辨率'print(f'期望截图的分辨率为:762*1316 实际分辨率为{h}*{w}')click((300, 650))time.sleep(1.2)tofu = screenshot()if tofu is not None:cv.imwrite(r'E:\tofu.bmp', tofu)

游戏控制模块

在这个游戏控制模块中,主要完成图像的处理和目标的检测,并通过简单的算法计算出操作间隔,然后调用 模拟器模块 中的相应函数来实现操作。
来看看源码:

import time
import cv2 as cv
import numpy as np
import 模拟器开始按钮图片 = cv.imread(r"E:\bbbb.bmp", 0)  # 开始按钮def 是彩色图片(图片):if 图片 is None:print('是彩色图片() 参数错误:', '图片为空')return Falsereturn len(图片.shape) > 2def 查找图片(大图, 小图, 相似度=0.8):if 是彩色图片(大图):大图 = cv.cvtColor(大图, cv.COLOR_BGR2GRAY)if 是彩色图片(小图):小图 = cv.cvtColor(小图, cv.COLOR_BGR2GRAY)res = cv.matchTemplate(大图, 小图, cv.TM_CCOEFF_NORMED)  # 模板匹配loc = np.where(res >= 相似度)  # 过滤结果for pt in zip(*loc[::-1]):left = int(pt[0])top = int(pt[1])right = int(pt[0] + 小图.shape[1])bottom = int(pt[1] + 小图.shape[0])area = ((left, top), (right, bottom))return area  # 实际操作区域def find_cube(灰色截图):sw = 720关键区域 = 灰色截图[600:720, 1:sw]  # 裁剪出感兴趣的区域_, 黑白图像 = cv.threshold(关键区域, 248, 255, cv.THRESH_BINARY)  # 图像二值化contours, hierarchy = cv.findContours(黑白图像, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)  # 查找轮廓max_area, max_cnt = 0, None  # 设置最大面积和最大轮廓的默认值for cnt in contours:area = cv.contourArea(cnt)if area > 5000 and area > max_area:  # 筛选出轮廓max_area = areamax_cnt = cntif max_cnt is None:# print('没有发现豆腐')return 0x, y, w, h = cv.boundingRect(max_cnt)  # 计算出边框center_x = sw / 2  # 中线位置cube_x = x + w if x + w < center_x else x  # 取离中线最近的豆腐边线x(豆腐不确定从哪边来)dist = abs(center_x - cube_x)  # 豆腐边缘到中线的距离return distdef 跳跃检测():for i in range(100):  # 每次跳跃前循环检测画面截图 = 模拟器.screenshot()截图_灰色 = cv.cvtColor(截图, cv.COLOR_BGR2GRAY)  # 转成灰度图片if 查找图片(截图_灰色, 开始按钮图片):print('游戏已结束')return Truedist = find_cube(截图_灰色)  # 算出豆腐离中线距离if 150< dist < 200:print(f'---跳---')jump()  # 点击鼠标(跳跃)time.sleep(0.1)breakreturn Falsedef jump():坐标 = (300, 800)模拟器.click(坐标)if __name__ == '__main__':截图 = 模拟器.screenshot()if 查找图片(截图, 开始按钮图片):print('找到开始按钮')jump()  # 点击开始time.sleep(0.5)else:print('游戏不在开始画面')exit(0)# time.sleep(0.6)#截图 = 模拟器.screenshot()# 截图_灰色 = cv.cvtColor(截图,cv.COLOR_BGR2GRAY)#find_cube(截图_灰色)#cv.waitKey()for i in range(100):  # 最大预计跳跃次数if 跳跃检测():break

课程总结

虽然这个游戏的玩法比较简单,但是要拿到特别高的分数还是不容易的。在本教程中,霸夫老师也只是以启发大家为目标,教大家去分析如何写出一个自动化游戏教程,程序功能虽然比较简单,但其中涉及的思路分析,图像处理,数据计算、算法优化、设计模式等是很值得大家去细细学习体会的。

课后习题

1.(编程题)在教程的示例代码中继续改进,示例中jump()函数中点击的是固定坐标,将坐标的取值改为查找到的start.bmp图片的中心点。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/53812.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

苹果能引领端侧AI大模型时代吗?

苹果能引领端侧AI时代吗&#xff1f; 这份完整版的大模型 AI 学习资料已经上传CSDN&#xff0c;朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】 北京时间9月10日凌晨&#xff0c;苹果正式发布了iPhone 16&#xff0c;这是苹果第一款真正意义上的 …

网络安全(sql注入)

这里写目录标题 一. information_schema.tables 和 information_schema.schemata是information_schema数据库中的两张表1. information_schema.schemata2. information_schema.tables 二. 判断注入类型1. 判断数字型还是字符型注入2. 判断注入闭合是""还是 三. 判断表…

浅谈模型在信贷营销中的应用

浅谈模型在信贷营销中的应用 当前在信贷营销场景中,用户流量竞争愈加激烈,获客成本持续攀高,客户消费观念和消费信心趋向保守,传统的信贷营销方式效果逐渐乏力,借助数据挖掘技术对用户进行多元优化及精细化管理已经成为企业在经营发展中的普遍趋势。在此背景下,本文将围…

什么是API网关(API Gateway)?

1. 什么是API网关&#xff08;API Gateway&#xff09;&#xff1f; 在微服务体系结构中&#xff0c;客户端可能与多个前端服务进行交互。 API 网关位于客户端与服务之间。 它充当反向代理&#xff0c;将来自客户端的请求路由到服务。 它还可以执行各种横切任务&#xff0c;例…

什么是CPU、GPU、NPU?(包懂+会)

目录 举例子 CPU&#xff1a;主厨 GPU&#xff1a;大量的厨房助理 NPU&#xff1a;面包机 总结 讲理论 CPU&#xff08;中央处理器&#xff09; GPU&#xff08;图形处理单元&#xff09; NPU&#xff08;神经网络处理单元&#xff09; 对比分析 举例子 CPU&#xff…

【网络安全】-文件下载漏洞-pikachu

文件操作漏洞包括文件上传漏洞&#xff0c;文件包含漏洞&#xff0c;文件下载漏洞。 文章目录  前言 什么是文件下载漏洞&#xff1f; 1.常见形式&#xff1a; 常见链接形式&#xff1a; 常见参数&#xff1a; 2.利用方式&#xff1a; 3.举例&#xff1a;pikachu不安全的文件…

【Qt】按钮样式--按钮内部布局(调整按钮文本和图标放置在任意位置)

要求&#xff1a; 有一个按钮&#xff0c;要求按钮的右下角显示开关&#xff0c;点击切换开关状态 ps&#xff1a;注意&#xff0c;要求你添加完了之后&#xff0c;整个按钮的点击区域不变&#xff08;就是说&#xff0c;点击右下角的文本&#xff0c;也可以触发按钮的点击事件…

CentOS7 使用yum报错:[Errno 14] HTTP Error 404 - Not Found 正在尝试其它镜像。

CentOS7 使用yum报错&#xff1a;[Errno 14] HTTP Error 404 - Not Found 正在尝试其它镜像。 CentOS镜像下载、VM虚拟机下载 下载地址&#xff1a;www.macfxb.cn 一、问题描述 安装完CentOS7 后 使用yum报错 如下图 二、解决方案 1.查看自己的系统架构 我的是aarch64 uname …

python 学习一张图

python学习一张图&#xff0c;python的特点的是学的快&#xff0c;一段时间不用&#xff0c;忘记的也快&#xff0c;弄一张图及一些入门案例吧。 写一个简单的测试&#xff1a; #!/usr/bin/python # -*- coding: UTF-8 -*- import osdef add_num(a, b):return a bif __name__…

【STM32】BH1750光敏传感

1.BH1750介绍 BH1750是一个光敏传感&#xff0c;采用I2C协议&#xff0c;对于I2C的从机&#xff0c;都有自己的地址&#xff0c;用来主机选择和哪个从机通信&#xff0c;对于OLED来说&#xff0c;只有单片机通过I2C往OLED中写数据。而BH1750来说&#xff0c;有单片机往BH1750写…

DNAT和SNAT实践

NAT分SNAT和DNAT两种。从名字上区分&#xff1a; SNAT将源IP地址替换为出口网络的IP地址&#xff0c;以便内网地址可以访问外网服务。一般受限于公网IP有限&#xff0c;一个内网集合想访问外网服务&#xff0c;则用统一的出口做代理。出口配置公网IP&#xff0c;帮助从此发出的…

Note24091101_基恩士日期获取相关测试01

基恩士日期获取相关测试 1、SEC和RSEC的使用&#xff1a; 资料如图&#xff1a; 要点提示&#xff1a;SEC和RSEC成对使用。 日期转秒&#xff0c;秒转日期测试如图所示&#xff1a; 2. LDWK与LDWKB星期接点的使用示例&#xff1a; 资料如图&#xff1a; 仿真如图&…

2018年系统架构师案例分析试题五

目录 案例 【题目】 【问题 1】(7 分) 【问题 2】(12 分) 【问题 3】(6 分) 【答案】 【问题 1】解析 【问题 2】解析 【问题 3】解析 相关推荐 案例 阅读以下关于 Web 系统设计的叙述&#xff0c;在答题纸上回答问题 1 至问题 3。 【题目】 某银行拟将以分行为主体…

287. 寻找重复数(stl法)

目录 一&#xff1a;题目&#xff1a; 二&#xff1a;代码&#xff1a; 三&#xff1a;结果&#xff1a; 一&#xff1a;题目&#xff1a; 给定一个包含 n 1 个整数的数组 nums &#xff0c;其数字都在 [1, n] 范围内&#xff08;包括 1 和 n&#xff09;&#xff0c;可知…

数模方法论-线性规划

一、基本概念 在实际生产过程中&#xff0c;人们经常面临如何有效利用现有资源来安排生产&#xff0c;以实现最大经济效益的问题。这类问题构成了运筹学的一个重要分支——数学规划&#xff0c;而线性规划&#xff08;Linear Programming, LP&#xff09;是数学规划中的一个关键…

Facebook的虚拟现实计划:未来社交的全新视角

随着科技的不断进步&#xff0c;虚拟现实&#xff08;VR&#xff09;正逐步成为我们日常生活的一部分。作为全球领先的社交平台&#xff0c;Facebook正在大力投入虚拟现实技术&#xff0c;以重新定义社交互动的方式。本文将深入探讨Facebook的虚拟现实计划&#xff0c;分析其如…

网络高级(学习)2024.9.11

目录 Modbus库函数 1.初始化和释放函数 2.功能函数 3.功能案例 Modbus RTU 1.特点 2.协议格式 3.编程思路 Modbus库函数 1.初始化和释放函数 modbus_t* modbus_new_tcp(const char *ip, int port) 功能&#xff1a;以TCP方式创建Modbus实例&#xff0c;并初始化 参数…

基于vue框架的城市智慧地铁管理系统73c2d(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。

系统程序文件列表 项目功能&#xff1a;用户,站点查询,车次线路,站点周边 开题报告内容 基于Vue框架的城市智慧地铁管理系统开题报告 一、研究背景与意义 1.1 研究背景 随着城市化进程的加速和人口的不断增长&#xff0c;城市交通压力日益增大。地铁作为城市公共交通的重要…

C++--模板

1 泛型编程 如何将Swap实现乘成一个通用的交换函数 void Swap(int& left, int& right) {int temp left;left right;right temp; }void Swap(double& left, double& right) {double temp left;left right;right temp; }void Swap(char& left, char&…

深入理解Java虚拟机:Jvm总结-Java内存区域与内存溢出异常

第二章 Java内存区域与内存溢出异常 2.1 意义 对于C、C程序开发来说&#xff0c;程序员需要维护每一个对象从开始到终结。Java的虚拟自动内存管理机制&#xff0c;让java程序员不需要手写delete或者free代码&#xff0c;不容易出现内存泄漏和内存溢出问题&#xff0c;但是如果…