Clean push: Removed heavy files & added only latest snapshot
This commit is contained in:
666
qt_app_pyside1/ui/config_panel.py
Normal file
666
qt_app_pyside1/ui/config_panel.py
Normal file
@@ -0,0 +1,666 @@
|
||||
from PySide6.QtWidgets import (
|
||||
QWidget, QVBoxLayout, QHBoxLayout, QLabel, QComboBox,
|
||||
QSlider, QCheckBox, QPushButton, QGroupBox, QFormLayout,
|
||||
QSpinBox, QDoubleSpinBox, QTabWidget, QLineEdit, QFileDialog,
|
||||
QSpacerItem, QSizePolicy
|
||||
)
|
||||
from PySide6.QtCore import Qt, Signal, Slot
|
||||
from PySide6.QtGui import QFont
|
||||
|
||||
class ConfigPanel(QWidget):
|
||||
"""Side panel for application configuration."""
|
||||
|
||||
config_changed = Signal(dict) # Emitted when configuration changes are applied
|
||||
theme_toggled = Signal(bool) # Emitted when theme toggle button is clicked (True = dark)
|
||||
device_switch_requested = Signal(str)
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.setObjectName("ConfigPanel")
|
||||
self.setStyleSheet(self._panel_qss())
|
||||
self.initUI()
|
||||
self.dark_theme = True # Start with dark theme
|
||||
|
||||
def _panel_qss(self):
|
||||
return """
|
||||
#ConfigPanel {
|
||||
background: #181C20;
|
||||
border-top-left-radius: 18px;
|
||||
border-bottom-left-radius: 18px;
|
||||
border: none;
|
||||
}
|
||||
QTabWidget::pane {
|
||||
border-radius: 12px;
|
||||
background: #232323;
|
||||
}
|
||||
QTabBar::tab {
|
||||
background: #232323;
|
||||
color: #bbb;
|
||||
border-radius: 10px 10px 0 0;
|
||||
padding: 8px 18px;
|
||||
font-size: 15px;
|
||||
}
|
||||
QTabBar::tab:selected {
|
||||
background: #03DAC5;
|
||||
color: #181C20;
|
||||
}
|
||||
QGroupBox {
|
||||
border: 1px solid #30343A;
|
||||
border-radius: 12px;
|
||||
margin-top: 16px;
|
||||
background: #232323;
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
font-size: 15px;
|
||||
}
|
||||
QGroupBox:title {
|
||||
subcontrol-origin: margin;
|
||||
left: 12px;
|
||||
top: 8px;
|
||||
padding: 0 4px;
|
||||
background: transparent;
|
||||
}
|
||||
QLabel, QCheckBox, QRadioButton {
|
||||
color: #eee;
|
||||
font-size: 14px;
|
||||
}
|
||||
QLineEdit, QSpinBox, QDoubleSpinBox {
|
||||
background: #181C20;
|
||||
border: 1.5px solid #30343A;
|
||||
border-radius: 8px;
|
||||
color: #fff;
|
||||
padding: 6px 10px;
|
||||
font-size: 14px;
|
||||
}
|
||||
QSlider::groove:horizontal {
|
||||
height: 8px;
|
||||
background: #30343A;
|
||||
border-radius: 4px;
|
||||
}
|
||||
QSlider::handle:horizontal {
|
||||
background: #03DAC5;
|
||||
border-radius: 10px;
|
||||
width: 20px;
|
||||
}
|
||||
QPushButton {
|
||||
background: #03DAC5;
|
||||
color: #181C20;
|
||||
border-radius: 10px;
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
padding: 8px 18px;
|
||||
border: none;
|
||||
}
|
||||
QPushButton:hover {
|
||||
background: #018786;
|
||||
color: #fff;
|
||||
}
|
||||
QPushButton:pressed {
|
||||
background: #03DAC5;
|
||||
color: #232323;
|
||||
}
|
||||
QCheckBox::indicator {
|
||||
border-radius: 6px;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
QCheckBox::indicator:checked {
|
||||
background: #03DAC5;
|
||||
border: 1.5px solid #018786;
|
||||
}
|
||||
QCheckBox::indicator:unchecked {
|
||||
background: #232323;
|
||||
border: 1.5px solid #30343A;
|
||||
}
|
||||
"""
|
||||
|
||||
def initUI(self):
|
||||
"""Initialize UI components"""
|
||||
layout = QVBoxLayout(self)
|
||||
layout.setContentsMargins(18, 18, 18, 18)
|
||||
layout.setSpacing(10)
|
||||
|
||||
# Create tab widget for better organization
|
||||
tabs = QTabWidget()
|
||||
tabs.setStyleSheet("") # Use panel QSS
|
||||
|
||||
# Detection tab
|
||||
detection_tab = QWidget()
|
||||
detection_layout = QVBoxLayout(detection_tab)
|
||||
|
||||
# Device selection
|
||||
device_group = QGroupBox("Inference Device")
|
||||
device_layout = QVBoxLayout(device_group)
|
||||
|
||||
self.device_combo = QComboBox()
|
||||
self.device_combo.addItems(["AUTO", "CPU", "GPU", "MYRIAD", "VPU"])
|
||||
device_layout.addWidget(self.device_combo)
|
||||
|
||||
detection_layout.addWidget(device_group)
|
||||
|
||||
# Detection settings
|
||||
detection_group = QGroupBox("Detection Settings")
|
||||
detection_form = QFormLayout(detection_group)
|
||||
|
||||
self.conf_slider = QSlider(Qt.Horizontal)
|
||||
self.conf_slider.setRange(10, 100)
|
||||
self.conf_slider.setValue(50)
|
||||
self.conf_slider.setTracking(True)
|
||||
self.conf_slider.valueChanged.connect(self.update_conf_label)
|
||||
|
||||
self.conf_label = QLabel("50%")
|
||||
conf_layout = QHBoxLayout()
|
||||
conf_layout.addWidget(self.conf_slider)
|
||||
conf_layout.addWidget(self.conf_label)
|
||||
|
||||
self.tracking_checkbox = QCheckBox("Enable")
|
||||
self.tracking_checkbox.setChecked(True)
|
||||
|
||||
model_layout = QHBoxLayout()
|
||||
self.model_path = QLineEdit()
|
||||
self.model_path.setReadOnly(True)
|
||||
self.model_path.setPlaceholderText("Auto-detected")
|
||||
|
||||
self.browse_btn = QPushButton("...")
|
||||
self.browse_btn.setMaximumWidth(30)
|
||||
self.browse_btn.clicked.connect(self.browse_model)
|
||||
|
||||
model_layout.addWidget(self.model_path)
|
||||
model_layout.addWidget(self.browse_btn)
|
||||
|
||||
detection_form.addRow("Confidence Threshold:", conf_layout)
|
||||
detection_form.addRow("Object Tracking:", self.tracking_checkbox)
|
||||
detection_form.addRow("Model Path:", model_layout)
|
||||
detection_layout.addWidget(detection_group)
|
||||
# Add quick switch buttons for YOLO11n/YOLO11x
|
||||
quick_switch_layout = QHBoxLayout()
|
||||
self.cpu_switch_btn = QPushButton("Switch to CPU (YOLO11n)")
|
||||
self.gpu_switch_btn = QPushButton("Switch to GPU (YOLO11x)")
|
||||
self.cpu_switch_btn.clicked.connect(lambda: self.quick_switch_device("CPU"))
|
||||
self.gpu_switch_btn.clicked.connect(lambda: self.quick_switch_device("GPU"))
|
||||
quick_switch_layout.addWidget(self.cpu_switch_btn)
|
||||
quick_switch_layout.addWidget(self.gpu_switch_btn)
|
||||
detection_layout.addLayout(quick_switch_layout)
|
||||
# --- Current Model Info Section (PREMIUM FORMAT) ---
|
||||
model_info_group = QGroupBox()
|
||||
model_info_group.setTitle("")
|
||||
model_info_group.setStyleSheet("""
|
||||
QGroupBox {
|
||||
border: 1.5px solid #03DAC5;
|
||||
border-radius: 12px;
|
||||
margin-top: 16px;
|
||||
background: #181C20;
|
||||
font-weight: bold;
|
||||
color: #03DAC5;
|
||||
font-size: 16px;
|
||||
}
|
||||
""")
|
||||
model_info_layout = QVBoxLayout(model_info_group)
|
||||
model_info_layout.setContentsMargins(16, 10, 16, 10)
|
||||
# Title
|
||||
title = QLabel("Current Model")
|
||||
title.setStyleSheet("font-size: 17px; font-weight: bold; color: #03DAC5; margin-bottom: 8px;")
|
||||
model_info_layout.addWidget(title)
|
||||
# Info rows
|
||||
row_style = "font-size: 15px; color: #fff; font-family: 'Consolas', 'SF Mono', 'monospace'; padding: 2px 0;"
|
||||
row_widget = QWidget()
|
||||
row_layout = QVBoxLayout(row_widget)
|
||||
row_layout.setContentsMargins(0, 0, 0, 0)
|
||||
row_layout.setSpacing(2)
|
||||
# Model
|
||||
model_row = QHBoxLayout()
|
||||
model_label = QLabel("Model:")
|
||||
model_label.setStyleSheet(row_style + "font-weight: 600; color: #80cbc4;")
|
||||
self.current_model_label = QLabel("-")
|
||||
self.current_model_label.setStyleSheet(row_style)
|
||||
model_row.addWidget(model_label)
|
||||
model_row.addWidget(self.current_model_label, 1)
|
||||
row_layout.addLayout(model_row)
|
||||
# Device
|
||||
device_row = QHBoxLayout()
|
||||
device_label = QLabel("Device:")
|
||||
device_label.setStyleSheet(row_style + "font-weight: 600; color: #80cbc4;")
|
||||
self.current_device_label = QLabel("-")
|
||||
self.current_device_label.setStyleSheet(row_style)
|
||||
device_row.addWidget(device_label)
|
||||
device_row.addWidget(self.current_device_label, 1)
|
||||
row_layout.addLayout(device_row)
|
||||
# Recommended For
|
||||
rec_row = QHBoxLayout()
|
||||
rec_label = QLabel("Recommended For:")
|
||||
rec_label.setStyleSheet(row_style + "font-weight: 600; color: #80cbc4;")
|
||||
self.model_recommendation_label = QLabel("")
|
||||
self.model_recommendation_label.setStyleSheet(row_style)
|
||||
rec_row.addWidget(rec_label)
|
||||
rec_row.addWidget(self.model_recommendation_label, 1)
|
||||
row_layout.addLayout(rec_row)
|
||||
model_info_layout.addWidget(row_widget)
|
||||
model_info_layout.addStretch(1)
|
||||
detection_layout.addWidget(model_info_group)
|
||||
|
||||
# --- OpenVINO Devices Info Section ---
|
||||
devices_info_group = QGroupBox()
|
||||
devices_info_group.setTitle("")
|
||||
devices_info_group.setStyleSheet("""
|
||||
QGroupBox {
|
||||
border: 1.5px solid #80cbc4;
|
||||
border-radius: 12px;
|
||||
margin-top: 16px;
|
||||
background: #181C20;
|
||||
font-weight: bold;
|
||||
color: #80cbc4;
|
||||
font-size: 16px;
|
||||
}
|
||||
""")
|
||||
devices_info_layout = QVBoxLayout(devices_info_group)
|
||||
devices_info_layout.setContentsMargins(16, 10, 16, 10)
|
||||
devices_title = QLabel("Available OpenVINO Devices")
|
||||
devices_title.setStyleSheet("font-size: 16px; font-weight: bold; color: #80cbc4; margin-bottom: 8px;")
|
||||
devices_info_layout.addWidget(devices_title)
|
||||
self.devices_info_text = QLabel("Yolov11n and Yolov11x models are optimized for CPU and GPU respectively.<br>")
|
||||
self.devices_info_text.setStyleSheet("font-size: 14px; color: #fff; font-family: 'Consolas', 'SF Mono', 'monospace';")
|
||||
self.devices_info_text.setWordWrap(True)
|
||||
self.devices_info_text.setTextFormat(Qt.RichText)
|
||||
self.devices_info_text.setObjectName("devices_info_text")
|
||||
devices_info_layout.addWidget(self.devices_info_text)
|
||||
devices_info_layout.addStretch(1)
|
||||
detection_layout.addWidget(devices_info_group)
|
||||
|
||||
display_tab = QWidget()
|
||||
display_layout = QVBoxLayout(display_tab)
|
||||
|
||||
# Display options
|
||||
display_group = QGroupBox("Display Options")
|
||||
display_form = QFormLayout(display_group)
|
||||
|
||||
self.labels_checkbox = QCheckBox()
|
||||
self.labels_checkbox.setChecked(True)
|
||||
|
||||
self.confidence_checkbox = QCheckBox()
|
||||
self.confidence_checkbox.setChecked(True)
|
||||
|
||||
self.perf_checkbox = QCheckBox()
|
||||
self.perf_checkbox.setChecked(True)
|
||||
|
||||
self.max_width = QSpinBox()
|
||||
self.max_width.setRange(320, 4096)
|
||||
self.max_width.setValue(800)
|
||||
self.max_width.setSingleStep(10)
|
||||
self.max_width.setSuffix(" px")
|
||||
|
||||
display_form.addRow("Show Labels:", self.labels_checkbox)
|
||||
display_form.addRow("Show Confidence:", self.confidence_checkbox)
|
||||
display_form.addRow("Show Performance:", self.perf_checkbox)
|
||||
display_form.addRow("Max Display Width:", self.max_width)
|
||||
|
||||
display_layout.addWidget(display_group)
|
||||
|
||||
# Analytics Group
|
||||
analytics_group = QGroupBox("Analytics Settings")
|
||||
analytics_form = QFormLayout(analytics_group)
|
||||
|
||||
self.charts_checkbox = QCheckBox()
|
||||
self.charts_checkbox.setChecked(True)
|
||||
|
||||
self.history_spinbox = QSpinBox()
|
||||
self.history_spinbox.setRange(10, 10000)
|
||||
self.history_spinbox.setValue(1000)
|
||||
self.history_spinbox.setSingleStep(100)
|
||||
self.history_spinbox.setSuffix(" frames")
|
||||
|
||||
analytics_form.addRow("Enable Live Charts:", self.charts_checkbox)
|
||||
analytics_form.addRow("History Length:", self.history_spinbox)
|
||||
|
||||
display_layout.addWidget(analytics_group)
|
||||
|
||||
# Violation tab
|
||||
violation_tab = QWidget()
|
||||
violation_layout = QVBoxLayout(violation_tab)
|
||||
|
||||
# Violation settings
|
||||
violation_group = QGroupBox("Violation Detection")
|
||||
violation_form = QFormLayout(violation_group)
|
||||
|
||||
self.red_light_grace = QDoubleSpinBox()
|
||||
self.red_light_grace.setRange(0.1, 5.0)
|
||||
self.red_light_grace.setValue(2.0)
|
||||
self.red_light_grace.setSingleStep(0.1)
|
||||
self.red_light_grace.setSuffix(" sec")
|
||||
|
||||
self.stop_sign_duration = QDoubleSpinBox()
|
||||
self.stop_sign_duration.setRange(0.5, 5.0)
|
||||
self.stop_sign_duration.setValue(2.0)
|
||||
self.stop_sign_duration.setSingleStep(0.1)
|
||||
self.stop_sign_duration.setSuffix(" sec")
|
||||
|
||||
self.speed_tolerance = QSpinBox()
|
||||
self.speed_tolerance.setRange(0, 20)
|
||||
self.speed_tolerance.setValue(5)
|
||||
self.speed_tolerance.setSingleStep(1)
|
||||
self.speed_tolerance.setSuffix(" km/h")
|
||||
|
||||
violation_form.addRow("Red Light Grace:", self.red_light_grace)
|
||||
violation_form.addRow("Stop Sign Duration:", self.stop_sign_duration)
|
||||
violation_form.addRow("Speed Tolerance:", self.speed_tolerance)
|
||||
|
||||
self.enable_red_light = QCheckBox("Enabled")
|
||||
self.enable_red_light.setChecked(True)
|
||||
|
||||
self.enable_stop_sign = QCheckBox("Enabled")
|
||||
self.enable_stop_sign.setChecked(True)
|
||||
|
||||
self.enable_speed = QCheckBox("Enabled")
|
||||
self.enable_speed.setChecked(True)
|
||||
|
||||
self.enable_lane = QCheckBox("Enabled")
|
||||
self.enable_lane.setChecked(True)
|
||||
|
||||
violation_form.addRow("Red Light Detection:", self.enable_red_light)
|
||||
violation_form.addRow("Stop Sign Detection:", self.enable_stop_sign)
|
||||
violation_form.addRow("Speed Detection:", self.enable_speed)
|
||||
violation_form.addRow("Lane Detection:", self.enable_lane)
|
||||
|
||||
violation_layout.addWidget(violation_group)
|
||||
|
||||
# Add all tabs
|
||||
tabs.addTab(detection_tab, "Detection")
|
||||
tabs.addTab(display_tab, "Display")
|
||||
tabs.addTab(violation_tab, "Violations")
|
||||
|
||||
layout.addWidget(tabs)
|
||||
|
||||
# Theme toggle
|
||||
self.theme_toggle = QPushButton("🌙 Dark Theme")
|
||||
self.theme_toggle.setFixedHeight(36)
|
||||
self.theme_toggle.setStyleSheet("margin-top: 8px;")
|
||||
self.theme_toggle.clicked.connect(self.toggle_theme)
|
||||
layout.addWidget(self.theme_toggle)
|
||||
|
||||
# Spacer to push buttons to bottom
|
||||
layout.addItem(QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding))
|
||||
|
||||
# Control buttons (fixed at bottom)
|
||||
btns = QHBoxLayout()
|
||||
self.apply_btn = QPushButton("Apply")
|
||||
self.apply_btn.setFixedHeight(32)
|
||||
self.apply_btn.clicked.connect(self.apply_config)
|
||||
|
||||
self.reset_btn = QPushButton("Reset")
|
||||
self.reset_btn.setFixedHeight(32)
|
||||
self.reset_btn.clicked.connect(self.reset_config)
|
||||
|
||||
btns.addWidget(self.apply_btn)
|
||||
btns.addWidget(self.reset_btn)
|
||||
layout.addLayout(btns)
|
||||
|
||||
layout.addStretch(1) # Push everything to the top
|
||||
|
||||
# Set tooltips for major controls
|
||||
self.device_combo.setToolTip("Select inference device (CPU, GPU, etc.)")
|
||||
self.cpu_switch_btn.setToolTip("Switch to CPU-optimized YOLO11n model")
|
||||
self.gpu_switch_btn.setToolTip("Switch to GPU-optimized YOLO11x model")
|
||||
self.conf_slider.setToolTip("Set detection confidence threshold")
|
||||
self.tracking_checkbox.setToolTip("Enable or disable object tracking")
|
||||
self.model_path.setToolTip("Path to the detection model")
|
||||
self.browse_btn.setToolTip("Browse for a model file")
|
||||
self.labels_checkbox.setToolTip("Show/hide detection labels on video")
|
||||
self.confidence_checkbox.setToolTip("Show/hide confidence scores on video")
|
||||
self.perf_checkbox.setToolTip("Show/hide performance overlay")
|
||||
self.max_width.setToolTip("Maximum display width for video")
|
||||
self.charts_checkbox.setToolTip("Enable/disable live analytics charts")
|
||||
self.history_spinbox.setToolTip("Number of frames to keep in analytics history")
|
||||
self.red_light_grace.setToolTip("Grace period for red light violation (seconds)")
|
||||
self.stop_sign_duration.setToolTip("Stop sign violation duration (seconds)")
|
||||
self.speed_tolerance.setToolTip("Speed tolerance for speed violation (km/h)")
|
||||
self.enable_red_light.setToolTip("Enable/disable red light violation detection")
|
||||
self.enable_stop_sign.setToolTip("Enable/disable stop sign violation detection")
|
||||
self.enable_speed.setToolTip("Enable/disable speed violation detection")
|
||||
self.enable_lane.setToolTip("Enable/disable lane violation detection")
|
||||
self.theme_toggle.setToolTip("Toggle between dark and light theme")
|
||||
self.apply_btn.setToolTip("Apply all changes")
|
||||
self.reset_btn.setToolTip("Reset all settings to default")
|
||||
|
||||
@Slot(int)
|
||||
def update_conf_label(self, value):
|
||||
"""Update confidence threshold label"""
|
||||
self.conf_label.setText(f"{value}%")
|
||||
|
||||
@Slot()
|
||||
def browse_model(self):
|
||||
"""Browse for model file"""
|
||||
file_path, _ = QFileDialog.getOpenFileName(
|
||||
self,
|
||||
"Select Model File",
|
||||
"",
|
||||
"OpenVINO Models (*.xml);;PyTorch Models (*.pt);;All Files (*)"
|
||||
)
|
||||
|
||||
if file_path:
|
||||
self.model_path.setText(file_path)
|
||||
|
||||
@Slot()
|
||||
def toggle_theme(self):
|
||||
"""Toggle between light and dark theme"""
|
||||
self.dark_theme = not self.dark_theme
|
||||
|
||||
if self.dark_theme:
|
||||
self.theme_toggle.setText("🌙 Dark Theme")
|
||||
else:
|
||||
self.theme_toggle.setText("☀️ Light Theme")
|
||||
|
||||
self.theme_toggled.emit(self.dark_theme)
|
||||
|
||||
@Slot()
|
||||
def apply_config(self):
|
||||
"""Apply configuration changes"""
|
||||
config = self.get_config()
|
||||
self.config_changed.emit(config)
|
||||
|
||||
@Slot()
|
||||
def reset_config(self):
|
||||
"""Reset configuration to defaults"""
|
||||
self.device_combo.setCurrentText("AUTO")
|
||||
self.conf_slider.setValue(50)
|
||||
self.tracking_checkbox.setChecked(True)
|
||||
self.labels_checkbox.setChecked(True)
|
||||
self.confidence_checkbox.setChecked(True)
|
||||
self.perf_checkbox.setChecked(True)
|
||||
self.max_width.setValue(800)
|
||||
self.red_light_grace.setValue(2.0)
|
||||
self.stop_sign_duration.setValue(2.0)
|
||||
self.speed_tolerance.setValue(5)
|
||||
self.enable_red_light.setChecked(True)
|
||||
self.enable_stop_sign.setChecked(True)
|
||||
self.enable_speed.setChecked(True)
|
||||
self.enable_lane.setChecked(True)
|
||||
self.model_path.setText("")
|
||||
|
||||
self.apply_config()
|
||||
|
||||
def quick_switch_device(self, device: str):
|
||||
index = self.device_combo.findText(device)
|
||||
if index >= 0:
|
||||
self.device_combo.setCurrentIndex(index)
|
||||
self.device_switch_requested.emit(device)
|
||||
self.apply_config()
|
||||
|
||||
def update_model_info(self, model_info: dict):
|
||||
if not model_info:
|
||||
self.current_model_label.setText("No model loaded")
|
||||
self.current_device_label.setText("None")
|
||||
self.model_recommendation_label.setText("None")
|
||||
return
|
||||
model_name = model_info.get("model_name", "Unknown")
|
||||
device = model_info.get("device", "Unknown")
|
||||
recommended_for = model_info.get("recommended_for", "Unknown")
|
||||
self.current_model_label.setText(model_name)
|
||||
self.current_device_label.setText(device)
|
||||
self.model_recommendation_label.setText(recommended_for)
|
||||
if device == "CPU":
|
||||
self.cpu_switch_btn.setEnabled(False)
|
||||
self.cpu_switch_btn.setText("✓ CPU Active (YOLO11n)")
|
||||
self.gpu_switch_btn.setEnabled(True)
|
||||
self.gpu_switch_btn.setText("Switch to GPU (YOLO11x)")
|
||||
elif device == "GPU":
|
||||
self.cpu_switch_btn.setEnabled(True)
|
||||
self.cpu_switch_btn.setText("Switch to CPU (YOLO11n)")
|
||||
self.gpu_switch_btn.setEnabled(False)
|
||||
self.gpu_switch_btn.setText("✓ GPU Active (YOLO11x)")
|
||||
else:
|
||||
self.cpu_switch_btn.setEnabled(True)
|
||||
self.cpu_switch_btn.setText("Switch to CPU (YOLO11n)")
|
||||
self.gpu_switch_btn.setEnabled(True)
|
||||
self.gpu_switch_btn.setText("Switch to GPU (YOLO11x)")
|
||||
|
||||
@Slot(object, object)
|
||||
def update_live_stats(self, fps, inference_time):
|
||||
"""Update FPS and inference time labels in the settings panel."""
|
||||
if fps is not None:
|
||||
self.fps_label.setText(f"FPS: {fps:.1f}")
|
||||
else:
|
||||
self.fps_label.setText("FPS: --")
|
||||
if inference_time is not None:
|
||||
self.infer_label.setText(f"Inference: {inference_time:.1f} ms")
|
||||
else:
|
||||
self.infer_label.setText("Inference: -- ms")
|
||||
|
||||
@Slot(object, object)
|
||||
def set_video_stats(self, stats):
|
||||
"""Update FPS and inference time labels in the settings panel from stats dict."""
|
||||
fps = stats.get('fps', None)
|
||||
inference_time = None
|
||||
if 'detection_time_ms' in stats:
|
||||
inference_time = float(stats['detection_time_ms'])
|
||||
elif 'detection_time' in stats:
|
||||
inference_time = float(stats['detection_time'])
|
||||
self.update_live_stats(fps, inference_time)
|
||||
|
||||
def get_config(self):
|
||||
"""
|
||||
Get current configuration from UI.
|
||||
|
||||
Returns:
|
||||
Configuration dictionary
|
||||
"""
|
||||
return {
|
||||
'detection': {
|
||||
'device': self.device_combo.currentText(),
|
||||
'confidence_threshold': self.conf_slider.value() / 100.0,
|
||||
'enable_tracking': self.tracking_checkbox.isChecked(),
|
||||
'model_path': self.model_path.text() if self.model_path.text() else None
|
||||
},
|
||||
'display': {
|
||||
'show_labels': self.labels_checkbox.isChecked(),
|
||||
'show_confidence': self.confidence_checkbox.isChecked(),
|
||||
'show_performance': self.perf_checkbox.isChecked(),
|
||||
'max_display_width': self.max_width.value()
|
||||
},
|
||||
'violations': {
|
||||
'red_light_grace_period': self.red_light_grace.value(),
|
||||
'stop_sign_duration': self.stop_sign_duration.value(),
|
||||
'speed_tolerance': self.speed_tolerance.value(),
|
||||
'enable_red_light': self.enable_red_light.isChecked(),
|
||||
'enable_stop_sign': self.enable_stop_sign.isChecked(),
|
||||
'enable_speed': self.enable_speed.isChecked(),
|
||||
'enable_lane': self.enable_lane.isChecked()
|
||||
},
|
||||
'analytics': {
|
||||
'enable_charts': self.charts_checkbox.isChecked(),
|
||||
'history_length': self.history_spinbox.value()
|
||||
}
|
||||
}
|
||||
|
||||
def set_config(self, config):
|
||||
"""
|
||||
Set configuration in UI.
|
||||
|
||||
Args:
|
||||
config: Configuration dictionary
|
||||
"""
|
||||
if not config:
|
||||
return
|
||||
|
||||
# Detection settings
|
||||
detection = config.get('detection', {})
|
||||
if 'device' in detection:
|
||||
index = self.device_combo.findText(detection['device'])
|
||||
if index >= 0:
|
||||
self.device_combo.setCurrentIndex(index)
|
||||
|
||||
if 'confidence_threshold' in detection:
|
||||
self.conf_slider.setValue(int(detection['confidence_threshold'] * 100))
|
||||
|
||||
if 'enable_tracking' in detection:
|
||||
self.tracking_checkbox.setChecked(detection['enable_tracking'])
|
||||
|
||||
if 'model_path' in detection and detection['model_path']:
|
||||
self.model_path.setText(detection['model_path'])
|
||||
|
||||
# Display settings
|
||||
display = config.get('display', {})
|
||||
if 'show_labels' in display:
|
||||
self.labels_checkbox.setChecked(display['show_labels'])
|
||||
|
||||
if 'show_confidence' in display:
|
||||
self.confidence_checkbox.setChecked(display['show_confidence'])
|
||||
|
||||
if 'show_performance' in display:
|
||||
self.perf_checkbox.setChecked(display['show_performance'])
|
||||
|
||||
if 'max_display_width' in display:
|
||||
self.max_width.setValue(display['max_display_width'])
|
||||
|
||||
# Violation settings
|
||||
violations = config.get('violations', {})
|
||||
if 'red_light_grace_period' in violations:
|
||||
self.red_light_grace.setValue(violations['red_light_grace_period'])
|
||||
|
||||
if 'stop_sign_duration' in violations:
|
||||
self.stop_sign_duration.setValue(violations['stop_sign_duration'])
|
||||
|
||||
if 'speed_tolerance' in violations:
|
||||
self.speed_tolerance.setValue(violations['speed_tolerance'])
|
||||
|
||||
if 'enable_red_light' in violations:
|
||||
self.enable_red_light.setChecked(violations['enable_red_light'])
|
||||
|
||||
if 'enable_stop_sign' in violations:
|
||||
self.enable_stop_sign.setChecked(violations['enable_stop_sign'])
|
||||
|
||||
if 'enable_speed' in violations:
|
||||
self.enable_speed.setChecked(violations['enable_speed'])
|
||||
|
||||
if 'enable_lane' in violations:
|
||||
self.enable_lane.setChecked(violations['enable_lane'])
|
||||
|
||||
# Analytics settings
|
||||
analytics = config.get('analytics', {})
|
||||
if 'enable_charts' in analytics:
|
||||
self.charts_checkbox.setChecked(analytics['enable_charts'])
|
||||
|
||||
if 'history_length' in analytics:
|
||||
self.history_spinbox.setValue(analytics['history_length'])
|
||||
|
||||
@Slot(object)
|
||||
def update_devices_info(self, device_info: dict):
|
||||
"""
|
||||
Update the OpenVINO devices info section with the given device info dict.
|
||||
"""
|
||||
print(f"[UI] update_devices_info called with: {device_info}", flush=True) # DEBUG
|
||||
if not device_info:
|
||||
self.devices_info_text.setText("<span style='color:#ffb300;'>No OpenVINO device info received.<br>Check if OpenVINO is installed and the backend emits device_info_ready.</span>")
|
||||
return
|
||||
if 'error' in device_info:
|
||||
self.devices_info_text.setText(f"<span style='color:#ff5370;'>Error: {device_info['error']}</span>")
|
||||
return
|
||||
text = ""
|
||||
for device, props in device_info.items():
|
||||
text += f"<b>{device}</b><br>"
|
||||
if isinstance(props, dict) and props:
|
||||
for k, v in props.items():
|
||||
text += f" <span style='color:#b2dfdb;'>{k}</span>: <span style='color:#fff'>{v}</span><br>"
|
||||
else:
|
||||
text += " <span style='color:#888'>No properties</span><br>"
|
||||
text += "<br>"
|
||||
self.devices_info_text.setText(f"<div style='font-size:13px;'>{text}</div>")
|
||||
self.devices_info_text.repaint() # Force repaint in case of async update
|
||||
Reference in New Issue
Block a user