| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216 |
- import pyautogui
- import cv2
- import numpy as np
- import time
- import threading
- from pynput import keyboard
- import os
- class MacImageClicker:
- def __init__(self):
- self.is_monitoring = False
- self.target_image = None
- self.confidence_threshold = 0.95
- self.hotkey = keyboard.Key.f8
- self.check_interval = 0.000001
-
- # macOS 特定设置
- pyautogui.FAILSAFE = True
- pyautogui.PAUSE = 0.1
-
- # 查找目标图片
- self.target_image_path = self.find_target_image()
-
- def find_target_image(self):
- """在项目根目录查找目标图片"""
- current_dir = os.getcwd()
- image_files = []
-
- # 查找所有可能的图片文件
- for file in os.listdir(current_dir):
- if file.lower().endswith(('.png', '.jpg', '.jpeg')):
- image_files.append(file)
-
- if not image_files:
- print("在项目根目录未找到任何图片文件 (png, jpg, jpeg)")
- return None
-
- # 优先选择包含 target 关键字的图片
- target_files = [f for f in image_files if 'target' in f.lower()]
- if target_files:
- selected = target_files[0]
- else:
- selected = image_files[0]
-
- full_path = os.path.join(current_dir, selected)
- print(f"找到目标图片: {selected}")
- return full_path
- def load_target_image(self):
- """加载目标图片"""
- if not self.target_image_path:
- print("未找到目标图片文件")
- return False
-
- try:
- self.target_image = cv2.imread(self.target_image_path)
- if self.target_image is not None:
- print(f"成功加载目标图片: {os.path.basename(self.target_image_path)}")
- print(f"图片尺寸: {self.target_image.shape[1]}x{self.target_image.shape[0]}")
- return True
- else:
- print("图片加载失败,可能是格式不支持")
- return False
- except Exception as e:
- print(f"加载图片时出错: {e}")
- return False
- def get_screenshot(self):
- """获取屏幕截图 - macOS 版本"""
- try:
- # 使用 pyautogui 截图,在 macOS 上兼容性更好
- screenshot = pyautogui.screenshot()
- screenshot_cv = cv2.cvtColor(np.array(screenshot), cv2.COLOR_RGB2BGR)
- return screenshot_cv
- except Exception as e:
- print(f"截图失败: {e}")
- return None
- def find_and_click(self):
- """在屏幕上查找目标图片并点击"""
- if self.target_image is None:
- return False
-
- try:
- # 获取屏幕截图
- screenshot = self.get_screenshot()
- if screenshot is None:
- return False
-
- # 模板匹配
- result = cv2.matchTemplate(screenshot, self.target_image, cv2.TM_CCOEFF_NORMED)
- min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
-
- # 调试信息(可选,可以注释掉以减少输出)
- # print(f"当前匹配度: {max_val:.3f}")
-
- if max_val >= self.confidence_threshold:
- # 计算目标中心位置
- h, w = self.target_image.shape[:2]
- center_x = max_loc[0] + w // 2
- center_y = max_loc[1] + h // 2
-
- # 先记录当前位置
- current_pos = pyautogui.position()
- print(f"📍 从当前位置 ({current_pos.x}, {current_pos.y}) 移动到目标位置 ({center_x}, {center_y})")
-
- pyautogui.moveTo(center_x, center_y, duration=0.0001)
-
- # 执行点击
- pyautogui.click()
-
- print(f"✅ 已点击位置: ({center_x}, {center_y}), 相似度: {max_val:.3f}")
- return True
-
- except Exception as e:
- print(f"查找或点击时出错: {e}")
-
- return False
- def monitoring_loop(self):
- """监控循环"""
- print("监控线程启动")
- while True:
- if self.is_monitoring:
- self.find_and_click()
- time.sleep(self.check_interval)
- def toggle_monitoring(self):
- """切换监控状态"""
- self.is_monitoring = not self.is_monitoring
-
- if self.is_monitoring:
- # 开启监控时确保图片已加载
- if self.target_image is None:
- if not self.load_target_image():
- self.is_monitoring = False
- print("❌ 无法加载目标图片,监控未开启")
- return
-
- status = "🟢 开启" if self.is_monitoring else "🔴 关闭"
- print(f"监控状态: {status}")
-
- if self.is_monitoring:
- print("开始监控屏幕,寻找目标图片...")
- def on_press(self, key):
- """键盘按下事件"""
- if key == self.hotkey:
- self.toggle_monitoring()
- elif key == keyboard.Key.esc:
- # ESC 键退出程序
- print("退出程序")
- os._exit(0)
- def check_mac_permissions(self):
- """检查 macOS 权限"""
- try:
- # 尝试截图来测试权限
- test_screenshot = pyautogui.screenshot()
- print("✅ 屏幕录制权限: 已授权")
- return True
- except Exception:
- print("❌ 屏幕录制权限: 未授权")
- print("请前往: 系统设置 > 隐私与安全性 > 屏幕录制")
- print("为终端或您使用的 IDE 开启屏幕录制权限")
- return False
- def start(self):
- """启动程序"""
- print("🖥️ macOS 图像点击工具")
- print("=" * 40)
-
- # 检查权限
- if not self.check_mac_permissions():
- return
-
- # 查找并加载目标图片
- if not self.load_target_image():
- print("请确保项目根目录有图片文件 (png, jpg, jpeg)")
- return
-
- print(f"🎯 目标图片: {os.path.basename(self.target_image_path)}")
- print(f"📏 相似度阈值: {self.confidence_threshold}")
- print(f"🎹 控制快捷键:")
- print(f" - F8: 开启/关闭监控")
- print(f" - ESC: 退出程序")
- print("=" * 40)
- print("等待指令...")
-
- # 启动监控线程
- monitor_thread = threading.Thread(target=self.monitoring_loop, daemon=True)
- monitor_thread.start()
-
- # 启动键盘监听
- try:
- with keyboard.Listener(on_press=self.on_press) as listener:
- listener.join()
- except KeyboardInterrupt:
- print("\n程序被用户中断")
- except Exception as e:
- print(f"程序出错: {e}")
- if __name__ == "__main__":
- # 确保程序在 macOS 上运行
- import platform
- if platform.system() != 'Darwin':
- print("警告: 这个工具是针对 macOS 优化的")
- print("但检测到您正在运行:", platform.system())
- print("继续运行可能遇到兼容性问题")
-
- response = input("是否继续? (y/n): ")
- if response.lower() != 'y':
- exit()
-
- clicker = MacImageClicker()
- clicker.start()
|