13.1.13. 设置编辑器#
许多相机应用需要一些非程序员也能更改的设置 -- 例如阈值、模式或 Wi-Fi 密码 -- 而无需改动脚本。OpenMV Cam Settings Editor 就是 IDE 为此提供的工具:一个 JSON 文件描述这些控件,编辑器将该描述转换成表单,你的脚本再用 json.load() 读回保存的值。该文件既是配置,也是其自身编辑器的定义,因此存储这些值的同一个配置文件也定义了编辑它们的 GUI 布局。
工具 → OpenMV Cam Settings Editor 子菜单包含其三个操作。
Open OpenMV Cam Settings Config File 会从已连接相机的驱动器读取配置并在编辑器中打开;保存时会将其写回相机。
Open Config File 对你计算机上的
.json文件执行相同操作,用于离线准备配置。Create Default Config 会将一个起始配置写入磁盘并将其打开 -- 这个示例展示了每一种控件类型,可随时精简为你自己的应用所需的设置。

打开默认配置的设置编辑器 -- JSON 文件的各项控件以表单形式布局(选项卡、滑块、下拉菜单、复选框),底部为 Save 和 Cancel。#
13.1.13.1. 配置文件剖析#
配置文件是一个包含两个键的单一 JSON 对象:
title(字符串,可选)-- 编辑器窗口的标题。默认为
OpenMV Cam Settings Editor。controls(数组,必需)-- 编辑器按顺序渲染为表单各行的控件对象列表。这就是整个 GUI。
{
"title": "Camera Settings",
"controls": [
{ "type": "slider", "name": "threshold", "label": "Threshold", "value": 50 },
{ "type": "checkbox", "name": "draw_overlays", "label": "Draw Overlays", "value": true }
]
}
controls 中的每一项都是一个控件 -- 文本字段、数字、复选框、下拉菜单、滑块、group、选项卡条、静态 label 等等。其 type 决定使用哪种控件;对象的其余部分对其进行配置。编辑器无法识别的任何键在保存文件时都会原样保留,因此你可以在文件中与控件一起保存你自己的元数据。
13.1.13.3. 保存与读取值#
保存值的控件 -- 复选框、滑块、文本字段 -- 会将该值保存在 value 键中。当你点击保存时,编辑器会将每个控件当前的 value 就地写回该控件对象本身,并重写文件。文件保持其结构:没有任何内容移动,只有 value 键发生变化。不存在从 name 到值的单独扁平映射 -- 值就存在于控件内部,就在它们被定义的地方。
这就是为什么布局对你的脚本很重要。controls 和 tabs 数组保持你构建它们时的顺序,因此无法像字典那样按名称对文件进行索引 -- config["controls"]["threshold"] 是行不通的。这个小型辅助函数弥补了这一差距:向它提供直达你所需值的名称路径,它就会为你遍历整棵树。
import json
def find(node, *path):
"""Return the control at a path of names; read its value with
["value"]. The tab strip and any unnamed group are transparent,
so you list only the tabs and controls you gave a name."""
for key in path:
match = _child(node, key)
if match is None:
raise KeyError(key)
node = match
return node
def _child(node, key):
for member in node.get("controls", []) + node.get("tabs", []):
if member.get("name") == key or member.get("title") == key:
return member
if "name" not in member and ("controls" in member or "tabs" in member):
match = _child(member, key) # see through an unnamed group / the tab strip
if match is not None:
return match
return None
with open("config.json") as file:
config = json.load(file)
threshold = find(config, "threshold")["value"]
路径中的每一步都是控件的 name,或选项卡的 title*(选项卡本身没有 *name,不过你可以添加一个,且会被保留)。选项卡条以及任何你未命名的 group 都是透明的 -- find 会穿过它们 -- 因此你只需列出选项卡和你已命名的控件,其形式接近于嵌套的 config[...][...] 查找。已命名的 group 是独立的一步,因此 find 也可以返回其复选框的值。为每个控件指定一个唯一的 name,这样路径就永远不会有歧义。完整示例 演示了从嵌套的示例布局中读取值。
由于配置是纯 JSON,你的脚本不依赖于编辑器的任何部分 -- 编辑器只是写入你的脚本本就会读取的文件。设备既可以携带其配置,又可以拥有一种友好的修改方式,而脚本始终只是一个单纯的值读取者。
有一种控件类型会在保存时强制校验其输入:带有 mask 或 regex 的 lineedit 在其文本无效或不完整时会拒绝编辑器保存,并指出需要修正的字段。其他所有控件都在你编辑时约束输入 -- 滑块无法超出其范围,spinbox 会被限制在其边界内 -- 因此保存的文件始终是有效的。
13.1.13.4. 配置文件参考#
各控件类型的说明见下面的页面,按其功能分组。