DawnC commited on
Commit
93e593f
·
verified ·
1 Parent(s): 12d9ea9

Upload statistics_processor.py

Browse files

fixed the calculation difference about testing and Ops

Files changed (1) hide show
  1. statistics_processor.py +217 -94
statistics_processor.py CHANGED
@@ -4,23 +4,111 @@ from typing import Dict, List, Optional, Any
4
  class StatisticsProcessor:
5
  """
6
  統計分析處理器 - 負責複雜的物件統計分析和數據轉換
7
-
8
- 此類別專門處理物件統計信息的深度分析、Places365信息處理,
9
- 以及基於統計數據生成替換內容的複雜邏輯。
10
  """
11
 
12
- def __init__(self):
13
  """初始化統計分析處理器"""
14
  self.logger = logging.getLogger(self.__class__.__name__)
15
- self.logger.debug("StatisticsProcessor initialized successfully")
16
-
17
- def generate_statistics_replacements(self, object_statistics: Optional[Dict]) -> Dict[str, str]:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  """
19
  基於物體統計信息生成模板替換內容
20
-
21
  Args:
22
  object_statistics: 物體統計信息
23
-
24
  Returns:
25
  Dict[str, str]: 統計信息基礎的替換內容
26
  """
@@ -30,9 +118,12 @@ class StatisticsProcessor:
30
  return replacements
31
 
32
  try:
 
 
 
33
  # 處理植物元素
34
- if "potted plant" in object_statistics:
35
- count = object_statistics["potted plant"]["count"]
36
  if count == 1:
37
  replacements["plant_elements"] = "a potted plant"
38
  elif count <= 3:
@@ -40,59 +131,12 @@ class StatisticsProcessor:
40
  else:
41
  replacements["plant_elements"] = f"multiple potted plants ({count} total)"
42
 
43
- # 處理座位(椅子)相關
44
- if "chair" in object_statistics:
45
- count = object_statistics["chair"]["count"]
46
-
47
- # 使用統一的數字轉換邏輯
48
- number_words = {
49
- 1: "one", 2: "two", 3: "three", 4: "four",
50
- 5: "five", 6: "six", 7: "seven", 8: "eight",
51
- 9: "nine", 10: "ten", 11: "eleven", 12: "twelve"
52
- }
53
-
54
- if count == 1:
55
- replacements["seating"] = "a chair"
56
- replacements["furniture"] = "a chair"
57
- elif count in number_words:
58
- word_count = number_words[count]
59
- replacements["seating"] = f"{word_count} chairs"
60
- replacements["furniture"] = f"{word_count} chairs"
61
- elif count <= 20:
62
- replacements["seating"] = f"several chairs"
63
- replacements["furniture"] = f"several chairs"
64
- else:
65
- replacements["seating"] = f"numerous chairs ({count} total)"
66
- replacements["furniture"] = f"numerous chairs"
67
-
68
- # 處理混合家具情況(當存在多種家具類型時)
69
- furniture_items = []
70
- furniture_counts = []
71
-
72
- # 收集所有家具類型的統計
73
- for furniture_type in ["chair", "dining table", "couch", "bed"]:
74
- if furniture_type in object_statistics:
75
- count = object_statistics[furniture_type]["count"]
76
- if count > 0:
77
- furniture_items.append(furniture_type)
78
- furniture_counts.append(count)
79
-
80
- # 如果只有椅子,那就用上面的方式
81
- # 如果有多種家具類型,生成組合描述
82
- if len(furniture_items) > 1 and "furniture" not in replacements:
83
- main_furniture = furniture_items[0] # 數量最多的家具類型
84
- main_count = furniture_counts[0]
85
-
86
- if main_furniture == "chair":
87
- number_words = ["", "one", "two", "three", "four", "five", "six"]
88
- if main_count <= 6:
89
- replacements["furniture"] = f"{number_words[main_count]} chairs and other furniture"
90
- else:
91
- replacements["furniture"] = "multiple chairs and other furniture"
92
-
93
  # 處理人員
94
- if "person" in object_statistics:
95
- count = object_statistics["person"]["count"]
96
  if count == 1:
97
  replacements["people_and_vehicles"] = "a person"
98
  replacements["pedestrian_flow"] = "an individual walking"
@@ -103,9 +147,9 @@ class StatisticsProcessor:
103
  replacements["people_and_vehicles"] = f"many people ({count} individuals)"
104
  replacements["pedestrian_flow"] = f"a crowd of {count} people"
105
 
106
- # 處理桌子設置
107
- if "dining table" in object_statistics:
108
- count = object_statistics["dining table"]["count"]
109
  if count == 1:
110
  replacements["table_setup"] = "a dining table"
111
  replacements["table_description"] = "a dining surface"
