2.4 素材准备
屏幕截图处理后如上,在装备识别之前,我们需要先准备很多素材图片用来对比。
比如:武器名、q托、握把、q口
武器名:
q托
2.5 裁剪图片
为了方便图片对比,我们需要将截取的装备栏部分的图片裁剪成和素材一样大小的图片。
比如,我们要检测武器一的名字:
#读取之前的截屏
screen = cv2.imread("./resource/shotcut/screen.bmp", 0)
#裁剪出武器1名字
screenWepon1 = screen[0:40, 45:125]
#拿裁剪的图片和武器素材的目录作为入参,进行对比
w1Name = compareAndGetName(screenWepon1, "./resource/guns/")
1
2
3
4
5
6
2.6 对比图片
#对比图片获取名字
def compareAndGetName(screenImg, dir):
#获取目录下所有文件
content = os.listdir(dir)
name = 'none'
max = 0
#遍历文件
for fileName in content:
#使用opencv读取文件
curWepone = cv2.imread(dir + fileName, 0)
#使用SSIM算法拿到图片相似度
res = calculate_ssim(numpy.asarray(screenImg), numpy.asarray(curWepone))
#获取相似度最大的
if max < res and res > 0.5:
max = res
name = str(fileName)[:-4]
return name
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
SSIM算法:
def calculate_ssim(img1, img2):
if not img1.shape == img2.shape:
raise ValueError('Input images must have the same dimensions.')
if img1.ndim == 2:
return ssim(img1, img2)
elif img1.ndim == 3:
if img1.shape[2] == 3:
ssims = []
for i in range(3):
ssims.append(ssim(img1, img2))
return numpy.array(ssims).mean()
elif img1.shape[2] == 1:
return ssim(numpy.squeeze(img1), numpy.squeeze(img2))
else:
raise ValueError('Wrong input image dimensions.')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
到这,我们就能获取到装备栏1位置的武器名字了。
2.7 操作鼠标
知道武器名字后,同理,我们可以获取到装备的配件。
然后,监听鼠标左键按下,然后开始下移鼠标。
我们以m762武器为例:
射速:86, 每一发子弹间隔86毫秒
后坐力:
[42, 36, 36, 36, 42, 43, 42, 43, 54, 55, 54, 55, 54, 55, 54, 55, 62, 62, 62, 62, 62, 62, 62, 62,62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 77, 78, 77, 78]
表示每发子弹打出后,需要在y轴下移的距离,用来与后坐力对冲。
def moveMouse():
#从识别的数据中,再更具当前选择的武器,获取此刻的武器(比如按下1键,武器装备栏1为m762,那么此时武器就是m762)
curWepone = getCurrentWepone()
if (curWepone.name == 'none'):
return
#基础y轴补偿(没任何配件)
basic = curWepone.basic
#射速
speed = curWepone.speed
startTime = round(time.perf_counter(), 3) * 1000
for i in range(curWepone.maxBullets):
#是否可以开火,比如左键抬起,就中断。
if not canFire():
break
#系数,比如按住shift屏息,就需要再原来基础上乘1.33
holdK = 1.0
if c_contants.hold:
holdK = curWepone.hold
#乘以系数后实际的移动距离
moveSum = int(round(basic[i] * curWepone.k * holdK, 2))
while True:
if (moveSum > 10):
#移动鼠标
pydirectinput.move(xOffset=0, yOffset=10, relative=True)
moveSum -= 10
elif (moveSum > 0):
pydirectinput.move(xOffset=0, yOffset=moveSum, relative=True)
moveSum = 0
elapsed = (round(time.perf_counter(), 3) * 1000 - startTime)
if not canFire() or elapsed > (i + 1) * speed + 10:
break
time.sleep(0.01)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
代码中的while循环:
其实再第一发子弹射出后,我们只需要下移42的距离,然后计算出需要等待的时间(0.086-移动鼠标的时间),然后第二发子弹射出,以此类推。
while循环的作用是防止屏幕抖动太厉害。因为直接移动42的距离,游戏中抖的厉害,所以我们再86毫秒的间隔里分了多次来移动鼠标。
python中的sleep函数不准确,所以我们要自己来计时,防止错过每发子弹的时间间隔。
不准确还有个好处,随机,正好不用自己来随机防止检测了。
————————————————