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.rhkb.cn/news/421791.html

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

相关文章

828华为云征文 | 华为云Flexusx实例,高效部署Servas书签管理工具的优选平台

前言 华为云Flexus X实例&#xff0c;Servas书签管理工具部署的优选平台&#xff01;828节日特惠&#xff0c;让高效管理您的知识宝藏触手可及。Flexus X实例以其卓越的算力、灵活的资源配置和智能调优技术&#xff0c;为Servas提供了稳定、高效的运行环境。无论是快速访问、安…

链表相关OJ

目录 1、移除链表元素 &#xff08;1&#xff09;题目描述 &#xff08;2&#xff09;算法原理 2、链表的中间结点 &#xff08;1&#xff09;题目描述 &#xff08;2&#xff09;算法原理 3、链表中倒数第K个结点 &#xff08;1&#xff09;题目描述 &#xff0…

ssrf漏洞利用+CTF实例

引发ssrf漏洞的几个函数 file_get_contents() 把整个文件读入一个字符串中&#xff0c;获取本地或者远程文件内容fsockopen() 获得套接字信息curl_exec() 执行一个curl会话&#xff0c;由curl_init()初始化一个新的会话&#xff0c;返回一个curl句柄fopen() 打开文件或者URLre…

【C语言】内存函数详细讲解

文章目录 前言strerror的声明和使用字符串分类函数字符转换函数内存拷贝函数&#xff08;memcpy)memcpy的声明和使用memcpy函数的模拟实现 内存拷贝函数&#xff08;memmove&#xff09;memmove的声明和使用memmove模拟实现 内存比较函数&#xff08;memcmp&#xff09;memcmp的…

如何解决在idea中的hadoop日志错误

在idea中操作hadoop的时候&#xff0c;每次运行代码都会发现有个日志错误&#xff0c;虽然不影响程序运行&#xff0c;但是无法打印日志。这是缺少依赖&#xff0c;和windows上缺少log4j的文件 解决方案&#xff1a; 1、导入slf4j依赖 2、导入hadoop中的log4j文件 1、从hado…

Datawhale X 李宏毅苹果书 AI夏令营 《深度学习详解》第十九章 ChatGPT

19.1 ChatGPT 简介和功能 1、对话框可以输入任何东西 2、可以继续追问 19.2 对于 ChatGPT 的误解 1、第一个误解是 ChatGPT 的回答是罐头讯息 2、另外一个常见的误解是 ChatGPT 的答案是网络搜索的结果 3、那 ChatGPT 真正在做的事情是什么呢&#xff1f;一言以蔽之就是做…

开放式激光振镜运动控制器在Ubuntu+Qt下的文本标刻

开放式激光振镜运动控制器在UbuntuQt下的文本标刻 上节课程我们讲述了如何通过UbuntuQt进行振镜校正&#xff08;详情点击→开放式激光振镜运动控制器在UbuntuQt下的激光振镜校正&#xff09;&#xff0c;本节文本标刻是在振镜校正的前提下实现的。 在正式学习之前&#xff0…

F12抓包08:查看网站Cookie

课程大纲 1、查看Cookie 1. 应用界面查看&#xff1a;按F12进入浏览器的开发者模式 - “应用”&#xff08;Application&#xff09; - Cookie&#xff0c;可查看Cookie并进行增、删、改、查操作。 2. 控制台命令行查看&#xff1a;按F12进入浏览器的开发者模式 - “控制台”&…

2025年第八届计算机图形和虚拟国际会议(ICCGV 2025)即将召开!

2025年第八届计算机图形和虚拟国际会议&#xff08;ICCGV 2025&#xff09;将于2025年2月21-23日在中国成都举行。随着信息技术的飞速发展&#xff0c;计算机图形学与虚拟现实技术正以前所未有的速度重塑着我们的认知世界与交互体验。从沉浸式游戏到精准医疗模拟&#xff0c;从…

坐牢第三十八天(Qt)

