import logging from typing import Dict, List, Optional, Any class StatisticsProcessor: """ 統計分析處理器 - 負責複雜的物件統計分析和數據轉換 此類別專門處理物件統計信息的深度分析、Places365信息處理, 以及基於統計數據生成替換內容的複雜邏輯。 """ def __init__(self): """初始化統計分析處理器""" self.logger = logging.getLogger(self.__class__.__name__) self.logger.debug("StatisticsProcessor initialized successfully") def generate_statistics_replacements(self, object_statistics: Optional[Dict]) -> Dict[str, str]: """ 基於物體統計信息生成模板替換內容 Args: object_statistics: 物體統計信息 Returns: Dict[str, str]: 統計信息基礎的替換內容 """ replacements = {} if not object_statistics: return replacements try: # 處理植物元素 if "potted plant" in object_statistics: count = object_statistics["potted plant"]["count"] if count == 1: replacements["plant_elements"] = "a potted plant" elif count <= 3: replacements["plant_elements"] = f"{count} potted plants" else: replacements["plant_elements"] = f"multiple potted plants ({count} total)" # 處理座位(椅子)相關 if "chair" in object_statistics: count = object_statistics["chair"]["count"] # 使用統一的數字轉換邏輯 number_words = { 1: "one", 2: "two", 3: "three", 4: "four", 5: "five", 6: "six", 7: "seven", 8: "eight", 9: "nine", 10: "ten", 11: "eleven", 12: "twelve" } if count == 1: replacements["seating"] = "a chair" replacements["furniture"] = "a chair" elif count in number_words: word_count = number_words[count] replacements["seating"] = f"{word_count} chairs" replacements["furniture"] = f"{word_count} chairs" elif count <= 20: replacements["seating"] = f"several chairs" replacements["furniture"] = f"several chairs" else: replacements["seating"] = f"numerous chairs ({count} total)" replacements["furniture"] = f"numerous chairs" # 處理混合家具情況(當存在多種家具類型時) furniture_items = [] furniture_counts = [] # 收集所有家具類型的統計 for furniture_type in ["chair", "dining table", "couch", "bed"]: if furniture_type in object_statistics: count = object_statistics[furniture_type]["count"] if count > 0: furniture_items.append(furniture_type) furniture_counts.append(count) # 如果只有椅子,那就用上面的方式 # 如果有多種家具類型,生成組合描述 if len(furniture_items) > 1 and "furniture" not in replacements: main_furniture = furniture_items[0] # 數量最多的家具類型 main_count = furniture_counts[0] if main_furniture == "chair": number_words = ["", "one", "two", "three", "four", "five", "six"] if main_count <= 6: replacements["furniture"] = f"{number_words[main_count]} chairs and other furniture" else: replacements["furniture"] = "multiple chairs and other furniture" # 處理人員 if "person" in object_statistics: count = object_statistics["person"]["count"] if count == 1: replacements["people_and_vehicles"] = "a person" replacements["pedestrian_flow"] = "an individual walking" elif count <= 5: replacements["people_and_vehicles"] = f"{count} people" replacements["pedestrian_flow"] = f"{count} people walking" else: replacements["people_and_vehicles"] = f"many people ({count} individuals)" replacements["pedestrian_flow"] = f"a crowd of {count} people" # 處理桌子設置 if "dining table" in object_statistics: count = object_statistics["dining table"]["count"] if count == 1: replacements["table_setup"] = "a dining table" replacements["table_description"] = "a dining surface" else: replacements["table_setup"] = f"{count} dining tables" replacements["table_description"] = f"{count} dining surfaces" self.logger.debug(f"Generated {len(replacements)} statistics-based replacements") except Exception as e: self.logger.warning(f"Error generating statistics replacements: {str(e)}") return replacements def generate_places365_replacements(self, places365_info: Optional[Dict]) -> Dict[str, str]: """ 基於Places365信息生成模板替換內容 Args: places365_info: Places365場景分類信息 Returns: Dict[str, str]: Places365基礎的替換內容 """ replacements = {} if not places365_info or places365_info.get('confidence', 0) <= 0.35: replacements["places365_context"] = "" replacements["places365_atmosphere"] = "" return replacements try: scene_label = places365_info.get('scene_label', '').replace('_', ' ') attributes = places365_info.get('attributes', []) # 生成場景上下文 if scene_label: replacements["places365_context"] = f"characteristic of a {scene_label}" else: replacements["places365_context"] = "" # 生成氛圍描述 if 'natural_lighting' in attributes: replacements["places365_atmosphere"] = "with natural illumination" elif 'artificial_lighting' in attributes: replacements["places365_atmosphere"] = "under artificial lighting" else: replacements["places365_atmosphere"] = "" self.logger.debug("Generated Places365-based replacements") except Exception as e: self.logger.warning(f"Error generating Places365 replacements: {str(e)}") replacements["places365_context"] = "" replacements["places365_atmosphere"] = "" return replacements def analyze_scene_composition(self, detected_objects: List[Dict]) -> Dict: """ 分析場景組成以確定模板複雜度 Args: detected_objects: 檢測到的物件列表 Returns: Dict: 場景組成統計信息 """ try: total_objects = len(detected_objects) # 統計不同類型的物件 object_categories = {} for obj in detected_objects: class_name = obj.get("class_name", "unknown") object_categories[class_name] = object_categories.get(class_name, 0) + 1 # 計算場景多樣性 unique_categories = len(object_categories) return { "total_objects": total_objects, "unique_categories": unique_categories, "category_distribution": object_categories, "complexity_score": min(total_objects * 0.3 + unique_categories * 0.7, 10) } except Exception as e: self.logger.warning(f"Error analyzing scene composition: {str(e)}") return {"total_objects": 0, "unique_categories": 0, "complexity_score": 0} def generate_zone_descriptions(self, zone_data: Dict[str, Any], section: Dict[str, Any]) -> List[str]: """ 生成功能區域描述 Args: zone_data: 區域數據字典 section: 區域配置信息 Returns: List[str]: 區域描述列表 """ try: descriptions = [] if not zone_data: return descriptions # 直接處理區域資料(zone_data 本身就是區域字典) sorted_zones = sorted(zone_data.items(), key=lambda x: len(x[1].get("objects", [])), reverse=True) for zone_name, zone_info in sorted_zones: description = zone_info.get("description", "") objects = zone_info.get("objects", []) if objects: # 使用現有描述或生成基於物件的描述 if description and not any(tech in description.lower() for tech in ['zone', 'area', 'region']): zone_desc = description else: # 生成更自然的區域描述 clean_zone_name = zone_name.replace('_', ' ').replace(' area', '').replace(' zone', '') object_list = ', '.join(objects[:3]) if 'crossing' in zone_name or 'pedestrian' in zone_name: zone_desc = f"In the central crossing area, there are {object_list}." elif 'vehicle' in zone_name or 'traffic' in zone_name: zone_desc = f"The vehicle movement area includes {object_list}." elif 'control' in zone_name: zone_desc = f"Traffic control elements include {object_list}." else: zone_desc = f"The {clean_zone_name} contains {object_list}." if len(objects) > 3: zone_desc += f" Along with {len(objects) - 3} additional elements." descriptions.append(zone_desc) return descriptions except Exception as e: self.logger.error(f"Error generating zone descriptions: {str(e)}") return [] def generate_object_summary(self, object_data: List[Dict], section: Dict[str, Any]) -> str: """ 生成物件摘要描述 Args: object_data: 物件數據列表 section: 摘要配置信息 Returns: str: 物件摘要描述 """ try: if not object_data: return "" # 統計物件類型並計算重要性 object_stats = {} for obj in object_data: class_name = obj.get("class_name", "unknown") confidence = obj.get("confidence", 0.5) if class_name not in object_stats: object_stats[class_name] = {"count": 0, "total_confidence": 0} object_stats[class_name]["count"] += 1 object_stats[class_name]["total_confidence"] += confidence # 按重要性排序(結合數量和置信度) sorted_objects = [] for class_name, stats in object_stats.items(): count = stats["count"] avg_confidence = stats["total_confidence"] / count importance = count * 0.6 + avg_confidence * 0.4 sorted_objects.append((class_name, count, importance)) sorted_objects.sort(key=lambda x: x[2], reverse=True) # 生成自然語言描述 descriptions = [] for class_name, count, _ in sorted_objects[:5]: clean_name = class_name.replace('_', ' ') if count == 1: article = "an" if clean_name[0].lower() in 'aeiou' else "a" descriptions.append(f"{article} {clean_name}") else: descriptions.append(f"{count} {clean_name}s") if len(descriptions) == 1: return f"The scene features {descriptions[0]}." elif len(descriptions) == 2: return f"The scene features {descriptions[0]} and {descriptions[1]}." else: main_items = ", ".join(descriptions[:-1]) return f"The scene features {main_items}, and {descriptions[-1]}." except Exception as e: self.logger.error(f"Error generating object summary: {str(e)}") return "" def generate_conclusion(self, template: Dict[str, Any], zone_data: Dict[str, Any], object_data: List[Dict]) -> str: """ 生成結論描述 Args: template: 模板配置信息 zone_data: 區域數據 object_data: 物件數據 Returns: str: 結論描述 """ try: scene_type = template.get("scene_type", "general") zones_count = len(zone_data) objects_count = len(object_data) if scene_type == "indoor": conclusion = f"This indoor environment demonstrates clear functional organization with {zones_count} distinct areas and {objects_count} identified objects." elif scene_type == "outdoor": conclusion = f"This outdoor scene shows dynamic activity patterns across {zones_count} functional zones with {objects_count} detected elements." else: conclusion = f"The scene analysis reveals {zones_count} functional areas containing {objects_count} identifiable objects." return conclusion except Exception as e: self.logger.error(f"Error generating conclusion: {str(e)}") return ""