Add PySide6 camera UI, YOLO/Tesseract detection pipeline, capture metadata, configuration, and project gitignore.
126 lines
4.0 KiB
Python
126 lines
4.0 KiB
Python
from __future__ import annotations
|
|
|
|
from copy import deepcopy
|
|
from typing import Any
|
|
|
|
from PySide6.QtCore import Qt, Signal
|
|
from PySide6.QtWidgets import (
|
|
QCheckBox,
|
|
QDialog,
|
|
QFormLayout,
|
|
QHBoxLayout,
|
|
QLabel,
|
|
QPushButton,
|
|
QSlider,
|
|
QSpinBox,
|
|
QVBoxLayout,
|
|
QWidget,
|
|
)
|
|
|
|
|
|
CAMERA_PROPERTY_LABELS = {
|
|
"brightness": "Jasnosc",
|
|
"contrast": "Kontrast",
|
|
"saturation": "Nasycenie",
|
|
"hue": "Barwa",
|
|
"gain": "Gain",
|
|
"exposure": "Ekspozycja",
|
|
"sharpness": "Ostrosc",
|
|
"auto_exposure": "Auto ekspozycja",
|
|
"focus": "Focus",
|
|
"auto_focus": "Auto focus",
|
|
}
|
|
|
|
|
|
class PropertySlider(QWidget):
|
|
value_changed = Signal(str, object)
|
|
|
|
def __init__(self, name: str, value: float | None) -> None:
|
|
super().__init__()
|
|
self.name = name
|
|
self.enabled_box = QCheckBox()
|
|
self.enabled_box.setChecked(value is not None)
|
|
self.slider = QSlider(Qt.Horizontal)
|
|
self.slider.setRange(-100, 100)
|
|
self.slider.setValue(int(value) if value is not None else 0)
|
|
self.value_box = QSpinBox()
|
|
self.value_box.setRange(-100, 100)
|
|
self.value_box.setValue(self.slider.value())
|
|
|
|
layout = QHBoxLayout(self)
|
|
layout.setContentsMargins(0, 0, 0, 0)
|
|
layout.addWidget(self.enabled_box)
|
|
layout.addWidget(self.slider, 1)
|
|
layout.addWidget(self.value_box)
|
|
|
|
self.slider.valueChanged.connect(self.value_box.setValue)
|
|
self.value_box.valueChanged.connect(self.slider.setValue)
|
|
self.slider.valueChanged.connect(self._emit_value)
|
|
self.enabled_box.toggled.connect(self._emit_value)
|
|
|
|
def _emit_value(self) -> None:
|
|
self.value_changed.emit(self.name, self.value())
|
|
|
|
def value(self) -> float | None:
|
|
if not self.enabled_box.isChecked():
|
|
return None
|
|
return float(self.slider.value())
|
|
|
|
|
|
class SettingsDialog(QDialog):
|
|
settings_saved = Signal(dict)
|
|
|
|
def __init__(self, config: dict[str, Any], parent: QWidget | None = None) -> None:
|
|
super().__init__(parent)
|
|
self.setWindowTitle("Ustawienia obrazu")
|
|
self.setMinimumWidth(520)
|
|
self.config = deepcopy(config)
|
|
self.property_widgets: dict[str, PropertySlider] = {}
|
|
|
|
camera_cfg = self.config["camera"]
|
|
main_layout = QVBoxLayout(self)
|
|
form = QFormLayout()
|
|
|
|
self.width_box = QSpinBox()
|
|
self.width_box.setRange(160, 7680)
|
|
self.width_box.setValue(int(camera_cfg.get("width", 1920)))
|
|
self.height_box = QSpinBox()
|
|
self.height_box.setRange(120, 4320)
|
|
self.height_box.setValue(int(camera_cfg.get("height", 1080)))
|
|
self.fps_box = QSpinBox()
|
|
self.fps_box.setRange(1, 240)
|
|
self.fps_box.setValue(int(camera_cfg.get("fps", 30)))
|
|
|
|
form.addRow("Szerokosc", self.width_box)
|
|
form.addRow("Wysokosc", self.height_box)
|
|
form.addRow("FPS", self.fps_box)
|
|
|
|
for name, label in CAMERA_PROPERTY_LABELS.items():
|
|
widget = PropertySlider(name, camera_cfg.get("properties", {}).get(name))
|
|
self.property_widgets[name] = widget
|
|
form.addRow(QLabel(label), widget)
|
|
|
|
main_layout.addLayout(form)
|
|
|
|
buttons = QHBoxLayout()
|
|
buttons.addStretch(1)
|
|
cancel_button = QPushButton("Anuluj")
|
|
save_button = QPushButton("Zapisz")
|
|
save_button.setDefault(True)
|
|
buttons.addWidget(cancel_button)
|
|
buttons.addWidget(save_button)
|
|
main_layout.addLayout(buttons)
|
|
|
|
cancel_button.clicked.connect(self.reject)
|
|
save_button.clicked.connect(self._save)
|
|
|
|
def _save(self) -> None:
|
|
self.config["camera"]["width"] = int(self.width_box.value())
|
|
self.config["camera"]["height"] = int(self.height_box.value())
|
|
self.config["camera"]["fps"] = int(self.fps_box.value())
|
|
self.config["camera"]["properties"] = {
|
|
name: widget.value() for name, widget in self.property_widgets.items()
|
|
}
|
|
self.settings_saved.emit(self.config["camera"])
|
|
self.accept()
|