730 lines
30 KiB
Python
730 lines
30 KiB
Python
#!/usr/bin/env python
|
|
"""
|
|
System Validation Script for Traffic Monitoring Application
|
|
|
|
This script performs a comprehensive check of the system components,
|
|
dependencies, and configuration to ensure the application is properly set up.
|
|
It validates:
|
|
1. Required Python packages
|
|
2. Model files existence and format
|
|
3. Configuration file correctness
|
|
4. UI components
|
|
5. Controller functionality
|
|
6. Hardware compatibility (GPU/OpenVINO)
|
|
7. Camera accessibility
|
|
|
|
Usage:
|
|
python validate_system.py [--fix] [--verbose]
|
|
|
|
Options:
|
|
--fix Attempt to fix common issues (install packages, download models)
|
|
--verbose Show detailed output for all checks
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
import json
|
|
import platform
|
|
import importlib
|
|
import subprocess
|
|
import argparse
|
|
import traceback
|
|
from pathlib import Path
|
|
from typing import Dict, List, Tuple, Any, Optional
|
|
|
|
# Add parent directory to path to ensure imports work
|
|
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
|
|
|
# Colors for terminal output
|
|
class Colors:
|
|
HEADER = '\033[95m'
|
|
BLUE = '\033[94m'
|
|
GREEN = '\033[92m'
|
|
YELLOW = '\033[93m'
|
|
RED = '\033[91m'
|
|
END = '\033[0m'
|
|
BOLD = '\033[1m'
|
|
UNDERLINE = '\033[4m'
|
|
|
|
# Define required packages with minimum versions
|
|
REQUIRED_PACKAGES = {
|
|
'PySide6': '6.0.0',
|
|
'opencv-python': '4.5.0',
|
|
'numpy': '1.20.0',
|
|
'openvino': '2021.4.0',
|
|
'PyYAML': '5.4.0',
|
|
'Pillow': '8.0.0',
|
|
'matplotlib': '3.3.0',
|
|
'pandas': '1.2.0',
|
|
'torch': '1.8.0',
|
|
'torchvision': '0.9.0',
|
|
}
|
|
|
|
# Define required model files
|
|
REQUIRED_MODELS = [
|
|
'mobilenetv2.bin',
|
|
'mobilenetv2.xml',
|
|
'yolo11n.bin',
|
|
'yolo11n.xml',
|
|
'yolo11x.bin',
|
|
'yolo11x.xml',
|
|
]
|
|
|
|
def print_header(message: str) -> None:
|
|
"""Print a formatted header message"""
|
|
print(f"\n{Colors.HEADER}{Colors.BOLD}{'='*80}{Colors.END}")
|
|
print(f"{Colors.HEADER}{Colors.BOLD} {message} {Colors.END}")
|
|
print(f"{Colors.HEADER}{Colors.BOLD}{'='*80}{Colors.END}\n")
|
|
|
|
def print_result(test_name: str, status: bool, message: str = "") -> None:
|
|
"""Print a test result with appropriate formatting"""
|
|
status_text = f"{Colors.GREEN}✓ PASS{Colors.END}" if status else f"{Colors.RED}✗ FAIL{Colors.END}"
|
|
print(f"{test_name:<40} {status_text:<15} {message}")
|
|
|
|
def get_package_version(package_name: str) -> Optional[str]:
|
|
"""Get installed version of a package"""
|
|
# Try using importlib.metadata first (Python 3.8+)
|
|
try:
|
|
# Try importlib.metadata (Python 3.8+)
|
|
try:
|
|
import importlib.metadata
|
|
return importlib.metadata.version(package_name)
|
|
except (ImportError, AttributeError):
|
|
# Fallback for Python < 3.8
|
|
try:
|
|
import pkg_resources
|
|
return pkg_resources.get_distribution(package_name).version
|
|
except ImportError:
|
|
# pkg_resources not available
|
|
pass
|
|
except Exception as e:
|
|
# Other pkg_resources error
|
|
pass
|
|
# Distribution not found or other pkg_resources error
|
|
pass
|
|
except Exception:
|
|
# Continue with other methods if any exception occurs
|
|
pass
|
|
|
|
# Try to import the package and check __version__
|
|
try:
|
|
pkg = importlib.import_module(package_name)
|
|
if hasattr(pkg, "__version__"):
|
|
return pkg.__version__
|
|
except (ImportError, AttributeError):
|
|
pass
|
|
|
|
# Try pip list as a fallback for getting version info
|
|
try:
|
|
result = subprocess.run(
|
|
[sys.executable, "-m", "pip", "show", package_name],
|
|
capture_output=True,
|
|
text=True
|
|
)
|
|
if result.returncode == 0:
|
|
for line in result.stdout.split('\n'):
|
|
if line.lower().startswith('version:'):
|
|
return line.split(':', 1)[1].strip()
|
|
except Exception:
|
|
pass
|
|
|
|
# If we got here, we couldn't determine the version
|
|
return None
|
|
|
|
def compare_versions(current: str, required: str) -> bool:
|
|
"""Compare two version strings"""
|
|
if current is None:
|
|
return False
|
|
|
|
# Simple version comparison for now - can be enhanced with packaging.version
|
|
current_parts = [int(x) for x in current.split('.')]
|
|
required_parts = [int(x) for x in required.split('.')]
|
|
|
|
# Pad with zeros to ensure equal length
|
|
while len(current_parts) < len(required_parts):
|
|
current_parts.append(0)
|
|
while len(required_parts) < len(current_parts):
|
|
required_parts.append(0)
|
|
|
|
# Compare each part
|
|
for c, r in zip(current_parts, required_parts):
|
|
if c > r:
|
|
return True
|
|
if c < r:
|
|
return False
|
|
|
|
# Equal versions
|
|
return True
|
|
|
|
def check_packages(fix: bool = False, verbose: bool = False) -> Tuple[bool, List[str]]:
|
|
"""Check if all required packages are installed with correct versions"""
|
|
print_header("Checking Required Packages")
|
|
all_passed = True
|
|
missing_packages = []
|
|
|
|
for package, min_version in REQUIRED_PACKAGES.items():
|
|
current_version = get_package_version(package)
|
|
if current_version is None:
|
|
print_result(package, False, "Not installed")
|
|
all_passed = False
|
|
missing_packages.append(package)
|
|
elif not compare_versions(current_version, min_version):
|
|
print_result(package, False, f"Version {current_version} < required {min_version}")
|
|
all_passed = False
|
|
missing_packages.append(f"{package}=={min_version}")
|
|
else:
|
|
print_result(package, True, f"Version {current_version}")
|
|
|
|
# Try to fix missing packages if requested
|
|
if fix and missing_packages:
|
|
print(f"\n{Colors.YELLOW}Attempting to install missing packages...{Colors.END}")
|
|
try:
|
|
cmd = [sys.executable, "-m", "pip", "install"] + missing_packages
|
|
if verbose:
|
|
print(f"Running: {' '.join(cmd)}")
|
|
subprocess.check_call(cmd)
|
|
print(f"{Colors.GREEN}Package installation complete.{Colors.END}")
|
|
# Re-check packages after installation
|
|
return check_packages(fix=False, verbose=verbose)
|
|
except subprocess.CalledProcessError:
|
|
print(f"{Colors.RED}Failed to install packages!{Colors.END}")
|
|
|
|
return all_passed, missing_packages
|
|
|
|
def check_models(base_dir: Path, fix: bool = False, verbose: bool = False) -> Tuple[bool, List[str]]:
|
|
"""Check if all required model files exist"""
|
|
print_header("Checking Model Files")
|
|
all_passed = True
|
|
missing_models = []
|
|
|
|
# Check for models in different possible locations
|
|
search_dirs = [
|
|
base_dir,
|
|
base_dir / "openvino_models",
|
|
base_dir / "models",
|
|
base_dir.parent / "openvino_models",
|
|
base_dir.parent / "models"
|
|
]
|
|
|
|
# Add specific model subdirectories that we know about
|
|
additional_dirs = []
|
|
for directory in search_dirs:
|
|
if directory.exists():
|
|
# Check for yolo11x_openvino_model subdirectory
|
|
yolo11x_dir = directory / "yolo11x_openvino_model"
|
|
if yolo11x_dir.exists():
|
|
additional_dirs.append(yolo11x_dir)
|
|
|
|
# Check for yolo11n_openvino_model subdirectory
|
|
yolo11n_dir = directory / "yolo11n_openvino_model"
|
|
if yolo11n_dir.exists():
|
|
additional_dirs.append(yolo11n_dir)
|
|
|
|
# Add all direct subdirectories of models directory
|
|
if directory.name == "models" and directory.exists():
|
|
for subdir in directory.iterdir():
|
|
if subdir.is_dir():
|
|
additional_dirs.append(subdir)
|
|
|
|
# Add the additional directories to our search paths
|
|
search_dirs.extend(additional_dirs)
|
|
|
|
for model_file in REQUIRED_MODELS:
|
|
found = False
|
|
found_path = None
|
|
for directory in search_dirs:
|
|
if not directory.exists():
|
|
continue
|
|
|
|
model_path = directory / model_file
|
|
if model_path.exists():
|
|
found = True
|
|
found_path = model_path
|
|
print_result(model_file, True, f"Found in {directory}")
|
|
break
|
|
|
|
if not found:
|
|
print_result(model_file, False, "Not found")
|
|
all_passed = False
|
|
missing_models.append(model_file)
|
|
elif verbose:
|
|
print(f" Full path: {found_path}")
|
|
|
|
# TODO: Implement model download functionality if fix=True
|
|
if fix and missing_models:
|
|
print(f"\n{Colors.YELLOW}Automatic model download not implemented yet.{Colors.END}")
|
|
print(f"{Colors.YELLOW}Please download missing models manually.{Colors.END}")
|
|
|
|
return all_passed, missing_models
|
|
|
|
def check_config(base_dir: Path, fix: bool = False, verbose: bool = False) -> Tuple[bool, List[str]]:
|
|
"""Check if configuration files exist and are valid"""
|
|
print_header("Checking Configuration Files")
|
|
all_passed = True
|
|
issues = []
|
|
|
|
# Check main config.json
|
|
config_path = base_dir / "config.json"
|
|
if not config_path.exists():
|
|
print_result("config.json", False, "Not found")
|
|
all_passed = False
|
|
issues.append("Missing config.json")
|
|
|
|
# Create default config if fix is enabled
|
|
if fix:
|
|
print(f"{Colors.YELLOW}Creating default config.json...{Colors.END}")
|
|
default_config = {
|
|
"video_sources": {
|
|
"default_camera_id": 0,
|
|
"default_video": ""
|
|
},
|
|
"detection_models": {
|
|
"yolo_model_xml": "openvino_models/yolo11n.xml",
|
|
"yolo_model_bin": "openvino_models/yolo11n.bin"
|
|
},
|
|
"detection_settings": {
|
|
"confidence_threshold": 0.5,
|
|
"use_gpu": True
|
|
},
|
|
"ui_settings": {
|
|
"theme": "dark",
|
|
"show_fps": True,
|
|
"default_tab": 0
|
|
}
|
|
}
|
|
with open(config_path, 'w') as f:
|
|
json.dump(default_config, f, indent=4)
|
|
print(f"{Colors.GREEN}Created default config.json{Colors.END}")
|
|
else:
|
|
# Validate config.json
|
|
try:
|
|
with open(config_path, 'r') as f:
|
|
config = json.load(f)
|
|
|
|
# Check for required sections
|
|
required_sections = ["video_sources", "detection_models", "detection_settings"]
|
|
missing_sections = [s for s in required_sections if s not in config]
|
|
|
|
if missing_sections:
|
|
print_result("config.json structure", False, f"Missing sections: {', '.join(missing_sections)}")
|
|
all_passed = False
|
|
issues.append(f"Config missing sections: {', '.join(missing_sections)}")
|
|
|
|
# Fix config if requested
|
|
if fix:
|
|
print(f"{Colors.YELLOW}Adding missing sections to config.json...{Colors.END}")
|
|
for section in missing_sections:
|
|
if section == "video_sources":
|
|
config["video_sources"] = {"default_camera_id": 0, "default_video": ""}
|
|
elif section == "detection_models":
|
|
config["detection_models"] = {
|
|
"yolo_model_xml": "openvino_models/yolo11n.xml",
|
|
"yolo_model_bin": "openvino_models/yolo11n.bin"
|
|
}
|
|
elif section == "detection_settings":
|
|
config["detection_settings"] = {"confidence_threshold": 0.5, "use_gpu": True}
|
|
|
|
with open(config_path, 'w') as f:
|
|
json.dump(config, f, indent=4)
|
|
print(f"{Colors.GREEN}Updated config.json with missing sections{Colors.END}")
|
|
else:
|
|
print_result("config.json structure", True, "All required sections present")
|
|
|
|
# Check model paths in config
|
|
model_xml = config.get("detection_models", {}).get("yolo_model_xml", "")
|
|
model_bin = config.get("detection_models", {}).get("yolo_model_bin", "")
|
|
|
|
if not (base_dir / model_xml).exists() and model_xml:
|
|
print_result("Model path in config", False, f"Model XML not found at {model_xml}")
|
|
all_passed = False
|
|
issues.append(f"Invalid model path: {model_xml}")
|
|
else:
|
|
print_result("Model XML path", True, f"{model_xml}")
|
|
|
|
if not (base_dir / model_bin).exists() and model_bin:
|
|
print_result("Model path in config", False, f"Model BIN not found at {model_bin}")
|
|
all_passed = False
|
|
issues.append(f"Invalid model path: {model_bin}")
|
|
else:
|
|
print_result("Model BIN path", True, f"{model_bin}")
|
|
|
|
except json.JSONDecodeError:
|
|
print_result("config.json", False, "Invalid JSON format")
|
|
all_passed = False
|
|
issues.append("Invalid JSON in config.json")
|
|
|
|
if fix:
|
|
print(f"{Colors.YELLOW}Backing up and creating new config.json...{Colors.END}")
|
|
# Backup invalid config
|
|
os.rename(config_path, config_path.with_suffix('.json.bak'))
|
|
# Create new default config
|
|
default_config = {
|
|
"video_sources": {"default_camera_id": 0, "default_video": ""},
|
|
"detection_models": {
|
|
"yolo_model_xml": "openvino_models/yolo11n.xml",
|
|
"yolo_model_bin": "openvino_models/yolo11n.bin"
|
|
},
|
|
"detection_settings": {"confidence_threshold": 0.5, "use_gpu": True},
|
|
"ui_settings": {"theme": "dark", "show_fps": True, "default_tab": 0}
|
|
}
|
|
with open(config_path, 'w') as f:
|
|
json.dump(default_config, f, indent=4)
|
|
print(f"{Colors.GREEN}Created new default config.json{Colors.END}")
|
|
|
|
# Check for camera configuration files in violations directory
|
|
camera_config_dir = base_dir / "violations" / "checkpoints"
|
|
if camera_config_dir.exists():
|
|
has_camera_configs = any(f.endswith('.yaml') for f in os.listdir(camera_config_dir))
|
|
print_result("Camera configurations", has_camera_configs,
|
|
"Found camera config files" if has_camera_configs else "No camera config files found (not critical)")
|
|
else:
|
|
print_result("Camera configurations", True, "Camera config directory not found (not critical)")
|
|
|
|
return all_passed, issues
|
|
|
|
def check_ui_components(base_dir: Path, verbose: bool = False) -> Tuple[bool, List[str]]:
|
|
"""Check if all UI components exist and can be imported"""
|
|
print_header("Checking UI Components")
|
|
all_passed = True
|
|
issues = []
|
|
|
|
# List of critical UI files to check
|
|
ui_files = [
|
|
"ui/main_window.py",
|
|
"ui/fixed_live_tab.py",
|
|
"ui/analytics_tab.py",
|
|
"ui/violations_tab.py",
|
|
"ui/export_tab.py",
|
|
"ui/config_panel.py"
|
|
]
|
|
|
|
# Check file existence
|
|
for ui_file in ui_files:
|
|
file_path = base_dir / ui_file
|
|
if file_path.exists():
|
|
print_result(ui_file, True, "File exists")
|
|
else:
|
|
print_result(ui_file, False, "File not found")
|
|
all_passed = False
|
|
issues.append(f"Missing UI file: {ui_file}")
|
|
|
|
# Try importing main window
|
|
if verbose:
|
|
print("\nAttempting to import main window class...")
|
|
try:
|
|
sys.path.insert(0, str(base_dir))
|
|
from ui.main_window import MainWindow
|
|
print_result("MainWindow import", True, "Import successful")
|
|
except ImportError as e:
|
|
print_result("MainWindow import", False, f"Import failed: {str(e)}")
|
|
all_passed = False
|
|
issues.append(f"Failed to import MainWindow: {str(e)}")
|
|
except Exception as e:
|
|
print_result("MainWindow import", False, f"Error: {str(e)}")
|
|
all_passed = False
|
|
issues.append(f"Error importing MainWindow: {str(e)}")
|
|
if verbose:
|
|
traceback.print_exc()
|
|
|
|
return all_passed, issues
|
|
|
|
def check_controllers(base_dir: Path, verbose: bool = False) -> Tuple[bool, List[str]]:
|
|
"""Check if all controllers exist and can be imported"""
|
|
print_header("Checking Controllers")
|
|
all_passed = True
|
|
issues = []
|
|
|
|
# List of controller files to check
|
|
controller_files = [
|
|
"controllers/video_controller_new.py",
|
|
"controllers/analytics_controller.py",
|
|
"controllers/model_manager.py",
|
|
"controllers/performance_overlay.py"
|
|
]
|
|
|
|
# Check file existence
|
|
for controller_file in controller_files:
|
|
file_path = base_dir / controller_file
|
|
if file_path.exists():
|
|
print_result(controller_file, True, "File exists")
|
|
else:
|
|
print_result(controller_file, False, "File not found")
|
|
all_passed = False
|
|
issues.append(f"Missing controller file: {controller_file}")
|
|
|
|
# Try importing video controller
|
|
if verbose:
|
|
print("\nAttempting to import VideoController...")
|
|
try:
|
|
sys.path.insert(0, str(base_dir))
|
|
from controllers.video_controller_new import VideoController
|
|
print_result("VideoController import", True, "Import successful")
|
|
except ImportError as e:
|
|
print_result("VideoController import", False, f"Import failed: {str(e)}")
|
|
all_passed = False
|
|
issues.append(f"Failed to import VideoController: {str(e)}")
|
|
except Exception as e:
|
|
print_result("VideoController import", False, f"Error: {str(e)}")
|
|
all_passed = False
|
|
issues.append(f"Error importing VideoController: {str(e)}")
|
|
if verbose:
|
|
traceback.print_exc()
|
|
|
|
return all_passed, issues
|
|
|
|
def check_hardware_compatibility(verbose: bool = False) -> Tuple[bool, Dict[str, Any]]:
|
|
"""Check hardware compatibility for OpenVINO and GPU acceleration"""
|
|
print_header("Checking Hardware Compatibility")
|
|
result = {
|
|
"cpu_compatible": True,
|
|
"gpu_available": False,
|
|
"openvino_available": False,
|
|
"system_info": {
|
|
"os": platform.system(),
|
|
"processor": platform.processor(),
|
|
"python_version": platform.python_version(),
|
|
}
|
|
}
|
|
|
|
# Print system information
|
|
print(f"OS: {result['system_info']['os']}")
|
|
print(f"Processor: {result['system_info']['processor']}")
|
|
print(f"Python Version: {result['system_info']['python_version']}")
|
|
|
|
# Check OpenVINO using subprocess to avoid import errors
|
|
openvino_check_cmd = [sys.executable, "-c", "import openvino; print(openvino.__version__)"]
|
|
try:
|
|
openvino_output = subprocess.run(openvino_check_cmd, capture_output=True, text=True)
|
|
if openvino_output.returncode == 0:
|
|
openvino_version = openvino_output.stdout.strip()
|
|
result["openvino_available"] = True
|
|
result["openvino_version"] = openvino_version
|
|
print_result("OpenVINO", True, f"Version {openvino_version}")
|
|
|
|
# Try to get available devices
|
|
device_check_cmd = [
|
|
sys.executable,
|
|
"-c",
|
|
"from openvino.runtime import Core; ie = Core(); print(','.join(ie.available_devices))"
|
|
]
|
|
device_output = subprocess.run(device_check_cmd, capture_output=True, text=True)
|
|
if device_output.returncode == 0:
|
|
devices = device_output.stdout.strip().split(',')
|
|
result["available_devices"] = devices
|
|
print(f"Available devices: {', '.join(devices)}")
|
|
|
|
# Check for GPU
|
|
if any("GPU" in device for device in devices):
|
|
result["gpu_available"] = True
|
|
print_result("GPU acceleration", True, "GPU device available for inference")
|
|
else:
|
|
print_result("GPU acceleration", False, "No GPU device available for inference")
|
|
else:
|
|
print_result("Device query", False, "Could not query OpenVINO devices")
|
|
if verbose and device_output.stderr:
|
|
print(f"Error: {device_output.stderr}")
|
|
else:
|
|
print_result("OpenVINO", False, "OpenVINO not installed or not working")
|
|
if verbose and openvino_output.stderr:
|
|
print(f"Error: {openvino_output.stderr}")
|
|
except Exception as e:
|
|
print_result("OpenVINO", False, f"Error checking OpenVINO: {str(e)}")
|
|
result["openvino_available"] = False
|
|
if verbose:
|
|
traceback.print_exc()
|
|
|
|
# Check for CUDA if torch is available using subprocess
|
|
torch_check_cmd = [
|
|
sys.executable,
|
|
"-c",
|
|
"import torch; print(f'{torch.__version__},{torch.cuda.is_available()}')"
|
|
]
|
|
try:
|
|
torch_output = subprocess.run(torch_check_cmd, capture_output=True, text=True)
|
|
if torch_output.returncode == 0:
|
|
torch_info = torch_output.stdout.strip().split(',')
|
|
if len(torch_info) == 2:
|
|
torch_version = torch_info[0]
|
|
cuda_available = torch_info[1].lower() == 'true'
|
|
result["torch_available"] = True
|
|
result["torch_version"] = torch_version
|
|
result["cuda_available"] = cuda_available
|
|
|
|
if cuda_available:
|
|
# Get CUDA details
|
|
cuda_info_cmd = [
|
|
sys.executable,
|
|
"-c",
|
|
"import torch; print(f'{torch.version.cuda},{torch.cuda.device_count()},{torch.cuda.get_device_name(0) if torch.cuda.device_count() > 0 else \"Unknown\"}')"
|
|
]
|
|
cuda_output = subprocess.run(cuda_info_cmd, capture_output=True, text=True)
|
|
if cuda_output.returncode == 0:
|
|
cuda_info = cuda_output.stdout.strip().split(',')
|
|
if len(cuda_info) == 3:
|
|
cuda_version = cuda_info[0]
|
|
device_count = cuda_info[1]
|
|
device_name = cuda_info[2]
|
|
|
|
print_result("PyTorch CUDA", True,
|
|
f"CUDA {cuda_version}, {device_count} device(s): {device_name}")
|
|
result["cuda_version"] = cuda_version
|
|
result["cuda_device_count"] = int(device_count)
|
|
result["cuda_device_name"] = device_name
|
|
|
|
# Update GPU availability
|
|
result["gpu_available"] = True
|
|
else:
|
|
print_result("PyTorch CUDA details", False, "Could not get CUDA details")
|
|
if verbose and cuda_output.stderr:
|
|
print(f"Error: {cuda_output.stderr}")
|
|
else:
|
|
print_result("PyTorch CUDA", False, "CUDA not available")
|
|
else:
|
|
print_result("PyTorch", False, "PyTorch not installed")
|
|
if verbose and torch_output.stderr:
|
|
print(f"Error: {torch_output.stderr}")
|
|
except Exception as e:
|
|
print_result("PyTorch check", False, f"Error: {str(e)}")
|
|
result["torch_available"] = False
|
|
if verbose:
|
|
traceback.print_exc()
|
|
|
|
# Consider the system compatible if either OpenVINO is available or GPU acceleration is available
|
|
return result["openvino_available"] or result["gpu_available"], result
|
|
|
|
def check_camera_access(verbose: bool = False) -> Tuple[bool, List[int]]:
|
|
"""Check if cameras are accessible"""
|
|
print_header("Checking Camera Access")
|
|
|
|
available_cameras = []
|
|
camera_access = False
|
|
|
|
# Use subprocess to run OpenCV check to avoid direct import errors
|
|
cv2_check_script = """
|
|
import cv2
|
|
import json
|
|
import sys
|
|
|
|
def check_cameras(max_id=3):
|
|
results = []
|
|
for camera_id in range(max_id+1):
|
|
cap = cv2.VideoCapture(camera_id)
|
|
if cap.isOpened():
|
|
ret, frame = cap.read()
|
|
if ret:
|
|
h, w = frame.shape[:2]
|
|
results.append({
|
|
'id': camera_id,
|
|
'accessible': True,
|
|
'width': w,
|
|
'height': h
|
|
})
|
|
else:
|
|
results.append({
|
|
'id': camera_id,
|
|
'accessible': False
|
|
})
|
|
cap.release()
|
|
else:
|
|
results.append({
|
|
'id': camera_id,
|
|
'accessible': False
|
|
})
|
|
return results
|
|
|
|
# Only check additional cameras if verbose mode is enabled
|
|
max_id = 3 if len(sys.argv) > 1 and sys.argv[1] == 'verbose' else 0
|
|
results = check_cameras(max_id)
|
|
print(json.dumps(results))
|
|
"""
|
|
|
|
try:
|
|
# Execute the camera check script
|
|
cmd = [sys.executable, "-c", cv2_check_script]
|
|
if verbose:
|
|
cmd.append("verbose")
|
|
|
|
result = subprocess.run(cmd, capture_output=True, text=True)
|
|
|
|
if result.returncode == 0:
|
|
try:
|
|
camera_results = json.loads(result.stdout)
|
|
for camera in camera_results:
|
|
camera_id = camera.get('id', 0)
|
|
if camera.get('accessible', False):
|
|
camera_access = True
|
|
available_cameras.append(camera_id)
|
|
resolution = f"{camera.get('width', 'unknown')}x{camera.get('height', 'unknown')}"
|
|
print_result(f"Camera (ID: {camera_id})", True, f"Accessible, Resolution: {resolution}")
|
|
else:
|
|
print_result(f"Camera (ID: {camera_id})", False, "Not accessible")
|
|
except json.JSONDecodeError:
|
|
print_result("Camera check", False, "Error parsing camera results")
|
|
if verbose:
|
|
print(f"Output: {result.stdout}")
|
|
else:
|
|
print_result("Camera access", False, "OpenCV not installed or error accessing cameras")
|
|
if verbose and result.stderr:
|
|
print(f"Error: {result.stderr}")
|
|
except Exception as e:
|
|
print_result("Camera check", False, f"Error: {str(e)}")
|
|
if verbose:
|
|
traceback.print_exc()
|
|
|
|
return camera_access, available_cameras
|
|
|
|
def main():
|
|
"""Main function to run system validation"""
|
|
parser = argparse.ArgumentParser(description="Validate Traffic Monitoring System")
|
|
parser.add_argument("--fix", action="store_true", help="Attempt to fix issues")
|
|
parser.add_argument("--verbose", action="store_true", help="Show detailed output")
|
|
args = parser.parse_args()
|
|
|
|
# Get base directory
|
|
base_dir = Path(os.path.dirname(os.path.abspath(__file__)))
|
|
|
|
print(f"\n{Colors.BOLD}Traffic Monitoring System Validation{Colors.END}")
|
|
print(f"Base directory: {base_dir}")
|
|
print(f"Python executable: {sys.executable}")
|
|
|
|
# Run all checks
|
|
packages_ok, missing_packages = check_packages(fix=args.fix, verbose=args.verbose)
|
|
models_ok, missing_models = check_models(base_dir, fix=args.fix, verbose=args.verbose)
|
|
config_ok, config_issues = check_config(base_dir, fix=args.fix, verbose=args.verbose)
|
|
ui_ok, ui_issues = check_ui_components(base_dir, verbose=args.verbose)
|
|
controllers_ok, controller_issues = check_controllers(base_dir, verbose=args.verbose)
|
|
hw_ok, hw_info = check_hardware_compatibility(verbose=args.verbose)
|
|
camera_ok, available_cameras = check_camera_access(verbose=args.verbose)
|
|
|
|
# Print summary
|
|
print_header("Validation Summary")
|
|
print_result("Python Packages", packages_ok, f"{len(missing_packages)} issues" if missing_packages else "All required packages found")
|
|
print_result("Model Files", models_ok, f"{len(missing_models)} issues" if missing_models else "All model files found")
|
|
print_result("Configuration", config_ok, f"{len(config_issues)} issues" if config_issues else "Configuration valid")
|
|
print_result("UI Components", ui_ok, f"{len(ui_issues)} issues" if ui_issues else "All UI components found")
|
|
print_result("Controllers", controllers_ok, f"{len(controller_issues)} issues" if controller_issues else "All controllers found")
|
|
print_result("Hardware Compatibility", hw_ok, "GPU or OpenVINO available" if hw_ok else "No GPU or OpenVINO")
|
|
print_result("Camera Access", camera_ok, f"{len(available_cameras)} cameras available" if camera_ok else "No cameras accessible")
|
|
|
|
# Overall result
|
|
all_ok = packages_ok and models_ok and config_ok and ui_ok and controllers_ok and hw_ok
|
|
|
|
print(f"\n{Colors.BOLD}Overall Result: {'SUCCESS' if all_ok else 'ISSUES FOUND'}{Colors.END}")
|
|
if all_ok:
|
|
print(f"{Colors.GREEN}The system is correctly set up and should run without issues.{Colors.END}")
|
|
else:
|
|
print(f"{Colors.YELLOW}Please fix the issues reported above before running the application.{Colors.END}")
|
|
|
|
if missing_packages:
|
|
print(f"\n{Colors.BOLD}Missing Packages:{Colors.END}")
|
|
print(f"Run: {sys.executable} -m pip install " + " ".join(missing_packages))
|
|
|
|
if missing_models:
|
|
print(f"\n{Colors.BOLD}Missing Models:{Colors.END}")
|
|
print("Download missing model files or check their paths in config.json")
|
|
|
|
return 0 if all_ok else 1
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|