13.1.13. ตัวแก้ไขการตั้งค่า#
แอปพลิเคชันกล้องจำนวนมากต้องการการตั้งค่าไม่กี่อย่างที่ผู้ที่ไม่ใช่โปรแกรมเมอร์สามารถเปลี่ยนได้ -- ค่าเกณฑ์ โหมด รหัสผ่าน Wi-Fi -- โดยไม่ต้องแตะสคริปต์ OpenMV Cam Settings Editor เป็นเครื่องมือของ IDE สำหรับสิ่งนั้น: ไฟล์ JSON อธิบายตัวควบคุม ตัวแก้ไขเปลี่ยนคำอธิบายนั้นเป็นฟอร์ม และสคริปต์ของคุณอ่านค่าที่บันทึกกลับด้วย json.load() ไฟล์เป็นทั้งการกำหนดค่าและคำจำกัดความของตัวแก้ไขของตัวเอง ดังนั้นการกำหนดค่าเดียวกันที่เก็บค่าก็จัดวาง GUI สำหรับแก้ไขค่าเหล่านั้นด้วย
เมนูย่อย Tools → OpenMV Cam Settings Editor มีการกระทำสามอย่าง
Open OpenMV Cam Settings Config File อ่านการกำหนดค่าจากไดรฟ์ของกล้องที่เชื่อมต่อและเปิดในตัวแก้ไข การบันทึกจะเขียนกลับไปยังกล้อง
Open Config File ทำเช่นเดียวกันสำหรับไฟล์
.jsonบนคอมพิวเตอร์ของคุณ สำหรับเตรียมการกำหนดค่าแบบออฟไลน์Create Default Config จะเขียนคอนฟิกเริ่มต้นลงในดิสก์และเปิดขึ้นมา -- เป็นตัวอย่างที่ลองใช้คอนโทรลทุกประเภท พร้อมให้ตัดทอนลงเหลือเฉพาะการตั้งค่าที่แอปพลิเคชันของคุณต้องการ