@@ -113,54 +157,133 @@ class StatisticsProcessor:
113
  replacements["table_setup"] = f"{count} dining tables"
114
  replacements["table_description"] = f"{count} dining surfaces"
115
 
116
- self.logger.debug(f"Generated {len(replacements)} statistics-based replacements")
117
 
118
  except Exception as e:
119
  self.logger.warning(f"Error generating statistics replacements: {str(e)}")
120
 
121
  return replacements
122
 
123
- def generate_places365_replacements(self, places365_info: Optional[Dict]) -> Dict[str, str]:
124
  """
125
- 基於Places365信息生成模板替換內容
126
-
 
127
  Args:
128
- places365_info: Places365場景分類信息
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
129
 
130
- Returns:
131
- Dict[str, str]: Places365基礎的替換內容
 
132
  """
133
  replacements = {}
134
 
135
  if not places365_info or places365_info.get('confidence', 0) <= 0.35:
136
  replacements["places365_context"] = ""
137
- replacements["places365_atmosphere"] = ""
138
  return replacements
139
 
140
  try:
141
- scene_label = places365_info.get('scene_label', '').replace('_', ' ')
142
- attributes = places365_info.get('attributes', [])
143
-
144
- # 生成場景上下文
145
- if scene_label:
146
- replacements["places365_context"] = f"characteristic of a {scene_label}"
147
- else:
148
- replacements["places365_context"] = ""
149
-
150
- # 生成氛圍描述
151
- if 'natural_lighting' in attributes:
152
- replacements["places365_atmosphere"] = "with natural illumination"
153
- elif 'artificial_lighting' in attributes:
154
- replacements["places365_atmosphere"] = "under artificial lighting"
155
- else:
156
- replacements["places365_atmosphere"] = ""
157
-
158
- self.logger.debug("Generated Places365-based replacements")
 
 
 
159
 
160
  except Exception as e:
161
  self.logger.warning(f"Error generating Places365 replacements: {str(e)}")
162
- replacements["places365_context"] = ""
163
- replacements["places365_atmosphere"] = ""
164
 
165
  return replacements
166
 
 
4
  class StatisticsProcessor:
5
  """
6
  統計分析處理器 - 負責複雜的物件統計分析和數據轉換
7
+ 增加了決策穩健性機制來處理環境差異
 
 
8
  """
9
 
10
+ def __init__(self, stability_config=None):
11
  """初始化統計分析處理器"""
12
  self.logger = logging.getLogger(self.__class__.__name__)
