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
相关产品推荐
相关产品推荐

