13.1.13. Editor pengaturan#

Banyak aplikasi kamera membutuhkan beberapa pengaturan yang dapat diubah oleh non-pemrogram -- sebuah ambang, sebuah mode, kata sandi Wi-Fi -- tanpa menyentuh skrip. OpenMV Cam Settings Editor adalah alat IDE untuk itu: sebuah berkas JSON mendeskripsikan kontrolnya, editor mengubah deskripsi itu menjadi sebuah formulir, dan skrip Anda membaca kembali nilai tersimpan dengan json.load(). Berkas ini sekaligus merupakan konfigurasi dan definisi editornya sendiri, sehingga konfigurasi yang sama yang menyimpan nilai juga menata GUI untuk menyuntingnya.

Submenu Tools → OpenMV Cam Settings Editor memuat tiga aksinya.

  • Open OpenMV Cam Settings Config File membaca konfigurasi dari drive kamera yang terhubung dan membukanya di editor; menyimpan akan menuliskannya kembali ke kamera.

  • Open Config File melakukan hal yang sama untuk berkas .json di komputer Anda, untuk menyiapkan konfigurasi secara luring.

  • Create Default Config menulis konfigurasi awal ke disk dan membukanya -- sebuah contoh yang menguji setiap jenis kontrol, siap dipangkas menjadi pengaturan yang dibutuhkan aplikasi Anda sendiri.

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

Editor pengaturan dengan konfigurasi bawaan terbuka -- kontrol dari berkas JSON ditata sebagai formulir (tab, slider, dropdown, kotak centang), dengan Save dan Cancel di bagian bawah.#

13.1.13.1. Anatomi file konfigurasi#

File konfigurasi adalah satu objek JSON dengan dua kunci:

  • title (string, opsional) -- judul jendela editor. Default-nya OpenMV Cam Settings Editor.

  • controls (array, wajib) -- daftar objek kontrol yang dirender editor, secara berurutan, sebagai baris-baris formulir. Ini adalah keseluruhan GUI.

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

Setiap entri dalam controls adalah satu kontrol -- kolom teks, angka, checkbox, dropdown, slider, group, strip tab, label statis, dan seterusnya. type-nya memilih widget; sisa objek mengonfigurasinya. Kunci apa pun yang tidak dikenali editor dibiarkan tak tersentuh saat file disimpan, sehingga Anda dapat menyimpan metadata Anda sendiri dalam file bersama kontrol.

13.1.13.2. Kunci yang dimiliki setiap kontrol#

Setiap objek kontrol menerima kunci-kunci ini, apa pun type-nya:

  • type (string, wajib) -- widget mana yang akan dibangun, mis. "slider" atau "combobox". type yang hilang atau tidak dikenali akan merender placeholder Unknown control yang dinonaktifkan alih-alih menggagalkan seluruh file, sehingga salah ketik hanya merugikan satu kontrol, bukan formulir.

  • name (string) -- pengidentifikasi untuk penggunaan Anda. Editor tidak pernah membacanya; ia hanya mempertahankannya. Beri setiap kontrol name yang unik dan skrip Anda menggunakannya untuk menemukan nilai tersimpan kontrol tersebut.

  • label (string) -- teks yang ditampilkan di samping atau pada kontrol. Untuk sebagian besar kontrol ini adalah teks kaya -- tag HTML dan tautan <a href> berfungsi.

  • tooltip (string) -- teks hover untuk kontrol.

  • enabled (boolean, default true) -- atur ke false untuk menampilkan kontrol dalam keadaan redup dan hanya-baca.

Kontrol kontainer (group, tabs) menggunakan title alih-alih label untuk judulnya, dan tabs mengambil tooltip-nya per tab; perbedaannya dicatat pada halaman masing-masing kontrol.

13.1.13.3. Menyimpan dan membaca nilai#

Kontrol yang menyimpan nilai -- checkbox, slider, kolom teks -- membawanya dalam kunci value. Saat Anda mengeklik Save, editor menulis value setiap kontrol saat ini langsung kembali ke objek kontrol yang sama, di tempat, dan menulis ulang file. File mempertahankan strukturnya: tidak ada yang berpindah, hanya kunci value yang berubah. Tidak ada peta datar terpisah dari name ke nilai -- nilai-nilai berada di dalam kontrol, tepat di tempat mereka didefinisikan.

Itulah mengapa tata letak penting bagi skrip Anda. Array controls dan tabs mempertahankan urutan saat Anda membangunnya, sehingga file tidak dapat diindeks berdasarkan nama seperti kamus -- config["controls"]["threshold"] tidak berfungsi. Bantuan kecil ini menjembatani celah tersebut: berikan jalur nama hingga ke nilai yang Anda inginkan, dan ia akan menelusuri pohon untuk Anda.

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

Setiap langkah dalam jalur adalah name sebuah kontrol, atau title sebuah tab (tab tidak mengambil name miliknya sendiri, meskipun Anda boleh menambahkan satu dan itu dipertahankan). Strip tab dan group apa pun yang tidak Anda beri nama bersifat transparan -- find menelusurinya -- sehingga Anda hanya mencantumkan tab dan kontrol yang Anda beri label, mendekati pencarian config[...][...] bersarang. Sebuah group yang bernama merupakan satu langkah tersendiri, sehingga find juga dapat mengembalikan nilai checkbox-nya. Beri setiap kontrol name yang unik agar sebuah jalur tidak pernah ambigu. Contoh lengkap membaca nilai dari tata letak demo bersarang.

Karena konfigurasi adalah JSON biasa, tidak ada apa pun dalam skrip Anda yang bergantung pada editor -- editor hanya menulis file yang sudah dibaca skrip Anda. Sebuah perangkat dapat membawa konfigurasinya dan cara yang ramah untuk mengubahnya sementara skrip tetap menjadi pembaca nilai biasa.

Satu jenis kontrol memberlakukan masukannya saat Save: sebuah lineedit dengan mask atau regex menolak membiarkan editor menyimpan selama teksnya tidak valid atau tidak lengkap, dan menyebutkan kolom yang harus diperbaiki. Setiap kontrol lain membatasi masukan saat Anda mengedit -- slider tidak dapat keluar dari rentangnya, spinbox membatasi ke batasnya -- sehingga file yang disimpan selalu valid.

13.1.13.4. Referensi file konfigurasi#

Jenis-jenis kontrol didokumentasikan pada halaman di bawah ini, dikelompokkan berdasarkan fungsinya.