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

MSS截图转NumPy传入cv2.matchTemplate匹配异常问题

问题核心原因

你遇到的截图全黑、匹配失败问题和色彩空间转换无关,核心是两个逻辑错误:

  • Windows高分屏缩放适配缺失:如果你系统开了125%/150%等显示缩放,默认运行的程序DPI感知等级不足,MSS会按缩放后的逻辑分辨率计算坐标,你写死的截图区域坐标超出实际逻辑屏幕边界,抓到的像素值全为0,自然imshow全黑、模板匹配无结果。本地读取PNG能跑是因为不存在屏幕坐标抓取的问题。
  • 坐标体系不统一:你用来计算距离的参考点pta = np.array([[1036, 746]])是全屏绝对坐标,但模板匹配输出的坐标是截图区域内的相对坐标,直接计算欧氏距离结果完全错误。
  • 附带小bug:cv2.waitKey的按键判断逻辑写法错误,按q关闭窗口的功能不生效;未做无匹配结果的边界判断,没找到模板时会触发空数组计算报错。
修复方案
  1. 程序启动时开启Windows DPI感知,让MSS获取真实物理屏幕坐标,避免截图越界。
  2. 把模板匹配得到的相对坐标加上截图区域的左上角偏移,转换为全屏绝对坐标后再计算距离。
  3. 补全无匹配结果的异常判断,修正窗口按键响应逻辑。
  4. 调试阶段先全屏截图确认MSS输出正常,再调整局部截图的坐标参数,避免坐标越界。
修复后完整代码
import cv2
import numpy as np
import mss 
import time
from scipy.spatial.distance import cdist
import ctypes

# 开启Windows DPI感知,解决高分屏缩放截图全黑问题
try:
    ctypes.windll.user32.SetProcessDPIAware()
except:
    # 非Windows系统直接跳过
    pass

time.sleep(3) # 原10秒等待过长,3秒足够完成窗口切换
def screen_template_closest():   
    with mss.mss() as sct:
        # 调试时可先打印屏幕分辨率确认坐标范围:print(sct.monitors)
        # 局部截图区域
        monitor = {"top": 1059, "left": 62, "width": 285, "height": 640}
        img = np.array(sct.grab(monitor))
        print("截图尺寸:", img.shape)
            
    # 显示原始截图
    cv2.imshow("OpenCV/Numpy normal", img)
    # 显示灰度截图
    img_gray = cv2.cvtColor(img, cv2.COLOR_BGRA2GRAY)
    cv2.imshow('OpenCV/Numpy grayscale', img_gray)

    # 读取模板
    template = cv2.imread('C:\\Users\\Faon\\projetadminEnv3\\test\\templates.PNG', 0)
    h, w = template.shape
    res = cv2.matchTemplate(img_gray, template, cv2.TM_CCOEFF_NORMED)
    threshold = 0.75
    loc = np.where(res >= threshold)
    
    coordsFinded = []
    count = 0
    mask = np.zeros(img.shape[:2], np.uint8)
    
    for pt in zip(*loc[::-1]):
        if mask[pt[1] + h//2, pt[0] + w//2] != 255:
            mask[pt[1]:pt[1]+h, pt[0]:pt[0]+w] = 255
            count += 1
            cv2.rectangle(img, pt, (pt[0] + w, pt[1] + h), (0,255,0), 3)
            # 把截图相对坐标转成全屏绝对坐标
            abs_x = pt[0] + monitor["left"]
            abs_y = pt[1] + monitor["top"]
            coordsFinded.append((abs_x, abs_y))
            
    cv2.imshow('Matches', img)
    # 修正waitKey响应逻辑
    if cv2.waitKey(0) & 0xFF == ord('q'):
        cv2.destroyAllWindows()

    # 无匹配结果直接返回
    if not coordsFinded:
        print("未找到符合阈值的匹配目标")
        return None

    # 计算离指定点最近的匹配目标
    pta = np.array([[1036, 746]])   
    others1 = np.array(coordsFinded)
    print("所有匹配到的目标全屏坐标:", others1)
    distances = cdist(pta, others1)
    winnerClose = others1[distances.argmin()]
    print("距离指定点最近的目标坐标:", winnerClose)  
    return winnerClose

print(screen_template_closest()) 
调试注意事项
  • 第一次运行先把monitor参数改成sct.monitors[1](对应主屏幕全屏),确认imshow能正常显示屏幕内容,再调整局部截图的坐标值,避免坐标越界。
  • 如果匹配不到目标,适当降低threshold阈值,确认模板是在当前屏幕缩放比例下截取的,不要用缩放前/缩放后的图跨比例匹配。
  • 参考点pta的坐标要和DPI适配后的物理坐标保持一致,不要用缩放前的旧坐标。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 22:12:25