如何高效检测屏幕区域内变为指定颜色的像素 支持三角形区域吗
像素区域检测优化与三角形检测区实现方案
你当前代码的性能瓶颈非常明显:每次循环都抓取全屏像素,再用getpixel()单点读取,哪怕只检测一个点速度都不会快,更不要说检测区域像素。
核心结论
- 所有系统原生的屏幕捕获接口都只支持输出矩形图像,不存在直接传入三角形顶点完成抓图的API,不可能跳过外接矩形抓图这一步。
- 三角形检测区域完全可以实现:抓完三角形的最小外接矩形图像后,只对三角形范围内的像素做颜色匹配,跳过区域外的像素,确实能减少待检测像素总量、提升运行速度。
- 直接把三角形顶点传给抓图函数不可行,必须自己实现区域内像素的筛选逻辑。
具体实现步骤
- 先缩小抓图范围
拿到三角形三个顶点的坐标后,先计算三个点x坐标的最小值、最大值,y坐标的最小值、最大值,将这四个值组成(x_min, y_min, x_max, y_max)的bbox参数传给抓图函数,只抓取这一小块矩形区域的屏幕内容,这一步比全屏抓图的性能提升最明显,通常能减少90%以上的无效数据。 - 替换低效的逐点读取方式
不要用getpixel()逐点读像素,抓图后直接将图像转为numpy数组,通过向量化操作批量比对颜色,速度比逐点调用API快10~100倍。 - 实现三角形区域像素筛选
用叉乘判断法快速判定像素点是否在三角形内部,只对内部点做颜色校验,跳过三角形外的所有点。这个判断全是整数运算,开销极低。
参考实现代码
import PIL.ImageGrab import mouse import numpy as np # 配置参数 TARGET_COLOR = (253, 146, 134) # 三角形三个顶点坐标,按实际需求修改 TRIANGLE_POINTS = np.array([ [400, 400], [600, 420], [510, 600] ]) # 预计算三角形最小外接矩形 x_min, y_min = TRIANGLE_POINTS.min(axis=0) x_max, y_max = TRIANGLE_POINTS.max(axis=0) BBOX = (x_min, y_min, x_max, y_max) # 把三角形顶点坐标转换为相对于抓图区域的局部坐标 LOCAL_TRI = TRIANGLE_POINTS - [x_min, y_min] def point_in_triangle(p, tri): """叉乘判断点p是否在三角形tri内部,纯整数运算速度极快 若需要包含三角形边线上的点,将判断中的<、>替换为<=、>=即可 """ a, b, c = tri ab = b - a ap = p - a bc = c - b bp = p - b ca = a - c cp = p - c cross1 = ab[0]*ap[1] - ab[1]*ap[0] cross2 = bc[0]*bp[1] - bc[1]*bp[0] cross3 = ca[0]*cp[1] - ca[1]*cp[0] # 三个叉乘同号则点在三角形内部 has_neg = (cross1 < 0) or (cross2 < 0) or (cross3 < 0) has_pos = (cross1 > 0) or (cross2 > 0) or (cross3 > 0) return not (has_neg and has_pos) # 预生成三角形区域掩码,三角形位置固定时仅需计算一次,大幅降低循环内开销 h = y_max - y_min w = x_max - x_min mask = np.zeros((h, w), dtype=bool) for y in range(h): for x in range(w): mask[y, x] = point_in_triangle(np.array([x, y]), LOCAL_TRI) while True: # 仅抓取最小外接矩形区域 img = PIL.ImageGrab.grab(bbox=BBOX) # 转numpy数组做批量颜色比对 img_arr = np.array(img) # 批量匹配所有等于目标色的像素 color_match = np.all(img_arr == TARGET_COLOR, axis=-1) # 仅保留三角形区域内的匹配结果 target_match = color_match & mask # 拿到所有匹配点的局部坐标,转换回全屏坐标 match_points = np.argwhere(target_match)[:, ::-1] + [x_min, y_min] if len(match_points) > 0: # 检测到目标色像素后执行点击,可根据实际需求修改逻辑 mouse.click()
额外提速建议
- 如果对速度要求极高,可以把
PIL.ImageGrab换成mss库的抓图接口,抓屏效率比PIL高3~5倍,其余逻辑完全通用。 - 如果不需要拿到所有匹配点的坐标,只是判断区域内是否存在目标色,可以在匹配到第一个符合要求的点时直接终止判断,不用遍历完所有像素。
- 三角形检测不是必须的,任何不规则形状的检测区都可以用同样的“先抓最小外接矩形+生成区域mask筛选”的逻辑实现,核心是尽可能减少无效抓图和无效计算。
内容的提问来源于stack exchange,提问作者PaperWarrior105
相关产品推荐
相关产品推荐

