---
tags: Python系統設計
---
# 图像识别
```python=
import subprocess
import sys
required_packages = ['opencv-python', 'numpy', 'pyautogui', 'keyboard']
for package in required_packages:
try:
__import__(package if package != 'opencv-python' else 'cv2')
except ImportError:
print(f"📦 缺少套件 {package},正在安装...")
subprocess.check_call([sys.executable, "-m", "pip", "install", package])
import cv2
import numpy as np
import pyautogui
import time
import tkinter as tk
import threading
import keyboard
import traceback # ✅ 新增:显示错误细节
import ctypes
import sys
try:
pyautogui.FAILSAFE = False
# === 读取模板 ===
template = cv2.imread('Boss.bmp', cv2.IMREAD_COLOR)
if template is None:
raise FileNotFoundError("❌ 模板图像 'Boss.bmp' 无法读取,请检查路径或格式")
template_gray = cv2.cvtColor(template, cv2.COLOR_BGR2GRAY)
template_h, template_w = template_gray.shape[:2]
scales = np.linspace(0.5, 1.5, 20)
# === Tkinter 浮动蓝框 ===
root = tk.Tk()
root.attributes('-topmost', True)
root.overrideredirect(True)
root.attributes('-alpha', 0.4)
if sys.platform == "win32":
hwnd = ctypes.windll.user32.GetParent(root.winfo_id())
styles = ctypes.windll.user32.GetWindowLongW(hwnd, -20)
styles |= 0x80000 | 0x20 # WS_EX_LAYERED | WS_EX_TRANSPARENT
ctypes.windll.user32.SetWindowLongW(hwnd, -20, styles)
canvas = tk.Canvas(root, bg='white', highlightthickness=0)
canvas.pack(fill=tk.BOTH, expand=True)
root.geometry("0x0+0+0")
def move_window(x, y, w, h):
root.geometry(f"{w}x{h}+{x}+{y}")
canvas.delete("all")
canvas.create_rectangle(0, 0, w, h, outline="blue", width=4)
def hide_window():
root.geometry("0x0+0+0")
canvas.delete("all")
# === 检测函数 ===
def find_and_show():
while not keyboard.is_pressed('esc'):
screenshot = pyautogui.screenshot()
img_rgb = np.array(screenshot)
img_bgr = cv2.cvtColor(img_rgb, cv2.COLOR_RGB2BGR)
img_gray = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2GRAY)
best_val = -1
best_loc = None
best_scale = 1.0
for scale in scales:
resized = cv2.resize(template_gray, (int(template_w * scale), int(template_h * scale)))
if resized.shape[0] > img_gray.shape[0] or resized.shape[1] > img_gray.shape[1]:
continue
res = cv2.matchTemplate(img_gray, resized, cv2.TM_CCOEFF_NORMED)
_, max_val, _, max_loc = cv2.minMaxLoc(res)
if max_val > best_val:
best_val = max_val
best_loc = max_loc
best_scale = scale
if best_val > 0.90:
w, h = int(template_w * best_scale), int(template_h * best_scale)
x, y = best_loc
center_x = x + w // 2
center_y = y + h // 2
# 将框放大 3 倍
w_large, h_large = int(w * 2), int(h * 2)
x_large = center_x - w_large // 2
y_large = center_y - h_large // 2
# 用 pyautogui 画一个框(可视化辅助)
# pyautogui.moveTo(x, y)
# pyautogui.dragRel(w, 0, duration=0.1)
# pyautogui.dragRel(0, h, duration=0.1)
# pyautogui.dragRel(-w, 0, duration=0.1)
# pyautogui.dragRel(0, -h, duration=0.1)
# hide_window() # 先隐藏蓝框(避免遮挡游戏)
pyautogui.moveTo(center_x, center_y, duration=0.2)
pyautogui.click()
# move_window(x, y, w, h) # 点击后再显示蓝框
# move_window(x_large, y_large, w_large, h_large) # ✅ 改成放大版
print(f"✅ 找到目标于 ({center_x}, {center_y}) 相似度: {best_val:.2f}")
else:
# hide_window()
print("🔍 没有找到目标...")
time.sleep(1)
print("🛑 检测到 Esc,结束程序")
root.destroy()
# === 启动检测线程 ===
threading.Thread(target=find_and_show, daemon=True).start()
def on_esc_press():
print("🛑 检测到 Esc,准备退出程式")
root.quit()
root.destroy()
keyboard.add_hotkey('esc', on_esc_press)
root.mainloop()
except Exception as e:
print("❗ 程序发生异常:", str(e))
traceback.print_exc()
input("\n⚠️ 按 Enter 退出(查看上方错误讯息)...")
```