Files
duck-preview/notes/03-mvp-summary.md
bartool cdeac53555 feat: Add Camera Settings dialog for UVC controls and Qt parameters
- Implemented CameraSettingsDialog to manage UVC and Qt camera controls.
- Integrated UVC parameter sliders and auto controls for brightness, contrast, saturation, hue, sharpness, gamma, white balance, backlight compensation, and exposure.
- Added functionality to change white balance and exposure settings via Qt controls.
- Updated MainWindow to open CameraSettingsDialog and manage UVC controller lifecycle.
- Enhanced AppMenuBar to include a Camera Settings option.
- Created tests for UVC controller abstraction layer and parameter info.
- Documented camera specifications and supported features in new markdown files.
2026-05-13 19:19:39 +02:00

6.6 KiB
Raw Permalink Blame History

Goal

Zbudować aplikację do podglądu kamery w czasie rzeczywistym (PySide6) z telemetrią, overlayami i systemem logowania do pliku — docelowo na Mac Mini z kamerą ELP.


Constraints & Preferences

  • Python 3.12.10, venv w .venv-win
  • Dev: Windows 11
  • Target: Mac Mini Intel i7, macOS Ventura, kamera ELP USB
  • PySide6 6.11.0, psutil, pytest, ruff
  • QVideoWidget porzucony — na Windows zasłania wszystkie child/sibling widgets przez natywny HWND D3D
  • Logi:
    • logs/ w katalogu projektu
    • nowy plik z timestamp per sesja
    • max 20 plików
  • CSV telemetrii:
    • co 5 sekund
    • flush po każdym wierszu
  • CPU:
    • pokazywać oba:
      • sys %
      • per-core % (jak Task Manager)
  • Zmiana formatu kamery przez stop+start
    • nie setCameraFormat na żywej kamerze

Progress

Done

Faza 07 MVP

  • scaffolding
  • CameraService
  • FrameDispatcher
  • TelemetryCollector
  • CameraView
  • TelemetryOverlay
  • IOverlayLayer
  • AppMenuBar
  • MainWindow

Rendering

  • Usunięto QVideoWidget
  • CameraView(QWidget) z paintEvent
    • render + overlay w jednym przejściu

Telemetria

TelemetrySnapshot — pola:

  • fps
  • target_fps
  • frame_time_ms
  • dropped_frames
  • cpu_percent_sys
  • cpu_percent_core
  • memory_mb

Kamera

  • CameraService.format_changed(float) sygnał
  • stop+start przy:
    • set_resolution
    • set_fps

Logowanie

  • _log_actual_format()
    • loguje rzeczywisty format po starcie kamery
    • warning jeśli FPS się nie zgadza

CameraFormat

CameraFormat dataclass z:

pixel_format: str

Przykłady:

  • MJPG
  • YUY2
  • NV12

w camera_enumerator.py

Logging

logging_setup.py

  • FileHandler
    • DEBUG
    • zawsze aktywny
  • StreamHandler
    • WARNING
    • przełączalny
  • nagłówek sesji:
    • wersja
    • platforma
    • Python
    • PySide6
    • CPU
    • RAM
  • pruning starych logów

CSV

csv_logger.py

  • CsvTelemetryLogger
  • throttling:
    • 5 s
  • flush po każdym wierszu

Menu

menu_bar.py

  • dostosowany do CameraFormat
  • set_log_file_path()
  • set_console_level()

Config

config.py

  • LOG_DIR
  • MAX_LOG_FILES
  • TELEMETRY_CSV_INTERVAL_S

Main

main.py

  • wywołuje setup_logging()
  • przekazuje log_path do MainWindow

Main Window

main_window.py

  • przyjmuje:
log_path: Path | None
  • tworzy:
CsvTelemetryLogger(log_path.with_suffix(".csv"))
  • podpina do:
    • telemetry.metrics_updated
  • wywołuje:
    • menu.set_log_file_path()
  • csv_logger.close() w closeEvent

Repo

.gitignore

  • dodano logs/

Testy i jakość

  • 20 testów jednostkowych
    • wszystkie zielone
  • ruff
    • czysty
    • wszystkie błędy naprawione

Artefakty sesji

Para plików per sesja:

logs/duck-preview_<timestamp>.log
logs/duck-preview_<timestamp>.csv

In Progress

  • (none)

Blocked

  • (none)

Key Decisions

Rendering

