找色不是比 RGB:用 HSV + inRange 让游戏颜色识别抗干扰
图色脚本里"找色"和"找图"一样基础:判断屏幕上某个点、某块区域是不是某种颜色,从而知道游戏处在什么状态(红血/蓝血、可交互高亮、技能冷却灰)。传统做法是读一个像素的 RGB,跟目标值做相等或容差比较。
问题来了:同一块红按钮,亮度一变、或者被半透明遮罩盖一下,RGB 就全变了,脚本立刻误判。这篇讲如何用 OpenCV 的 cv2.cvtColor 转 HSV + cv2.inRange,把"找色"做成只认色相、容忍亮度变化的稳方案。
一、为什么直接比 RGB 会翻车
RGB 把颜色拆成"红多少、绿多少、蓝多少"三个亮度通道。亮度(光照、gamma、叠加层)会同时改变三个通道,所以同一个"红色",亮一点暗一点,RGB 数值能差出一大截。
(255,220,0) 可能变成 (230,180,30),纯 RGB 容差稍微设小就漏检,设大又容易把背景金黄色也误判成按钮。
解法:把"色相(Hue)"和"亮度(Lightness)"分开。人眼判断"这是不是红色",靠的是色相,而不是它亮不亮——HSV 正好把这两者拆开。
二、HSV 是什么,为什么适合找色
| 通道 | 含义 | OpenCV 取值 |
|---|---|---|
| H (Hue) | 色相,颜色种类(红/绿/蓝) | 0~179 |
| S (Saturation) | 饱和度,颜色纯不纯 | 0~255 |
| V (Value) | 明度,亮不亮 | 0~255 |
关键点:色相 H 几乎不受亮度影响。所以找色时,我们只对 H 给很窄的容差,对 S/V 给较宽的容差,就能在"亮度多变"的画面里稳定认出同一种颜色。
cv2.COLOR_BGR2HSV,写成 RGB2HSV 颜色会错乱。另外 OpenCV 的 H 范围是 0~179(不是 0~360),网上很多教程按 0~360 写,照搬会找错色。
三、核心函数:cv2.inRange
函数签名:
mask = cv2.inRange(src, lowerb, upperb)
| 参数 | 含义 |
|---|---|
src | HSV 图像(注意:必须先用 cvtColor 转好) |
lowerb | 下限数组,如 np.array([0,100,100]) |
upperb | 上限数组,如 np.array([10,255,255]) |
返回值:一张单通道二值掩膜——落在范围内的像素是 255(白),其余是 0(黑)。再用 cv2.countNonZero 数一下白点数量,就知道"这种颜色出现了多少"。
四、场景实战:在画面里找"红色按钮"
import cv2
import numpy as np
# 1) 读图(OpenCV 是 BGR!)
img = cv2.imread('game.png')
# 2) 转 HSV
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# 3) 定义"红色"范围:H 给窄区间(0~10),S/V 给宽容差
lower = np.array([0, 100, 100])
upper = np.array([10, 255, 255])
mask = cv2.inRange(hsv, lower, upper)
# 4) 统计命中像素数
count = cv2.countNonZero(mask)
print('红色像素数:', count)
if count > 200: # 阈值按按钮大小自定
print('画面里出现了红色按钮')
inRange 命中。亮度变化不再导致漏检,这正是图色脚本最需要的鲁棒性。
五、两个进阶技巧
- 红色跨 0 度处理:红色在 HSV 里分布在 H≈0 两侧(如 H=170~179 与 0~10)。用一段
inRange会漏掉另一半,正确做法是做两段掩膜再按位或:mask = mask1 | mask2。 - 收窄搜索区 + 形态学去噪:先用 ROI 裁出可能区域再 inRange,命中后用
cv2.morphologyEx开运算去掉零星噪点(见专栏 L10),避免把几个孤立杂色误判成"按钮"。
# 红色跨 0 度的正确写法
lower1 = np.array([0, 100, 100]); upper1 = np.array([10, 255, 255])
lower2 = np.array([170, 100, 100]); upper2 = np.array([179, 255, 255])
mask = cv2.inRange(hsv, lower1, upper1) | cv2.inRange(hsv, lower2, upper2)
本讲要点
- 找色别直接比 RGB,亮度一变就误判。
- 用
cv2.cvtColor(..., COLOR_BGR2HSV)转 HSV,只对 H 给窄容差、S/V 给宽容差。 cv2.inRange返回二值掩膜,配合cv2.countNonZero统计命中数量。- 记住 OpenCV 是 BGR、H 范围 0~179、红色要分两段。
下一篇我们用一张"升级路线图"把模板匹配、找色、预处理串起来,对比大漠插件与 OpenCV 在图色脚本里各自的适用边界。
