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

Python截图点击脚本异常:误点蓝色像素而非红色像素求助

问题描述

编写了一段Python脚本,用于截取指定区域屏幕截图并根据像素颜色点击特定像素,预期点击红色像素(255, 0, 0),但实际却误点击蓝色像素。尝试调整颜色匹配逻辑后仍无法解决问题,同时希望优化脚本运行效率。

脚本代码如下:

import mss
import pyautogui
import numpy as np
import keyboard

top, left, width, height = 521, 1071, 451, 443
target_color = (255, 0, 0)  

def click_at(x, y):
    pyautogui.click(x, y)  

def is_target_color(pixel):
   
    tolerance = 20
    r, g, b = pixel[:3]
    return abs(r - target_color[0]) < tolerance and abs(g - target_color[1]) < tolerance and abs(b - target_color[2]) < tolerance

def create_border_mask(width, height, border_thickness):
    mask = np.zeros((height, width), dtype=bool)
    mask[:border_thickness, :] = True
    mask[-border_thickness:, :] = True
    mask[:, :border_thickness] = True
    mask[:, -border_thickness:] = True
    return mask

border_thickness = 2
border_mask = create_border_mask(width, height, border_thickness)
screenshot_count = 0

def main():
    global screenshot_count
    with mss.mss() as sct:
        monitor = {"top": top, "left": left, "width": width, "height": height}

        while True:
            if keyboard.is_pressed("ctrl+1"):
                print("Stopping...")
                break

            screenshot = sct.grab(monitor)
            screenshot_count += 1
            print(f"Screenshot taken: {screenshot_count}")

            img = np.array(screenshot)

            found = False
            for y in range(height):
                for x in range(width):
                    if border_mask[y, x]:
                        pixel = img[y, x][:3]
                        if is_target_color(pixel):
                            click_at(left + x, top + y) 
                            found = True
                            break
                        else:
                            
                            pass
                if found:
                    break

    print(f"Total screenshots taken: {screenshot_count}")

if __name__ == "__main__":
    main()

问题分析与解决方案

1. 颜色误判的核心原因

mss截取的图像格式是BGRA(蓝-绿-红-透明度),而你代码中默认按RGB顺序解析像素,导致颜色通道完全颠倒:

  • 提取pixel[:3]得到的是(B, G, R),而非预期的(R, G, B)
  • 判断红色(255,0,0)时,实际在检查蓝色通道是否接近255,自然会误点蓝色像素

修复方法:
有两种方式纠正通道顺序:

  • 方式一:修改is_target_color函数的通道解析顺序:
def is_target_color(pixel):
    tolerance = 20
    # 交换B和R的顺序,适配BGRA格式
    b, g, r = pixel[:3]
    return abs(r - target_color[0]) < tolerance and abs(g - target_color[1]) < tolerance and abs(b - target_color[2]) < tolerance
  • 方式二:将图像转换为RGB格式后再处理:
img = np.array(screenshot)
# 将BGRA转为RGB格式
img = img[..., [2, 1, 0]]

2. 脚本效率优化

原代码用双重for循环遍历像素,效率极低。利用numpy的向量化操作可以大幅提升速度,避免逐像素循环:

优化后的核心逻辑:

# 将图像转为RGB(如果用方式二)或直接处理BGRA
img = np.array(screenshot)
# 提取颜色通道(这里以BGRA为例,对应target_color的R、G、B要对应调整为B、G、R)
b_channel = img[..., 0]
g_channel = img[..., 1]
r_channel = img[..., 2]

# 计算每个像素与目标颜色的差值是否在容忍范围内
match_r = np.abs(r_channel - target_color[0]) < 20
match_g = np.abs(g_channel - target_color[1]) < 20
match_b = np.abs(b_channel - target_color[2]) < 20

# 合并匹配条件,同时应用边框mask
matches = match_r & match_g & match_b & border_mask

# 找到第一个匹配的像素坐标
y_indices, x_indices = np.where(matches)
if len(y_indices) > 0:
    # 取第一个匹配点
    x, y = x_indices[0], y_indices[0]
    click_at(left + x, top + y)

完整优化后代码

import mss
import pyautogui
import numpy as np
import keyboard

top, left, width, height = 521, 1071, 451, 443
target_color = (255, 0, 0)  
tolerance = 20

def click_at(x, y):
    pyautogui.click(x, y)  

def create_border_mask(width, height, border_thickness):
    mask = np.zeros((height, width), dtype=bool)
    mask[:border_thickness, :] = True
    mask[-border_thickness:, :] = True
    mask[:, :border_thickness] = True
    mask[:, -border_thickness:] = True
    return mask

border_thickness = 2
border_mask = create_border_mask(width, height, border_thickness)
screenshot_count = 0

def main():
    global screenshot_count
    with mss.mss() as sct:
        monitor = {"top": top, "left": left, "width": width, "height": height}

        while True:
            if keyboard.is_pressed("ctrl+1"):
                print("Stopping...")
                break

            screenshot = sct.grab(monitor)
            screenshot_count += 1
            print(f"Screenshot taken: {screenshot_count}")

            img = np.array(screenshot)
            # 提取BGRA通道
            b = img[..., 0]
            g = img[..., 1]
            r = img[..., 2]

            # 颜色匹配
            match = (np.abs(r - target_color[0]) < tolerance) & \
                    (np.abs(g - target_color[1]) < tolerance) & \
                    (np.abs(b - target_color[2]) < tolerance) & \
                    border_mask

            # 查找匹配点
            y_coords, x_coords = np.where(match)
            if len(y_coords) > 0:
                # 点击第一个匹配的像素
                click_at(left + x_coords[0], top + y_coords[0])

    print(f"Total screenshots taken: {screenshot_count}")

if __name__ == "__main__":
    main()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 12:04:53