""" Video Analysis Tab - Advanced video analysis with ROI configuration """ from PySide6.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QSplitter, QGroupBox, QLabel, QPushButton, QComboBox, QListWidget, QTextEdit, QSlider, QCheckBox, QFrame, QGridLayout, QSpinBox, QProgressBar) from PySide6.QtCore import Qt, Signal, QTimer from PySide6.QtGui import QFont, QPixmap class VideoAnalysisTab(QWidget): """ Video Analysis Tab with ROI configuration and advanced analytics Features: - ROI (Region of Interest) drawing and management - Traffic pattern analysis - Speed measurement zones - Counting lines configuration - Heatmap visualization - Advanced analytics reporting """ # Signals roi_changed = Signal(dict) analysis_started = Signal(str) export_requested = Signal(str, str) def __init__(self, parent=None): super().__init__(parent) self.roi_data = {} self.analysis_results = {} self._setup_ui() print("đŸŽŦ Video Analysis Tab initialized") def _setup_ui(self): """Setup the video analysis UI""" # Main splitter main_splitter = QSplitter(Qt.Horizontal) self.layout = QVBoxLayout(self) self.layout.addWidget(main_splitter) # Left panel - Video and ROI editor left_panel = self._create_left_panel() main_splitter.addWidget(left_panel) # Right panel - Analysis controls and results right_panel = self._create_right_panel() main_splitter.addWidget(right_panel) # Set splitter proportions main_splitter.setSizes([800, 400]) def _create_left_panel(self): """Create left panel with video analysis view""" panel = QFrame() layout = QVBoxLayout(panel) # Header with controls header = self._create_analysis_header() layout.addWidget(header) # Main analysis view (placeholder for now) self.analysis_view = QFrame() self.analysis_view.setMinimumSize(600, 400) self.analysis_view.setStyleSheet(""" QFrame { background-color: #2c3e50; border: 2px solid #34495e; border-radius: 8px; } """) layout.addWidget(self.analysis_view, 1) # ROI tools roi_tools = self._create_roi_tools() layout.addWidget(roi_tools) return panel def _create_analysis_header(self): """Create analysis header with controls""" header = QFrame() header.setFixedHeight(50) layout = QHBoxLayout(header) # Source selection layout.addWidget(QLabel("Source:")) self.source_combo = QComboBox() self.source_combo.addItems(["Live Camera 1", "Live Camera 2", "Recorded Video", "Import Video"]) layout.addWidget(self.source_combo) layout.addStretch() # Analysis controls self.start_analysis_btn = QPushButton("â–ļī¸ Start Analysis") self.start_analysis_btn.clicked.connect(self._start_analysis) layout.addWidget(self.start_analysis_btn) self.stop_analysis_btn = QPushButton("âšī¸ Stop") self.stop_analysis_btn.setEnabled(False) self.stop_analysis_btn.clicked.connect(self._stop_analysis) layout.addWidget(self.stop_analysis_btn) # Export button export_btn = QPushButton("📊 Export Results") export_btn.clicked.connect(self._export_results) layout.addWidget(export_btn) return header def _create_roi_tools(self): """Create ROI drawing tools""" tools = QGroupBox("ROI Tools") tools.setFixedHeight(80) layout = QHBoxLayout(tools) # ROI type selection layout.addWidget(QLabel("ROI Type:")) self.roi_type_combo = QComboBox() self.roi_type_combo.addItems([ "Traffic Count Zone", "Speed Measurement Zone", "Restricted Area", "Parking Detection", "Crosswalk Zone" ]) layout.addWidget(self.roi_type_combo) # ROI drawing buttons draw_rect_btn = QPushButton("📐 Rectangle") draw_rect_btn.clicked.connect(lambda: self._set_draw_mode("rectangle")) layout.addWidget(draw_rect_btn) draw_poly_btn = QPushButton("🔗 Polygon") draw_poly_btn.clicked.connect(lambda: self._set_draw_mode("polygon")) layout.addWidget(draw_poly_btn) draw_line_btn = QPushButton("📏 Line") draw_line_btn.clicked.connect(lambda: self._set_draw_mode("line")) layout.addWidget(draw_line_btn) layout.addStretch() # Clear ROI clear_btn = QPushButton("đŸ—‘ī¸ Clear All") clear_btn.clicked.connect(self._clear_all_roi) layout.addWidget(clear_btn) return tools def _create_right_panel(self): """Create right panel with controls and results""" panel = QFrame() layout = QVBoxLayout(panel) # ROI list roi_section = self._create_roi_section() layout.addWidget(roi_section) # Analysis settings settings_section = self._create_settings_section() layout.addWidget(settings_section) # Results section results_section = self._create_results_section() layout.addWidget(results_section) return panel def _create_roi_section(self): """Create ROI management section""" section = QGroupBox("ROI Management") layout = QVBoxLayout(section) # ROI list self.roi_list = QListWidget() self.roi_list.setMaximumHeight(120) layout.addWidget(self.roi_list) # ROI controls roi_controls = QHBoxLayout() edit_btn = QPushButton("âœī¸ Edit") edit_btn.clicked.connect(self._edit_selected_roi) roi_controls.addWidget(edit_btn) delete_btn = QPushButton("đŸ—‘ī¸ Delete") delete_btn.clicked.connect(self._delete_selected_roi) roi_controls.addWidget(delete_btn) duplicate_btn = QPushButton("📋 Copy") duplicate_btn.clicked.connect(self._duplicate_selected_roi) roi_controls.addWidget(duplicate_btn) layout.addLayout(roi_controls) return section def _create_settings_section(self): """Create analysis settings section""" section = QGroupBox("Analysis Settings") layout = QGridLayout(section) # Detection sensitivity layout.addWidget(QLabel("Sensitivity:"), 0, 0) self.sensitivity_slider = QSlider(Qt.Horizontal) self.sensitivity_slider.setRange(1, 10) self.sensitivity_slider.setValue(5) layout.addWidget(self.sensitivity_slider, 0, 1) self.sensitivity_label = QLabel("5") layout.addWidget(self.sensitivity_label, 0, 2) # Minimum object size layout.addWidget(QLabel("Min Size:"), 1, 0) self.min_size_spin = QSpinBox() self.min_size_spin.setRange(10, 1000) self.min_size_spin.setValue(50) self.min_size_spin.setSuffix(" px") layout.addWidget(self.min_size_spin, 1, 1, 1, 2) # Analysis options self.track_objects_cb = QCheckBox("Track Objects") self.track_objects_cb.setChecked(True) layout.addWidget(self.track_objects_cb, 2, 0, 1, 3) self.speed_analysis_cb = QCheckBox("Speed Analysis") self.speed_analysis_cb.setChecked(True) layout.addWidget(self.speed_analysis_cb, 3, 0, 1, 3) self.direction_analysis_cb = QCheckBox("Direction Analysis") self.direction_analysis_cb.setChecked(False) layout.addWidget(self.direction_analysis_cb, 4, 0, 1, 3) # Connect sensitivity slider to label self.sensitivity_slider.valueChanged.connect( lambda v: self.sensitivity_label.setText(str(v)) ) return section def _create_results_section(self): """Create analysis results section""" section = QGroupBox("Analysis Results") layout = QVBoxLayout(section) # Results summary summary_layout = QGridLayout() summary_layout.addWidget(QLabel("Objects Detected:"), 0, 0) self.objects_count_label = QLabel("0") summary_layout.addWidget(self.objects_count_label, 0, 1) summary_layout.addWidget(QLabel("Avg Speed:"), 1, 0) self.avg_speed_label = QLabel("0.0 km/h") summary_layout.addWidget(self.avg_speed_label, 1, 1) summary_layout.addWidget(QLabel("Violations:"), 2, 0) self.violations_count_label = QLabel("0") summary_layout.addWidget(self.violations_count_label, 2, 1) layout.addLayout(summary_layout) # Progress bar for analysis self.analysis_progress = QProgressBar() self.analysis_progress.setVisible(False) layout.addWidget(self.analysis_progress) # Detailed results self.results_text = QTextEdit() self.results_text.setMaximumHeight(150) self.results_text.setPlaceholderText("Analysis results will appear here...") layout.addWidget(self.results_text) # Export options export_layout = QHBoxLayout() export_csv_btn = QPushButton("📄 Export CSV") export_csv_btn.clicked.connect(lambda: self._export_data("csv")) export_layout.addWidget(export_csv_btn) export_json_btn = QPushButton("📋 Export JSON") export_json_btn.clicked.connect(lambda: self._export_data("json")) export_layout.addWidget(export_json_btn) layout.addLayout(export_layout) return section def _set_draw_mode(self, mode): """Set ROI drawing mode""" print(f"đŸŽŦ Draw mode set to: {mode}") # Implementation for setting drawing mode def _clear_all_roi(self): """Clear all ROI regions""" self.roi_list.clear() self.roi_data.clear() self.roi_changed.emit(self.roi_data) print("đŸŽŦ All ROI regions cleared") def _edit_selected_roi(self): """Edit the selected ROI""" current_item = self.roi_list.currentItem() if current_item: roi_name = current_item.text() print(f"đŸŽŦ Editing ROI: {roi_name}") def _delete_selected_roi(self): """Delete the selected ROI""" current_item = self.roi_list.currentItem() if current_item: roi_name = current_item.text() self.roi_list.takeItem(self.roi_list.row(current_item)) if roi_name in self.roi_data: del self.roi_data[roi_name] self.roi_changed.emit(self.roi_data) print(f"đŸŽŦ Deleted ROI: {roi_name}") def _duplicate_selected_roi(self): """Duplicate the selected ROI""" current_item = self.roi_list.currentItem() if current_item: roi_name = current_item.text() print(f"đŸŽŦ Duplicating ROI: {roi_name}") def _start_analysis(self): """Start video analysis""" self.start_analysis_btn.setEnabled(False) self.stop_analysis_btn.setEnabled(True) self.analysis_progress.setVisible(True) self.analysis_progress.setRange(0, 0) # Indeterminate progress source = self.source_combo.currentText() self.analysis_started.emit(source) # Add sample result self.results_text.append(f"Started analysis on: {source}") print(f"đŸŽŦ Started analysis on: {source}") def _stop_analysis(self): """Stop video analysis""" self.start_analysis_btn.setEnabled(True) self.stop_analysis_btn.setEnabled(False) self.analysis_progress.setVisible(False) self.results_text.append("Analysis stopped by user") print("đŸŽŦ Analysis stopped") def _export_results(self): """Export analysis results""" print("đŸŽŦ Exporting analysis results") self.export_requested.emit("analysis_results", "pdf") def _export_data(self, format_type): """Export data in specified format""" print(f"đŸŽŦ Exporting data as {format_type.upper()}") self.export_requested.emit("analysis_data", format_type) def add_roi(self, roi_name, roi_type, coordinates): """Add a new ROI region""" self.roi_data[roi_name] = { 'type': roi_type, 'coordinates': coordinates } # Add to list self.roi_list.addItem(f"{roi_name} ({roi_type})") # Emit change signal self.roi_changed.emit(self.roi_data) print(f"đŸŽŦ Added ROI: {roi_name} ({roi_type})") def update_analysis_results(self, results): """Update analysis results display""" self.analysis_results.update(results) # Update summary labels self.objects_count_label.setText(str(results.get('objects_detected', 0))) self.avg_speed_label.setText(f"{results.get('average_speed', 0.0):.1f} km/h") self.violations_count_label.setText(str(results.get('violations', 0))) # Add to results text if 'message' in results: self.results_text.append(results['message']) def set_analysis_progress(self, value): """Set analysis progress""" if self.analysis_progress.isVisible(): if value < 0: self.analysis_progress.setRange(0, 0) # Indeterminate else: self.analysis_progress.setRange(0, 100) self.analysis_progress.setValue(value)