from PySide6.QtWidgets import ( QMainWindow, QTabWidget, QDockWidget, QMessageBox, QApplication, QFileDialog, QSplashScreen ) from PySide6.QtCore import Qt, QTimer, QSettings, QSize, Slot from PySide6.QtGui import QIcon, QPixmap, QAction import os import sys import json import time import traceback from datetime import datetime from pathlib import Path print("β Basic PySide6 imports successful") print("π LOADING MODERN UI - main_window1.py") print("=" * 50) # Custom exception handler for Qt # Ensure Qt is imported before using Qt.qInstallMessageHandler try: from PySide6.QtCore import Qt as QtCoreQt if hasattr(QtCoreQt, 'qInstallMessageHandler'): def qt_message_handler(mode, context, message): print(f"Qt Message: {message} (Mode: {mode})") QtCoreQt.qInstallMessageHandler(qt_message_handler) except Exception as e: print(f"β οΈ Could not install Qt message handler: {e}") # Import UI components with fallback handling try: from ui.fixed_live_tab import LiveTab print("β Imported LiveTab") except ImportError as e: print(f"β οΈ Could not import LiveTab: {e}") # Create a basic fallback LiveTab from PySide6.QtWidgets import QWidget, QLabel, QVBoxLayout from PySide6.QtCore import Signal class LiveTab(QWidget): source_changed = Signal(object) video_dropped = Signal(object) snapshot_requested = Signal() run_requested = Signal(bool) def __init__(self): super().__init__() self.current_source = None layout = QVBoxLayout(self) label = QLabel("Live Tab (Fallback Mode)") layout.addWidget(label) def update_display(self, *args): pass def update_display_np(self, *args): pass def update_stats(self, *args): pass try: from ui.analytics_tab import AnalyticsTab print("β Imported AnalyticsTab") except ImportError as e: print(f"β οΈ Could not import AnalyticsTab: {e}") from PySide6.QtWidgets import QWidget, QLabel, QVBoxLayout class AnalyticsTab(QWidget): def __init__(self): super().__init__() layout = QVBoxLayout(self) label = QLabel("Analytics Tab (Fallback Mode)") layout.addWidget(label) def update_analytics(self, *args): pass try: from ui.violations_tab import ViolationsTab print("β Imported ViolationsTab") except ImportError as e: print(f"β οΈ Could not import ViolationsTab: {e}") from PySide6.QtWidgets import QWidget, QLabel, QVBoxLayout, QPushButton class ViolationsTab(QWidget): def __init__(self): super().__init__() layout = QVBoxLayout(self) label = QLabel("Violations Tab (Fallback Mode)") self.clear_btn = QPushButton("Clear") layout.addWidget(label) layout.addWidget(self.clear_btn) def add_violation(self, *args): pass try: from ui.export_tab import ExportTab print("β Imported ExportTab") except ImportError as e: print(f"β οΈ Could not import ExportTab: {e}") from PySide6.QtWidgets import QWidget, QLabel, QVBoxLayout, QPushButton, QComboBox class ExportTab(QWidget): def __init__(self): super().__init__() layout = QVBoxLayout(self) label = QLabel("Export Tab (Fallback Mode)") self.export_format_combo = QComboBox() self.export_data_combo = QComboBox() self.reset_btn = QPushButton("Reset") self.save_config_btn = QPushButton("Save Config") self.reload_config_btn = QPushButton("Reload Config") self.export_btn = QPushButton("Export") layout.addWidget(label) layout.addWidget(self.export_format_combo) layout.addWidget(self.export_data_combo) layout.addWidget(self.reset_btn) layout.addWidget(self.save_config_btn) layout.addWidget(self.reload_config_btn) layout.addWidget(self.export_btn) def update_config_display(self, *args): pass def update_export_preview(self, *args): pass def get_config_from_ui(self): return {} try: from ui.config_panel import ConfigPanel print("β Imported ConfigPanel") except ImportError as e: print(f"β οΈ Could not import ConfigPanel: {e}") from PySide6.QtWidgets import QWidget, QLabel, QVBoxLayout from PySide6.QtCore import Signal class ConfigPanel(QWidget): config_changed = Signal(dict) theme_toggled = Signal(bool) def __init__(self): super().__init__() layout = QVBoxLayout(self) label = QLabel("Config Panel (Fallback Mode)") layout.addWidget(label) def set_config(self, *args): pass def reset_config(self): pass # Import controllers with fallback handling try: from controllers.video_controller_new import VideoController print("β Imported VideoController") except ImportError as e: print(f"β οΈ Could not import VideoController: {e}") from PySide6.QtCore import QObject, Signal class VideoController(QObject): frame_ready = Signal(object, object, dict) frame_np_ready = Signal(object) stats_ready = Signal(dict) raw_frame_ready = Signal(object, list, float) violation_detected = Signal(dict) def __init__(self, model_manager=None): super().__init__() self._running = False def set_source(self, source): print(f"VideoController (fallback): set_source called with {source}") return True def start(self): print("VideoController (fallback): start called") self._running = True def stop(self): print("VideoController (fallback): stop called") self._running = False def capture_snapshot(self): print("VideoController (fallback): capture_snapshot called") return None try: from controllers.analytics_controller import AnalyticsController print("β Imported AnalyticsController") except ImportError as e: print(f"β οΈ Could not import AnalyticsController: {e}") from PySide6.QtCore import QObject, Signal class AnalyticsController(QObject): analytics_updated = Signal(dict) def __init__(self): super().__init__() def process_frame_data(self, *args): pass def clear_statistics(self): pass def register_violation(self, *args): pass def get_analytics(self): return {'detection_counts': {}} try: from controllers.performance_overlay import PerformanceOverlay print("β Imported PerformanceOverlay") except ImportError as e: print(f"β οΈ Could not import PerformanceOverlay: {e}") from PySide6.QtWidgets import QWidget class PerformanceOverlay(QWidget): def __init__(self): super().__init__() self.setVisible(False) def update_stats(self): pass try: from controllers.model_manager import ModelManager print("β Imported ModelManager") except ImportError as e: print(f"β οΈ Could not import ModelManager: {e}") class ModelManager: def __init__(self, config_file=None): print("ModelManager (fallback): initialized") def update_config(self, config): pass # Import utilities with fallback handling try: from utils.helpers import load_configuration, save_configuration, save_snapshot print("β Imported utilities") except ImportError as e: print(f"β οΈ Could not import utilities: {e}") import json import os def load_configuration(config_file): try: if os.path.exists(config_file): with open(config_file, 'r') as f: return json.load(f) else: return {} except Exception as e: print(f"Error loading config: {e}") return {} def save_configuration(config, config_file): try: with open(config_file, 'w') as f: json.dump(config, f, indent=2) return True except Exception as e: print(f"Error saving config: {e}") return False def save_snapshot(frame, file_path): try: # Try using PySide6's QPixmap to save from PySide6.QtGui import QPixmap if hasattr(frame, 'shape'): # NumPy array try: import cv2 cv2.imwrite(file_path, frame) except ImportError: print("OpenCV not available for saving") return None else: # QPixmap or similar if hasattr(frame, 'save'): frame.save(file_path) else: print("Unknown frame format for saving") return None return file_path except Exception as e: print(f"Error saving snapshot: {e}") return None class MainWindow(QMainWindow): """Main application window.""" def __init__(self): super().__init__() print("π INITIALIZING MODERN UI - MainWindow1") print("=" * 50) # Initialize settings and configuration self.settings = QSettings("OpenVINO", "TrafficMonitoring") self.config_file = os.path.join(os.path.dirname(os.path.dirname(__file__)), "config.json") self.config = load_configuration(self.config_file) # Set up UI self.setupUI() # Initialize controllers self.setupControllers() # Connect signals and slots self.connectSignals() # Restore settings self.restoreSettings() # Apply theme - Start with distinctive dark theme self.applyTheme(True) # Start with dark theme # Show ready message with modern styling self.statusBar().showMessage("π Modern UI Ready - All Systems Go!") print("β MODERN UI (MainWindow1) FULLY LOADED!") print("=" * 50) def setupUI(self): """Set up the user interface""" # Window properties with modern styling self.setWindowTitle("π Traffic Monitoring System - MODERN UI (OpenVINO PySide6)") self.setMinimumSize(1200, 800) self.resize(1400, 900) # Add a distinctive window icon or styling print("π¨ Setting up MODERN UI interface...") # Set up central widget with tabs self.tabs = QTabWidget() # Create tabs with enhanced styling self.live_tab = LiveTab() self.analytics_tab = AnalyticsTab() self.violations_tab = ViolationsTab() self.export_tab = ExportTab() # Add tabs to tab widget with modern icons/styling self.tabs.addTab(self.live_tab, "π₯ Live Detection") self.tabs.addTab(self.analytics_tab, "π Analytics") self.tabs.addTab(self.violations_tab, "π¨ Violations") self.tabs.addTab(self.export_tab, "πΎ Export & Config") # Set central widget self.setCentralWidget(self.tabs) # Create config panel in dock widget with modern styling self.config_panel = ConfigPanel() dock = QDockWidget("βοΈ Settings Panel", self) dock.setObjectName("SettingsDock") # Set object name to avoid warning dock.setWidget(self.config_panel) dock.setFeatures(QDockWidget.DockWidgetMovable | QDockWidget.DockWidgetClosable) dock.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea) self.addDockWidget(Qt.RightDockWidgetArea, dock) # Create status bar with modern styling self.statusBar().showMessage("π Modern UI Initialized - Ready for Action!") # Create menu bar self.setupMenus() # Create performance overlay self.performance_overlay = PerformanceOverlay() print("β MODERN UI setup completed!") def setupControllers(self): """Set up controllers and models""" # Load config from file try: # Initialize model manager self.model_manager = ModelManager(self.config_file) print("β Model manager initialized") # Create video controller self.video_controller = VideoController(self.model_manager) print("β Video controller initialized") # Create analytics controller self.analytics_controller = AnalyticsController() print("β Analytics controller initialized") # Setup update timer for performance overlay if hasattr(self, 'performance_overlay'): self.perf_timer = QTimer() self.perf_timer.timeout.connect(self.performance_overlay.update_stats) self.perf_timer.start(1000) # Update every second print("β Performance overlay timer started") else: print("β οΈ Performance overlay not available") except Exception as e: QMessageBox.critical( self, "Initialization Error", f"Error initializing controllers: {str(e)}\n\nPlease check if all required modules are available." ) print(f"β Controller initialization error: {e}") traceback.print_exc() def connectSignals(self): """Connect signals and slots between components""" # Video controller connections - With extra debug print("π Connecting video controller signals...") try: # Connect for UI frame updates (QPixmap-based) if hasattr(self.live_tab, 'update_display'): self.video_controller.frame_ready.connect(self.live_tab.update_display, Qt.QueuedConnection) print("β Connected frame_ready signal") else: print("β οΈ live_tab.update_display method not found") # Connect for direct NumPy frame display (critical for live video) if hasattr(self.live_tab, 'update_display_np'): self.video_controller.frame_np_ready.connect(self.live_tab.update_display_np, Qt.QueuedConnection) print("β Connected frame_np_ready signal") else: print("β οΈ live_tab.update_display_np method not found") # Connect stats signal if hasattr(self.live_tab, 'update_stats'): self.video_controller.stats_ready.connect(self.live_tab.update_stats, Qt.QueuedConnection) print("β Connected stats_ready to live_tab") else: print("β οΈ live_tab.update_stats method not found") # Also connect stats signal to update traffic light status in main window self.video_controller.stats_ready.connect(self.update_traffic_light_status, Qt.QueuedConnection) print("β Connected stats_ready signals") # Connect raw frame data for analytics if hasattr(self.analytics_controller, 'process_frame_data'): self.video_controller.raw_frame_ready.connect(self.analytics_controller.process_frame_data) print("β Connected raw_frame_ready signal") else: print("β οΈ analytics_controller.process_frame_data method not found") # Connect violation detection signal try: self.video_controller.violation_detected.connect(self.handle_violation_detected, Qt.QueuedConnection) print("β Connected violation_detected signal") except Exception as e: print(f"β οΈ Could not connect violation signal: {e}") except Exception as e: print(f"β Error connecting video controller signals: {e}") traceback.print_exc() # Live tab connections - with safety checks try: if hasattr(self.live_tab, 'source_changed'): self.live_tab.source_changed.connect(self.video_controller.set_source) print("β Connected live_tab.source_changed") if hasattr(self.live_tab, 'video_dropped'): self.live_tab.video_dropped.connect(self.video_controller.set_source) print("β Connected live_tab.video_dropped") if hasattr(self.live_tab, 'snapshot_requested'): self.live_tab.snapshot_requested.connect(self.take_snapshot) print("β Connected live_tab.snapshot_requested") if hasattr(self.live_tab, 'run_requested'): self.live_tab.run_requested.connect(self.toggle_video_processing) print("β Connected live_tab.run_requested") except Exception as e: print(f"β οΈ Error connecting live_tab signals: {e}") # Config panel connections - with safety checks try: if hasattr(self.config_panel, 'config_changed'): self.config_panel.config_changed.connect(self.apply_config) print("β Connected config_panel.config_changed") if hasattr(self.config_panel, 'theme_toggled'): self.config_panel.theme_toggled.connect(self.applyTheme) print("β Connected config_panel.theme_toggled") except Exception as e: print(f"β οΈ Error connecting config_panel signals: {e}") # Analytics controller connections - with safety checks try: if hasattr(self.analytics_controller, 'analytics_updated'): if hasattr(self.analytics_tab, 'update_analytics'): self.analytics_controller.analytics_updated.connect(self.analytics_tab.update_analytics) print("β Connected analytics_controller to analytics_tab") if hasattr(self.export_tab, 'update_export_preview'): self.analytics_controller.analytics_updated.connect(self.export_tab.update_export_preview) print("β Connected analytics_controller to export_tab") except Exception as e: print(f"β οΈ Error connecting analytics_controller signals: {e}") # Tab-specific connections - with safety checks try: if hasattr(self.violations_tab, 'clear_btn') and hasattr(self.analytics_controller, 'clear_statistics'): self.violations_tab.clear_btn.clicked.connect(self.analytics_controller.clear_statistics) print("β Connected violations_tab.clear_btn") if hasattr(self.export_tab, 'reset_btn') and hasattr(self.config_panel, 'reset_config'): self.export_tab.reset_btn.clicked.connect(self.config_panel.reset_config) print("β Connected export_tab.reset_btn") if hasattr(self.export_tab, 'save_config_btn'): self.export_tab.save_config_btn.clicked.connect(self.save_config) print("β Connected export_tab.save_config_btn") if hasattr(self.export_tab, 'reload_config_btn'): self.export_tab.reload_config_btn.clicked.connect(self.load_config) print("β Connected export_tab.reload_config_btn") if hasattr(self.export_tab, 'export_btn'): self.export_tab.export_btn.clicked.connect(self.export_data) print("β Connected export_tab.export_btn") except Exception as e: print(f"β οΈ Error connecting tab-specific signals: {e}") print("π Signal connection process completed") def setupMenus(self): """Set up application menus""" # File menu file_menu = self.menuBar().addMenu("&File") open_action = QAction("&Open Video...", self) open_action.setShortcut("Ctrl+O") open_action.triggered.connect(self.open_video_file) file_menu.addAction(open_action) file_menu.addSeparator() snapshot_action = QAction("Take &Snapshot", self) snapshot_action.setShortcut("Ctrl+S") snapshot_action.triggered.connect(self.take_snapshot) file_menu.addAction(snapshot_action) file_menu.addSeparator() exit_action = QAction("E&xit", self) exit_action.setShortcut("Alt+F4") exit_action.triggered.connect(self.close) file_menu.addAction(exit_action) # View menu view_menu = self.menuBar().addMenu("&View") toggle_config_action = QAction("Show/Hide &Settings Panel", self) toggle_config_action.setShortcut("F4") toggle_config_action.triggered.connect(self.toggle_config_panel) view_menu.addAction(toggle_config_action) toggle_perf_action = QAction("Show/Hide &Performance Overlay", self) toggle_perf_action.setShortcut("F5") toggle_perf_action.triggered.connect(self.toggle_performance_overlay) view_menu.addAction(toggle_perf_action) # Help menu help_menu = self.menuBar().addMenu("&Help") about_action = QAction("&About", self) about_action.triggered.connect(self.show_about_dialog) help_menu.addAction(about_action) @Slot(dict) def apply_config(self, config): """ Apply configuration changes. Args: config: Configuration dictionary """ # Update configuration if not config: return # Update config for section in config: if section in self.config: self.config[section].update(config[section]) else: self.config[section] = config[section] # Update model manager if self.model_manager: self.model_manager.update_config(self.config) # Save config to file save_configuration(self.config, self.config_file) # Update export tab self.export_tab.update_config_display(self.config) # Update status self.statusBar().showMessage("Configuration applied", 2000) @Slot() def load_config(self): """Load configuration from file""" # Ask for confirmation if needed if self.video_controller and self.video_controller._running: reply = QMessageBox.question( self, "Reload Configuration", "Reloading configuration will stop current processing. Continue?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No ) if reply == QMessageBox.No: return # Stop processing self.video_controller.stop() # Load config self.config = load_configuration(self.config_file) # Update UI self.config_panel.set_config(self.config) self.export_tab.update_config_display(self.config) # Update model manager if self.model_manager: self.model_manager.update_config(self.config) # Update status self.statusBar().showMessage("Configuration loaded", 2000) @Slot() def save_config(self): """Save configuration to file""" # Get config from UI ui_config = self.export_tab.get_config_from_ui() for section in ui_config: if section in self.config: self.config[section].update(ui_config[section]) else: self.config[section] = ui_config[section] # Save to file if save_configuration(self.config, self.config_file): self.statusBar().showMessage("Configuration saved", 2000) else: self.statusBar().showMessage("Error saving configuration", 2000) # Update model manager if self.model_manager: self.model_manager.update_config(self.config) @Slot() def open_video_file(self): """Open video file dialog""" file_path, _ = QFileDialog.getOpenFileName( self, "Open Video File", "", "Video Files (*.mp4 *.avi *.mov *.mkv *.webm);;All Files (*)" ) if file_path: # Update live tab self.live_tab.source_changed.emit(file_path) # Update status self.statusBar().showMessage(f"Loaded video: {os.path.basename(file_path)}") @Slot() def take_snapshot(self): """Take snapshot of current frame""" if self.video_controller: # Get current frame frame = self.video_controller.capture_snapshot() if frame is not None: # Save frame to file save_dir = self.settings.value("snapshot_dir", ".") file_path = os.path.join(save_dir, "snapshot_" + str(int(time.time())) + ".jpg") saved_path = save_snapshot(frame, file_path) if saved_path: self.statusBar().showMessage(f"Snapshot saved: {saved_path}", 3000) else: self.statusBar().showMessage("Error saving snapshot", 3000) else: self.statusBar().showMessage("No frame to capture", 3000) @Slot() def toggle_config_panel(self): """Toggle configuration panel visibility""" dock_widgets = self.findChildren(QDockWidget) for dock in dock_widgets: dock.setVisible(not dock.isVisible()) @Slot() def toggle_performance_overlay(self): """Toggle performance overlay visibility""" if self.performance_overlay.isVisible(): self.performance_overlay.hide() else: # Position in the corner self.performance_overlay.move(self.pos().x() + 10, self.pos().y() + 30) self.performance_overlay.show() @Slot(bool) def applyTheme(self, dark_theme): """ Apply light or dark theme. Args: dark_theme: True for dark theme, False for light theme """ if dark_theme: # Apply a modern dark theme with distinctive styling dark_stylesheet = """ QMainWindow { background-color: #1e1e1e; color: #ffffff; border: none; } QTabWidget::pane { border: 1px solid #404040; background-color: #2d2d2d; border-radius: 8px; } QTabBar::tab { background-color: #404040; color: #ffffff; padding: 12px 20px; margin-right: 2px; border-top-left-radius: 8px; border-top-right-radius: 8px; font-weight: bold; font-size: 11px; } QTabBar::tab:selected { background-color: #0078d4; color: #ffffff; } QTabBar::tab:hover { background-color: #555555; } QStatusBar { background-color: #333333; color: #ffffff; border-top: 1px solid #555555; font-weight: bold; } QMenuBar { background-color: #2d2d2d; color: #ffffff; border-bottom: 1px solid #555555; padding: 4px; } QMenuBar::item { background-color: transparent; padding: 8px 16px; border-radius: 4px; } QMenuBar::item:selected { background-color: #0078d4; } QMenu { background-color: #2d2d2d; color: #ffffff; border: 1px solid #555555; border-radius: 4px; } QMenu::item { padding: 8px 24px; } QMenu::item:selected { background-color: #0078d4; } QDockWidget { background-color: #2d2d2d; color: #ffffff; titlebar-close-icon: none; titlebar-normal-icon: none; border: 1px solid #555555; border-radius: 4px; } QDockWidget::title { background-color: #404040; color: #ffffff; padding: 8px; text-align: center; font-weight: bold; border-top-left-radius: 4px; border-top-right-radius: 4px; } QWidget { background-color: #2d2d2d; color: #ffffff; } QLabel { color: #ffffff; font-size: 11px; } QPushButton { background-color: #0078d4; color: #ffffff; border: none; padding: 10px 20px; border-radius: 6px; font-weight: bold; font-size: 10px; } QPushButton:hover { background-color: #106ebe; } QPushButton:pressed { background-color: #005a9e; } QComboBox { background-color: #404040; color: #ffffff; border: 1px solid #555555; padding: 8px; border-radius: 4px; font-size: 10px; } QComboBox::drop-down { border: none; background-color: #0078d4; border-top-right-radius: 4px; border-bottom-right-radius: 4px; width: 20px; } QComboBox::down-arrow { image: none; border: 2px solid #ffffff; border-top: none; border-left: none; width: 6px; height: 6px; margin-right: 4px; transform: rotate(45deg); } QComboBox QAbstractItemView { background-color: #404040; color: #ffffff; selection-background-color: #0078d4; border: 1px solid #555555; } /* Make the title bar more distinctive */ QMainWindow::title { background-color: #1e1e1e; color: #0078d4; font-weight: bold; font-size: 14px; } """ self.setStyleSheet(dark_stylesheet) # Also update window title to show it's the modern UI self.setWindowTitle("π Traffic Monitoring System - MODERN UI (OpenVINO PySide6)") else: # Light theme with modern styling light_stylesheet = """ QMainWindow { background-color: #f5f5f5; color: #333333; } QTabWidget::pane { border: 1px solid #cccccc; background-color: #ffffff; border-radius: 8px; } QTabBar::tab { background-color: #e0e0e0; color: #333333; padding: 12px 20px; margin-right: 2px; border-top-left-radius: 8px; border-top-right-radius: 8px; font-weight: bold; } QTabBar::tab:selected { background-color: #0078d4; color: #ffffff; } QTabBar::tab:hover { background-color: #d0d0d0; } QStatusBar { background-color: #e0e0e0; color: #333333; border-top: 1px solid #cccccc; font-weight: bold; } QPushButton { background-color: #0078d4; color: #ffffff; border: none; padding: 10px 20px; border-radius: 6px; font-weight: bold; } QPushButton:hover { background-color: #106ebe; } """ self.setStyleSheet(light_stylesheet) self.setWindowTitle("βοΈ Traffic Monitoring System - LIGHT UI (OpenVINO PySide6)") # Update status bar to show theme change theme_name = "π DARK MODERN" if dark_theme else "βοΈ LIGHT MODERN" self.statusBar().showMessage(f"Theme applied: {theme_name} UI", 3000) @Slot() def export_data(self): """Export data to file""" export_format = self.export_tab.export_format_combo.currentText() export_data = self.export_tab.export_data_combo.currentText() # Get file type filter based on format if export_format == "CSV": file_filter = "CSV Files (*.csv)" default_ext = ".csv" elif export_format == "JSON": file_filter = "JSON Files (*.json)" default_ext = ".json" elif export_format == "Excel": file_filter = "Excel Files (*.xlsx)" default_ext = ".xlsx" elif export_format == "PDF Report": file_filter = "PDF Files (*.pdf)" default_ext = ".pdf" else: file_filter = "All Files (*)" default_ext = ".txt" # Get save path file_path, _ = QFileDialog.getSaveFileName( self, "Export Data", f"traffic_data{default_ext}", file_filter ) if not file_path: return try: # Get analytics data analytics = self.analytics_controller.get_analytics() # Export based on format if export_format == "CSV": try: from utils.helpers import create_export_csv result = create_export_csv(analytics['detection_counts'], file_path) except ImportError: print("CSV export not available - utils.helpers not found") result = False elif export_format == "JSON": try: from utils.helpers import create_export_json result = create_export_json(analytics, file_path) except ImportError: # Fallback JSON export try: with open(file_path, 'w') as f: json.dump(analytics, f, indent=2, default=str) result = True except Exception as e: print(f"JSON export error: {e}") result = False elif export_format == "Excel": # Requires openpyxl try: import pandas as pd df = pd.DataFrame({ 'Class': list(analytics['detection_counts'].keys()), 'Count': list(analytics['detection_counts'].values()) }) df.to_excel(file_path, index=False) result = True except Exception as e: print(f"Excel export error: {e}") result = False else: # Not implemented QMessageBox.information( self, "Not Implemented", f"Export to {export_format} is not yet implemented." ) return if result: self.statusBar().showMessage(f"Data exported to {file_path}", 3000) else: self.statusBar().showMessage("Error exporting data", 3000) except Exception as e: QMessageBox.critical( self, "Export Error", f"Error exporting data: {str(e)}" ) @Slot() def show_about_dialog(self): """Show about dialog""" QMessageBox.about( self, "About Traffic Monitoring System", "
Based on OpenVINOβ’ and PySide6
" "Version 1.0.0
" "Β© 2025 GSOC Project
" ) @Slot(bool) def toggle_video_processing(self, start): """ Start or stop video processing. Args: start: True to start processing, False to stop """ if self.video_controller: if start: try: # Make sure the source is correctly set to what the LiveTab has current_source = self.live_tab.current_source print(f"DEBUG: MainWindow toggle_processing with source: {current_source} (type: {type(current_source)})") # Validate source if current_source is None: self.statusBar().showMessage("Error: No valid source selected") return # For file sources, verify file exists if isinstance(current_source, str) and not current_source.isdigit(): if not os.path.exists(current_source): self.statusBar().showMessage(f"Error: File not found: {current_source}") return # Ensure the source is set before starting print(f"π₯ Setting video controller source to: {current_source}") self.video_controller.set_source(current_source) # Now start processing after a short delay to ensure source is set print("β±οΈ Scheduling video processing start after 200ms delay...") QTimer.singleShot(200, lambda: self._start_video_processing()) source_desc = f"file: {os.path.basename(current_source)}" if isinstance(current_source, str) and os.path.exists(current_source) else f"camera: {current_source}" self.statusBar().showMessage(f"Video processing started with {source_desc}") except Exception as e: print(f"β Error starting video: {e}") traceback.print_exc() self.statusBar().showMessage(f"Error: {str(e)}") else: try: print("π Stopping video processing...") self.video_controller.stop() print("β Video controller stopped") self.statusBar().showMessage("Video processing stopped") except Exception as e: print(f"β Error stopping video: {e}") traceback.print_exc() def _start_video_processing(self): """Actual video processing start with extra error handling""" try: print("π Starting video controller...") self.video_controller.start() print("β Video controller started successfully") except Exception as e: print(f"β Error in video processing start: {e}") traceback.print_exc() self.statusBar().showMessage(f"Video processing error: {str(e)}") def closeEvent(self, event): """Handle window close event""" # Stop processing if self.video_controller and self.video_controller._running: self.video_controller.stop() # Save settings self.saveSettings() # Accept close event event.accept() def restoreSettings(self): """Restore application settings""" # Restore window geometry geometry = self.settings.value("geometry") if geometry: self.restoreGeometry(geometry) # Restore window state state = self.settings.value("windowState") if state: self.restoreState(state) def saveSettings(self): """Save application settings""" # Save window geometry self.settings.setValue("geometry", self.saveGeometry()) # Save window state self.settings.setValue("windowState", self.saveState()) # Save current directory as snapshot directory self.settings.setValue("snapshot_dir", os.getcwd()) @Slot(dict) def update_traffic_light_status(self, stats): """Update status bar with traffic light information if detected""" traffic_light_info = stats.get('traffic_light_color', 'unknown') # Handle both string and dictionary return formats if isinstance(traffic_light_info, dict): traffic_light_color = traffic_light_info.get('color', 'unknown') confidence = traffic_light_info.get('confidence', 0.0) confidence_str = f" (Confidence: {confidence:.2f})" if confidence > 0 else "" else: traffic_light_color = traffic_light_info confidence_str = "" if traffic_light_color != 'unknown': current_message = self.statusBar().currentMessage() if not current_message or "Traffic Light" not in current_message: # Handle both dictionary and string formats if isinstance(traffic_light_color, dict): color_text = traffic_light_color.get("color", "unknown").upper() else: color_text = str(traffic_light_color).upper() self.statusBar().showMessage(f"Traffic Light: {color_text}{confidence_str}") @Slot(dict) def handle_violation_detected(self, violation): """Handle a detected traffic violation""" try: # Get track ID safely track_id = violation.get('track_id', violation.get('id', 'Unknown')) timestamp = violation.get('timestamp', datetime.now()) # Flash red status message self.statusBar().showMessage(f"π¨ RED LIGHT VIOLATION DETECTED - Vehicle ID: {track_id}", 5000) # Add to violations tab if hasattr(self.violations_tab, 'add_violation'): self.violations_tab.add_violation(violation) else: print("β οΈ violations_tab.add_violation method not found") # Update analytics if self.analytics_controller and hasattr(self.analytics_controller, 'register_violation'): self.analytics_controller.register_violation(violation) else: print("β οΈ analytics_controller.register_violation method not found") print(f"π¨ Violation processed: Track ID={track_id} at {timestamp}") except Exception as e: print(f"β Error handling violation: {e}") traceback.print_exc()