import logging import traceback import numpy as np from typing import Dict, List, Any, Optional logger = logging.getLogger(__name__) class ZoneEvaluator: """ 負責功能區域辨識的可行性評估和物件關聯性計算 評估是否應該進行區域劃分以及計算物件間的功能關聯性 """ def __init__(self): """初始化區域評估器""" try: # 定義物件間的功能關聯性評分表 # 分數越高表示兩個物件在功能上越相關,更可能出現在同一功能區域 self.relationship_pairs = { # 家具組合關係 - 這些組合通常出現在特定功能區域 frozenset([56, 60]): 1.0, # 椅子+桌子 (dining/work area) frozenset([57, 62]): 0.9, # 沙發+電視 (living area) frozenset([59, 58]): 0.7, # 床+植物 (bedroom decor) # 工作相關組合 - 工作環境的典型配置 frozenset([63, 66]): 0.9, # 筆電+鍵盤 (workspace) frozenset([63, 64]): 0.8, # 筆電+滑鼠 (workspace) frozenset([60, 63]): 0.8, # 桌子+筆電 (workspace) # 廚房相關組合 - 廚房設備的常見的物品 frozenset([68, 72]): 0.9, # 微波爐+冰箱 (kitchen) frozenset([69, 71]): 0.8, # 烤箱+水槽 (kitchen) # 用餐相關組合 - 餐廳或用餐區域的典型物品 frozenset([60, 40]): 0.8, # 桌子+酒杯 (dining) frozenset([60, 41]): 0.8, # 桌子+杯子 (dining) frozenset([56, 40]): 0.7, # 椅子+酒杯 (dining) # 交通相關組合 - 城市交通的環境 frozenset([2, 9]): 0.8, # 汽車+交通燈 (traffic) frozenset([0, 9]): 0.7, # 行人+交通燈 (crosswalk) } logger.info("ZoneEvaluator initialized with predefined relationship pairs") except Exception as e: logger.error(f"Failed to initialize ZoneEvaluator: {str(e)}") logger.error(traceback.format_exc()) raise def evaluate_zone_identification_feasibility(self, detected_objects: List[Dict], scene_type: str) -> bool: """ 基於物件關聯性和分布特徵的彈性可行性評估 決定是否應該進行功能區域劃分 Args: detected_objects: 檢測到的物件列表 scene_type: 場景類型 Returns: 是否適合進行區域識別 """ try: if len(detected_objects) < 2: logger.info("Insufficient objects for zone identification (minimum 2 required)") return False # 計算不同置信度層級的物件分布 # 高信心度物件更可靠,用於核心區域判斷 high_conf_objects = [obj for obj in detected_objects if obj.get("confidence", 0) >= 0.6] # 中等置信度物件提供補充資訊 medium_conf_objects = [obj for obj in detected_objects if obj.get("confidence", 0) >= 0.4] # 基礎條件:至少需要一定數量的可信物件才值得進行區域分析 if len(medium_conf_objects) < 2: logger.info("Insufficient medium confidence objects for zone identification") return False # 評估物件間的功能關聯性,關聯性高的物件更適合劃分功能區域 functional_relationships = self.calculate_functional_relationships(detected_objects) # 評估空間分布多樣性 - 物件分散在多個區域才有劃分的意義 spatial_diversity = self.calculate_spatial_diversity(detected_objects) # 綜合評分機制,用各項指標加權計算最終可行性評分 feasibility_score = 0 # 物件數量的貢獻(權重30%)- 更多物件提供更多劃分依據 object_count_score = min(len(detected_objects) / 5.0, 1.0) * 0.3 # 信心度質量貢獻(權重25%)- 高置信度物件比例影響可靠性 confidence_score = len(high_conf_objects) / max(len(detected_objects), 1) * 0.25 # 功能關聯性貢獻(權重25%)- 有功能關聯的物件更適合劃分區域 relationship_score = functional_relationships * 0.25 # 空間多樣性貢獻(權重20%)- 分散的物件才需要區域劃分 diversity_score = spatial_diversity * 0.20 feasibility_score = object_count_score + confidence_score + relationship_score + diversity_score # 動態閾值:根據場景複雜度調整可行性標準 complexity_threshold = self.get_complexity_threshold(scene_type) is_feasible = feasibility_score >= complexity_threshold logger.info(f"Zone identification feasibility: {is_feasible} (score: {feasibility_score:.3f}, threshold: {complexity_threshold:.3f})") logger.debug(f"Score breakdown - objects: {object_count_score:.3f}, confidence: {confidence_score:.3f}, relationships: {relationship_score:.3f}, diversity: {diversity_score:.3f}") return is_feasible except Exception as e: logger.error(f"Error evaluating zone identification feasibility: {str(e)}") logger.error(traceback.format_exc()) return False def calculate_functional_relationships(self, detected_objects: List[Dict]) -> float: """ 計算物件間的功能關聯性評分 基於常見的物件組合模式評估功能相關性 Args: detected_objects: 檢測到的物件列表 Returns: 功能關聯性評分 (0.0-1.0) """ try: detected_class_ids = set(obj.get("class_id") for obj in detected_objects) max_possible_score = 0 actual_score = 0 # 遍歷所有預定義的關聯性組合,計算實際場景中的關聯性評分 for pair, score in self.relationship_pairs.items(): max_possible_score += score # 如果檢測到的物件中包含這個關聯組合,累加其評分 if pair.issubset(detected_class_ids): actual_score += score logger.debug(f"Found functional relationship: {pair} with score {score}") # 標準化評分:實際評分除以最大可能評分 relationship_score = actual_score / max_possible_score if max_possible_score > 0 else 0 logger.info(f"Functional relationships calculated: {relationship_score:.3f} (found {actual_score:.1f}/{max_possible_score:.1f} possible relationships)") return relationship_score except Exception as e: logger.error(f"Error calculating functional relationships: {str(e)}") logger.error(traceback.format_exc()) return 0 def calculate_spatial_diversity(self, detected_objects: List[Dict]) -> float: """ 計算物件空間分布的多樣性 評估物件是否分散在不同區域,避免所有物件集中在單一區域 Args: detected_objects: 檢測到的物件列表 Returns: 空間多樣性評分 (0.0-1.0) """ try: # 收集所有物件所在的不同區域 regions = set(obj.get("region", "center") for obj in detected_objects) unique_regions = len(regions) # 標準化多樣性評分:假設理想情況是物件分散在2個以上區域 # 更多區域意味著更高的空間多樣性,更適合進行區域劃分 diversity_score = min(unique_regions / 2.0, 1.0) logger.info(f"Spatial diversity calculated: {diversity_score:.3f} (objects distributed across {unique_regions} regions)") return diversity_score except Exception as e: logger.error(f"Error calculating spatial diversity: {str(e)}") logger.error(traceback.format_exc()) return 0 def get_complexity_threshold(self, scene_type: str) -> float: """ 根據場景類型返回適當的複雜度閾值 平衡不同場景的區域劃分需求 Args: scene_type: 場景類型 Returns: 複雜度閾值 (0.0-1.0) """ try: # 較簡單場景需要較高分數才進行區域劃分 # 這些場景通常功能較為單純,不太需要細分 simple_scenes = ["bedroom", "bathroom", "closet"] # 較複雜場景可以較低分數進行區域劃分 # 這些場景通常有多種功能,適合劃分不同區域 complex_scenes = ["living_room", "kitchen", "office_workspace", "dining_area"] if scene_type in simple_scenes: threshold = 0.65 # 較高閾值,避免過度細分 logger.debug(f"Using high threshold {threshold} for simple scene: {scene_type}") elif scene_type in complex_scenes: threshold = 0.45 # 較低閾值,允許合理劃分 logger.debug(f"Using low threshold {threshold} for complex scene: {scene_type}") else: threshold = 0.55 # 中等閾值,平衡策略 logger.debug(f"Using medium threshold {threshold} for scene: {scene_type}") return threshold except Exception as e: logger.error(f"Error getting complexity threshold for scene '{scene_type}': {str(e)}") logger.error(traceback.format_exc()) return 0.55 # 預設中等閾值 def analyze_object_clustering(self, detected_objects: List[Dict]) -> Dict: """ 分析物件的聚集模式 識別物件是否形成明顯的聚集群組,這有助於功能區域的劃分 Args: detected_objects: 檢測到的物件列表 Returns: 包含聚集分析結果的字典 """ try: clustering_result = { "has_clusters": False, "cluster_count": 0, "cluster_regions": [], "clustering_score": 0.0 } if len(detected_objects) < 3: logger.info("Insufficient objects for clustering analysis") return clustering_result # 統計每個區域的物件數量 region_counts = {} for obj in detected_objects: region = obj.get("region", "unknown") region_counts[region] = region_counts.get(region, 0) + 1 # 找出有顯著物件聚集的區域(物件數量 >= 2) significant_regions = [region for region, count in region_counts.items() if count >= 2] # 計算聚集:聚集區域數量與總區域數量的比例 total_regions_with_objects = len([count for count in region_counts.values() if count > 0]) clustering_score = len(significant_regions) / max(total_regions_with_objects, 1) clustering_result.update({ "has_clusters": len(significant_regions) >= 2, "cluster_count": len(significant_regions), "cluster_regions": significant_regions, "clustering_score": clustering_score }) logger.info(f"Object clustering analysis: {len(significant_regions)} clusters found in regions {significant_regions}") return clustering_result except Exception as e: logger.error(f"Error analyzing object clustering: {str(e)}") logger.error(traceback.format_exc()) return { "has_clusters": False, "cluster_count": 0, "cluster_regions": [], "clustering_score": 0.0 }