从0开始的计算机视觉自动游戏脚本开发学习Day1

        出于想要通过学习和创造一改自己最近颓丧的状态,也出于自己的专业兴趣,决定做点自己的小项目

        学校教的课程还都只停留在理论,在毫无实践经验的情况下,我抱着试试看的心态尝试完全通过chatgpt的指导来一步步探索,发现chatgpt意外的强大。题外话有点多了2333

一、图像的截取

        想要利用计算机视觉实时操作,对图像的截取肯定是第一步

import pyautogui

# 截取屏幕
screenshot = pyautogui.screenshot()
# 将截图保存为图像
screenshot.save("screenshot.png")

以上为利用pyautogui库的自带函数对整个屏幕进行截图

7deb860e6fa5431eb679a952e1e9e774.png

而实际操作中往往只需要对所需窗口进行截图:

import win32gui
import win32con
import pyautogui
import cv2
from PIL import ImageGrab

# 获取窗口句柄
def get_window_handle(window_name):
    handle = win32gui.FindWindow(None, window_name)
    if handle == 0:
        raise Exception(f"Window '{window_name}' not found!")
    return handle

# 获取窗口的边界框(左, 上, 右, 下)
def get_window_rect(handle):
    rect = win32gui.GetWindowRect(handle)
    # rect 包括 (left, top, right, bottom) 四个值
    return rect

# 截取窗口图像
def capture_window(window_name):
    # 获取窗口句柄
    handle = get_window_handle(window_name)
    # 获取窗口边界框
    rect = get_window_rect(handle)
    # 调整窗口边界(某些窗口可能有标题栏和边框,需要裁剪)
    left, top, right, bottom = rect
    width = right - left
    height = bottom - top
    # 截取该区域的图像
    screenshot = ImageGrab.grab(bbox=(left, top, right, bottom))
    # 将PIL图像转换为OpenCV格式
    screenshot_cv = cv2.cvtColor(np.array(screenshot), cv2.COLOR_RGB2BGR)
    
    return screenshot_cv

二、对地图中标志物的识别

        所测试的游戏是早就过气了的pokemmo(叠个甲  所做仅用于个人的学习和探索,今后成果也不会用于盈利和对游戏性的破坏,选择这款游戏单纯是因为游戏操作与地图简单)

        游戏流程中肯定需要判定目标地点并进行移动,那么首先就需要对目标地点进行识别

        我选择了最简单好做的方法:识别特征标志物

        若识别到地图中存在该标志物,便返回其相对于人物的位置,若识别不到便输出错误信息

       那么该如何判定标志物是否存在呢?

                使用特征匹配算法将地图中的特征与目标点的特征进行匹配。

import cv2

# 加载目标点和地图的图像
marked_img = cv2.imread('target.jpg', 0)
map_img = cv2.imread('map.jpg', 0)

# 使用模板匹配来查找标志物在地图中的位置
result = cv2.matchTemplate(map_img, marker_img, cv2.TM_CCOEFF_NORMED)

                对图像判定预测概率。如果预测结果的最高概率低于某个设定的阈值,可以认为该图像上不存在该标志物。

#计算最大概率和最小概率
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)

threshold=‘预先设定好的阈值’

if max_val < threshold:
    return "Unknown"
else:
    return "Finded"

        需要反复测试来寻找最佳阈值。

        在识别到后,通过比较坐标来找到目标点相对人物方位,如果xy距离都小于一定值,则直接判定为到达出“OK”

        由于在该游戏中人物位于窗口中心,所以直接用窗口中心的坐标。

