AI打遊戲-伍(遊戲,啟動!)

發表於2023-09-24

AI打遊戲-伍(遊戲,啟動!)

目標

  • 使用程式碼呼叫yolo模型,並解析預測結果
  • 讀取遊戲影片預測結果,並視覺化
  • 讀取遊戲視窗預測結果,並視覺化
  • 根據預測結果,模擬操作滑鼠操作

步驟

官方檔案

程式碼預測靜態圖片

  • 讀取遊戲截圖,送入yolo網路預測
  • 解析預測結果
import cv2
from ultralytics import YOLO

model = YOLO('runs/detect/train/weights/best.pt')
image = cv2.imread('E:\\ai-play-game\\project-1-at-2023-09-13-17-05-6275bec0\\images\\0d332b6a-8100.jpg')
# 預測結果(返回列表,因為同時輸入一組圖片)
result = model(image)[0]

print(f"result.names: {result.names}")
print(f"result.boxes: {result.boxes}")
# 觀察列印結果,可以找到不同的輸出型別:xywh,xywhn,xyxy,xyxyn

# 如果使用GPU訓練,則tensor在GPU中,先使用.cpu()轉到記憶體中才能使用
# 由於opencv框選標記使用xyxy,剛好可以使用result.boxes.data
# 內容格式:[[x1,y1,x2,y2,置信值,類別]]
print(f"座標資訊:{result.boxes.data.cpu().numpy().tolist()}")

視覺化預測結果

  • 列印座標不夠直觀,使用opencv顯示出結果
  • 讀取影片程式碼
import cv2

def main():
    image = cv2.imread('E:\\ai-play-game\\project-1-at-2023-09-13-17-05-6275bec0\\images\\0d332b6a-8100.jpg')
    # 顯示圖片
    cv2.imshow("image", image)
    # 顯示5秒或按"Esc"鍵退出
    if cv2.waitKey(5000) & 0xFF == 27:
        cv2.destroyAllWindows()


if __name__ == "__main__":
    main()
  • 加上yolo後
import cv2
from ultralytics import YOLO

# 載入模型
model = YOLO('runs/detect/train/weights/best.pt')
# 類別對應的名字,及rgb顏色
clazz_dict = {
    0: ('hellhound', (255, 0, 0)),
    1: ('samurais', (0, 255, 0)),
    2: ('player', (0, 0, 255)),
    3: ('fireflies', (255, 255, 0)),
}


def ai_boxes(image):
    """
    增加ai識別的框
    :param image: 圖片畫素張量
    :return: 增加顯示後的張量
    """
    result = model(image)[0]
    boxes = result.boxes.data.cpu().numpy().tolist()
    for x1, y1, x2, y2, conf, cls in boxes:
        x1, y1, x2, y2, cls = int(x1), int(y1), int(x2), int(y2), int(cls)
        cls_name, cls_rgb = clazz_dict[cls]
        # 增加框
        cv2.rectangle(image, (x1, y1), (x2, y2), cls_rgb, 1)
        # 增加文字
        cv2.putText(image, cls_name, (x1, y1), cv2.FONT_HERSHEY_COMPLEX, 0.5, cls_rgb, 1)
    return image


def main():
    image = cv2.imread('E:\\ai-play-game\\project-1-at-2023-09-13-17-05-6275bec0\\images\\0d332b6a-8100.jpg')
    image = ai_boxes(image)
    # 顯示圖片
    cv2.imshow("image", image)
    # 顯示5秒或按"Esc"鍵退出
    if cv2.waitKey(5000) & 0xFF == 27:
        cv2.destroyAllWindows()


if __name__ == "__main__":
    main()

視覺化解析影片

  • 將來源替換成影片
  • 讀取影片程式碼
import cv2

def main():
    cap = cv2.VideoCapture("E:\\ai-play-game\\2023-09-12 23-27-51.mp4")
    while cap.isOpened():
        ret, frame = cap.read()
        if ret:
            cv2.imshow("video", frame)
        # 按"Esc"鍵退出
        if cv2.waitKey(1) & 0xFF == 27:
            break

    cap.release()
    cv2.destroyAllWindows()


