Files
2025-08-26 13:24:53 -07:00

1002 lines
40 KiB
Python

# from PySide6.QtWidgets import (
# QWidget, QVBoxLayout, QHBoxLayout, QLabel, QPushButton, QSlider, QCheckBox,
# QFileDialog, QSizePolicy, QGridLayout, QFrame, QSpacerItem, QTabWidget,
# QComboBox, QSpinBox, QDoubleSpinBox, QGroupBox, QScrollArea, QTextEdit,
# QProgressBar, QSplitter, QListWidget, QListWidgetItem
# )
# from PySide6.QtCore import Signal, Qt, QTimer, QThread
# from PySide6.QtGui import QPixmap, QIcon, QFont, QPainter, QPen, QBrush, QColor
# import json
# import os
# from pathlib import Path
# class SmartIntersectionOverlay(QFrame):
# """Advanced overlay for Smart Intersection analytics."""
# def __init__(self, parent=None):
# super().__init__(parent)
# self.setStyleSheet("""
# background: rgba(0,20,40,0.85);
# border: 2px solid #03DAC5;
# border-radius: 12px;
# color: #fff;
# font-family: 'Consolas', 'SF Mono', 'monospace';
# font-size: 12px;
# """)
# self.setFixedHeight(140)
# self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
# self.setAttribute(Qt.WA_TransparentForMouseEvents)
# layout = QVBoxLayout(self)
# layout.setContentsMargins(16, 12, 16, 12)
# layout.setSpacing(4)
# # Title
# title = QLabel("🚦 Smart Intersection Analytics")
# title.setStyleSheet("color: #03DAC5; font-weight: bold; font-size: 14px;")
# layout.addWidget(title)
# # Scene data
# self.scene_label = QLabel("Scene: Multi-Camera Fusion")
# self.tracking_label = QLabel("Active Tracks: 0")
# self.roi_label = QLabel("ROI Events: 0")
# # Camera data
# self.camera_label = QLabel("Cameras: North(0) East(0) South(0) West(0)")
# # Analytics data
# self.analytics_label = QLabel("Analytics: Crosswalk(0) Lane(0) Safety(0)")
# for w in [self.scene_label, self.tracking_label, self.roi_label,
# self.camera_label, self.analytics_label]:
# w.setStyleSheet("color: #fff;")
# layout.addWidget(w)
# def update_smart_intersection(self, scene_data):
# """Update smart intersection specific data"""
# if not scene_data:
# return
# # Update tracking info
# active_tracks = scene_data.get('active_tracks', 0)
# self.tracking_label.setText(f"Active Tracks: {active_tracks}")
# # Update ROI events
# roi_events = scene_data.get('roi_events', 0)
# self.roi_label.setText(f"ROI Events: {roi_events}")
# # Update camera data
# cameras = scene_data.get('cameras', {})
# north = cameras.get('north', 0)
# east = cameras.get('east', 0)
# south = cameras.get('south', 0)
# west = cameras.get('west', 0)
# self.camera_label.setText(f"Cameras: North({north}) East({east}) South({south}) West({west})")
# # Update analytics
# analytics = scene_data.get('analytics', {})
# crosswalk = analytics.get('crosswalk_events', 0)
# lane = analytics.get('lane_events', 0)
# safety = analytics.get('safety_events', 0)
# self.analytics_label.setText(f"Analytics: Crosswalk({crosswalk}) Lane({lane}) Safety({safety})")
# class IntersectionROIWidget(QFrame):
# """Widget for defining and managing ROI regions for smart intersection"""
# roi_updated = Signal(dict)
# def __init__(self, parent=None):
# super().__init__(parent)
# self.setStyleSheet("""
# QFrame {
# background: #1a1a1a;
# border: 1px solid #424242;
# border-radius: 8px;
# }
# """)
# self.setFixedWidth(300)
# layout = QVBoxLayout(self)
# layout.setContentsMargins(16, 16, 16, 16)
# # Title
# title = QLabel("🎯 Region of Interest (ROI)")
# title.setStyleSheet("color: #03DAC5; font-weight: bold; font-size: 14px;")
# layout.addWidget(title)
# # ROI Type selection
# type_layout = QHBoxLayout()
# type_layout.addWidget(QLabel("Type:"))
# self.roi_type = QComboBox()
# self.roi_type.addItems(["Crosswalk", "Traffic Lane", "Safety Zone", "Intersection Center"])
# type_layout.addWidget(self.roi_type)
# layout.addLayout(type_layout)
# # ROI List
# self.roi_list = QListWidget()
# self.roi_list.setMaximumHeight(120)
# layout.addWidget(self.roi_list)
# # ROI Controls
# roi_controls = QHBoxLayout()
# self.add_roi_btn = QPushButton("Add ROI")
# self.delete_roi_btn = QPushButton("Delete")
# self.add_roi_btn.setStyleSheet("background: #27ae60; color: white; border-radius: 4px; padding: 6px;")
# self.delete_roi_btn.setStyleSheet("background: #e74c3c; color: white; border-radius: 4px; padding: 6px;")
# roi_controls.addWidget(self.add_roi_btn)
# roi_controls.addWidget(self.delete_roi_btn)
# layout.addLayout(roi_controls)
# # Analytics settings
# analytics_group = QGroupBox("Analytics Settings")
# analytics_layout = QVBoxLayout(analytics_group)
# self.enable_tracking = QCheckBox("Multi-Object Tracking")
# self.enable_speed = QCheckBox("Speed Estimation")
# self.enable_direction = QCheckBox("Direction Analysis")
# self.enable_safety = QCheckBox("Safety Monitoring")
# for cb in [self.enable_tracking, self.enable_speed, self.enable_direction, self.enable_safety]:
# cb.setChecked(True)
# cb.setStyleSheet("color: white;")
# analytics_layout.addWidget(cb)
# layout.addWidget(analytics_group)
# # Connect signals
# self.add_roi_btn.clicked.connect(self._add_roi)
# self.delete_roi_btn.clicked.connect(self._delete_roi)
# # Initialize with default ROIs
# self._init_default_rois()
# def _init_default_rois(self):
# """Initialize with default intersection ROIs"""
# default_rois = [
# "North Crosswalk",
# "South Crosswalk",
# "East Crosswalk",
# "West Crosswalk",
# "Center Intersection",
# "North Lane",
# "South Lane",
# "East Lane",
# "West Lane"
# ]
# for roi in default_rois:
# item = QListWidgetItem(roi)
# item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
# item.setCheckState(Qt.Checked)
# self.roi_list.addItem(item)
# def _add_roi(self):
# """Add new ROI"""
# roi_type = self.roi_type.currentText()
# roi_name = f"{roi_type}_{self.roi_list.count() + 1}"
# item = QListWidgetItem(roi_name)
# item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
# item.setCheckState(Qt.Checked)
# self.roi_list.addItem(item)
# self._emit_roi_update()
# def _delete_roi(self):
# """Delete selected ROI"""
# current_row = self.roi_list.currentRow()
# if current_row >= 0:
# self.roi_list.takeItem(current_row)
# self._emit_roi_update()
# def _emit_roi_update(self):
# """Emit ROI configuration update"""
# roi_config = {
# 'rois': [],
# 'analytics': {
# 'tracking': self.enable_tracking.isChecked(),
# 'speed': self.enable_speed.isChecked(),
# 'direction': self.enable_direction.isChecked(),
# 'safety': self.enable_safety.isChecked()
# }
# }
# for i in range(self.roi_list.count()):
# item = self.roi_list.item(i)
# roi_config['rois'].append({
# 'name': item.text(),
# 'enabled': item.checkState() == Qt.Checked
# })
# self.roi_updated.emit(roi_config)
# class MultiCameraView(QFrame):
# """Multi-camera view for smart intersection"""
# def __init__(self, parent=None):
# super().__init__(parent)
# self.setStyleSheet("""
# QFrame {
# background: #0a0a0a;
# border: 2px solid #424242;
# border-radius: 8px;
# }
# """)
# layout = QGridLayout(self)
# layout.setContentsMargins(8, 8, 8, 8)
# layout.setSpacing(4)
# # Create camera views
# self.camera_views = {}
# positions = [('North', 0, 1), ('West', 1, 0), ('East', 1, 2), ('South', 2, 1)]
# for pos_name, row, col in positions:
# view = self._create_camera_view(pos_name)
# self.camera_views[pos_name.lower()] = view
# layout.addWidget(view, row, col)
# # Center intersection view
# center_view = self._create_intersection_center()
# layout.addWidget(center_view, 1, 1)
# def _create_camera_view(self, position):
# """Create individual camera view"""
# view = QFrame()
# view.setStyleSheet("""
# background: #1a1a1a;
# border: 1px solid #555;
# border-radius: 4px;
# """)
# view.setMinimumSize(160, 120)
# view.setMaximumSize(200, 150)
# layout = QVBoxLayout(view)
# layout.setContentsMargins(4, 4, 4, 4)
# # Title
# title = QLabel(f"📹 {position}")
# title.setStyleSheet("color: #03DAC5; font-weight: bold; font-size: 10px;")
# title.setAlignment(Qt.AlignCenter)
# layout.addWidget(title)
# # Video area
# video_area = QLabel("No feed")
# video_area.setStyleSheet("background: #000; color: #666; border: 1px dashed #333;")
# video_area.setAlignment(Qt.AlignCenter)
# video_area.setMinimumHeight(80)
# layout.addWidget(video_area)
# # Stats
# stats = QLabel("Objects: 0")
# stats.setStyleSheet("color: #aaa; font-size: 9px;")
# stats.setAlignment(Qt.AlignCenter)
# layout.addWidget(stats)
# return view
# def _create_intersection_center(self):
# """Create center intersection overview"""
# view = QFrame()
# view.setStyleSheet("""
# background: #2a1a1a;
# border: 2px solid #03DAC5;
# border-radius: 8px;
# """)
# view.setMinimumSize(160, 120)
# view.setMaximumSize(200, 150)
# layout = QVBoxLayout(view)
# layout.setContentsMargins(8, 8, 8, 8)
# title = QLabel("🚦 Intersection")
# title.setStyleSheet("color: #03DAC5; font-weight: bold; font-size: 12px;")
# title.setAlignment(Qt.AlignCenter)
# layout.addWidget(title)
# # Intersection map
# map_area = QLabel("Scene Map")
# map_area.setStyleSheet("background: #000; color: #03DAC5; border: 1px solid #03DAC5;")
# map_area.setAlignment(Qt.AlignCenter)
# map_area.setMinimumHeight(80)
# layout.addWidget(map_area)
# # Total stats
# total_stats = QLabel("Total Objects: 0")
# total_stats.setStyleSheet("color: #03DAC5; font-size: 10px; font-weight: bold;")
# total_stats.setAlignment(Qt.AlignCenter)
# layout.addWidget(total_stats)
# return view
# def update_camera_feed(self, camera_position, pixmap, object_count=0):
# """Update specific camera feed"""
# if camera_position.lower() in self.camera_views:
# view = self.camera_views[camera_position.lower()]
# video_label = view.findChild(QLabel)
# if video_label and pixmap:
# scaled = pixmap.scaled(video_label.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation)
# video_label.setPixmap(scaled)
# # Update stats
# stats_labels = view.findChildren(QLabel)
# if len(stats_labels) >= 3: # title, video, stats
# stats_labels[2].setText(f"Objects: {object_count}")
# class DiagnosticOverlay(QFrame):
# """Semi-transparent overlay for diagnostics."""
# def __init__(self, parent=None):
# super().__init__(parent)
# self.setStyleSheet("""
# background: rgba(0,0,0,0.5);
# border-radius: 8px;
# color: #fff;
# font-family: 'Consolas', 'SF Mono', 'monospace';
# font-size: 13px;
# """)
# # self.setFixedWidth(260) # Remove fixed width
# self.setFixedHeight(90)
# self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) # Allow horizontal stretch
# self.setAttribute(Qt.WA_TransparentForMouseEvents)
# layout = QVBoxLayout(self)
# layout.setContentsMargins(12, 8, 12, 8)
# self.model_label = QLabel("Model: -")
# self.device_label = QLabel("Device: -")
# self.stats_label = QLabel("Cars: 0 | Trucks: 0 | Ped: 0 | TLights: 0 | Moto: 0")
# for w in [self.model_label, self.device_label, self.stats_label]:
# w.setStyleSheet("color: #fff;")
# layout.addWidget(w)
# layout.addStretch(1)
# def update_overlay(self, model, device, cars, trucks, peds, tlights, motorcycles):
# self.model_label.setText(f"Model: {model}")
# self.device_label.setText(f"Device: {device}")
# self.stats_label.setText(f"Cars: {cars} | Trucks: {trucks} | Ped: {peds} | TLights: {tlights} | Moto: {motorcycles}")
# class VideoDetectionTab(QWidget):
# file_selected = Signal(str)
# play_clicked = Signal()
# pause_clicked = Signal()
# stop_clicked = Signal()
# detection_toggled = Signal(bool)
# screenshot_clicked = Signal()
# seek_changed = Signal(int)
# auto_select_model_device = Signal()
# # Smart Intersection signals
# smart_intersection_enabled = Signal(bool)
# multi_camera_mode_enabled = Signal(bool)
# roi_configuration_changed = Signal(dict)
# scene_analytics_toggled = Signal(bool)
# def __init__(self):
# super().__init__()
# self.video_loaded = False
# self.smart_intersection_mode = False
# self.multi_camera_mode = False
# # Load smart intersection config
# self.load_smart_intersection_config()
# # Main layout
# main_layout = QHBoxLayout(self)
# main_layout.setContentsMargins(16, 16, 16, 16)
# main_layout.setSpacing(16)
# # Left panel - video and controls
# left_panel = self._create_left_panel()
# main_layout.addWidget(left_panel, 3) # 3/4 of the space
# # Right panel - smart intersection controls
# right_panel = self._create_right_panel()
# main_layout.addWidget(right_panel, 1) # 1/4 of the space
# def load_smart_intersection_config(self):
# """Load smart intersection configuration"""
# config_path = Path(__file__).parent.parent / "config" / "smart-intersection" / "desktop-config.json"
# try:
# if config_path.exists():
# with open(config_path, 'r') as f:
# self.smart_config = json.load(f)
# else:
# self.smart_config = self._get_default_config()
# except Exception as e:
# print(f"Error loading smart intersection config: {e}")
# self.smart_config = self._get_default_config()
# def _get_default_config(self):
# """Get default smart intersection configuration"""
# return {
# "desktop_app_config": {
# "scene_analytics": {
# "enable_multi_camera": True,
# "enable_roi_analytics": True,
# "enable_vlm_integration": True
# },
# "camera_settings": {
# "max_cameras": 4,
# "default_fps": 30
# },
# "analytics_settings": {
# "object_tracking": True,
# "speed_estimation": True,
# "direction_analysis": True,
# "safety_monitoring": True
# }
# }
# }
# def _create_left_panel(self):
# """Create main video panel"""
# panel = QWidget()
# layout = QVBoxLayout(panel)
# layout.setContentsMargins(0, 0, 0, 0)
# layout.setSpacing(16)
# # Smart Intersection Mode Toggle
# mode_bar = self._create_mode_bar()
# layout.addWidget(mode_bar)
# # File select bar
# file_bar = self._create_file_bar()
# layout.addWidget(file_bar)
# # Video display area (with tabs for different modes)
# self.video_tabs = QTabWidget()
# self.video_tabs.setStyleSheet("""
# QTabWidget::pane {
# border: 1px solid #424242;
# background: #121212;
# border-radius: 8px;
# }
# QTabBar::tab {
# background: #232323;
# color: #fff;
# padding: 8px 16px;
# margin-right: 2px;
# border-top-left-radius: 8px;
# border-top-right-radius: 8px;
# }
# QTabBar::tab:selected {
# background: #03DAC5;
# color: #000;
# }
# """)
# # Single camera tab
# self.single_cam_widget = self._create_single_camera_view()
# self.video_tabs.addTab(self.single_cam_widget, "📹 Single Camera")
# # Multi-camera tab
# self.multi_cam_widget = MultiCameraView()
# self.video_tabs.addTab(self.multi_cam_widget, "🚦 Multi-Camera Intersection")
# layout.addWidget(self.video_tabs)
# # Analytics overlay
# self.analytics_overlay = self._create_analytics_overlay()
# layout.addWidget(self.analytics_overlay)
# # Control bar
# control_bar = self._create_control_bar()
# layout.addWidget(control_bar)
# return panel
# def _create_mode_bar(self):
# """Create smart intersection mode toggle bar"""
# bar = QFrame()
# bar.setStyleSheet("""
# QFrame {
# background: #1a2332;
# border: 2px solid #03DAC5;
# border-radius: 12px;
# padding: 8px;
# }
# """)
# bar.setFixedHeight(60)
# layout = QHBoxLayout(bar)
# layout.setContentsMargins(16, 8, 16, 8)
# # Smart Intersection Toggle
# self.smart_intersection_toggle = QCheckBox("🚦 Smart Intersection Mode")
# self.smart_intersection_toggle.setStyleSheet("""
# QCheckBox {
# color: #03DAC5;
# font-weight: bold;
# font-size: 14px;
# }
# QCheckBox::indicator {
# width: 20px;
# height: 20px;
# }
# QCheckBox::indicator:checked {
# background: #03DAC5;
# border: 2px solid #03DAC5;
# border-radius: 4px;
# }
# """)
# self.smart_intersection_toggle.toggled.connect(self._toggle_smart_intersection)
# layout.addWidget(self.smart_intersection_toggle)
# layout.addSpacing(32)
# # Multi-camera Toggle
# self.multi_camera_toggle = QCheckBox("📹 Multi-Camera Fusion")
# self.multi_camera_toggle.setStyleSheet("""
# QCheckBox {
# color: #e67e22;
# font-weight: bold;
# font-size: 14px;
# }
# QCheckBox::indicator {
# width: 20px;
# height: 20px;
# }
# QCheckBox::indicator:checked {
# background: #e67e22;
# border: 2px solid #e67e22;
# border-radius: 4px;
# }
# """)
# self.multi_camera_toggle.toggled.connect(self._toggle_multi_camera)
# layout.addWidget(self.multi_camera_toggle)
# layout.addStretch()
# # Status indicator
# self.mode_status = QLabel("Standard Detection Mode")
# self.mode_status.setStyleSheet("color: #bbb; font-size: 12px;")
# layout.addWidget(self.mode_status)
# return bar
# def _create_file_bar(self):
# """Create file selection bar"""
# widget = QWidget()
# bar = QHBoxLayout(widget)
# self.file_btn = QPushButton()
# self.file_btn.setIcon(QIcon.fromTheme("folder-video"))
# self.file_btn.setText("Select Video")
# self.file_btn.setStyleSheet("padding: 8px 18px; border-radius: 8px; background: #232323; color: #fff;")
# self.file_label = QLabel("No file selected")
# self.file_label.setStyleSheet("color: #bbb; font-size: 13px;")
# self.file_btn.clicked.connect(self._select_file)
# bar.addWidget(self.file_btn)
# bar.addWidget(self.file_label)
# bar.addStretch()
# return widget
# def _create_single_camera_view(self):
# """Create single camera view widget"""
# widget = QWidget()
# layout = QVBoxLayout(widget)
# layout.setContentsMargins(0, 0, 0, 0)
# # Video frame
# video_frame = QFrame()
# video_frame.setStyleSheet("""
# background: #121212;
# border: 1px solid #424242;
# border-radius: 8px;
# """)
# video_frame.setMinimumSize(640, 360)
# video_frame.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
# video_layout = QVBoxLayout(video_frame)
# video_layout.setContentsMargins(0, 0, 0, 0)
# video_layout.setAlignment(Qt.AlignCenter)
# self.video_label = QLabel()
# self.video_label.setAlignment(Qt.AlignCenter)
# self.video_label.setStyleSheet("background: transparent; color: #888; font-size: 18px;")
# self.video_label.setText("No video loaded. Please select a file.")
# self.video_label.setMinimumSize(640, 360)
# self.video_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
# video_layout.addWidget(self.video_label)
# layout.addWidget(video_frame)
# return widget
# def _create_analytics_overlay(self):
# """Create analytics overlay that switches based on mode"""
# container = QWidget()
# self.overlay_layout = QVBoxLayout(container)
# self.overlay_layout.setContentsMargins(0, 0, 0, 0)
# # Standard overlay
# self.standard_overlay = DiagnosticOverlay()
# self.standard_overlay.setStyleSheet(self.standard_overlay.styleSheet() + "border: 1px solid #03DAC5;")
# # Smart intersection overlay
# self.smart_overlay = SmartIntersectionOverlay()
# # Badge bar
# self.badge_bar = QHBoxLayout()
# self.badge_bar.setContentsMargins(0, 8, 0, 8)
# self.fps_badge = QLabel("FPS: --")
# self.fps_badge.setStyleSheet("background: #27ae60; color: #fff; border-radius: 12px; padding: 4px 24px; font-weight: bold; font-size: 15px;")
# self.fps_badge.setAlignment(Qt.AlignCenter)
# self.inference_badge = QLabel("Inference: -- ms")
# self.inference_badge.setStyleSheet("background: #2980b9; color: #fff; border-radius: 12px; padding: 4px 24px; font-weight: bold; font-size: 15px;")
# self.inference_badge.setAlignment(Qt.AlignCenter)
# self.badge_bar.addWidget(self.fps_badge)
# self.badge_bar.addSpacing(12)
# self.badge_bar.addWidget(self.inference_badge)
# self.badge_bar.addSpacing(18)
# # Add current overlay (start with standard)
# self.current_overlay = self.standard_overlay
# self.badge_bar.addWidget(self.current_overlay)
# self.badge_bar.addStretch()
# self.overlay_layout.addLayout(self.badge_bar)
# return container
# def _create_control_bar(self):
# """Create control bar"""
# widget = QWidget()
# control_bar = QHBoxLayout(widget)
# control_bar.setContentsMargins(0, 16, 0, 0)
# # Playback controls
# self.play_btn = QPushButton()
# self.play_btn.setIcon(QIcon.fromTheme("media-playback-start"))
# self.play_btn.setToolTip("Play")
# self.play_btn.setFixedSize(48, 48)
# self.play_btn.setEnabled(False)
# self.play_btn.setStyleSheet(self._button_style())
# self.pause_btn = QPushButton()
# self.pause_btn.setIcon(QIcon.fromTheme("media-playback-pause"))
# self.pause_btn.setToolTip("Pause")
# self.pause_btn.setFixedSize(48, 48)
# self.pause_btn.setEnabled(False)
# self.pause_btn.setStyleSheet(self._button_style())
# self.stop_btn = QPushButton()
# self.stop_btn.setIcon(QIcon.fromTheme("media-playback-stop"))
# self.stop_btn.setToolTip("Stop")
# self.stop_btn.setFixedSize(48, 48)
# self.stop_btn.setEnabled(False)
# self.stop_btn.setStyleSheet(self._button_style())
# for btn, sig in zip([self.play_btn, self.pause_btn, self.stop_btn],
# [self.play_clicked.emit, self.pause_clicked.emit, self.stop_clicked.emit]):
# btn.clicked.connect(sig)
# control_bar.addWidget(self.play_btn)
# control_bar.addWidget(self.pause_btn)
# control_bar.addWidget(self.stop_btn)
# control_bar.addSpacing(16)
# # Progress bar
# self.progress = QSlider(Qt.Horizontal)
# self.progress.setStyleSheet("QSlider::groove:horizontal { height: 6px; background: #232323; border-radius: 3px; } QSlider::handle:horizontal { background: #03DAC5; border-radius: 8px; width: 18px; }")
# self.progress.setMinimumWidth(240)
# self.progress.setEnabled(False)
# self.progress.valueChanged.connect(self.seek_changed.emit)
# control_bar.addWidget(self.progress, 2)
# self.timestamp = QLabel("00:00 / 00:00")
# self.timestamp.setStyleSheet("color: #bbb; font-size: 13px;")
# control_bar.addWidget(self.timestamp)
# control_bar.addSpacing(16)
# # Detection toggle & screenshot
# self.detection_toggle = QCheckBox("Enable Detection")
# self.detection_toggle.setChecked(True)
# self.detection_toggle.setStyleSheet("color: #fff; font-size: 14px;")
# self.detection_toggle.setEnabled(False)
# self.detection_toggle.toggled.connect(self.detection_toggled.emit)
# control_bar.addWidget(self.detection_toggle)
# self.screenshot_btn = QPushButton()
# self.screenshot_btn.setIcon(QIcon.fromTheme("camera-photo"))
# self.screenshot_btn.setText("Screenshot")
# self.screenshot_btn.setToolTip("Save current frame as image")
# self.screenshot_btn.setEnabled(False)
# self.screenshot_btn.setStyleSheet(self._button_style())
# self.screenshot_btn.clicked.connect(self.screenshot_clicked.emit)
# control_bar.addWidget(self.screenshot_btn)
# control_bar.addStretch()
# return widget
# def _create_right_panel(self):
# """Create right panel for smart intersection controls"""
# panel = QScrollArea()
# panel.setWidgetResizable(True)
# panel.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
# panel.setStyleSheet("""
# QScrollArea {
# background: #1a1a1a;
# border: 1px solid #424242;
# border-radius: 8px;
# }
# """)
# content = QWidget()
# layout = QVBoxLayout(content)
# layout.setContentsMargins(16, 16, 16, 16)
# layout.setSpacing(16)
# # Smart Intersection Controls
# intersection_group = QGroupBox("🚦 Smart Intersection")
# intersection_group.setStyleSheet("""
# QGroupBox {
# color: #03DAC5;
# font-weight: bold;
# font-size: 14px;
# border: 2px solid #03DAC5;
# border-radius: 8px;
# margin-top: 12px;
# padding-top: 8px;
# }
# QGroupBox::title {
# subcontrol-origin: margin;
# left: 16px;
# padding: 0 8px 0 8px;
# }
# """)
# intersection_layout = QVBoxLayout(intersection_group)
# # Scene Analytics Toggle
# self.scene_analytics_toggle = QCheckBox("Scene Analytics")
# self.scene_analytics_toggle.setChecked(True)
# self.scene_analytics_toggle.setStyleSheet("color: white; font-size: 12px;")
# self.scene_analytics_toggle.toggled.connect(self.scene_analytics_toggled.emit)
# intersection_layout.addWidget(self.scene_analytics_toggle)
# # Multi-object tracking
# self.multi_tracking_toggle = QCheckBox("Multi-Object Tracking")
# self.multi_tracking_toggle.setChecked(True)
# self.multi_tracking_toggle.setStyleSheet("color: white; font-size: 12px;")
# intersection_layout.addWidget(self.multi_tracking_toggle)
# # Speed estimation
# self.speed_estimation_toggle = QCheckBox("Speed Estimation")
# self.speed_estimation_toggle.setChecked(True)
# self.speed_estimation_toggle.setStyleSheet("color: white; font-size: 12px;")
# intersection_layout.addWidget(self.speed_estimation_toggle)
# layout.addWidget(intersection_group)
# # ROI Management
# self.roi_widget = IntersectionROIWidget()
# self.roi_widget.roi_updated.connect(self.roi_configuration_changed.emit)
# layout.addWidget(self.roi_widget)
# # Analytics Summary
# analytics_group = QGroupBox("📊 Analytics Summary")
# analytics_group.setStyleSheet(intersection_group.styleSheet().replace("#03DAC5", "#e67e22"))
# analytics_layout = QVBoxLayout(analytics_group)
# self.total_objects_label = QLabel("Total Objects: 0")
# self.crosswalk_events_label = QLabel("Crosswalk Events: 0")
# self.lane_events_label = QLabel("Lane Violations: 0")
# self.safety_alerts_label = QLabel("Safety Alerts: 0")
# for label in [self.total_objects_label, self.crosswalk_events_label,
# self.lane_events_label, self.safety_alerts_label]:
# label.setStyleSheet("color: white; font-size: 12px;")
# analytics_layout.addWidget(label)
# layout.addWidget(analytics_group)
# # Performance Monitoring
# perf_group = QGroupBox("⚡ Performance")
# perf_group.setStyleSheet(intersection_group.styleSheet().replace("#03DAC5", "#9b59b6"))
# perf_layout = QVBoxLayout(perf_group)
# self.gpu_usage_label = QLabel("GPU Usage: -%")
# self.memory_usage_label = QLabel("Memory: - MB")
# self.processing_time_label = QLabel("Processing: - ms")
# for label in [self.gpu_usage_label, self.memory_usage_label, self.processing_time_label]:
# label.setStyleSheet("color: white; font-size: 12px;")
# perf_layout.addWidget(label)
# layout.addWidget(perf_group)
# layout.addStretch()
# panel.setWidget(content)
# return panel
# def _toggle_smart_intersection(self, enabled):
# """Toggle smart intersection mode"""
# self.smart_intersection_mode = enabled
# self.smart_intersection_enabled.emit(enabled)
# # Switch overlay
# if enabled:
# self._switch_to_smart_overlay()
# self.mode_status.setText("🚦 Smart Intersection Active")
# self.mode_status.setStyleSheet("color: #03DAC5; font-weight: bold; font-size: 12px;")
# else:
# self._switch_to_standard_overlay()
# self.mode_status.setText("Standard Detection Mode")
# self.mode_status.setStyleSheet("color: #bbb; font-size: 12px;")
# # Enable/disable multi-camera toggle
# self.multi_camera_toggle.setEnabled(enabled)
# if not enabled:
# self.multi_camera_toggle.setChecked(False)
# def _toggle_multi_camera(self, enabled):
# """Toggle multi-camera mode"""
# self.multi_camera_mode = enabled
# self.multi_camera_mode_enabled.emit(enabled)
# if enabled:
# self.video_tabs.setCurrentIndex(1) # Switch to multi-camera tab
# self.mode_status.setText("🚦 Multi-Camera Intersection Active")
# else:
# self.video_tabs.setCurrentIndex(0) # Switch to single camera tab
# if self.smart_intersection_mode:
# self.mode_status.setText("🚦 Smart Intersection Active")
# def _switch_to_smart_overlay(self):
# """Switch to smart intersection overlay"""
# self.badge_bar.removeWidget(self.current_overlay)
# self.current_overlay.setParent(None)
# self.current_overlay = self.smart_overlay
# self.badge_bar.addWidget(self.current_overlay)
# def _switch_to_standard_overlay(self):
# """Switch to standard overlay"""
# self.badge_bar.removeWidget(self.current_overlay)
# self.current_overlay.setParent(None)
# self.current_overlay = self.standard_overlay
# self.badge_bar.addWidget(self.current_overlay)
# def _button_style(self):
# return """
# QPushButton {
# background: #232323;
# border-radius: 24px;
# color: #fff;
# font-size: 15px;
# border: none;
# }
# QPushButton:hover {
# background: #03DAC5;
# color: #222;
# }
# QPushButton:pressed {
# background: #018786;
# }
# """
# def _select_file(self):
# file_path, _ = QFileDialog.getOpenFileName(self, "Select Video File", "", "Video Files (*.mp4 *.avi *.mov *.mkv *.webm);;All Files (*)")
# if file_path:
# self.file_label.setText(file_path)
# self.file_selected.emit(file_path)
# self.video_loaded = True
# self._enable_controls(True)
# self.video_label.setText("")
# self.auto_select_model_device.emit()
# def _enable_controls(self, enabled):
# self.play_btn.setEnabled(enabled)
# self.pause_btn.setEnabled(enabled)
# self.stop_btn.setEnabled(enabled)
# self.progress.setEnabled(enabled)
# self.detection_toggle.setEnabled(enabled)
# self.screenshot_btn.setEnabled(enabled)
# if enabled:
# self.auto_select_model_device.emit()
# def update_display(self, pixmap):
# """Update display with new frame"""
# if pixmap:
# if self.multi_camera_mode:
# # In multi-camera mode, distribute to different camera views
# # For now, just update the single view
# scaled = pixmap.scaled(self.video_label.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation)
# self.video_label.setPixmap(scaled)
# else:
# scaled = pixmap.scaled(self.video_label.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation)
# self.video_label.setPixmap(scaled)
# self._set_controls_enabled(True)
# self.video_label.setStyleSheet("background: transparent; color: #888; font-size: 18px;")
# else:
# self.video_label.clear()
# self.video_label.setText("No video loaded. Please select a video file.")
# self._set_controls_enabled(False)
# self.video_label.setStyleSheet("background: transparent; color: #F44336; font-size: 18px;")
# def _set_controls_enabled(self, enabled):
# for btn in [self.play_btn, self.pause_btn, self.stop_btn, self.progress, self.detection_toggle, self.screenshot_btn]:
# btn.setEnabled(enabled)
# def update_stats(self, stats):
# """Update statistics display"""
# if self.smart_intersection_mode:
# # Update smart intersection overlay
# scene_data = {
# 'active_tracks': stats.get('total_objects', 0),
# 'roi_events': stats.get('roi_events', 0),
# 'cameras': {
# 'north': stats.get('north_objects', 0),
# 'east': stats.get('east_objects', 0),
# 'south': stats.get('south_objects', 0),
# 'west': stats.get('west_objects', 0)
# },
# 'analytics': {
# 'crosswalk_events': stats.get('crosswalk_events', 0),
# 'lane_events': stats.get('lane_events', 0),
# 'safety_events': stats.get('safety_events', 0)
# }
# }
# self.smart_overlay.update_smart_intersection(scene_data)
# # Update right panel analytics
# self.total_objects_label.setText(f"Total Objects: {stats.get('total_objects', 0)}")
# self.crosswalk_events_label.setText(f"Crosswalk Events: {stats.get('crosswalk_events', 0)}")
# self.lane_events_label.setText(f"Lane Violations: {stats.get('lane_events', 0)}")
# self.safety_alerts_label.setText(f"Safety Alerts: {stats.get('safety_events', 0)}")
# else:
# # Update standard overlay
# cars = stats.get('cars', 0)
# trucks = stats.get('trucks', 0)
# peds = stats.get('peds', 0)
# tlights = stats.get('tlights', 0)
# motorcycles = stats.get('motorcycles', 0)
# model = stats.get('model', stats.get('model_name', '-'))
# device = stats.get('device', stats.get('device_name', '-'))
# self.standard_overlay.update_overlay(model, device, cars, trucks, peds, tlights, motorcycles)
# # Update performance badges
# fps = stats.get('fps', None)
# inference = stats.get('inference', stats.get('detection_time', stats.get('detection_time_ms', None)))
# if fps is not None:
# self.fps_badge.setText(f"FPS: {fps:.2f}")
# else:
# self.fps_badge.setText("FPS: --")
# if inference is not None:
# self.inference_badge.setText(f"Inference: {inference:.1f} ms")
# else:
# self.inference_badge.setText("Inference: -- ms")
# # Update performance panel
# self.gpu_usage_label.setText(f"GPU Usage: {stats.get('gpu_usage', 0):.1f}%")
# self.memory_usage_label.setText(f"Memory: {stats.get('memory_usage', 0):.1f} MB")
# self.processing_time_label.setText(f"Processing: {stats.get('processing_time', 0):.1f} ms")
# def update_progress(self, value, max_value, timestamp):
# self.progress.setMaximum(max_value)
# self.progress.setValue(value)
# if isinstance(timestamp, float) or isinstance(timestamp, int):
# timestamp_str = f"{timestamp:.2f}"
# else:
# timestamp_str = str(timestamp)
# self.timestamp.setText(timestamp_str)
# def update_multi_camera_feed(self, camera_position, pixmap, object_count=0):
# """Update specific camera feed in multi-camera mode"""
# if self.multi_camera_mode:
# self.multi_cam_widget.update_camera_feed(camera_position, pixmap, object_count)
# def get_smart_intersection_config(self):
# """Get current smart intersection configuration"""
# return {
# 'enabled': self.smart_intersection_mode,
# 'multi_camera': self.multi_camera_mode,
# 'scene_analytics': self.scene_analytics_toggle.isChecked(),
# 'multi_tracking': self.multi_tracking_toggle.isChecked(),
# 'speed_estimation': self.speed_estimation_toggle.isChecked()
# }