You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

cv2.matchTemplate的minMaxLoc返回位置异常致鼠标移至屏幕边缘,如何修复?

问题排查:cv2.matchTemplate定位后鼠标移到屏幕边缘

我编写了Python脚本,通过cv2.matchTemplate函数在屏幕上查找指定图像,提取坐标后让鼠标移动到对应位置。但运行代码时,鼠标总是移到屏幕边缘,无法定位问题原因,恳请协助排查。

我的代码

import numpy as np
import mss
import cv2
import time
import pyautogui

# 按顺序要搜索的模板
TEMPLATES_BY_ORDER = ['EmailField.png',
                      'PasswordField.png', 'CheckBox.png', 'SignInButton.png']


def main():
    time.sleep(5)
    currentImage = 0

    with mss.mss() as sct:
        # 获取主显示器尺寸
        monitor = {"top": 0, "left": 0, "width": pyautogui.size()[
            0], "height": pyautogui.size()[1]}

        while currentImage < 1:
            # 当前模板的路径
            template_img_path = f"images/{TEMPLATES_BY_ORDER[currentImage]}"

            # 读取屏幕帧和要搜索的模板图像
            screen_frame = np.array(sct.grab(monitor))[:, :, :3]
            template_img = cv2.imread(template_img_path, cv2.IMREAD_COLOR)

            screen_frame_dementions = screen_frame.shape

            resized_img = cv2.resize(
                template_img, (screen_frame_dementions[1], screen_frame_dementions[0]))

            # 设置下一个要搜索的图像
            currentImage += 1

            # 匹配模板与屏幕帧
            result = cv2.matchTemplate(
                screen_frame, resized_img, cv2.TM_CCOEFF_NORMED)

            # 获取模板在屏幕帧中的坐标
            __, __, __, max_loc = cv2.minMaxLoc(result)
            x, y = max_loc
            pyautogui.moveTo(x, y)
            if cv2.waitKey(25) & 0xFF == ord("q"):
                cv2.destroyAllWindows()
                break


if __name__ == "__main__":
    main()

相关截图

  • 待搜索的屏幕截图:
    屏幕截图
  • 目标模板test.png:
    test.png截图

问题分析与修复方案

1. 核心错误:错误缩放模板图像

你把模板图像直接缩放到和屏幕帧一样大,完全违背了cv2.matchTemplate的工作逻辑——模板尺寸必须小于等于目标图像尺寸,否则匹配结果只会有一个坐标点(0,0),这就是鼠标移到屏幕左上角边缘的直接原因。

修复:删掉缩放模板的代码,直接使用原始尺寸的模板进行匹配。

2. 坐标未调整到模板中心

max_loc返回的是模板左上角的坐标,直接移动鼠标到这里体验不佳,应该将坐标调整到模板的中心位置。

3. 缺少匹配阈值判断

没有验证匹配的相似度,可能会把低相似度的错误区域当成目标,导致鼠标移到错误位置。建议设置一个阈值(比如0.8),只有当最大相似度超过阈值时才执行移动操作。

4. 循环逻辑问题

当前循环只执行一次(while currentImage <1),无法遍历TEMPLATES_BY_ORDER中的多个模板,可根据需求调整循环条件。


修正后的代码

import numpy as np
import mss
import cv2
import time
import pyautogui

# 按顺序要搜索的模板
TEMPLATES_BY_ORDER = ['EmailField.png',
                      'PasswordField.png', 'CheckBox.png', 'SignInButton.png']

# 匹配阈值,可根据实际情况调整
MATCH_THRESHOLD = 0.8


def main():
    time.sleep(5)
    currentImage = 0

    with mss.mss() as sct:
        # 获取主显示器尺寸
        monitor = {"top": 0, "left": 0, "width": pyautogui.size()[0], 
                   "height": pyautogui.size()[1]}

        # 遍历所有模板(可根据需求修改循环逻辑)
        while currentImage < len(TEMPLATES_BY_ORDER):
            template_img_path = f"images/{TEMPLATES_BY_ORDER[currentImage]}"
            screen_frame = np.array(sct.grab(monitor))[:, :, :3]
            template_img = cv2.imread(template_img_path, cv2.IMREAD_COLOR)

            # 检查模板是否成功读取
            if template_img is None:
                print(f"无法读取模板:{template_img_path}")
                currentImage += 1
                continue

            # 获取模板的宽高
            template_h, template_w = template_img.shape[:2]

            # 直接使用原始模板匹配,不再缩放
            result = cv2.matchTemplate(screen_frame, template_img, cv2.TM_CCOEFF_NORMED)
            min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)

            # 验证匹配相似度是否达标
            if max_val >= MATCH_THRESHOLD:
                # 计算模板中心坐标
                center_x = max_loc[0] + template_w // 2
                center_y = max_loc[1] + template_h // 2
                print(f"找到目标:{TEMPLATES_BY_ORDER[currentImage]},坐标:({center_x}, {center_y})")
                pyautogui.moveTo(center_x, center_y)
                # 找到目标后可选择暂停或继续,这里注释掉则继续下一个模板
                # break
            else:
                print(f"未找到匹配的目标:{TEMPLATES_BY_ORDER[currentImage]},相似度:{max_val}")

            currentImage += 1
            time.sleep(1)  # 可选:添加延迟,避免频繁截图匹配

            if cv2.waitKey(25) & 0xFF == ord("q"):
                cv2.destroyAllWindows()
                break


if __name__ == "__main__":
    main()

内容的提问来源于stack exchange,提问作者bob

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 01:15:31