1、使用Qt绘画事件处理画一个闹钟 widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QDebug> #include <QPaintEvent>//画画处理事件 #include <QPainter>//画画 #include <QTime> //时间类 #include <QTimer>…

电流互感器电压互感器

一&#xff0c;电流互感器 用途&#xff1a;对信号做精确采样和适当补偿功能&#xff0c;方便对5A以内的交流电进行信号采集。主要作用就是对电流进行测量和取样。 扩展&#xff1a;对应输出模拟交流信号可以调节&#xff0c;可根据电位器&#xff08;调节放大比例&#xff0…

Ali_Yun Port

Ali_Yun Port 云服务器端口

基于云原生向量数据库 PieCloudVector 的 RAG 实践

近年来&#xff0c;人工智能生成内容&#xff08;AIGC&#xff09;已然成为最热门的话题之一。工业界出现了各种内容生成工具&#xff0c;能够跨多种模态产生多样化的内容。这些主流的模型能够取得卓越表现&#xff0c;归功于创新的算法、模型规模的大幅扩展&#xff0c;以及海…

FlinkCDC 3.2.0 新增优点 Pattern Replacement in routing rules

新增优点&#xff1a;Pattern Replacement in routing rules flinkcdc 3.2.0版本相较于3.1.0版本&#xff0c;避免了多表多sink多次写 route 路由的麻烦&#xff0c;类似于统一前后缀的形式多表多sink&#xff0c;通过<>正则&#xff0c;大大减少了书写 官网&#xff1…

【干货分享】Ftrans安全数据交换系统 搭建跨网数据传输通道

安全数据交换系统是一种专门设计用于在不同的网络、系统或组织之间安全地传输数据的软件或硬件解决方案。这种系统通常包含多种安全特性&#xff0c;以确保数据在传输过程中的保密性、完整性和可用性。 安全数据交换系统可以解决哪些问题&#xff1f; 安全数据交换系统主要解…

图分类!!!

deepwalk 使用图中节点与节点的共现关系来学习节点的向量表示。那么关键的问题就是如何来描述节点与节点的共现关系&#xff0c;DeepWalk给出的方法是使用随机游走(RandomWalk)的方式在图中进行节点采样,RandomWalk是一种可重复访问已访问节点的深度优先遍历算法。给定当前访问…

CogView-3-Plus:深度解锁智谱AI的图像生成新力量

一、引言&#xff1a;AI助力创意与效率的全面提升 在如今这个瞬息万变的科技时代&#xff0c;AI大模型早就不是实验室里的“神秘武器”&#xff0c;它们已经实实在在地融入到我们的日常工作中了&#xff0c;尤其是在图像生成和内容创作这块儿&#xff0c;简直是效率神器。只要几…

微软 Power Apps MDA 模型驱动应用解决Image字段查询出来缩略图问题变原图方法(c#+Plugin方式)

微软 Power Apps MDA 模型驱动应用解决Image字段查询出来缩略图问题变原图方法&#xff08;c#Plugin方式&#xff09; 在某些特定的场景中&#xff0c;需要将Image字段中的图片取出来&#xff0c;一般来说直接查询这个字段可以直接取&#xff0c;取出来的就是一个Base64格式的图…

OpenHarmony鸿蒙( Beta5.0)智能窗户通风设备开发详解

鸿蒙开发往期必看&#xff1a; 一分钟了解”纯血版&#xff01;鸿蒙HarmonyOS Next应用开发&#xff01; “非常详细的” 鸿蒙HarmonyOS Next应用开发学习路线&#xff01;&#xff08;从零基础入门到精通&#xff09; “一杯冰美式的时间” 了解鸿蒙HarmonyOS Next应用开发路…

springboot luttuc redis 集成protobuf,手动序列化反序列化

前置需知&#xff1a; 1.本文章和网上大部分博客配置不太一样&#xff0c;各位看官要分析一下自己的需求。集成protobuf 本文章主要是手动调用protobuf的序列化方法&#xff0c;而不是交由springboot 去做&#xff0c;会偏向原生java 使用方式 2.由于为了和公司其他的项目达成…