Spaces:
Running
on
Zero
Running
on
Zero
import logging | |
import numpy as np | |
from typing import Dict, List, Optional, Any | |
class ProminenceCalculator: | |
""" | |
重要性計算器 - 專門處理物件重要性評估和篩選邏輯 | |
負責計算物件的重要性分數、類別重要性係數以及重要物件的篩選 | |
""" | |
def __init__(self, min_prominence_score: float = 0.1): | |
""" | |
初始化重要性計算器 | |
Args: | |
min_prominence_score: 物件顯著性的最低分數閾值 | |
""" | |
self.logger = logging.getLogger(self.__class__.__name__) | |
self.min_prominence_score = min_prominence_score | |
def calculate_prominence_score(self, obj: Dict) -> float: | |
""" | |
計算物件的重要性評分 | |
基本上權重設定為信心度 > 尺寸 > 空間 > 類別重要性 | |
Args: | |
obj: 物件字典,包含檢測信息 | |
Returns: | |
float: 重要性評分 (0.0-1.0) | |
""" | |
try: | |
# 基礎置信度評分 (權重: 40%) | |
confidence = obj.get("confidence", 0.5) | |
confidence_score = confidence * 0.4 | |
# 大小評分 (權重: 30%) | |
normalized_area = obj.get("normalized_area", 0.1) | |
# 使用對數縮放避免過大物件主導評分 | |
size_score = min(np.log(normalized_area * 10 + 1) / np.log(11), 1.0) * 0.3 | |
# 位置評分 (權重: 20%) | |
# 中心區域的物件通常更重要 | |
center_x, center_y = obj.get("normalized_center", [0.5, 0.5]) | |
distance_from_center = np.sqrt((center_x - 0.5)**2 + (center_y - 0.5)**2) | |
position_score = (1 - min(distance_from_center * 2, 1.0)) * 0.2 | |
# 類別重要性評分 (權重: 10%) | |
class_importance = self.get_class_importance(obj.get("class_name", "unknown")) | |
class_score = class_importance * 0.1 | |
total_score = confidence_score + size_score + position_score + class_score | |
# 確保評分在有效範圍內 | |
return max(0.0, min(1.0, total_score)) | |
except Exception as e: | |
self.logger.warning(f"Error calculating prominence score for object: {str(e)}") | |
return 0.5 # 返回中等評分作為備用 | |
def get_class_importance(self, class_name: str) -> float: | |
""" | |
根據物件類別返回重要性係數 | |
Args: | |
class_name: 物件類別名稱 | |
Returns: | |
float: 類別重要性係數 (0.0-1.0) | |
""" | |
# 高重要性物件(人、車輛、建築) | |
high_importance = ["person", "car", "truck", "bus", "motorcycle", "bicycle", "building"] | |
# 中等重要性物件(家具、電器) | |
medium_importance = ["chair", "couch", "tv", "laptop", "refrigerator", "dining table", "bed"] | |
# 低重要性物件(小物品、配件) | |
low_importance = ["handbag", "backpack", "umbrella", "cell phone", "remote", "mouse"] | |
class_name_lower = class_name.lower() | |
if any(item in class_name_lower for item in high_importance): | |
return 1.0 | |
elif any(item in class_name_lower for item in medium_importance): | |
return 0.7 | |
elif any(item in class_name_lower for item in low_importance): | |
return 0.4 | |
else: | |
return 0.6 # 預設中等重要性 | |
def filter_prominent_objects(self, detected_objects: List[Dict], | |
min_prominence_score: float = 0.5, | |
max_categories_to_return: Optional[int] = None) -> List[Dict]: | |
""" | |
獲取最重要的物件,基於置信度、大小和位置計算重要性評分 | |
Args: | |
detected_objects: 檢測到的物件列表 | |
min_prominence_score: 最小重要性分數閾值,範圍 0.0-1.0 | |
max_categories_to_return: 可選的最大返回類別數量限制 | |
Returns: | |
List[Dict]: 按重要性排序的物件列表 | |
""" | |
try: | |
if not detected_objects: | |
return [] | |
prominent_objects = [] | |
for obj in detected_objects: | |
# 計算重要性評分 | |
prominence_score = self.calculate_prominence_score(obj) | |
# 只保留超過閾值的物件 | |
if prominence_score >= min_prominence_score: | |
obj_copy = obj.copy() | |
obj_copy['prominence_score'] = prominence_score | |
prominent_objects.append(obj_copy) | |
# 按重要性評分排序(從高到低) | |
prominent_objects.sort(key=lambda x: x.get('prominence_score', 0), reverse=True) | |
# 如果指定了最大類別數量限制,進行過濾 | |
if max_categories_to_return is not None and max_categories_to_return > 0: | |
categories_seen = set() | |
filtered_objects = [] | |
for obj in prominent_objects: | |
class_name = obj.get("class_name", "unknown") | |
# 如果是新類別且未達到限制 | |
if class_name not in categories_seen: | |
if len(categories_seen) < max_categories_to_return: | |
categories_seen.add(class_name) | |
filtered_objects.append(obj) | |
else: | |
# 已見過的類別,直接添加 | |
filtered_objects.append(obj) | |
return filtered_objects | |
return prominent_objects | |
except Exception as e: | |
self.logger.error(f"Error calculating prominent objects: {str(e)}") | |
return [] | |