🔥 新作首發 🎮 天堂私服 YOLOv8 物件偵測實戰 — 從資料蒐集、模型訓練到即時偵測 立即閱讀 →
熱門系列
Like Share Discussion Bookmark Smile

J.J. Huang   2026-04-18   Python OpenCV 08.專案實作篇   瀏覽次數:次   DMCA.com Protection Status

Python | OpenCV 專案:天堂私服 YOLOv8 物件偵測實戰

⚠️ 免責聲明

本文章內容僅供學術研究與電腦視覺技術學習之用途,所有程式碼與技術說明均以教育目的為出發點,用於探討資料蒐集、影像標記、YOLOv8 模型訓練與即時物件偵測等技術在實際場景中的應用方式。

  • 本文作者不提供任何形式的輔助程式販售、散佈或商業服務
  • 本文所有範例程式僅限在自行架設的私有伺服器環境中測試,不得用於任何正式營運的線上遊戲伺服器。
  • 使用遊戲輔助程式可能違反個別遊戲的使用者條款,並導致帳號封鎖、法律責任等後果,讀者須自行承擔一切相關風險與責任
  • 本文技術內容若被用於任何違法或損害他人利益之行為,作者概不負責
  • 私有伺服器的架設與使用涉及遊戲著作權相關法律問題,讀者應自行評估所在地區的法規,並確認於合法範圍內使用。

本文的核心目的是展示 資料蒐集 → 標記 → YOLOv8 訓練 → 即時偵測 這套完整流程,私服環境僅作為一個可控、高效的資料來源範例。相同的流程同樣適用於工廠瑕疵偵測、倉儲物件辨識、醫療影像分析等正當場景。

📚 前言

在上一篇 MediaPipe 手勢控制應用 中,我們完成了手勢辨識的互動應用。

這一篇是一個真實的遊戲輔助開發實戰:天堂私服 YOLOv8 物件偵測

天堂私服的最大優勢是你能完全掌控遊戲環境:可以任意召喚怪物、調整地圖、控制光線與場景,讓資料蒐集變得極為高效。這個流程可以套用到任何你想偵測的遊戲物件。

🎯 專案目標

  • 用私服環境快速蒐集遊戲截圖資料集
  • 使用 LabelImg 標記怪物、NPC、道具等物件
  • 以 YOLOv8 訓練自訂偵測模型
  • 即時擷取遊戲畫面並進行物件偵測

🛠️ 套件安裝

1
2
pip install ultralytics pygetwindow pywin32
pip install labelImg # 標記工具

💡 pywin32 提供 win32guiwin32ui,用來呼叫 Windows PrintWindow API 擷取被遮擋的遊戲畫面。若 import win32gui 報錯,補跑一次 post-install:

1
python -m pywin32_postinstall -install

最小化時 Windows 不會 render 畫面,仍無法擷取。

🧰 共用工具:視窗擷取模組

擷取視窗畫面的邏輯,蒐集與偵測兩個步驟都會用到,抽出來共用。

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
33
34
35
36
37
38
39
40
41
42
43
44
# window_capture.py
from ctypes import windll
import numpy as np
import pygetwindow as gw
import win32gui
import win32ui

def find_game_window(title_keyword):
"""回傳符合標題關鍵字、可見、未最小化的視窗;找不到回傳 None"""
for w in gw.getAllWindows():
if (title_keyword.lower() in w.title.lower()
and w.visible and not w.isMinimized
and w.width > 0 and w.height > 0):
return w
return None

def list_visible_windows():
"""列出所有可見且有標題的視窗,方便診斷"""
return [w.title for w in gw.getAllWindows() if w.title.strip() and w.visible]

def capture_window(hwnd):
"""用 PrintWindow 擷取視窗畫面:被遮擋也能抓,最小化會拿到黑畫面"""
left, top, right, bottom = win32gui.GetWindowRect(hwnd)
w, h = right - left, bottom - top
if w <= 0 or h <= 0:
return None

hwnd_dc = win32gui.GetWindowDC(hwnd)
mfc_dc = win32ui.CreateDCFromHandle(hwnd_dc)
save_dc = mfc_dc.CreateCompatibleDC()
save_bmp = win32ui.CreateBitmap()
save_bmp.CreateCompatibleBitmap(mfc_dc, w, h)
save_dc.SelectObject(save_bmp)

