VisionScout / zone_evaluator.py
DawnC's picture
Upload 59 files
e6a18b7 verified
raw
history blame
12 kB
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
}