ตัวแก้ไขการตั้งค่าที่เปิดการกำหนดค่าเริ่มต้นไว้ -- ตัวควบคุมในไฟล์ JSON ถูกจัดวางเป็นแบบฟอร์ม (แท็บ แถบเลื่อน เมนูดรอปดาวน์ ช่องทำเครื่องหมาย) พร้อมปุ่ม Save และ Cancel ที่ด้านล่าง#
13.1.13.1. โครงสร้างของไฟล์คอนฟิก#
ไฟล์คอนฟิกคือออบเจกต์ JSON เดียวที่มีสองคีย์:
title (string, ไม่บังคับ) -- ชื่อหน้าต่างของเอดิเตอร์ ค่าเริ่มต้นคือ
OpenMV Cam Settings Editorcontrols (array, จำเป็น) -- รายการออบเจกต์คอนโทรลที่เอดิเตอร์เรนเดอร์ ตามลำดับ เป็นแถวของฟอร์ม นี่คือ GUI ทั้งหมด
{
"title": "Camera Settings",
"controls": [
{ "type": "slider", "name": "threshold", "label": "Threshold", "value": 50 },
{ "type": "checkbox", "name": "draw_overlays", "label": "Draw Overlays", "value": true }
]
}
แต่ละรายการใน controls คือคอนโทรลหนึ่งตัว -- ฟิลด์ข้อความ, ตัวเลข, เช็คบ็อกซ์, ดรอปดาวน์, slider, group, แถบแท็บ, label แบบคงที่ และอื่น ๆ ค่า type ของมันเลือกวิดเจ็ต ส่วนที่เหลือของออบเจกต์ใช้กำหนดค่าให้กับมัน คีย์ใด ๆ ที่เอดิเตอร์ไม่รู้จักจะไม่ถูกแตะต้องเมื่อบันทึกไฟล์ ดังนั้นคุณจึงสามารถเก็บเมทาดาทาของคุณเองไว้ในไฟล์ควบคู่กับคอนโทรลได้
13.1.13.3. การบันทึกและการอ่านค่า#
คอนโทรลที่เก็บค่า -- เช็คบ็อกซ์, slider, ฟิลด์ข้อความ -- จะเก็บค่าไว้ในคีย์ value เมื่อคุณคลิก Save เอดิเตอร์จะเขียนค่า value ปัจจุบันของแต่ละคอนโทรลกลับเข้าไปในออบเจกต์คอนโทรลเดิมนั้นโดยตรง ณ ตำแหน่งเดิม และเขียนไฟล์ใหม่ ไฟล์จะรักษาโครงสร้างเดิมไว้: ไม่มีอะไรเคลื่อนที่ มีเพียงคีย์ value เท่านั้นที่เปลี่ยน ไม่มีแมปแบบแบนราบแยกต่างหากที่จับคู่ name กับค่า -- ค่าต่าง ๆ อยู่ภายในคอนโทรล ตรงจุดที่มันถูกนิยามไว้
นั่นคือเหตุผลว่าทำไมเลย์เอาต์จึงสำคัญต่อสคริปต์ของคุณ อาร์เรย์ controls และ tabs จะรักษาลำดับที่คุณสร้างไว้ ดังนั้นไฟล์จึงไม่สามารถถูกดัชนีด้วยชื่อแบบดิกชันนารีได้ -- config["controls"]["threshold"] ใช้ไม่ได้ ตัวช่วยเล็ก ๆ นี้ช่วยเชื่อมช่องว่างนั้น: ให้มันด้วยพาธของชื่อลงไปจนถึงค่าที่คุณต้องการ แล้วมันจะเดินผ่านโครงสร้างต้นไม้ให้คุณ
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"]
แต่ละขั้นในเส้นทางคือ name ของตัวควบคุม หรือ title ของแท็บ (แท็บไม่มี name ของตัวเอง แม้ว่าคุณจะเพิ่มได้และมันจะถูกเก็บไว้ก็ตาม) แถบแท็บและ group ใด ๆ ที่คุณไม่ได้ตั้งชื่อจะโปร่งใส -- find จะไล่ผ่านมัน -- ดังนั้นคุณจึงระบุเฉพาะแท็บและตัวควบคุมที่คุณตั้งชื่อไว้เท่านั้น ซึ่งใกล้เคียงกับการค้นหาแบบซ้อน config[...][...] group ที่ตั้งชื่อแล้วเป็นขั้นตอนของตัวเอง ดังนั้น find จึงสามารถคืนค่าเช็กบ็อกซ์ของมันได้ด้วย กำหนด name ที่ไม่ซ้ำกันให้กับทุกตัวควบคุมเพื่อไม่ให้เส้นทางกำกวม ตัวอย่างฉบับเต็ม จะอ่านค่าออกจากเลย์เอาต์สาธิตแบบซ้อน
เนื่องจากคอนฟิกเป็น JSON ธรรมดา จึงไม่มีอะไรในสคริปต์ของคุณที่ขึ้นอยู่กับเอดิเตอร์ -- เอดิเตอร์เพียงแค่เขียนไฟล์ที่สคริปต์ของคุณอ่านอยู่แล้ว อุปกรณ์หนึ่งสามารถพกพาคอนฟิกของมันและวิธีที่ใช้งานง่ายในการเปลี่ยนแปลงมัน ในขณะที่สคริปต์ยังคงเป็นเพียงตัวอ่านค่าธรรมดา
มีคอนโทรลประเภทหนึ่งที่บังคับตรวจสอบอินพุตเมื่อ Save: lineedit ที่มี mask หรือ regex จะไม่ยอมให้เอดิเตอร์บันทึกในขณะที่ข้อความไม่ถูกต้องหรือไม่สมบูรณ์ และจะระบุชื่อฟิลด์ที่ต้องแก้ไข คอนโทรลอื่น ๆ ทุกตัวจะจำกัดอินพุตในขณะที่คุณแก้ไข -- slider ไม่สามารถออกนอกช่วงของมันได้ spinbox จะบีบให้อยู่ในขอบเขตของมัน -- ดังนั้นไฟล์ที่บันทึกจึงถูกต้องเสมอ
13.1.13.4. การอ้างอิงไฟล์คอนฟิก#
ประเภทของคอนโทรลถูกอธิบายไว้ในหน้าด้านล่าง โดยจัดกลุ่มตามสิ่งที่มันทำ