13
+
14
+ # 穩定性配置參數
15
+ self.stability_config = stability_config or {
16
+ 'confidence_tolerance': 0.05, # 信心度容差範圍
17
+ 'count_stability_threshold': 0.8, # 計數穩定性閾值
18
+ 'decision_buffer_zone': 0.1, # 決策緩衝區
19
+ 'prefer_specific_descriptions': True, # 優先使用具體描述
20
+ 'multi_furniture_threshold': 2, # 多家具類型的最小閾值
21
+ }
22
+
23
+ self.logger.debug("StatisticsProcessor initialized with stability enhancements")
24
+
25
+ def _stabilize_object_counts(self, object_statistics):
26
+ """
27
+ 穩定化物件計數,減少環境差異影響
28
+
29
+ Args:
30
+ object_statistics: 原始物件統計數據
31
+
32
+ Returns:
33
+ 穩定化後的物件統計數據
34
+ """
35
+ if not object_statistics:
36
+ return object_statistics
37
+
38
+ stabilized_stats = {}
39
+
40
+ for obj_type, stats in object_statistics.items():
41
+ stabilized_stats[obj_type] = stats.copy()
42
+
43
+ # 穩定化信心度 - 將接近的值標準化到區間中點
44
+ confidence = stats.get('confidence', 0.0)
45
+ if confidence > 0:
46
+ # 將信心度調整到標準化區間
47
+ tolerance = self.stability_config['confidence_tolerance']
48
+ stabilized_confidence = round(confidence / tolerance) * tolerance
49
+ stabilized_stats[obj_type]['confidence'] = max(stabilized_confidence, confidence)
50
+
51
+ return stabilized_stats
52
+
53
+ def _should_use_specific_furniture_description(self, furniture_items, furniture_counts, object_statistics):
54
+ """
55
+ 決定是否使用具體的家具描述(如 "six chairs")還是通用描述(如 "furniture pieces")
56
+ 增加了決策穩健性邏輯
57
+
58
+ Args:
59
+ furniture_items: 檢測到的家具類型列表
60
+ furniture_counts: 對應的家具數量列表
61
+ object_statistics: 完整的物件統計數據
62
+
63
+ Returns:
64
+ tuple: (是否使用具體描述, 主要家具類型, 主要家具數量)
65
+ """
66
+ # 如果沒有檢測到家具,返回通用描述
67
+ if not furniture_items:
68
+ return False, None, 0
69
+
70
+ # 如果只有一種家具類型,優先使用具體描述
71
+ if len(furniture_items) == 1:
72
+ return True, furniture_items[0], furniture_counts[0]
73
+
74
+ # 多種家具類型的決策邏輯
75
+ total_furniture_count = sum(furniture_counts)
76
+ main_furniture = furniture_items[0]
77
+ main_count = furniture_counts[0]
78
+
79
+ # 計算主要家具類型的比例
80
+ main_furniture_ratio = main_count / total_furniture_count if total_furniture_count > 0 else 0
81
+
82
+ # 決策緩衝區機制
83
+ buffer_zone = self.stability_config['decision_buffer_zone']
84
+ dominance_threshold = 0.7 + buffer_zone # 主導性閾值加上緩衝區
85
+
86
+ # 椅子的特殊處理邏輯
87
+ if main_furniture == "chair":
88
+ chair_stats = object_statistics.get("chair", {})
89
+ chair_confidence = chair_stats.get('confidence', 0.0)
90
+
91
+ # 如果椅子檢測信心度很高且數量占主導地位,使用具體描述
92
+ confidence_threshold = 0.8 - buffer_zone # 降低閾值增加穩定性
93
+
94
+ if (chair_confidence >= confidence_threshold and
95
+ main_furniture_ratio >= dominance_threshold):
96
+ return True, main_furniture, main_count
97
+
98
+ # 如果椅子數量適中且是唯一明確的家具類型,也使用具體描述
99
+ if main_count <= 8 and main_furniture_ratio >= 0.6:
100
+ return True, main_furniture, main_count
101
+
102
+ # 其他情況使用通用描述
103
+ return False, main_furniture, main_count
104
+
105
+ def generate_statistics_replacements(self, object_statistics):
106
  """
107
  基於物體統計信息生成模板替換內容
108
+
109
  Args:
110
  object_statistics: 物體統計信息
111
+
112
  Returns:
113
  Dict[str, str]: 統計信息基礎的替換內容
114
  """
 
118
  return replacements
119
 
120
  try:
121
+ # 首先穩定化物件統計數據
122
+ stabilized_stats = self._stabilize_object_counts(object_statistics)
123
+
124
  # 處理植物元素
125
+ if "potted plant" in stabilized_stats:
126
+ count = stabilized_stats["potted plant"]["count"]
127
  if count == 1:
128
  replacements["plant_elements"] = "a potted plant"
129
  elif count <= 3:
 
131
  else:
132
  replacements["plant_elements"] = f"multiple potted plants ({count} total)"
133
 
134
+ # 椅子和家具的穩健處理邏輯
135
+ self._process_furniture_with_stability(stabilized_stats, replacements)
136
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
137
  # 處理人員
138
+ if "person" in stabilized_stats:
139
+ count = stabilized_stats["person"]["count"]
140
  if count == 1:
141
  replacements["people_and_vehicles"] = "a person"
142
  replacements["pedestrian_flow"] = "an individual walking"
 
147
  replacements["people_and_vehicles"] = f"many people ({count} individuals)"
148
  replacements["pedestrian_flow"] = f"a crowd of {count} people"
149
 
150
+ # 處理桌子設置(保持原有邏輯)
151
+ if "dining table" in stabilized_stats:
152
+ count = stabilized_stats["dining table"]["count"]
153
  if count == 1:
154
  replacements["table_setup"] = "a dining table"
155
  replacements["table_description"] = "a dining surface"
 
157
  replacements["table_setup"] = f"{count} dining tables"
158
  replacements["table_description"] = f"{count} dining surfaces"
159
 
160
+ self.logger.debug(f"Generated {len(replacements)} stability-enhanced replacements")
161
 
162
  except Exception as e:
163
  self.logger.warning(f"Error generating statistics replacements: {str(e)}")
164
 
165
  return replacements
166
 