if __name__ == "__main__":
    main()
  • 加上YOLO後
import cv2
from ultralytics import YOLO

# 載入模型
model = YOLO('runs/detect/train/weights/best.pt')
# 類別對應的名字,及rgb顏色
clazz_dict = {
    0: ('hellhound', (255, 0, 0)),
    1: ('samurais', (0, 255, 0)),
    2: ('player', (0, 0, 255)),
    3: ('fireflies', (255, 255, 0)),
}


def ai_boxes(image):
    """
    增加ai識別的框
    :param image: 圖片畫素張量
    :return: 增加顯示後的張量
    """
    result = model(image)[0]
    boxes = result.boxes.data.cpu().numpy().tolist()
    for x1, y1, x2, y2, conf, cls in boxes:
        x1, y1, x2, y2, cls = int(x1), int(y1), int(x2), int(y2), int(cls)
        cls_name, cls_rgb = clazz_dict[cls]
        # 增加框
        cv2.rectangle(image, (x1, y1), (x2, y2), cls_rgb, 2)
        # 增加文字
        cv2.putText(image, cls_name, (x1, y1), cv2.FONT_HERSHEY_COMPLEX, 1, cls_rgb, 2)
    return image


def main():
    cap = cv2.VideoCapture("E:\\ai-play-game\\2023-09-12 23-27-51.mp4")
    while cap.isOpened():
        ret, frame = cap.read()
        if ret:
            frame = ai_boxes(frame)
            cv2.imshow("video", frame)
        # 按"Esc"鍵退出
        if cv2.waitKey(1) & 0xFF == 27:
            break

    cap.release()
    cv2.destroyAllWindows()


if __name__ == "__main__":
    main()

讀取遊戲視窗

  • pip安裝依賴
pip install pywin32
  • 讀取視窗程式碼
import cv2
from ultralytics import YOLO
import win32gui
import numpy as np
from PIL import ImageGrab

def main():
    # 讀取遊戲視窗,需要先開啟遊戲
    win_id = win32gui.FindWindow(None, 'Tap Ninja')
    while True:
        # 獲取視窗位置資訊
        win_bbox = win32gui.GetWindowRect(win_id)
        # 讀取視窗位置畫素資訊
        game_window = np.array(ImageGrab.grab(bbox=win_bbox))
        # 兩個庫色彩模式不同,轉換色彩模式
        image = cv2.cvtColor(game_window, cv2.COLOR_BGR2RGB)

        cv2.imshow("video", image)
        # 按"Esc"鍵退出
        if cv2.waitKey(1) & 0xFF == 27:
            break
    cv2.destroyAllWindows()


if __name__ == "__main__":
    main()
  • 加上YOLO後
import cv2
from ultralytics import YOLO
import win32gui
import numpy as np
from PIL import ImageGrab

# 載入模型
model = YOLO('runs/detect/train/weights/best.pt')
# 類別對應的名字,及rgb顏色
clazz_dict = {
    0: ('hellhound', (255, 0, 0)),
    1: ('samurais', (0, 255, 0)),
    2: ('player', (0, 0, 255)),
    3: ('fireflies', (255, 255, 0)),
}


def ai_boxes(image):
    """
    增加ai識別的框
    :param image: 圖片畫素張量
    :return: 增加顯示後的張量
    """
    result = model(image)[0]
    boxes = result.boxes.data.cpu().numpy().tolist()
    for x1, y1, x2, y2, conf, cls in boxes:
        x1, y1, x2, y2, cls = int(x1), int(y1), int(x2), int(y2), int(cls)
        cls_name, cls_rgb = clazz_dict[cls]
        # 增加框
        cv2.rectangle(image, (x1, y1), (x2, y2), cls_rgb, 2)
        # 增加文字
        cv2.putText(image, cls_name, (x1, y1), cv2.FONT_HERSHEY_COMPLEX, 1, cls_rgb, 2)
    return image


