- 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.
6.6 KiB
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,ruffQVideoWidgetporzucony — 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
flushpo każdym wierszu
- CPU:
- pokazywać oba:
- sys %
- per-core % (jak Task Manager)
- pokazywać oba:
- Zmiana formatu kamery przez
stop+start- nie
setCameraFormatna żywej kamerze
- nie
Progress
Done
Faza 0–7 MVP
- scaffolding
CameraServiceFrameDispatcherTelemetryCollectorCameraViewTelemetryOverlayIOverlayLayerAppMenuBarMainWindow
Rendering
- Usunięto
QVideoWidget CameraView(QWidget)zpaintEvent- render + overlay w jednym przejściu
Telemetria
TelemetrySnapshot — pola:
fpstarget_fpsframe_time_msdropped_framescpu_percent_syscpu_percent_corememory_mb
Kamera
CameraService.format_changed(float)sygnałstop+startprzy:set_resolutionset_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:
MJPGYUY2NV12
w camera_enumerator.py
Logging
logging_setup.py
FileHandlerDEBUG- zawsze aktywny
StreamHandlerWARNING- przełączalny
- nagłówek sesji:
- wersja
- platforma
- Python
- PySide6
- CPU
- RAM
- pruning starych logów
CSV
csv_logger.py
CsvTelemetryLogger- throttling:
- 5 s
flushpo każdym wierszu
Menu
menu_bar.py
- dostosowany do
CameraFormat set_log_file_path()set_console_level()
Config
config.py
LOG_DIRMAX_LOG_FILESTELEMETRY_CSV_INTERVAL_S
Main
main.py
- wywołuje
setup_logging() - przekazuje
log_pathdoMainWindow
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()wcloseEvent
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
-
Przetestować na Windows:
- czy logi powstają w
logs/ - czy CSV zapisuje dane co ~5 s
- czy logi powstają w
-
Przenieść na Mac Mini i przetestować z kamerą ELP:
- sprawdzić
pixel_formatw logu - sprawdzić wykrycie backendu AVFoundation
- sprawdzić
-
Zweryfikować overlay telemetrii na żywym obrazie
-
(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.widthfmt.heightfmt.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
- długa linia w
F401I001- w
camera_service.py - w
main.py
- w
Relevant Files
Entry Point
app/main.py- wywołuje
setup_logging() - przekazuje
log_path
- wywołuje
Config
app/config.pyLOG_DIRMAX_LOG_FILESTELEMETRY_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.pyTelemetrySnapshotTelemetryCollector
Camera
-
app/camera/camera_enumerator.pyCameraFormatCameraInfopixel_format_name()
-
app/camera/camera_service.pyCameraServiceformat_changed_log_actual_format()
UI
-
app/ui/main_window.py- kompletny
- podpięty
CsvTelemetryLogger
-
app/ui/menu_bar.pyset_log_file_path()set_console_level()
-
app/ui/camera_view.pyCameraView- rejestr
IOverlayLayer
Overlay
-
app/overlay/overlay_layer.pyIOverlayLayerABC
-
app/overlay/telemetry_overlay.pyTelemetryOverlay(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/
- zawiera
-
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