13.1.13. El editor de ajustes#
Muchas aplicaciones de cámara necesitan un puñado de ajustes que una persona no programadora pueda cambiar – un umbral, un modo, una contraseña de Wi-Fi – sin tocar el script. El OpenMV Cam Settings Editor es la herramienta del IDE para ello: un archivo JSON describe los controles, el editor convierte esa descripción en un formulario, y tu script vuelve a leer los valores guardados con json.load(). El archivo es a la vez la configuración y la definición de su propio editor, de modo que la misma configuración que almacena los valores también dispone la interfaz gráfica para editarlos.
El submenú Tools → OpenMV Cam Settings Editor contiene sus tres acciones.
Open OpenMV Cam Settings Config File lee la configuración desde la unidad de la cámara conectada y la abre en el editor; al guardar se vuelve a escribir en la cámara.
Open Config File hace lo mismo para un archivo
.jsonde tu ordenador, para preparar una configuración sin conexión.Create Default Config escribe una configuración inicial en disco y la abre – un ejemplo que ejercita todos los tipos de control, listo para reducirse a los ajustes que necesita tu propia aplicación.

El editor de configuración con la configuración predeterminada abierta – los controles del archivo JSON dispuestos como un formulario (pestañas, deslizadores, menús desplegables, casillas de verificación), con Save y Cancel en la parte inferior.#
13.1.13.1. Anatomía de un archivo de configuración#
Un archivo de configuración es un único objeto JSON con dos claves:
title (cadena, opcional) – el título de la ventana del editor. El valor predeterminado es
OpenMV Cam Settings Editor.controls (arreglo, obligatorio) – la lista de objetos de control que el editor representa, en orden, como filas de un formulario. Esta es toda la interfaz gráfica.
{
"title": "Camera Settings",
"controls": [
{ "type": "slider", "name": "threshold", "label": "Threshold", "value": 50 },
{ "type": "checkbox", "name": "draw_overlays", "label": "Draw Overlays", "value": true }
]
}
Cada entrada de controls es un control – un campo de texto, un número, una casilla de verificación, un menú desplegable, un deslizador, un grupo, una tira de pestañas, una etiqueta estática, etc. Su type selecciona el widget; el resto del objeto lo configura. Cualquier clave que el editor no reconozca se deja intacta cuando se guarda el archivo, de modo que puedes conservar tus propios metadatos en el archivo junto a los controles.
13.1.13.3. Guardar y leer valores#
Un control que contiene un valor – una casilla de verificación, un deslizador, un campo de texto – lo lleva en una clave value. Cuando haces clic en Guardar, el editor escribe el value actual de cada control de vuelta en ese mismo objeto de control, en su sitio, y reescribe el archivo. El archivo mantiene su estructura: nada se mueve, solo cambian las claves value. No hay un mapa plano aparte de name a valor – los valores viven dentro de los controles, justo donde se definen.
Por eso la disposición le importa a tu script. Los arreglos controls y tabs mantienen el orden en que los construiste, de modo que el archivo no puede indexarse por nombre como un diccionario – config["controls"]["threshold"] no funciona. Esta pequeña función auxiliar salva esa distancia: dale la ruta de nombres hasta el valor que quieres, y recorre el árbol por ti.
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"]
Cada paso de la ruta es el name de un control o el title de una pestaña (una pestaña no tiene un name propio, aunque puedes añadir uno y se conserva). La tira de pestañas y cualquier group al que no diste nombre son transparentes – find los recorre – de modo que enumeras solo las pestañas y los controles que etiquetaste, muy cerca de una consulta anidada config[...][...]. Un group con nombre es un paso propio, por lo que find también puede devolver el valor de su casilla de verificación. Asigna a cada control un name único para que una ruta nunca sea ambigua. El Ejemplo completo lee valores de la disposición de demostración anidada.
Como la configuración es JSON simple, nada en tu script depende del editor – el editor solo escribe el archivo que tu script ya lee. Un dispositivo puede llevar su configuración y una forma cómoda de cambiarla mientras el script sigue siendo un simple lector de valores.
Un tipo de control impone su entrada al guardar: un lineedit con una mask o regex impide que el editor guarde mientras su texto sea inválido o incompleto, y nombra los campos que hay que corregir. Todos los demás controles restringen la entrada mientras editas – un deslizador no puede salir de su rango, un spinbox se ajusta a sus límites – de modo que un archivo guardado siempre es válido.
13.1.13.4. Referencia del archivo de configuración#
Los tipos de control se documentan en las páginas siguientes, agrupados según lo que hacen.