find_feature 操作示例

返回:文档索引 / README

本文演示 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 的便捷封装,只返回置信度最高的那个匹配结果(BoxNone);同样支持列表输入

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 任务列表中即可找到并运行。

在 GitHub 查看源文件 ↗ · 页面生成时间: 2026年8月10日