P-1.4.2 [有例题]A_1_OWwg 1/20报告

最终代码如下:

from PIL.ImageGrab import grab #加载截图命令
from math import pi,asin #加载数学符号
from pykeyboard import PyKeyboard #加载键盘操作命令(配合‘某鼠标模拟器’)
from time import sleep #加载延时命令
pkb=PyKeyboard() #缩写对象PyKeyboard()
keyx= lambda x:6 if x>0 else 4 if x<0 else 7 #不同输入值对应不同的小键盘输出值
keyy= lambda x:5 if x>0 else 8 if x<0 else 7

xs=1920
ys=1080#设定屏幕大小
x0=xs/2
y0=ys/2#计算屏幕中点坐标
nx=0
ny=0
i=0
a=150
bb=150#a决定检索宽度,bb决定检索高度
while 1==1:
    im=grab((xs/2-a,ys/2-bb,xs/2+a,ys/2+bb))#截取当前图像
    pix=list(im.getdata())#将当前图像每一点的RGB值以一定顺序排列在列表pix中
    try:
        n=pix.index((255,0,19))#若能得到想要的RGB值在列表中的位置则→else
    except:
        x=xs/2
        y=ys/2#若列表中没有这个RGB值,则将输出坐标设为屏幕中央(后期不需要移动鼠标
    else:
        x=(xs/2-a)+n%(2*a)+50
        y=(ys/2-bb)+n//(2*a)+50#为输出坐标赋值,‘+50’是偏移量 用于瞄准身体而不是血条







    ax=xs-x
    ay=xs-(y+0.5*(xs-ys))
    b=xs/((2)**0.5)
    cx=(ax**2+b**2-((2)**0.5)*ax*b)**0.5
    xt=45-360*(asin(ax*(2)**0.5/(2*cx))/(2*pi))
    cy=(ay**2+b**2-((2)**0.5)*ay*b)**0.5
    yt=45-360*(asin(ay*(2)**0.5/(2*cy))/(2*pi))#x一圈3636像素 y一圈3600像素    
    nx=round(xt*3636/360)#此处得xt与yt函数可以简化
    ny=round(yt*3600/360)#round后误差仅在1像素即0.1度左右,是可以接受的误差
    #以上用已知的90度视角结合已知的角度→像素关系,得出需要移动的像素值

    pkb.tap_key(pkb.numpad_keys[keyx(nx)],n=abs(nx))
    pkb.tap_key(pkb.numpad_keys[keyy(ny)],n=abs(ny))#操作部,结合keyx/keyy函数、某鼠标模拟器,使鼠标移动所需要的距离
    sleep(0.05)#操作部控制鼠标模拟器有延迟,不进行sleep可能导致在鼠标移动前截图导致瞄准情况混乱

某鼠标模拟器1

运行结果:不好

为了减少list(im.getdata())的用时,我将检索范围缩小到鼠标周围边长为150的方块,程序整体用时为5.56s/100次(甚至没有加上sleep延时,0.05的延时就是加5s),17.98次/s,人在18帧的时候尚无法很好地瞄准,程序在运行的时候效果更差。

若想达到45次/s或更高速度,需要使程序整体用时降低到2.22s/100次或更少。

经过尝试,在检索区域为150*150时,grab()函数用时3.92s/100次,sleep(0.05)将用时5s/100次,这两个部分为核心问题。其次,list(im.getddata())函数用时0.9s左右,计算部与操作部用时极少,这三个部分是难以优化的。

试图解决核心问题一:
使用win32 APIs 截图,在检索区域为150*150时,用时为1.66s(区域为1*1时用时也接近1.66),即使检索区域为1920*1080,用时也仅为3.4s。示例如下:

import time
import win32gui, win32ui, win32con, win32api


def window_capture(filename):
    hwnd = 0  # 窗口的编号,0号表示当前活跃窗口
    # 根据窗口句柄获取窗口的设备上下文DC(Divice Context)
    hwndDC = win32gui.GetWindowDC(hwnd)
    # 根据窗口的DC获取mfcDC
    mfcDC = win32ui.CreateDCFromHandle(hwndDC)
    # mfcDC创建可兼容的DC
    saveDC = mfcDC.CreateCompatibleDC()
    # 创建bigmap准备保存图片
    saveBitMap = win32ui.CreateBitmap()
    # 获取监控器信息
    MoniterDev = win32api.EnumDisplayMonitors(None, None)
    w = MoniterDev[0][2][2]
    h = MoniterDev[0][2][3]
    # print w,h   #图片大小
    # 为bitmap开辟空间
    saveBitMap.CreateCompatibleBitmap(mfcDC, w, h)
    # 高度saveDC,将截图保存到saveBitmap中
    saveDC.SelectObject(saveBitMap)
    # 截取从左上角(0,0)长宽为(w,h)的图片
    saveDC.BitBlt((0, 0), (w, h), mfcDC, (0, 0), win32con.SRCCOPY)
    saveBitMap.SaveBitmapFile(saveDC, filename)


beg = time.time()#p.s.这里我学到了time.time()的用法,这是一个计时器,通过两次计时相减可得到某一段代码的用时
for i in range(10):
    window_capture("haha.jpg")
end = time.time()
print(end - beg)

来源网络

发现,仅需改变saveDC.BitBlt((0, 0), (w, h), mfcDC, (0, 0), win32con.SRCCOPY)中的w、h即可降低用时,此句最少用时为0.5s/100次左右。

受此启发,为了更好地解决核心问题1、2,我决定先学习win32 APIs的用法

例1.尝试用win32 APIs解决核心问题1、2


  1. 楼月鼠标模拟器
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值