13.1.13. 설정 편집기#

많은 카메라 애플리케이션에는 프로그래머가 아닌 사람이 스크립트를 건드리지 않고 변경할 수 있는 몇 가지 설정 – 임계값, 모드, Wi-Fi 비밀번호 – 이 필요합니다. OpenMV Cam Settings Editor가 바로 그것을 위한 IDE의 도구입니다. JSON 파일이 컨트롤을 기술하고, 편집기가 그 기술을 양식으로 바꾸며, 스크립트는 json.load()로 저장된 값을 다시 읽습니다. 이 파일은 구성이면서 동시에 자체 편집기의 정의이기도 하므로, 값을 저장하는 바로 그 구성이 그 값을 편집하기 위한 GUI 레이아웃도 구성합니다.

도구 → OpenMV Cam Settings Editor 하위 메뉴에 그 세 가지 동작이 들어 있습니다.

  • OpenMV Cam 설정 구성 파일 열기는 연결된 카메라의 드라이브에서 구성을 읽어 편집기에서 엽니다. 저장하면 카메라에 다시 기록됩니다.

  • 구성 파일 열기는 오프라인에서 구성을 준비하기 위해, 컴퓨터에 있는 .json 파일에 대해 같은 작업을 수행합니다.

  • Create Default Config 는 시작용 설정을 디스크에 작성하고 엽니다 – 모든 컨트롤 유형을 시연하는 예제로, 자신의 애플리케이션에 필요한 설정만 남기고 줄일 수 있도록 준비되어 있습니다.

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

기본 구성이 열려 있는 설정 편집기 – JSON 파일의 컨트롤이 양식 형태(탭, 슬라이더, 드롭다운, 체크박스)로 배치되어 있으며, 하단에 Save 및 Cancel 버튼이 있습니다.#

13.1.13.1. 설정 파일의 구조#

설정 파일은 두 개의 키를 가진 단일 JSON 객체입니다:

  • title (문자열, 선택) – 편집기 창의 제목입니다. 기본값은 OpenMV Cam Settings Editor 입니다.

  • controls (배열, 필수) – 편집기가 폼의 행으로 순서대로 렌더링하는 컨트롤 객체 목록입니다. 이것이 GUI 전체입니다.

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

controls 의 각 항목은 하나의 컨트롤입니다 – 텍스트 필드, 숫자, 체크박스, 드롭다운, 슬라이더, 그룹, 탭 막대, 정적 레이블 등입니다. 그 type 이 위젯을 선택하고, 객체의 나머지가 위젯을 설정합니다. 편집기가 인식하지 못하는 키는 파일을 저장할 때 그대로 유지되므로, 컨트롤과 함께 파일에 자신만의 메타데이터를 보관할 수 있습니다.

13.1.13.2. 모든 컨트롤이 공유하는 키#

모든 컨트롤 객체는 type 이 무엇이든 다음 키를 받습니다:

  • type (문자열, 필수) – 만들 위젯을 지정합니다, 예: "slider" 또는 "combobox". type 이 없거나 인식되지 않으면 파일 전체를 실패시키는 대신 비활성화된 Unknown control 자리표시자를 렌더링하므로, 오타가 있으면 폼 전체가 아니라 컨트롤 하나만 잃게 됩니다.

  • name (문자열) – 사용자 용도의 식별자입니다. 편집기는 이를 읽지 않고 보존하기만 합니다. 각 컨트롤에 고유한 name 을 부여하면 스크립트가 이를 사용해 해당 컨트롤의 저장된 값을 찾습니다.

  • label (문자열) – 컨트롤 옆이나 위에 표시되는 텍스트입니다. 대부분의 컨트롤에서 이것은 리치 텍스트입니다 – HTML 태그와 <a href> 링크가 동작합니다.

  • tooltip (문자열) – 컨트롤의 마우스 오버 텍스트입니다.

  • enabled (불리언, 기본값 true) – false 로 설정하면 컨트롤을 회색으로 표시하고 읽기 전용으로 만듭니다.

컨테이너 컨트롤(group, tabs)은 제목에 label 대신 title 을 사용하며, tabs 는 탭마다 툴팁을 받습니다. 차이점은 각 컨트롤의 페이지에 기재되어 있습니다.

13.1.13.3. 값 저장 및 읽기#

값을 가지는 컨트롤 – 체크박스, 슬라이더, 텍스트 필드 – 은 그 값을 value 키에 담습니다. Save 를 클릭하면 편집기는 각 컨트롤의 현재 value 를 동일한 컨트롤 객체 안 제자리에 그대로 기록하고 파일을 다시 씁니다. 파일은 구조를 유지합니다: 아무것도 이동하지 않고 value 키만 바뀝니다. name 을 값에 대응시키는 별도의 평면 맵은 없습니다 – 값은 컨트롤이 정의된 바로 그 안에 존재합니다.

바로 이 때문에 레이아웃이 스크립트에 중요합니다. controlstabs 배열은 만든 순서를 유지하므로 파일을 딕셔너리처럼 이름으로 인덱싱할 수 없습니다 – 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 시 입력을 강제합니다: mask 또는 regex 가 있는 lineedit 은 텍스트가 유효하지 않거나 미완성인 동안 편집기가 저장하지 못하게 막고, 수정해야 할 필드를 지목합니다. 다른 모든 컨트롤은 편집하는 동안 입력을 제약합니다 – 슬라이더는 범위를 벗어날 수 없고, 스핀박스는 경계 값으로 제한됩니다 – 그러므로 저장된 파일은 항상 유효합니다.

13.1.13.4. 설정 파일 레퍼런스#

컨트롤 유형은 하는 일에 따라 묶여 아래 페이지들에 문서화되어 있습니다.