Python | OpenCV 專案:天堂私服 YOLOv8 物件偵測實戰
⚠️ 免責聲明 本文章內容僅供學術研究與電腦視覺技術學習之用途 ,所有程式碼與技術說明均以教育目的為出發點,用於探討資料蒐集、影像標記、YOLOv8 模型訓練與即時物件偵測等技術在實際場景中的應用方式。
本文作者不提供任何形式的輔助程式販售、散佈或商業服務 。
本文所有範例程式僅限在自行架設的私有伺服器環境中測試 ,不得用於任何正式營運的線上遊戲伺服器。
使用遊戲輔助程式可能違反個別遊戲的使用者條款,並導致帳號封鎖、法律責任等後果,讀者須自行承擔一切相關風險與責任 。
本文技術內容若被用於任何違法或損害他人利益之行為,作者概不負責 。
私有伺服器的架設與使用涉及遊戲著作權相關法律問題,讀者應自行評估所在地區的法規,並確認於合法範圍內使用。
本文的核心目的是展示 資料蒐集 → 標記 → YOLOv8 訓練 → 即時偵測 這套完整流程,私服環境僅作為一個可控、高效的資料來源範例。相同的流程同樣適用於工廠瑕疵偵測、倉儲物件辨識、醫療影像分析等正當場景。
📚 前言 在上一篇 MediaPipe 手勢控制應用 中,我們完成了手勢辨識的互動應用。
這一篇是一個真實的遊戲輔助開發實戰:天堂私服 YOLOv8 物件偵測 。
天堂私服的最大優勢是你能完全掌控遊戲環境:可以任意召喚怪物、調整地圖、控制光線與場景,讓資料蒐集變得極為高效。這個流程可以套用到任何你想偵測的遊戲物件。
🎯 專案目標
用私服環境快速蒐集遊戲截圖資料集
使用 LabelImg 標記怪物、NPC、道具等物件
以 YOLOv8 訓練自訂偵測模型
即時擷取遊戲畫面並進行物件偵測
🛠️ 套件安裝 1 2 pip install ultralytics pygetwindow pywin32 pip install labelImg
💡 pywin32 提供 win32gui、win32ui,用來呼叫 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 from ctypes import windllimport numpy as npimport pygetwindow as gwimport win32guiimport win32uidef 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) 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
💻 步驟一:自動蒐集遊戲截圖 在私服中固定地點、怪物附近定時截圖,快速建立訓練資料集。
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 import cv2import osimport timefrom window_capture import find_game_window, capture_windowSAVE_DIR = "dataset/raw_images" INTERVAL = 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:05 d} .jpg" , frame) count += 1 if count % 50 == 0 : print(f"已蒐集:{count} /{TARGET} " ) time.sleep(INTERVAL) print(f"完成!共 {count} 張,儲存於 {SAVE_DIR} " )
💡 私服蒐集技巧 :
在同一張地圖、同一區域定點蒐集,減少背景多樣性帶來的干擾
不同時間段(白天/夜間)各蒐集一批,讓模型適應光線變化
如果要偵測多種怪物,分別在各怪物出沒的地圖蒐集
💻 步驟二:LabelImg 標記
標記流程:
Open Dir → 選擇 dataset/raw_images/
Change Save Dir → 選擇 dataset/raw_labels/
左側切換格式為 YOLO
按 W 畫框 → 輸入類別名稱(如 orc、troll、item)
按 Ctrl+S 儲存,D 切換下一張
開啟 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 import osimport shutilimport randomSRC_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 import oswith 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 from ultralytics import YOLOimport torchprint(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 , 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