def main():
    # 讀取遊戲視窗,需要先開啟遊戲
    win_id = win32gui.FindWindow(None, 'Tap Ninja')
    while True:
        # 獲取視窗位置資訊
        win_bbox = win32gui.GetWindowRect(win_id)
        # 讀取視窗位置畫素資訊
        game_window = np.array(ImageGrab.grab(bbox=win_bbox))
        # 兩個庫色彩模式不同,轉換色彩模式
        image = cv2.cvtColor(game_window, cv2.COLOR_BGR2RGB)

        image = ai_boxes(image)
        cv2.imshow("video", image)
        # 按"Esc"鍵退出
        if cv2.waitKey(1) & 0xFF == 27:
            break
    cv2.destroyAllWindows()


if __name__ == "__main__":
    main()

模擬滑鼠操作

  • pip安裝依賴
pip install pyautogui
  • 由於遊戲使用DirectX渲染,pyautogui需要管理員許可權才能在遊戲中模擬滑鼠操作
  • 重新一定要重新使用"管理員"開啟IDE !!!
import cv2
from ultralytics import YOLO
import win32gui
import numpy as np
from PIL import ImageGrab
import pyautogui

# 載入模型
model = YOLO('runs/detect/train/weights/best.pt')
# 類別對應的名字,及rgb顏色
clazz_dict = {
    0: ('hellhound', (255, 0, 0)),
    1: ('samurais', (0, 255, 0)),
    2: ('player', (0, 0, 255)),
    3: ('fireflies', (255, 255, 0)),
}


def controller(boxes):
    """
    控制模擬玩家操作
    :param boxes: YOLO預測結果
    """
    player_fire_x = None
    other_x1_list = []
    for x1, y1, x2, y2, conf, cls in boxes:
        if int(cls) == 2:
            # 操作位置:玩家前方一個身位的位置
            player_fire_x = x2 + (x2 - x1)
        else:
            other_x1_list.append(x1)
    if player_fire_x is not None and len(other_x1_list) > 0:
        for x1 in other_x1_list:
            if x1 < player_fire_x:
                # 點選滑鼠左鍵
                pyautogui.click(button='left')
                print("**************************** 點選 ****************************")


def ai_boxes(image):
    """
    增加ai識別的框
    :param image: 圖片畫素張量
    :return: 增加顯示後的張量
    """
    result = model(image)[0]
    boxes = result.boxes.data.cpu().numpy().tolist()
    for x1, y1, x2, y2, conf, cls in boxes:
        x1, y1, x2, y2, cls = int(x1), int(y1), int(x2), int(y2), int(cls)
        cls_name, cls_rgb = clazz_dict[cls]
        # 增加框
        cv2.rectangle(image, (x1, y1), (x2, y2), cls_rgb, 2)
        # 增加文字
        cv2.putText(image, cls_name, (x1, y1), cv2.FONT_HERSHEY_COMPLEX, 1, cls_rgb, 2)
    # 判斷位置並控制
    controller(boxes)
    return image


def main():
    # 讀取遊戲視窗,需要先開啟遊戲
    win_id = win32gui.FindWindow(None, 'Tap Ninja')
    while True:
        # 獲取視窗位置資訊
        win_bbox = win32gui.GetWindowRect(win_id)
        # 讀取視窗位置畫素資訊
        game_window = np.array(ImageGrab.grab(bbox=win_bbox))
        # 兩個庫色彩模式不同,轉換色彩模式
        image = cv2.cvtColor(game_window, cv2.COLOR_BGR2RGB)

        image = ai_boxes(image)
        cv2.imshow("video", image)
        # 按"Esc"鍵退出
        if cv2.waitKey(1) & 0xFF == 27:
            break
    cv2.destroyAllWindows()


if __name__ == "__main__":
    main()

小結

  • 看出識別結果不夠準確
  • 提升準確率

    • 調整訓練引數
    • 增加訓練集樣本數量
    • 區分訓練集和驗證集

總結

  • AI演演算法不僅是模型訓練,還包含了很多上下游工作
  • 通常是以下幾個步驟

    • 發現一個問題或者需求,分析解決方案
    • 收集資料
    • 標註資料
    • 模型訓練
    • 部署使用
    • 效果監控,收集資料,迭代演演算法

相關文章