13.1.13. L’éditeur de paramètres#

De nombreuses applications de caméra ont besoin d’une poignée de paramètres qu’un non-programmeur peut modifier – un seuil, un mode, un mot de passe Wi-Fi – sans toucher au script. L’OpenMV Cam Settings Editor est l’outil de l’IDE pour cela : un fichier JSON décrit les contrôles, l’éditeur transforme cette description en un formulaire, et votre script relit les valeurs enregistrées avec json.load(). Le fichier est à la fois la configuration et la définition de son propre éditeur, de sorte que la même config qui stocke les valeurs met aussi en page l’interface graphique servant à les modifier.

Le sous-menu Outils → OpenMV Cam Settings Editor contient ses trois actions.

  • Ouvrir le fichier de configuration OpenMV Cam Settings lit la config depuis le lecteur de la caméra connectée et l’ouvre dans l’éditeur ; l’enregistrement la réécrit sur la caméra.

  • Ouvrir un fichier de configuration fait de même pour un fichier .json sur votre ordinateur, afin de préparer une configuration hors ligne.

  • Create Default Config écrit une configuration de départ sur le disque et l’ouvre – un exemple qui met en œuvre tous les types de contrôle, prêt à être réduit aux paramètres dont votre propre application a besoin.

The OpenMV Cam Settings Editor showing the default demo configuration -- Camera, Processing, Network, and System tabs, with the Camera tab's exposure and gain sliders, resolution and pixel-format dropdowns, mirror and flip checkboxes, and a digital-zoom slider, above the Save and Cancel buttons

L’éditeur de paramètres avec la configuration par défaut ouverte – les contrôles du fichier JSON présentés sous forme de formulaire (onglets, curseurs, menus déroulants, cases à cocher), avec Save et Cancel en bas.#

13.1.13.1. Anatomie d’un fichier de configuration#

Un fichier de configuration est un unique objet JSON à deux clés :

  • title (string, facultatif) – le titre de la fenêtre de l’éditeur. Vaut par défaut OpenMV Cam Settings Editor.

  • controls (array, requis) – la liste des objets de contrôle que l’éditeur affiche, dans l’ordre, sous forme de lignes d’un formulaire. C’est là toute l’interface graphique.

{
  "title": "Camera Settings",
  "controls": [
    { "type": "slider", "name": "threshold", "label": "Threshold", "value": 50 },
    { "type": "checkbox", "name": "draw_overlays", "label": "Draw Overlays", "value": true }
  ]
}

Chaque entrée de controls est un contrôle – un champ de texte, un nombre, une case à cocher, une liste déroulante, un slider, un group, une barre d’onglets, un label statique, etc. Son type sélectionne le widget ; le reste de l’objet le configure. Toutes les clés que l’éditeur ne reconnaît pas sont laissées intactes lors de l’enregistrement du fichier, ce qui vous permet de conserver vos propres métadonnées dans le fichier aux côtés des contrôles.

13.1.13.2. Clés communes à tous les contrôles#

Chaque objet de contrôle accepte ces clés, quel que soit son type :

  • type (string, requis) – quel widget construire, p. ex. "slider" ou "combobox". Un type manquant ou non reconnu affiche un espace réservé Unknown control désactivé plutôt que de faire échouer le fichier entier ; une faute de frappe vous coûte donc un seul contrôle, et non le formulaire.

  • name (string) – un identifiant à votre usage. L’éditeur ne le lit jamais ; il se contente de le conserver. Donnez à chaque contrôle un name unique et votre script l’utilise pour retrouver la valeur enregistrée de ce contrôle.

  • label (string) – le texte affiché à côté du contrôle ou sur celui-ci. Pour la plupart des contrôles, il s’agit de texte enrichi – les balises HTML et les liens <a href> fonctionnent.

  • tooltip (string) – le texte au survol du contrôle.

  • enabled (boolean, par défaut true) – réglez sur false pour afficher le contrôle grisé et en lecture seule.

Les contrôles conteneurs (group, tabs) utilisent title au lieu de label pour leur en-tête, et tabs prend son tooltip par onglet ; les différences sont indiquées sur la page de chaque contrôle.

13.1.13.3. Enregistrer et lire les valeurs#

Un contrôle qui porte une valeur – une case à cocher, un slider, un champ de texte – la conserve dans une clé value. Lorsque vous cliquez sur Save, l’éditeur réécrit la value actuelle de chaque contrôle directement dans ce même objet de contrôle, sur place, et réécrit le fichier. Le fichier conserve sa structure : rien ne bouge, seules les clés value changent. Il n’existe pas de table plate distincte associant name à une valeur – les valeurs résident à l’intérieur des contrôles, là même où elles sont définies.

C’est pourquoi la disposition compte pour votre script. Les tableaux controls et tabs conservent l’ordre dans lequel vous les avez construits, si bien que le fichier ne peut pas être indexé par nom comme un dictionnaire – config["controls"]["threshold"] ne fonctionne pas. Ce petit assistant comble le fossé : donnez-lui le chemin de noms jusqu’à la valeur souhaitée, et il parcourt l’arbre pour vous.

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"]

Chaque étape du chemin est le name d’un contrôle, ou le title d’un onglet (un onglet n’a pas de name propre, bien que vous puissiez en ajouter un et il soit conservé). La barre d’onglets et tout group que vous n’avez pas nommé sont transparents – find les traverse – de sorte que vous ne listez que les onglets et les contrôles que vous avez étiquetés, proche d’une recherche config[...][...] imbriquée. Un group nommé est une étape à part entière, de sorte que find peut aussi renvoyer la valeur de sa case à cocher. Donnez à chaque contrôle un name unique afin qu’un chemin ne soit jamais ambigu. La page Exemple complet lit les valeurs de la disposition de démonstration imbriquée.

Comme la configuration est du simple JSON, rien dans votre script ne dépend de l’éditeur – l’éditeur se contente d’écrire le fichier que votre script lit déjà. Un appareil peut embarquer sa configuration et un moyen convivial de la modifier, tandis que le script reste un simple lecteur de valeurs.

Un type de contrôle impose sa saisie au moment du Save : un lineedit doté d’un mask ou d’une regex empêche l’éditeur d’enregistrer tant que son texte est invalide ou incomplet, et nomme les champs à corriger. Tout autre contrôle contraint la saisie au fil de l’édition – un slider ne peut pas sortir de sa plage, un spinbox se limite à ses bornes – de sorte qu’un fichier enregistré est toujours valide.

13.1.13.4. Référence du fichier de configuration#

Les types de contrôle sont documentés sur les pages ci-dessous, regroupés selon leur fonction.