Files
Traffic-Intersection-Monito…/qt_app_pyside1/ui/tabs/video_analysis_tab.py
2025-08-26 13:24:53 -07:00

401 lines
14 KiB
Python

"""
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)