| """ | |
| config.py - Configuration Management System | |
| """ | |
| import yaml | |
| from pathlib import Path | |
| from typing import Any, Dict, Optional | |
| class Config: | |
| def __init__(self, config_path: str = "config.yaml"): | |
| self.config_path = Path(config_path) | |
| self.config = self._load_config() | |
| print(f"β Configuration loaded") | |
| def _load_config(self) -> Dict: | |
| if not self.config_path.exists(): | |
| print(f"β οΈ Config file not found: {self.config_path}") | |
| print(" Using default configuration") | |
| return self._get_defaults() | |
| try: | |
| with open(self.config_path, 'r', encoding='utf-8') as f: | |
| config = yaml.safe_load(f) | |
| print(f" Loaded from: {self.config_path}") | |
| return config | |
| except Exception as e: | |
| print(f"β Error loading config: {e}") | |
| print(" Using default configuration") | |
| return self._get_defaults() | |
| def _get_defaults(self) -> Dict: | |
| return { | |
| 'detection': { | |
| 'model': 'yolov8m.pt', | |
| 'confidence_threshold': 0.50, | |
| 'min_detection_area': 900, | |
| 'dog_class_id': 16 | |
| }, | |
| 'pose_detection': { | |
| 'model': 'dog-pose-trained.pt', | |
| 'confidence_threshold': 0.5, | |
| 'input_size': 640, | |
| 'keypoint_8_indices': [0, 3, 7, 10, 12, 14, 17, 19] | |
| }, | |
| 'tracking': { | |
| 'max_iou_distance': 0.5, | |
| 'max_age': 90, | |
| 'n_init': 1, | |
| 'use_appearance': True, | |
| 'deletion_threshold_confirmed': 30, | |
| 'deletion_threshold_tentative': 5 | |
| }, | |
| 'reid': { | |
| 'model': 'hf-hub:BVRA/MegaDescriptor-L-384', | |
| 'threshold': 0.40, | |
| 'permanent_db_threshold_offset': 0.15, | |
| 'max_features_per_dog': 30 | |
| }, | |
| 'health': { | |
| 'temporal_window': 15, | |
| 'min_visible_keypoints': 12, | |
| 'min_view_score': 0.7, | |
| 'blur_threshold': 75 | |
| }, | |
| 'dataset': { | |
| 'min_images_per_dog': 14, | |
| 'max_images_per_dog': 30, | |
| 'min_frame_gap': 15, | |
| 'sample_rate': 1 | |
| }, | |
| 'map': { | |
| 'default_location': [38.9637, 35.2433], | |
| 'default_zoom': 13 | |
| }, | |
| 'database': { | |
| 'path': 'dog_monitoring.db', | |
| 'backup_enabled': True | |
| }, | |
| 'app': { | |
| 'max_video_duration': 600, | |
| 'max_memory_mb': 2000, | |
| 'max_total_dogs': 50 | |
| } | |
| } | |
| def get(self, path: str, default: Any = None) -> Any: | |
| keys = path.split('.') | |
| value = self.config | |
| for key in keys: | |
| if isinstance(value, dict) and key in value: | |
| value = value[key] | |
| else: | |
| return default | |
| return value | |
| def set(self, path: str, value: Any): | |
| keys = path.split('.') | |
| config = self.config | |
| for key in keys[:-1]: | |
| if key not in config: | |
| config[key] = {} | |
| config = config[key] | |
| config[keys[-1]] = value | |
| def save(self, output_path: Optional[str] = None): | |
| save_path = Path(output_path) if output_path else self.config_path | |
| try: | |
| with open(save_path, 'w', encoding='utf-8') as f: | |
| yaml.dump(self.config, f, default_flow_style=False, allow_unicode=True) | |
| print(f"β Configuration saved to {save_path}") | |
| except Exception as e: | |
| print(f"β Error saving config: {e}") | |
| def get_detection_config(self) -> Dict: | |
| return self.config.get('detection', self._get_defaults()['detection']) | |
| def get_pose_config(self) -> Dict: | |
| return self.config.get('pose_detection', self._get_defaults()['pose_detection']) | |
| def get_tracking_config(self) -> Dict: | |
| return self.config.get('tracking', self._get_defaults()['tracking']) | |
| def get_reid_config(self) -> Dict: | |
| return self.config.get('reid', self._get_defaults()['reid']) | |
| def get_health_config(self) -> Dict: | |
| return self.config.get('health', self._get_defaults()['health']) | |
| def get_dataset_config(self) -> Dict: | |
| return self.config.get('dataset', self._get_defaults()['dataset']) | |
| def get_map_config(self) -> Dict: | |
| return self.config.get('map', self._get_defaults()['map']) | |
| def get_database_config(self) -> Dict: | |
| return self.config.get('database', self._get_defaults()['database']) | |
| def get_app_config(self) -> Dict: | |
| return self.config.get('app', self._get_defaults()['app']) | |
| def print_config(self): | |
| print("\n" + "="*60) | |
| print("CURRENT CONFIGURATION") | |
| print("="*60) | |
| self._print_dict(self.config, indent=0) | |
| print("="*60 + "\n") | |
| def _print_dict(self, d: Dict, indent: int = 0): | |
| for key, value in d.items(): | |
| if isinstance(value, dict): | |
| print(" " * indent + f"{key}:") | |
| self._print_dict(value, indent + 1) | |
| else: | |
| print(" " * indent + f"{key}: {value}") | |
| def validate(self) -> bool: | |
| required_sections = ['detection', 'tracking', 'reid', 'health', 'database'] | |
| for section in required_sections: | |
| if section not in self.config: | |
| print(f"β Missing required section: {section}") | |
| return False | |
| print("β Configuration validated successfully") | |
| return True | |