13.1.13. A beállításszerkesztő#

Sok kameraalkalmazásnak szüksége van néhány olyan beállításra, amelyet egy nem programozó is módosíthat – egy küszöbérték, egy mód, egy Wi-Fi-jelszó – a szkript érintése nélkül. Az OpenMV Cam Settings Editor az IDE erre szolgáló eszköze: egy JSON-fájl írja le a vezérlőelemeket, a szerkesztő ezt a leírást űrlappá alakítja, a szkripted pedig a json.load() segítségével olvassa vissza a mentett értékeket. A fájl egyszerre a konfiguráció és a saját szerkesztőjének a definíciója, így ugyanaz a konfiguráció, amely tárolja az értékeket, rendezi el a szerkesztésükre szolgáló grafikus felületet is.

A Tools → OpenMV Cam Settings Editor almenü tartalmazza a három műveletét.

  • Az Open OpenMV Cam Settings Config File beolvassa a konfigurációt a csatlakoztatott kamera meghajtójáról, és megnyitja a szerkesztőben; mentéskor visszaírja a kamerára.

  • Az Open Config File ugyanezt teszi egy, a számítógépeden lévő .json fájllal, egy konfiguráció offline előkészítéséhez.

  • A Create Default Config egy kezdő konfigurációt ír a lemezre és megnyitja azt – egy példa, amely minden vezérlőtípust gyakorol, készen arra, hogy leegyszerűsítsd a saját alkalmazásod által igényelt beállításokra.

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

A beállításszerkesztő a megnyitott alapértelmezett konfigurációval – a JSON fájl vezérlőelemei űrlapként elrendezve (fülek, csúszkák, legördülő listák, jelölőnégyzetek), a Save és Cancel gombokkal az alján.#

13.1.13.1. Egy konfigurációs fájl felépítése#

Egy konfigurációs fájl egyetlen JSON objektum két kulccsal:

  • title (string, opcionális) – a szerkesztőablak címe. Alapértelmezés szerint OpenMV Cam Settings Editor.

  • controls (array, kötelező) – a vezérlőobjektumok listája, amelyeket a szerkesztő sorrendben, egy űrlap soraiként jelenít meg. Ez a teljes grafikus felület.

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

A controls minden egyes eleme egy vezérlő – egy szövegmező, egy szám, egy jelölőnégyzet, egy legördülő menü, egy csúszka, egy csoport, egy fülsáv, egy statikus felirat és így tovább. A type mezője választja ki a widgetet; az objektum többi része konfigurálja azt. A szerkesztő által nem felismert kulcsok érintetlenül maradnak a fájl mentésekor, így a vezérlők mellett saját metaadatokat is tárolhatsz a fájlban.

13.1.13.2. Minden vezérlő közös kulcsai#

Minden vezérlőobjektum elfogadja ezeket a kulcsokat, bármi is legyen a type értéke:

  • type (string, kötelező) – melyik widgetet kell felépíteni, pl. "slider" vagy "combobox". Hiányzó vagy fel nem ismert type esetén egy letiltott Unknown control helyőrző jelenik meg, ahelyett hogy az egész fájl meghiúsulna, így egy elgépelés csak egy vezérlőbe kerül, nem az egész űrlapba.

  • name (string) – egy azonosító a te használatodra. A szerkesztő soha nem olvassa; csak megőrzi. Adj minden vezérlőnek egyedi name értéket, és a szkripted ezzel találja meg az adott vezérlő mentett értékét.

  • label (string) – a vezérlő mellett vagy rajta megjelenő szöveg. A legtöbb vezérlő esetében ez formázott szöveg – HTML címkék és <a href> hivatkozások működnek.

  • tooltip (string) – a vezérlőhöz tartozó buboréksúgó szövege.

  • enabled (boolean, alapértelmezetten true) – állítsd false értékre, hogy a vezérlő kiszürkítve és csak olvashatóan jelenjen meg.

A tárolóvezérlők (group, tabs) a fejlécükhöz label helyett title mezőt használnak, a tabs pedig fülönként veszi fel a buboréksúgóját; a különbségek az egyes vezérlők oldalán szerepelnek.

13.1.13.3. Értékek mentése és olvasása#

Egy értéket hordozó vezérlő – egy jelölőnégyzet, egy csúszka, egy szövegmező – azt egy value kulcsban hordozza. Amikor a Mentés gombra kattintasz, a szerkesztő minden vezérlő aktuális value értékét helyben, ugyanabba a vezérlőobjektumba írja vissza, és újraírja a fájlt. A fájl megőrzi a szerkezetét: semmi sem mozdul el, csak a value kulcsok változnak. Nincs külön, lapos name-érték leképezés – az értékek a vezérlőkön belül élnek, pontosan ott, ahol definiálva vannak.

Ezért fontos az elrendezés a szkripted számára. A controls és tabs tömbök megtartják azt a sorrendet, amelyben felépítetted őket, így a fájl nem indexelhető név szerint, mint egy szótár – a config["controls"]["threshold"] nem működik. Ez a kis segédfüggvény áthidalja a szakadékot: add meg neki a nevek útvonalát egészen a kívánt értékig, és bejárja helyetted a fát.

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

Az útvonal minden lépése egy vezérlő name mezője vagy egy fül title mezője (egy fülnek nincs saját name mezője, bár hozzáadhatsz egyet, és az megőrződik). A fülsáv és bármely olyan group, amelynek nem adtál nevet, átlátszó – a find végiglép rajtuk –, így csak azokat a füleket és vezérlőket sorolod fel, amelyeket feliratoztál, közel egy beágyazott config[...][...] kereséshez. Egy elnevezett group saját lépés, így a find a jelölőnégyzetének értékét is visszaadhatja. Adj minden vezérlőnek egyedi name értéket, hogy egy útvonal soha ne legyen kétértelmű. Az Teljes példa a beágyazott bemutató-elrendezésből olvassa ki az értékeket.

Mivel a konfiguráció egyszerű JSON, a szkriptedben semmi sem függ a szerkesztőtől – a szerkesztő csak azt a fájlt írja, amelyet a szkripted amúgy is beolvas. Egy eszköz hordozhatja a konfigurációját és egy barátságos módot annak megváltoztatására, miközben a szkript az értékek egyszerű olvasója marad.

Egyetlen vezérlőtípus kényszeríti ki a bevitelét Mentéskor: egy mask vagy regex értékkel rendelkező lineedit megtagadja, hogy a szerkesztő mentsen, amíg a szövege érvénytelen vagy hiányos, és megnevezi a javítandó mezőket. Minden más vezérlő szerkesztés közben korlátozza a bevitelt – egy csúszka nem léphet ki a tartományából, egy spinbox a határaihoz igazodik –, így egy mentett fájl mindig érvényes.

13.1.13.4. Konfigurációs fájl referencia#

A vezérlőtípusok az alábbi oldalakon vannak dokumentálva, aszerint csoportosítva, hogy mit csinálnak.