QVideoWidget → własny CameraView(QWidget)

Jedyny skuteczny sposób obejścia problemu z natywnym HWND na Windows.

Overlay Architecture

IOverlayLayer ABC

Pluggable overlaye bez modyfikacji CameraView.

Gotowe pod:

  • YOLO
  • OCR
  • inne overlaye

Pipeline

FrameDispatcher

Pub/sub z drop_if_busy:

  • render może gubić klatki
  • telemetria nigdy

CPU Metrics

  • CPU per-core (psutil)
  • dzielone przez cpu_count
  • wynik zgodny z Task Manager

Memory Metrics

  • memory_info().wset (Windows)
  • zamiast rss
  • odpowiada Private Working Set

Logging Strategy

Dwa osobne pliki per sesja:

  • .log — diagnostyka
  • .csv — metryki szeregów czasowych

CameraFormat

CameraFormat dataclass zamiast krotki:

  • niesie pixel_format
  • potrzebny w logach

Next Steps

  1. Przetestować na Windows:

    • czy logi powstają w logs/
    • czy CSV zapisuje dane co ~5 s
  2. Przenieść na Mac Mini i przetestować z kamerą ELP:

    • sprawdzić pixel_format w logu
    • sprawdzić wykrycie backendu AVFoundation
  3. Zweryfikować overlay telemetrii na żywym obrazie

  4. (Opcjonalnie) dodać kolejne IOverlayLayer

    • YOLO
    • OCR

Critical Context

Camera Enumerator

CameraEnumerator.list_cameras() zwraca:

list[CameraInfo]

gdzie:

formats: list[CameraFormat]

menu_bar.py i camera_service.py iterują po:

  • fmt.width
  • fmt.height
  • fmt.max_fps

CSV Logger

Ścieżka CSV:

log_path.with_suffix(".csv")

Powstaje para:

  • .log
  • .csv

z tym samym timestamp.


Console Logging

logging_setup.set_console_level(debug: bool)

wywoływane z:

menu_bar._on_log_toggled

Pixel Format

pixel_format_name()

eksportowane z:

camera_enumerator.py

używane również w:

camera_service.py

Log Header

Nagłówek logu zawiera:

  • wersję aplikacji
  • platformę
  • Python
  • PySide6
  • liczbę CPU
  • RAM

Uruchamianie

.venv-win\Scripts\python.exe -m app.main

Ruff Fixes

Naprawiono:

  • E501
    • długa linia w camera_enumerator.py
  • F401
  • I001
    • w camera_service.py
    • w main.py

Relevant Files

Entry Point

  • app/main.py
    • wywołuje setup_logging()
    • przekazuje log_path

Config

  • app/config.py
    • LOG_DIR
    • MAX_LOG_FILES
    • TELEMETRY_CSV_INTERVAL_S

Logging

  • app/logging_setup.py
    • konfiguracja logowania
    • nagłówek sesji
    • pruning

Telemetry

  • app/telemetry/csv_logger.py

    • zapis CSV z throttlingiem
  • app/telemetry/telemetry_collector.py

    • TelemetrySnapshot
    • TelemetryCollector

Camera

  • app/camera/camera_enumerator.py

    • CameraFormat
    • CameraInfo
    • pixel_format_name()
  • app/camera/camera_service.py

    • CameraService
    • format_changed
    • _log_actual_format()

UI

  • app/ui/main_window.py

    • kompletny
    • podpięty CsvTelemetryLogger
  • app/ui/menu_bar.py

    • set_log_file_path()
    • set_console_level()
  • app/ui/camera_view.py

    • CameraView
    • rejestr IOverlayLayer

Overlay

  • app/overlay/overlay_layer.py

    • IOverlayLayer ABC
  • app/overlay/telemetry_overlay.py

    • TelemetryOverlay(IOverlayLayer)

Pipeline

  • app/pipeline/frame_dispatcher.py
    • pub/sub
    • drop_if_busy

Tests

  • tests/test_telemetry_collector.py

    • 12 testów
    • mockuje cpu_count
  • tests/test_frame_dispatcher.py

    • 8 testów

Repo / Docs

  • .gitignore

    • zawiera logs/
  • notes/01-mvp-preview.md

    • PRD
  • notes/01-mvp-plan.md

    • plan implementacji
  • notes/02-mvp-app.md

    • stan aplikacji
    • historia prób i decyzji architektonicznych