# flag=2 (PW_RENDERFULLCONTENT):支援 DWM 合成畫面,對多數現代應用必要
result = windll.user32.PrintWindow(hwnd, save_dc.GetSafeHdc(), 2)
img = np.frombuffer(save_bmp.GetBitmapBits(True), dtype=np.uint8).reshape((h, w, 4))

win32gui.DeleteObject(save_bmp.GetHandle())
save_dc.DeleteDC()
mfc_dc.DeleteDC()
win32gui.ReleaseDC(hwnd, hwnd_dc)

return img[:, :, :3].copy() if result == 1 else None # BGRA → BGR

💻 步驟一:自動蒐集遊戲截圖

在私服中固定地點、怪物附近定時截圖,快速建立訓練資料集。

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
33
34
# collect_screenshots.py
import cv2
import os
import time
from window_capture import find_game_window, capture_window

SAVE_DIR = "dataset/raw_images"
INTERVAL = 0.5 # 每隔 0.5 秒截一張
TARGET = 500 # 目標張數
WINDOW_TITLE = "Lineage" # 遊戲視窗標題(部分符合即可)

os.makedirs(SAVE_DIR, exist_ok=True)

game_win = find_game_window(WINDOW_TITLE)
if game_win is None:
print(f"找不到『{WINDOW_TITLE}』視窗,請先開啟遊戲")
exit()

print(f"開始蒐集,目標 {TARGET} 張,間隔 {INTERVAL} 秒(Ctrl+C 停止)")

count = 0
while count < TARGET:
frame = capture_window(game_win._hWnd)
if frame is None:
time.sleep(INTERVAL)
continue

cv2.imwrite(f"{SAVE_DIR}/{count:05d}.jpg", frame)
count += 1
if count % 50 == 0:
print(f"已蒐集:{count}/{TARGET}")
time.sleep(INTERVAL)

print(f"完成!共 {count} 張,儲存於 {SAVE_DIR}")

💡 私服蒐集技巧

  • 在同一張地圖、同一區域定點蒐集,減少背景多樣性帶來的干擾
  • 不同時間段(白天/夜間)各蒐集一批,讓模型適應光線變化
  • 如果要偵測多種怪物,分別在各怪物出沒的地圖蒐集

💻 步驟二:LabelImg 標記

1
2
# 安裝後直接執行
labelImg

