fullseye

FullseyeEngine — 运行已设计管道的运行时

日本語 · English · 简体中文 · 繁體中文 · 한국어 · Deutsch

FullseyeEngineengine.py)是一个运行时,用于执行在 Fullseye Studio 中搭建好的图像算子管道——无论是从自己的代码还是从 CLI 调用。它相当于 MVTec 的 HDevEngine——用可视化工具设计流程,再原封不动地从应用程序中调用,这正是两段式流程中后半段的角色。

管道是由 (op, a, b) 组成的阶段列表。引擎可以从 Studio 的 JSON、--ops 字符串,或 Python 列表中加载,检查输入输出的 sort,调整每个阶段的旋钮,并对 numpy 帧执行(整体执行、执行到中途、或逐阶段执行)。它还会进行结构验证(未知算子、sort 不一致),这与 Studio 诊断面板中的检查完全相同。


最简用法

import fullseye, numpy as np

frame = np.clip(np.random.default_rng(0).random((64, 64)), 0, 1)   # gray H×W in [0,1]

eng = fullseye.FullseyeEngine.load("edge.json")     # or .from_ops("gaussian,sobel_amp,otsu")
print(eng.input_sort(), "->", eng.output_sort())    # image -> region
out = eng.run(frame)                                # numpy in, numpy out
steps = eng.run_stepwise(frame)                     # 各阶段的中间结果(列表)

FullseyeEnginediagnose_stages 均从 fullseye(以及 engine)模块公开。


四种加载方式

构建方式 签名 用途
JSON 文件 FullseyeEngine.load(path) 读取 Studio 的 Save pipeline 输出
ops 字符串 FullseyeEngine.from_ops(ops, a=0.5, b=0.5, name="pipeline") 逗号分隔字符串,例如 "gaussian,sobel_amp,otsu"(共用旋钮)
dict FullseyeEngine.from_dict(d, name="pipeline") 从含 {"stages": [...]} 的字典构建
阶段列表 FullseyeEngine(stages=None, name="pipeline") 直接传入 [("gaussian",0.4,0.5), "otsu"](仅给名称的阶段默认 a=b=0.5)

from_dict 缺少 "stages" 键会抛出 ValueErrorload 会读取 JSON 后传给 from_dict,并以文件名(不含扩展名)作为 name


方法一览

方法 返回值 说明
load(path) (classmethod) FullseyeEngine 从 Studio 的 JSON 加载
from_ops(ops, a=0.5, b=0.5, name=…) (classmethod) FullseyeEngine 从逗号分隔的 ops 字符串加载(共用旋钮)
from_dict(d, name=…) (classmethod) FullseyeEngine {"stages": [...]} 加载
describe() list[dict] 每个阶段的 {index, op, a, b, in_sort, out_sort, halcon, known}
op_names() list[str] 各阶段的算子名称
input_sort() str \| None 管道所期望的输入 sort(第一个已知 op 的 in_sort)
output_sort() str \| None 管道返回的输出 sort(最后一个已知 op 的 out_sort)
validate() list[dict] 结构性问题 {index, op, severity, message}[] 表示健全
is_runnable() bool 若所有阶段都能解析为已知算子(没有 error)则为 True
get_knobs(i) tuple 阶段 i 的旋钮 (a, b)
set_knobs(i, a=None, b=None) self 修改阶段 i 的旋钮(可链式调用)
run(image, upto=None, coerce=True) ndarray / float / dict 执行管道。upto 仅执行第 0..upto 阶段
run_stepwise(image, coerce=True) list 每个阶段执行后的中间结果(长度 = 阶段数)
run_file(in_path, out_path=None, upto=None) 原始结果 读取图像、执行,若为栅格结果则可选保存
to_dict() dict {"fullseye_pipeline": 1, "name", "stages"}
to_ops() str 逗号分隔的 ops 字符串
to_python() str 单个 Python 函数的源代码(与 Studio 的 Export 相同)
save(path) None to_dict() 保存为 JSON
len(eng) int 阶段数

diagnose_stages(stages) 是一个不需要创建引擎即可验证阶段列表的函数,是 validate() 的实际实现。未知算子的 severity"error",相邻阶段 sort 不一致时为 "warning"

关于 sort(类型)

