VisionScout / functional_zone_detector.py
DawnC's picture
Upload 14 files
12d9ea9 verified
raw
history blame
11.6 kB
import logging
import traceback
from typing import Dict, List, Any, Optional
logger = logging.getLogger(__name__)
class FunctionalZoneDetector:
"""
負責基於物件關聯性的功能區域識別
處理物件組合分析和描述性區域命名
"""
def __init__(self):
"""初始化功能區域檢測器"""
try:
logger.info("FunctionalZoneDetector initialized successfully")
except Exception as e:
logger.error(f"Failed to initialize FunctionalZoneDetector: {str(e)}")
logger.error(traceback.format_exc())
raise
def identify_primary_functional_area(self, detected_objects: List[Dict]) -> Dict:
"""
識別主要功能區域,基於最強的物件關聯性組合
採用通用邏輯處理各種室內場景
Args:
detected_objects: 檢測到的物件列表
Returns:
主要功能區域字典或None
"""
try:
# 用餐區域檢測(桌椅組合)
dining_area = self.detect_functional_combination(
detected_objects,
primary_objects=[60], # dining table
supporting_objects=[56, 40, 41, 42, 43], # chair, wine glass, cup, fork, knife
min_supporting=2,
description_template="Dining area with table and seating arrangement"
)
if dining_area:
return dining_area
# 休息區域檢測(沙發電視組合或床)
seating_area = self.detect_functional_combination(
detected_objects,
primary_objects=[57, 59], # sofa, bed
supporting_objects=[62, 58, 56], # tv, potted plant, chair
min_supporting=1,
description_template="Seating and relaxation area"
)
if seating_area:
return seating_area
# 工作區域檢測(電子設備與家具組合)
work_area = self.detect_functional_combination(
detected_objects,
primary_objects=[63, 66], # laptop, keyboard
supporting_objects=[60, 56, 64], # dining table, chair, mouse
min_supporting=2,
description_template="Workspace area with electronics and furniture"
)
if work_area:
return work_area
return None
except Exception as e:
logger.error(f"Error identifying primary functional area: {str(e)}")
logger.error(traceback.format_exc())
return None
def identify_secondary_functional_area(self, detected_objects: List[Dict], existing_zones: Dict) -> Dict:
"""
識別次要功能區域,避免與主要區域重疊
Args:
detected_objects: 檢測到的物件列表
existing_zones: 已存在的功能區域
Returns:
次要功能區域字典或None
"""
try:
# 獲取已使用的區域
used_regions = set(zone.get("region") for zone in existing_zones.values())
# 裝飾區域檢測(植物集中區域)
decorative_area = self.detect_functional_combination(
detected_objects,
primary_objects=[58], # potted plant
supporting_objects=[75], # vase
min_supporting=0,
min_primary=3, # 至少需要3個植物
description_template="Decorative area with plants and ornamental items",
exclude_regions=used_regions
)
if decorative_area:
return decorative_area
# 儲存區域檢測(廚房電器組合)
storage_area = self.detect_functional_combination(
detected_objects,
primary_objects=[72, 68, 69], # refrigerator, microwave, oven
supporting_objects=[71], # sink
min_supporting=0,
min_primary=2,
description_template="Kitchen appliance and storage area",
exclude_regions=used_regions
)
if storage_area:
return storage_area
return None
except Exception as e:
logger.error(f"Error identifying secondary functional area: {str(e)}")
logger.error(traceback.format_exc())
return None
def detect_functional_combination(self, detected_objects: List[Dict], primary_objects: List[int],
supporting_objects: List[int], min_supporting: int,
description_template: str, min_primary: int = 1,
exclude_regions: set = None) -> Dict:
"""
通用的功能組合檢測方法
基於主要物件和支持物件的組合判斷功能區域
Args:
detected_objects: 檢測到的物件列表
primary_objects: 主要物件的class_id列表
supporting_objects: 支持物件的class_id列表
min_supporting: 最少需要的支持物件數量
description_template: 描述模板
min_primary: 最少需要的主要物件數量
exclude_regions: 需要排除的區域集合
Returns:
功能區域資訊字典,如果不符合條件則返回None
"""
try:
if exclude_regions is None:
exclude_regions = set()
# 收集主要物件
primary_objs = [obj for obj in detected_objects
if obj.get("class_id") in primary_objects and obj.get("confidence", 0) >= 0.4]
# 收集支持物件
supporting_objs = [obj for obj in detected_objects
if obj.get("class_id") in supporting_objects and obj.get("confidence", 0) >= 0.4]
# 檢查是否滿足最少數量要求
if len(primary_objs) < min_primary or len(supporting_objs) < min_supporting:
return None
# 按區域組織物件
region_combinations = {}
all_relevant_objs = primary_objs + supporting_objs
for obj in all_relevant_objs:
region = obj.get("region")
# 排除指定區域
if region in exclude_regions:
continue
if region not in region_combinations:
region_combinations[region] = {"primary": [], "supporting": [], "all": []}
region_combinations[region]["all"].append(obj)
if obj.get("class_id") in primary_objects:
region_combinations[region]["primary"].append(obj)
else:
region_combinations[region]["supporting"].append(obj)
# 找到最佳區域組合
best_region = None
best_score = 0
for region, objs in region_combinations.items():
# 計算該區域的評分
primary_count = len(objs["primary"])
supporting_count = len(objs["supporting"])
# 必須滿足最低要求
if primary_count < min_primary or supporting_count < min_supporting:
continue
# 計算組合評分(主要物件權重較高)
score = primary_count * 2 + supporting_count
if score > best_score:
best_score = score
best_region = region
if best_region is None:
return None
best_combination = region_combinations[best_region]
all_objects = [obj["class_name"] for obj in best_combination["all"]]
return {
"region": best_region,
"objects": all_objects,
"description": description_template
}
except Exception as e:
logger.error(f"Error detecting functional combination: {str(e)}")
logger.error(traceback.format_exc())
return None
def generate_descriptive_zone_key_from_data(self, zone_data: Dict, priority_level: str) -> str:
"""
基於區域與物品名產生一個比較有描述性的區域
Args:
zone_data: 區域數據字典
priority_level: 優先級別(primary/secondary)
Returns:
str: 描述性區域鍵名
"""
try:
objects = zone_data.get("objects", [])
region = zone_data.get("region", "")
description = zone_data.get("description", "")
# 基於物件內容確定功能類型
if any("dining" in obj.lower() or "table" in obj.lower() for obj in objects):
base_name = "dining area"
elif any("chair" in obj.lower() or "sofa" in obj.lower() for obj in objects):
base_name = "seating area"
elif any("bed" in obj.lower() for obj in objects):
base_name = "sleeping area"
elif any("laptop" in obj.lower() or "keyboard" in obj.lower() for obj in objects):
base_name = "workspace area"
elif any("plant" in obj.lower() or "vase" in obj.lower() for obj in objects):
base_name = "decorative area"
elif any("refrigerator" in obj.lower() or "microwave" in obj.lower() for obj in objects):
base_name = "kitchen area"
else:
# 基於描述內容推斷
if "dining" in description.lower():
base_name = "dining area"
elif "seating" in description.lower() or "relaxation" in description.lower():
base_name = "seating area"
elif "work" in description.lower():
base_name = "workspace area"
elif "decorative" in description.lower():
base_name = "decorative area"
else:
base_name = "functional area"
# 為次要區域添加位置標識以區分
if priority_level == "secondary" and region:
spatial_context = self.get_spatial_context_description(region)
if spatial_context:
return f"{spatial_context} {base_name}"
return base_name
except Exception as e:
logger.warning(f"Error generating descriptive zone key: {str(e)}")
return "activity area"
def get_spatial_context_description(self, region: str) -> str:
"""
獲取空間上下文描述
Args:
region: 區域位置標識
Returns:
str: 空間上下文描述
"""
try:
spatial_mapping = {
"top_left": "upper left",
"top_center": "upper",
"top_right": "upper right",
"middle_left": "left side",
"middle_center": "central",
"middle_right": "right side",
"bottom_left": "lower left",
"bottom_center": "lower",
"bottom_right": "lower right"
}
return spatial_mapping.get(region, "")
except Exception as e:
logger.warning(f"Error getting spatial context for region '{region}': {str(e)}")
return ""