find_feature 操作示例
本文演示
find_feature系列函数的用法。 每个示例都是可直接放入src/tasks/onetime/并注册运行的完整任务文件, 风格与src/tasks/test/下的调试任务保持一致。
函数速览
| 函数 | 何时用 |
|---|---|
find_feature(feature_name, box, threshold) |
对当前帧做一次模板匹配;找到时返回 List[Box],未找到时返回空列表;feature_name 也可传入列表 |
find_one(feature_name, box, threshold) |
find_feature 的便捷封装,只返回置信度最高的那个匹配结果(Box 或 None);同样支持列表输入 |
feature_name 接受 FeatureList 枚举值、枚举值组成的列表,或直接使用字符串。
框架会根据当前分辨率自动选取 _2k / _4k 后缀变体(如有);如果传入列表,会对列表中的每个元素分别做这一步处理。
不传
box时的默认搜索区域模板图片(
feature_name对应的素材文件)的推荐制作方式: 直接对游戏进行截图,然后使用本软件 debug 模式左侧「模板」Tab 内的功能, 对截图的某区域进行标记——该功能会自动将裁剪后的模板图片保存到assets/images/, 并将该区域的坐标写入assets/coco_annotations.json,无需手动调整数据结构。⚠️ 若使用外部标注软件,需自行维护
coco_annotations.json中的数据结构,不推荐。当调用时省略
box参数,框架会自动从coco_annotations.json读取该模板的标注位置, 并将其换算成相对比例,再映射到实际程序窗口的对应区域进行扫描。这意味着:你不需要手动计算坐标,只需通过「模板」Tab 正确标记模板在截图中的位置, 框架就能自动把搜索范围限定在屏幕上的合理区域,避免全屏误匹配。
如果需要在默认搜索区域的基础上增加容差,可使用
vertical_variance/horizontal_variance参数指定 y / x 方向的相对比例偏差,无需显式传入box。如果你需要动态指定搜索范围(例如根据上一步操作的结果缩小区域), 才需要显式传入
box。
示例一:检测单个图标并点击
场景:等待关闭按钮(
×)出现后点击。
# src/tasks/onetime/ExampleFindFeature.py
from src.data.FeatureList import FeatureList as fL
from src.core.BaseEfTask import BaseEfTask
class ExampleFindFeature(BaseEfTask):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.name = "示例:find_feature 点击图标"
self.description = "检测关闭按钮并点击"
def run(self):
# find_feature 返回 List[Box],未找到时返回空列表
# 不传 box:框架自动从 coco_annotations.json 读取 fL.close 的标注位置限定搜索区域
result = self.find_feature(feature=fL.close)
if not result:
self.log_info("未找到关闭按钮")
return
# 取第一个匹配结果点击
self.click(result[0], after_sleep=0.5)
self.log_info("已点击关闭按钮")
示例二:动态指定搜索区域(box 参数)
场景:上一步操作后 ESC 图标可能出现在右上角的不固定位置, 需要动态限制搜索范围;或者你希望覆盖模板默认位置,手动控制扫描区域。
# src/tasks/onetime/ExampleFindFeatureBox.py
from src.data.FeatureList import FeatureList as fL
from src.core.BaseEfTask import BaseEfTask
class ExampleFindFeatureBox(BaseEfTask):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.name = "示例:find_feature + box"
self.description = "动态指定搜索区域的模板匹配"
def run(self):
# box_of_screen 的参数是 0.0~1.0 的相对比例
# 显式传入 box 会覆盖从 coco_annotations.json 读取的默认搜索位置
# 这里只在右上角 20%×15% 的区域搜索,比默认区域更宽松
top_right = self.box_of_screen(0.8, 0.0, 1.0, 0.15)
result = self.find_feature(
feature=fL.esc,
box=top_right,
threshold=0.8, # 相似度阈值,越高越严格
)
if result:
self.log_info(f"在右上角找到 ESC 图标,坐标:{result[0].x}, {result[0].y}")
self.click(result[0])
else:
self.log_info("右上角未找到 ESC 图标")
示例三:检测多个候选图标之一
场景:列表中可能出现两种不同图标(例如聊天图标的亮色/暗色版本), 任意找到一种即可点击。
# src/tasks/onetime/ExampleFindFeatureMultiple.py
from src.data.FeatureList import FeatureList as fL
from src.core.BaseEfTask import BaseEfTask
class ExampleFindFeatureMultiple(BaseEfTask):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.name = "示例:find_feature 多候选图标"
self.description = "在多个候选图标中找到任意一个并点击"
def run(self):
# 传入列表,框架会依次尝试每个 feature_name,返回所有命中结果
result = self.find_feature(
feature=[fL.chat_icon, fL.chat_icon_dark, fL.chat_icon_2],
box=self.box.right,
threshold=0.75,
)
if not result:
self.log_info("未找到聊天图标")
return
# find_feature 按置信度从高到低排列,result[0] 是最佳匹配
self.log_info(f"找到图标:{result[0].name},相似度:{result[0].confidence:.2f}")
self.click(result[0], after_sleep=0.5)
示例四:用 find_one 取置信度最高的结果
场景:屏幕上同时存在多个相似图标(例如列表里有若干个「关闭」按钮), 只需要操作相似度最高的那个时,使用
find_one更简洁。find_one在内部调用find_feature后取置信度最大的Box返回; 未找到时返回None,无需手动取result[0]。
# src/tasks/onetime/ExampleFindOne.py
from src.data.FeatureList import FeatureList as fL
from src.core.BaseEfTask import BaseEfTask
class ExampleFindOne(BaseEfTask):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.name = "示例:find_one"
self.description = "取置信度最高的图标并点击"
def run(self):
# find_one 直接返回 Box 或 None,不需要 result[0]
# 模板的默认搜索位置(由 coco_annotations.json 中的标注坐标决定)会被自动使用
best = self.find_one(feature=fL.close, threshold=0.8)
if not best:
self.log_info("未找到关闭按钮")
return
self.log_info(f"找到关闭按钮,置信度:{best.confidence:.2f}")
self.click(best, after_sleep=0.5)
示例五:轮询等待图标出现
场景:某个图标需要等待数秒后才出现(如战斗结束后的奖励图标),
find_feature不会自动等待,需要用循环轮询。
# src/tasks/onetime/ExampleFindFeatureWait.py
from src.data.FeatureList import FeatureList as fL
from src.core.BaseEfTask import BaseEfTask
class ExampleFindFeatureWait(BaseEfTask):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.name = "示例:find_feature 轮询等待"
self.description = "等待图标出现后再执行操作"
def run(self):
# 最多等待 30 秒(60 次 × 0.5 秒)
result = None
for _ in range(60):
result = self.find_feature(
feature=fL.claim_gift,
box=self.box.bottom_right,
threshold=0.8,
)
if result:
break
self.next_frame()
self.sleep(0.5)
if not result:
self.log_info("等待领取礼物图标超时,任务结束")
return
self.log_info("检测到领取礼物图标,执行点击")
self.click(result[0], after_sleep=1)
注册与运行
将上述任意示例文件保存到 src/tasks/onetime/ 后,在 src/config.py 中注册:
config["onetime_tasks"].append(
["src.tasks.onetime.ExampleFindFeature", "ExampleFindFeature"]
)
重启程序(python main_debug.py),在 GUI 任务列表中即可找到并运行。