脚本流程#

脚本流程 visionflow::param::ScriptPipeline 是测量工具等工具中,帮助用户自定义解决项处理流程的中间类。 它允许用户定义预脚本和解决项,以及为解决项添加条件判断和依赖关系,并将这些定义转换为可执行的 Python 脚本。 用户也能够从已定义的处理流程中反向解析出各个信息。

脚本流程中数据表示规则#

为了将处理流程关系和脚本的表达逻辑统一在一个数据源中,我们对表达脚本做了一定的规约,限制了用户的表达形式。

预脚本#

脚本流程支持用户设置 预脚本。 你可以在预脚本中导入模块或定义一些全局变量以便后续使用。

visionflow::param::ScriptPipeline pipeline;
// 设置预脚本.
pipeline.set_pre_script("import external\n\nglobal_info = external.data");
import external

global_info = external.data

解决项#

脚本流程中支持用户自定义 解决项 作为处理流程中的基本单元。 解决项可以是一次函数调用,也可以是一个表达式。

  1. 函数调用:一个可调用的函数对象。

    • 例如: geo.find_linegeo.find_circle

    • 用户应清楚各个函数的输入输出参数信息。包括参数类型,取值范围等信息。

  2. 表达式:一个符合 Python 语法的表达式语句的变体。

    • 在表达式中,用户可以自行使用约定的符号 ${} 标识出表达式中的参数部分。

    • 例如: ${line}.length() + ${circle}.radius 这个表达式中有两项参数,分别是 linecircle

我们在执行时会根据解决方法中是否含有符号 $ 来区分两种不同的形式,并采取不同的参数填充形式。

同时 我们约定解决项的结果总是通过字典方式被存储在特定变量中 ,且后续使用时也通过特定变量直接读取数据。 因此默认会在预脚本之后定义字典 outs 用于存储解决项的结果。

pipeline.add_item("函数调用", "find_line");
pipeline.add_item("表达式", "${arg} + ${arg}");
pipeline.set_arg("表达式", "arg", "\"str\"");
outs = {}
outs["函数调用"] = find_line()
outs["表达式"] = "str" + "str"

可变参数和常量参数#

解决项参数支持两种形式:可变参数和常量参数。

  1. 可变参数:用户明确取值来自前面其他解决项结果或者结果的某个属性。

    • 解决项的参数值依赖于其他解决项的结果。

    • 我们约定;通过 $ 符号表示引用的解决项的对象变量。 这里的实现与表达式中的不同

    • 可以通过该符号重复引用同一个解决项。

  2. 常量参数:用户在参数设置阶段可以明确下来的参数。

    • 这些参数不依赖于其他解决项的结果,在执行阶段是完全确定的,不会发生改变的。

    • 我们约定:始终以直接对应的 Python 代码字符串表示。

pipeline.add_item("函数调用", "func");
// 添加常量参数.
pipeline.set_arg("函数调用", "arg", "0");

pipeline.add_item("表达式", "${arg} ** 2");
// 添加解决项可变参数.
pipeline.set_arg("表达式", "arg", "$.result", "函数调用");
outs = {}
outs["函数调用"] = func(
    arg=0,
)
if outs["函数调用"] is not None:
    outs["表达式"] = outs["函数调用"].result ** 2

条件判断和依赖关系#

上面那个例子最后自动添加了一个额外条件判断:即只有在 函数调用 的结果不为 None 时才执行 表达式 的计算。 我们认为,对于依赖其他解决项的解决项而言,被依赖对象不为空是必要条件。 但由于这一规则是普遍的,因此对于依赖的对象,总是会 自动判定依赖的解决项是否存在 。 仅在依赖的解决项存在的情况下才执行对应的解决方法。

同时我们也提供了 visionflow::param::ScriptPipeline::deps_on()visionflow::param::ScriptPipeline::used_by() 帮助用户判断自行判断依赖关系。

解决项支持设置条件判断,表明尽在另一项满足某种条件时才执行。 当然此时条件判断中的对象必须是一个 bool 或者可以被当作 bool 表达式计算的值。 条件判断与可变参数类似,通过 $ 符号引用解决项对象。

// 添加解决项.
pipeline.add_item("函数调用", "func");
pipeline.add_item("表达式", "${arg} ** 2");
// 添加解决项可变参数.
pipeline.set_arg("表达式", "arg", "$.result", "函数调用");
// 添加条件判断.
pipeline.set_condition(
    "表达式", "$.result > 0 and $.result < 100", "函数调用");
outs = {}
outs["函数调用"] = func()
if outs["函数调用"] is not None:
    if out["函数调用"].result > 0 and out["函数调用"].result < 100:
        outs["表达式"] = outs["函数调用"].result ** 2

脚本生成规则#

用户通过 visionflow::param::ScriptPipeline::to_script() 获取脚本流程对应的 Python 执行脚本。 解决项流程总是生成在一个函数内,函数签名则由用户定义。例如:

pipeline.set_pre_script("import external");
auto script = pipeline.to_script("pipeline(image, view=external.data)");
import external

def pipeline(image, view=external.data):
    outs = {}
    return outs

函数总是会将 outs 作为返回值,用户可以通过 outs 获取所有解决项的结果。