if max_val >= threshold:
    # 获取标志物左上角的位置
    top_left = max_loc
    bottom_right = (top_left[0] + marker_img.shape[1], top_left[1] + marker_img.shape[0])

    # 标志物的中心位置
    marker_center = (top_left[0] + marker_img.shape[1] // 2, top_left[1] + marker_img.shape[0] // 2)
    # 计算标志物相对于地图中心的位置
    dx = marker_center[0] - map_center[0]
    dy = marker_center[1] - map_center[1]

    # 判断标志物位于地图中心的哪个方位
    if abs(dx) <= 50 and abs(dy) <= 50:  # 如果标志物接近中心
        print("OK")
        cv2.putText(map_img, "OK", (map_center[0] - 50, map_center[1] - 10), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
    else:
        if dx > 0:
            x_pos = "右"
        else:
            x_pos = "左"
        if dy > 0:
            y_pos = "下"
        else:
            y_pos = "上"
        position = f"标志物位于地图中心的{x_pos}{y_pos}方位"
        print(position)
        cv2.putText(map_img, position, (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0), 2)
else:
    print("标志物未找到")

Day1阶段性成果:

        测试所用地图:Straton City

20c137174a95433380462d73bf9247bf.png

       目标标志物:

                道馆大门

c15e9462d7544a26bdc6fae2950ac4f5.png

        以下为代码

import time
import win32gui
import win32con
import pyautogui
import cv2
import numpy as np
from PIL import ImageGrab
import win32gui


def capture_window(window_name):
    # 获取窗口句柄s
    hwnd = win32gui.FindWindow(None, window_name)
    if hwnd == 0:
        print(f"未找到窗口: {window_name}")
        return None
    # 获取窗口的设备上下文
    left, top, right, bottom = win32gui.GetWindowRect(hwnd)
    width = right - left
    height = bottom - top

    # 获取截图ds
    screenshot = ImageGrab.grab(bbox=(left, top, right, bottom))

    # 将PIL图像转换为OpenCV格式
    screenshot_cv = cv2.cvtColor(np.array(screenshot), cv2.COLOR_RGB2BGR)

    return screenshot_cv

# 测试 - 传入游戏窗口名称(替换为你游戏窗口的名称)
time.sleep(3)
window_name = "PokeMМO"  # 示例:替换为游戏窗口的名称
image = capture_window(window_name)
dg1d = cv2.imread(r'C:\Users\28788\Desktop\TASK2\daoguan1door\dg1d.png')
while True:
    map_img=image = capture_window(window_name)
    marker_img=dg1d
    if map_img is None or marker_img is None:
        print("地图或标志物图片读取失败")
        exit()
    # 使用模板匹配来查找标志物在地图中的位置
    result = cv2.matchTemplate(map_img, marker_img, cv2.TM_CCOEFF_NORMED)
    min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
    # 定义匹配成功的阈值
    threshold = 0.55
    # 获取地图的尺寸
    map_h, map_w = map_img.shape[:2]
    # 地图的中心位置
    map_center = (map_w // 2, map_h // 2)
    if max_val >= threshold:
        # 获取标志物左上角的位置
        top_left = max_loc
        bottom_right = (top_left[0] + marker_img.shape[1], top_left[1] + marker_img.shape[0])

        # 绘制矩形框标注标志物
        cv2.rectangle(map_img, top_left, bottom_right, (0, 255, 0), 2)

        # 标志物的中心位置
        marker_center = (top_left[0] + marker_img.shape[1] // 2, top_left[1] + marker_img.shape[0] // 2)
        # 计算标志物相对于地图中心的位置
        dx = marker_center[0] - map_center[0]
        dy = marker_center[1] - map_center[1]

        # 判断标志物位于地图中心的哪个方位
        if abs(dx) <= 50 and abs(dy) <= 50:  # 如果标志物接近中心
            print("OK")
            cv2.putText(map_img, "OK", (map_center[0] - 50, map_center[1] - 10), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
        else:
            if dx > 0:
                x_pos = "右"
            else:
                x_pos = "左"
            if dy > 0:
                y_pos = "下"
            else:
                y_pos = "上"
            position = f"标志物位于地图中心的{x_pos}{y_pos}方位"
            print(position)
            cv2.putText(map_img, position, (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0), 2)
    else:
        print("标志物未找到")
    # 在窗口中显示结果
    #cv2.imshow('Map with Marker Detection', map_img)

    time.sleep(1)

# 显示图像
#cv2.imshow("Window Screenshot", image)
cv2.waitKey(0)
cv2.destroyAllWindows()

        测试结果:

        在该地图中,0.55-0.6的threshold值表现较为优秀

a97916699e7c401c817e510e267d9eea.png

783419ac75ed4eb28026f6d234c63079.png

364dd434d9d045089d7a678ed35732a2.png

        结果可以说是非常成功,识别准确的有点让我吃惊

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值