標記流程:

  1. Open Dir → 選擇 dataset/raw_images/
  2. Change Save Dir → 選擇 dataset/raw_labels/
  3. 左側切換格式為 YOLO
  4. W 畫框 → 輸入類別名稱(如 orctrollitem
  5. Ctrl+S 儲存,D 切換下一張
  6. 開啟 Auto Save 可省略手動存檔

建議標記的類別(依需求調整):

1
2
3
4
怪物類:orc, troll, dark_elf, zombie, ...
NPC 類:npc_shop, npc_quest, ...
道具類:item_weapon, item_armor, item_misc
角色類:player, other_player

💡 先只標記 1~2 個最重要的類別,訓練成功後再擴充。類別越少,模型越好訓練。

💻 步驟三:分割資料集

將原始截圖與標籤按 8:2 比例隨機分割為訓練集與驗證集,建立對應目錄結構。

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
33
34
35
# split_dataset.py
import os
import shutil
import random

SRC_IMAGES = "dataset/raw_images"
SRC_LABELS = "dataset/raw_labels"
DST_ROOT = "dataset"
VAL_RATIO = 0.2
random.seed(42)

for split in ["train", "val"]:
os.makedirs(f"{DST_ROOT}/images/{split}", exist_ok=True)
os.makedirs(f"{DST_ROOT}/labels/{split}", exist_ok=True)

files = [f for f in os.listdir(SRC_IMAGES)
if f.lower().endswith((".jpg", ".png"))]
random.shuffle(files)

val_set = set(files[:int(len(files) * VAL_RATIO)])

for fname in files:
split = "val" if fname in val_set else "train"
stem = os.path.splitext(fname)[0]

shutil.copy(f"{SRC_IMAGES}/{fname}",
f"{DST_ROOT}/images/{split}/{fname}")

lbl = f"{SRC_LABELS}/{stem}.txt"
if os.path.exists(lbl):
shutil.copy(lbl, f"{DST_ROOT}/labels/{split}/{stem}.txt")
else:
open(f"{DST_ROOT}/labels/{split}/{stem}.txt", "w").close()

print(f"train: {len(files)-len(val_set)}, val: {len(val_set)}")

💻 步驟四:建立 data.yaml

從 LabelImg 產生的 classes.txt 自動讀取類別,生成 YOLOv8 訓練所需的 data.yaml 設定檔。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# create_yaml.py
import os

# 從 LabelImg 產生的 classes.txt 讀取類別
with open("dataset/raw_labels/classes.txt") as f:
classes = [line.strip() for line in f if line.strip()]

yaml_content = f"""path: ./dataset
train: images/train
val: images/val

nc: {len(classes)}
names:
"""
for i, cls in enumerate(classes):
yaml_content += f" {i}: {cls}\n"

with open("data.yaml", "w") as f:
f.write(yaml_content)

print("data.yaml 已產生:")
print(yaml_content)

💻 步驟五:訓練 YOLOv8

以 YOLOv8s 預訓練模型為基礎,對遊戲截圖資料集進行訓練並輸出最佳偵測模型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# train.py
from ultralytics import YOLO
import torch

print(f"GPU:{'可用 - ' + torch.cuda.get_device_name(0) if torch.cuda.is_available() else 'CPU'}")

model = YOLO("yolov8s.pt")

model.train(
data="data.yaml",
epochs=100,
imgsz=640,
batch=16,
device=0 if torch.cuda.is_available() else "cpu",
workers=0, # Windows 必設 0
patience=20,
name="lineage_detector",
plots=True,
)

print(f"\n訓練完成!best.pt:{model.trainer.best}")

💻 步驟六:即時遊戲畫面偵測

這段內容已加密
需要 支持會員 或更高等級的密碼才能閱讀




圖:開啟遊戲視窗截圖並以 YOLOv8 即時推論,在單一顯示視窗內用綠色框線標注所有偵測到的物件與信心度

⚠️ 注意事項

  • 私服的優勢:可用 GM 指令隨時生怪、清場、調時間,蒐集成本極低。
  • 解析度要一致:訓練與推論的視窗尺寸盡量固定,否則讓 imgsz 涵蓋所有情境。
  • 標記品質 > 數量:500 張精標遠勝 2000 張草率標。
  • 視窗不能最小化:改用 PrintWindow 後被其他視窗「遮擋」也能擷取,但最小化時 Windows 根本不 render 畫面,仍會拿到黑畫面;程式偵測到最小化會自動結束。
  • 訓練路徑自動找:不同 Ultralytics 版本的 best.pt 位置會跑掉,程式已用 rglob 抓最新。
  • 顯示用手動 cv2,不要 results[0].plot():部分版本的 plot() 會另開視窗,畫在原 frame 上最可控。

📊 進階應用方向

  • 自動攻擊:偵測到怪物後,取邊界框中心座標,用 pyautogui 點擊
  • 自動撿取道具:偵測 item 類別,自動移動到物品位置按撿取
  • 血量監控:偵測 HP 條區域,用 OCR 或色彩分析判斷血量百分比

🎯 結語

從私服蒐集資料、LabelImg 標記、YOLOv8 訓練到即時偵測,整套流程一天內就能跑完;換成其他遊戲或模擬器,步驟完全一樣。

下一篇進入 天堂私服遊戲輔助(一)主程式 GUI 框架與 HP/MP 血量監控,把訓練好的模型整合進一套有 GUI 的完整輔助程式。

📖 如在學習過程中遇到疑問,或是想了解更多相關主題,建議回顧一下 Python | OpenCV 系列導讀,掌握完整的章節目錄,方便快速找到你需要的內容。

註:以上參考了
Ultralytics YOLOv8 官方文件
LabelImg GitHub
pygetwindow GitHub
pywin32 GitHub