13.1.13. De instellingeneditor#
Veel cameratoepassingen hebben een handvol instellingen nodig die een niet-programmeur kan wijzigen – een drempelwaarde, een modus, een wifi-wachtwoord – zonder het script aan te raken. De OpenMV Cam Settings Editor is het gereedschap van de IDE daarvoor: een JSON-bestand beschrijft de besturingselementen, de editor zet die beschrijving om in een formulier, en jouw script leest de opgeslagen waarden terug met json.load(). Het bestand is zowel de configuratie als de definitie van zijn eigen editor, zodat dezelfde configuratie die de waarden opslaat ook de GUI voor het bewerken ervan indeelt.
Het submenu Tools → OpenMV Cam Settings Editor bevat de drie acties ervan.
Open OpenMV Cam Settings Config File leest de configuratie van de schijf van de verbonden camera en opent deze in de editor; opslaan schrijft deze terug naar de camera.
Open Config File doet hetzelfde voor een
.json-bestand op je computer, om een configuratie offline voor te bereiden.Create Default Config schrijft een startconfiguratie naar schijf en opent die – een voorbeeld dat elk besturingselementtype demonstreert, klaar om te verkleinen tot de instellingen die je eigen toepassing nodig heeft.

De instellingeneditor met de standaardconfiguratie geopend – de bedieningselementen van het JSON-bestand weergegeven als een formulier (tabbladen, schuifregelaars, vervolgkeuzelijsten, selectievakjes), met Save en Cancel onderaan.#
13.1.13.1. Anatomie van een configuratiebestand#
Een configuratiebestand is een enkel JSON-object met twee sleutels:
title (string, optioneel) – de titel van het editorvenster. Standaard
OpenMV Cam Settings Editor.controls (array, vereist) – de lijst van besturingselement-objecten die de editor op volgorde weergeeft, als rijen van een formulier. Dit is de volledige GUI.
{
"title": "Camera Settings",
"controls": [
{ "type": "slider", "name": "threshold", "label": "Threshold", "value": 50 },
{ "type": "checkbox", "name": "draw_overlays", "label": "Draw Overlays", "value": true }
]
}
Elk item in controls is één besturingselement – een tekstveld, een getal, een selectievakje, een vervolgkeuzelijst, een schuifregelaar, een group, een tabbladstrook, een statisch label, enzovoort. De type ervan selecteert de widget; de rest van het object configureert die. Sleutels die de editor niet herkent, blijven ongewijzigd wanneer het bestand wordt opgeslagen, dus je kunt je eigen metadata in het bestand naast de besturingselementen bewaren.
13.1.13.3. Waarden opslaan en lezen#
Een besturingselement dat een waarde vasthoudt – een selectievakje, een schuifregelaar, een tekstveld – draagt die in een value-sleutel. Wanneer je op Save klikt, schrijft de editor de huidige value van elk besturingselement rechtstreeks terug in datzelfde besturingselement-object, ter plekke, en herschrijft het bestand. Het bestand behoudt zijn structuur: er verschuift niets, alleen de value-sleutels veranderen. Er is geen aparte platte toewijzing van name naar waarde – de waarden bevinden zich binnen de besturingselementen, precies waar ze zijn gedefinieerd.
Daarom is de indeling van belang voor je script. De controls- en tabs-arrays behouden de volgorde waarin je ze hebt opgebouwd, dus het bestand kan niet op naam worden geïndexeerd zoals een dictionary – config["controls"]["threshold"] werkt niet. Deze kleine helper overbrugt het gat: geef hem het pad van namen tot de waarde die je wilt, en hij loopt de boom voor je af.
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"]
Elke stap in het pad is de name van een besturingselement, of de title van een tabblad (een tabblad heeft geen eigen name, hoewel u er een kunt toevoegen en die wordt bewaard). De tabbalk en elke group die u geen naam hebt gegeven zijn transparant – find doorloopt ze – dus u somt alleen de tabbladen en de besturingselementen op die u hebt gelabeld, wat dicht in de buurt komt van een geneste config[...][...] -opzoeking. Een benoemde group is een eigen stap, dus find kan ook de waarde van het selectievakje ervan retourneren. Geef elk besturingselement een unieke name zodat een pad nooit dubbelzinnig is. Het Volledig voorbeeld leest waarden uit de geneste demo-lay-out.
Omdat de configuratie gewone JSON is, hangt niets in je script af van de editor – de editor schrijft alleen het bestand dat je script al leest. Een apparaat kan zijn configuratie en een vriendelijke manier om die te wijzigen bij zich dragen, terwijl het script een eenvoudige lezer van waarden blijft.
Eén besturingselementtype dwingt zijn invoer af bij Save: een lineedit met een mask of regex weigert de editor te laten opslaan zolang de tekst ongeldig of onvolledig is, en noemt de te corrigeren velden. Elk ander besturingselement beperkt de invoer terwijl je bewerkt – een slider kan zijn bereik niet verlaten, een spinbox begrenst tot zijn grenzen – dus een opgeslagen bestand is altijd geldig.
13.1.13.4. Referentie van het configuratiebestand#
De besturingselementtypen zijn gedocumenteerd op de onderstaande pagina’s, gegroepeerd naar wat ze doen.