167
+ def _process_furniture_with_stability(self, object_statistics, replacements):
168
  """
169
+ 使用穩健性邏輯處理家具描述, 解決測試與部署時的浮點數計算結果差異
170
+
171
+
172
  Args:
173
+ object_statistics: 穩定化後的物件統計數據
174
+ replacements: 要更新的替換字典
175
+ """
176
+ # 數字轉換字典
177
+ number_words = {
178
+ 1: "one", 2: "two", 3: "three", 4: "four",
179
+ 5: "five", 6: "six", 7: "seven", 8: "eight",
180
+ 9: "nine", 10: "ten", 11: "eleven", 12: "twelve"
181
+ }
182
+
183
+ # 收集所有家具類型的統計
184
+ furniture_items = []
185
+ furniture_counts = []
186
+
187
+ furniture_types = ["chair", "dining table", "couch", "bed"]
188
+ for furniture_type in furniture_types:
189
+ if furniture_type in object_statistics:
190
+ count = object_statistics[furniture_type]["count"]
191
+ if count > 0:
192
+ furniture_items.append(furniture_type)
193
+ furniture_counts.append(count)
194
+
195
+ # 使用穩健性決策邏輯
196
+ use_specific, main_furniture, main_count = self._should_use_specific_furniture_description(
197
+ furniture_items, furniture_counts, object_statistics
198
+ )
199
+
200
+ # 椅子的特殊處理
201
+ if "chair" in object_statistics:
202
+ chair_count = object_statistics["chair"]["count"]
203
+
204
+ if use_specific and main_furniture == "chair":
205
+ # 使用具體的椅子描述
206
+ if chair_count == 1:
207
+ replacements["seating"] = "a chair"
208
+ replacements["furniture"] = "a chair"
209
+ elif chair_count in number_words:
210
+ word_count = number_words[chair_count]
211
+ replacements["seating"] = f"{word_count} chairs"
212
+ replacements["furniture"] = f"{word_count} chairs"
213
+ elif chair_count <= 20:
214
+ replacements["seating"] = "several chairs"
215
+ replacements["furniture"] = "several chairs"
216
+ else:
217
+ replacements["seating"] = f"numerous chairs ({chair_count} total)"
218
+ replacements["furniture"] = "numerous chairs"
219
+
220
+ self.logger.debug(f"Using specific chair description: {replacements.get('furniture', 'N/A')}")
221
+
222
+ else:
223
+ # 使用通用家具描述
224
+ total_furniture = sum(furniture_counts)
225
+ if total_furniture == 1:
226
+ replacements["furniture"] = "a furniture piece"
227
+ elif total_furniture in number_words:
228
+ word_count = number_words[total_furniture]
229
+ replacements["furniture"] = f"{word_count} furniture pieces"
230
+ else:
231
+ replacements["furniture"] = f"several furniture pieces"
232
+
233
+ # 但椅子的 seating 描述保持具體
234
+ if chair_count in number_words:
235
+ word_count = number_words[chair_count]
236
+ replacements["seating"] = f"{word_count} chairs"
237
+ else:
238
+ replacements["seating"] = "several chairs"
239
+
240
+ self.logger.debug(f"Using generic furniture description: {replacements.get('furniture', 'N/A')}")
241
+
242
+ # 處理混合家具情況的額外邏輯
243
+ if len(furniture_items) > 1 and "furniture" not in replacements:
244
+ # 當有多種家具但沒有主導類型時的後備邏輯
245
+ total_count = sum(furniture_counts)
246
+ if total_count in number_words:
247
+ word_count = number_words[total_count]
248
+ replacements["furniture"] = f"{word_count} furniture pieces"
249
+ else:
250
+ replacements["furniture"] = "multiple furniture pieces"
251
 
252
+ def generate_places365_replacements(self, places365_info):
253
+ """
254
+ 基於Places365信息生成模板替換內容
255
  """
256
  replacements = {}
257
 
258
  if not places365_info or places365_info.get('confidence', 0) <= 0.35:
259
  replacements["places365_context"] = ""
 
260
  return replacements
261
 
262
  try:
263
+ scene_class = places365_info.get('scene_class', '').lower()
264
+ confidence = places365_info.get('confidence', 0.0)
265
+
266
+ # 基於場景類別添加上下文信息
267
+ if 'kitchen' in scene_class:
268
+ replacements["places365_context"] = "kitchen environment"
269
+ replacements["area_description"] = "culinary space"
270
+ elif 'bedroom' in scene_class:
271
+ replacements["places365_context"] = "sleeping area"
272
+ replacements["area_description"] = "rest space"
273
+ elif 'living' in scene_class or 'room' in scene_class:
274
+ replacements["places365_context"] = "living area"
275
+ replacements["area_description"] = "comfortable space"
276
+ elif 'office' in scene_class:
277
+ replacements["places365_context"] = "work environment"
278
+ replacements["area_description"] = "professional workspace"
279
+ elif 'street' in scene_class or 'road' in scene_class:
280
+ replacements["places365_context"] = "urban street"
281
+ replacements["area_description"] = "city thoroughfare"
282
+
283
+ self.logger.debug(f"Generated Places365 context: {replacements.get('places365_context', 'none')}")
284
 
285
  except Exception as e:
286
  self.logger.warning(f"Error generating Places365 replacements: {str(e)}")
 
 
287
 
288
  return replacements
289