每个算子都声明输入/输出的 sortimage(gray H×W float64 [0,1]) / region(二值 {0,1}) / color(H×W×3 RGB) / feature(标量 float) / contour(XLD dict) / volume(3D 堆栈) / any(可与任何类型连接)。当相邻阶段的 out→in 不匹配时,validate() 会给出警告(any 始终视为匹配)。


Python 使用示例

先验证再执行

import fullseye

eng = fullseye.FullseyeEngine.from_ops("gaussian,sobel_amp,otsu")
problems = eng.validate()
if not eng.is_runnable():                      # 存在 error(未知 op)时停止
    raise SystemExit(problems)
result = eng.run(frame)                         # 返回 region(二值)

执行到中途 / 逐阶段执行

mid = eng.run(frame, upto=1)                    # 执行到第 0..1 阶段(gaussian → sobel_amp)
for i, s in enumerate(eng.run_stepwise(frame)):  # 各阶段的中间结果
    print(i, eng.stages[i][0], getattr(s, "shape", s))

调整旋钮后重新执行

eng.set_knobs(0, a=0.3).set_knobs(2, a=0.4)     # 可链式调用
out = eng.run(frame)

文件输入输出(在代码内完成)

eng = fullseye.FullseyeEngine.load("edge.json")
result = eng.run_file("in.png", "out.png")      # 读取 → 执行 → 若为栅格则保存

保存 / 导出

eng.save("edge.json")                           # 保存为 JSON(可在 Studio 中重新打开)
print(eng.to_ops())                             # "gaussian,sobel_amp,otsu"
print(eng.to_python())                          # 输出为单个 Python 函数

to_python() 的输出示例:

import fullseye, numpy as np

def pipeline(frame):
    return fullseye.run_pipeline(frame, [
        ('gaussian', 0.500, 0.500),
        ('sobel_amp', 0.500, 0.500),
        ('otsu', 0.500, 0.500),
    ])

CLI: imgevolve.py run

可以从 CLI 执行已保存的管道(JSON 或 ops 字符串)。其内部使用 FullseyeEngine

py -3.11 imgevolve.py run <pipeline.json|ops> [inp] [--out PATH]
                          [--upto N] [--stepwise] [--describe] [--to-python] [--a A] [--b B]
参数 / 选项 含义
pipeline 管道 .json(Studio 的 Save pipeline)或逗号分隔的 ops 字符串
inp 输入图像(省略时仅可执行 --describe / --to-python)
--out PATH 结果的保存路径(仅保存栅格结果)
--upto N 执行到第 0..N 阶段
--stepwise 报告每个阶段的结果,若指定 --out 则保存为 PATH_00PATH_01、…
--describe 显示管道的输入输出、各阶段及验证结果(未提供输入图像时仅显示后结束)
--to-python 将管道输出为 Python 函数
--a / --b 以 ops 字符串构建时的共用旋钮(默认 0.5)

示例:

# 仅确认结构(无需图像)
py -3.11 imgevolve.py run edge.json --describe
#   pipeline 'edge': image -> region
#     0. gaussian      a=0.50 b=0.50   [image -> image]
#     1. sobel_amp     a=0.50 b=0.50   [image -> image]
#     2. otsu          a=0.50 b=0.50   [image -> region]

py -3.11 imgevolve.py run edge.json in.png --out result.png       # 执行并保存
py -3.11 imgevolve.py run edge.json in.png --stepwise --out step.png  # 保存每个阶段
py -3.11 imgevolve.py run "gaussian,sobel_amp,otsu" --to-python   # ops 字符串 → Python

包含未知算子(error)的管道可以用 --describe 显示,但执行时会停止并报告问题。


从其他项目调用(onocollo / evis / hillco 等)

由于 fullseye 的输入输出完全基于 numpy 数组,可以直接嵌入机器人/视觉管道中。这样就能实现 设计在 Studio、执行在各项目 的分工。

import fullseye

# 在启动时加载一次即可(轻量。仅保存 ops 的解析结果和旋钮)
PIPELINE = fullseye.FullseyeEngine.load("assets/segment.json")

def perceive(frame):                            # frame: 自行准备的 float64 gray [0,1]
    seg = PIPELINE.run(frame)                   # 输入 numpy,输出 numpy(不需要磁盘)
    return seg

要点:

感知栈(stereo / terrain / flow / detect / registration / pose)同样基于 numpy 运行(如 fullseye.disparity_map)。使用示例请参见 examples/(../examples/README.md)以及 PERCEPTION.md / PERCEPTION_REALDATA.md


相关文档