GIT-test/arbitrator.py
2026-02-21 23:42:50 +08:00

335 lines
13 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# -*- coding: utf-8 -*-
"""
双模式激光识别系统仲裁器
核心功能:
1. 双轨并行处理模式A和模式B的检测结果
2. 智能仲裁决策,选择最优模式
3. 边界情况处理和冲突解决
4. 性能优化策略
"""
import numpy as np
import time
class ModeArbitrator:
def __init__(self):
"""初始化仲裁器"""
# 工作模式
self.work_mode = 'auto' # auto, forced_single, forced_lamp, dual_display
# 算法使能状态
self.enable_mode_a = True
self.enable_mode_b = True
# 历史状态
self.last_mode = None # 上一帧使用的模式
self.last_a_score = 0
self.last_b_score = 0
self.consecutive_mode_count = 0 # 连续使用同一模式的帧数
# 模式失效检测
self.mode_a_failure_count = 0
self.mode_b_failure_count = 0
self.max_failure_count = 30 # 连续无检测的最大帧数
# 性能优化
self.use_alternating_frames = False # 是否使用交替帧策略
self.current_frame_parity = 0 # 帧奇偶性
# 调试信息
self.debug_info = {
'mode_a_score': 0,
'mode_b_score': 0,
'decision_reason': '',
'processing_time': 0
}
def set_work_mode(self, mode):
"""设置工作模式"""
self.work_mode = mode
def set_algorithm_enable(self, enable_a, enable_b):
"""设置算法使能状态"""
self.enable_mode_a = enable_a
self.enable_mode_b = enable_b
def set_performance_optimization(self, use_alternating):
"""设置性能优化策略"""
self.use_alternating_frames = use_alternating
def calculate_mode_a_score(self, results, frame=None):
"""计算模式A的场景适配分"""
if not results:
return 0
# 高置信度检测物数量1-3个为佳
count_score = 0
if 1 <= len(results) <= 3:
count_score = 1.0
elif len(results) > 3:
count_score = max(0, 1.0 - (len(results) - 3) * 0.2)
else:
count_score = 0.5
# 单个目标圆度和面积
circularity_scores = []
area_scores = []
for result in results:
# 圆度得分
circularity = result[5] # result格式: (cx, cy, w, h, area, circularity)
circ_score = min(circularity / 0.8, 1.0) if circularity > 0.5 else 0
circularity_scores.append(circ_score)
# 面积得分(适中为佳)
area = result[4]
if 100 <= area <= 2000:
area_score = 1.0
elif area < 100:
area_score = max(0, area / 100)
else:
area_score = max(0, 1.0 - (area - 2000) / 3000)
area_scores.append(area_score)
# 平均圆度和面积得分
avg_circularity_score = np.mean(circularity_scores) if circularity_scores else 0
avg_area_score = np.mean(area_scores) if area_scores else 0
# 离散度系数(目标越分散分越低)
dispersion_coefficient = 1.0
if len(results) > 1:
# 计算所有点之间的平均距离
distances = []
for i in range(len(results)):
for j in range(i + 1, len(results)):
dx = results[i][0] - results[j][0]
dy = results[i][1] - results[j][1]
distances.append(np.sqrt(dx*dx + dy*dy))
if distances:
avg_distance = np.mean(distances)
# 距离越大,离散度越高,得分越低
dispersion_coefficient = max(0.5, 1.0 - min(avg_distance / 300, 0.5))
# 总分计算
total_score = (
len(results) * 0.3 +
avg_circularity_score * 0.4 +
avg_area_score * 0.2 +
count_score * 0.1
) * dispersion_coefficient
return total_score * 100 # 转换为0-100的分数
def calculate_mode_b_score(self, results, frame=None):
"""计算模式B的场景适配分"""
if not results:
return 0
# 取置信度最高的结果
best_result = max(results, key=lambda x: x['confidence'])
# 拟合圆置信度
confidence_score = min(best_result['confidence'] / 70, 1.0) # 70分为满分
# 检测到的LED颗粒数
led_count = best_result['led_count']
led_score = min(np.log(max(led_count, 10)) / np.log(50), 1.0) # 10-50个LED
# 圆度合理性
circularity = best_result['circularity']
circularity_score = 0
if 0.4 <= circularity <= 0.8:
circularity_score = 1.0
elif circularity < 0.4:
circularity_score = max(0, circularity / 0.4)
else:
circularity_score = max(0, 1.0 - (circularity - 0.8) / 0.2)
# 总分计算
total_score = (
confidence_score * 0.5 +
led_score * 0.3 +
circularity_score * 0.2
) * 100 # 转换为0-100的分数
return total_score
def arbitrate(self, mode_a_results, mode_b_results, frame=None):
"""
智能仲裁决策
Args:
mode_a_results: 模式A的检测结果
mode_b_results: 模式B的检测结果
frame: 原始帧(可选,用于预筛选)
Returns:
selected_mode: 选中的模式 ('mode_a', 'mode_b', None)
selected_results: 选中的结果
debug_info: 调试信息
"""
start_time = time.time()
# 重置调试信息
self.debug_info = {
'mode_a_score': 0,
'mode_b_score': 0,
'decision_reason': '',
'processing_time': 0
}
# 检查使能状态
if not self.enable_mode_a and not self.enable_mode_b:
self.debug_info['decision_reason'] = 'Both algorithms disabled'
self.debug_info['processing_time'] = time.time() - start_time
return None, None, self.debug_info
# 强制模式
if self.work_mode == 'forced_single' and self.enable_mode_a:
self.debug_info['decision_reason'] = 'Forced single point mode'
self.debug_info['processing_time'] = time.time() - start_time
return 'mode_a', mode_a_results, self.debug_info
if self.work_mode == 'forced_lamp' and self.enable_mode_b:
self.debug_info['decision_reason'] = 'Forced lamp disk mode'
self.debug_info['processing_time'] = time.time() - start_time
return 'mode_b', mode_b_results, self.debug_info
# 双模显示
if self.work_mode == 'dual_display':
self.debug_info['decision_reason'] = 'Dual display mode'
self.debug_info['processing_time'] = time.time() - start_time
return 'dual', (mode_a_results, mode_b_results), self.debug_info
# 性能优化:交替帧策略
if self.use_alternating_frames:
self.current_frame_parity = 1 - self.current_frame_parity
if self.current_frame_parity == 0 and self.enable_mode_a:
self.debug_info['decision_reason'] = 'Alternating frame: mode A'
self.debug_info['processing_time'] = time.time() - start_time
return 'mode_a', mode_a_results, self.debug_info
elif self.current_frame_parity == 1 and self.enable_mode_b:
self.debug_info['decision_reason'] = 'Alternating frame: mode B'
self.debug_info['processing_time'] = time.time() - start_time
return 'mode_b', mode_b_results, self.debug_info
# 计算得分
a_score = 0
b_score = 0
if self.enable_mode_a:
a_score = self.calculate_mode_a_score(mode_a_results, frame)
self.debug_info['mode_a_score'] = a_score
# 模式失效检测
if not mode_a_results:
self.mode_a_failure_count += 1
else:
self.mode_a_failure_count = 0
if self.enable_mode_b:
b_score = self.calculate_mode_b_score(mode_b_results, frame)
self.debug_info['mode_b_score'] = b_score
# 模式失效检测
if not mode_b_results:
self.mode_b_failure_count += 1
else:
self.mode_b_failure_count = 0
# 自动仲裁逻辑
selected_mode = None
selected_results = None
# 单模式使能情况
if self.enable_mode_a and not self.enable_mode_b:
selected_mode = 'mode_a'
selected_results = mode_a_results
self.debug_info['decision_reason'] = 'Only mode A enabled'
elif self.enable_mode_b and not self.enable_mode_a:
selected_mode = 'mode_b'
selected_results = mode_b_results
self.debug_info['decision_reason'] = 'Only mode B enabled'
else:
# 双模式仲裁
if b_score > a_score * 1.2:
selected_mode = 'mode_b'
selected_results = mode_b_results
self.debug_info['decision_reason'] = f'Lamp mode score ({b_score:.1f}) > single mode ({a_score:.1f}) * 1.2'
elif a_score > b_score * 1.5:
selected_mode = 'mode_a'
selected_results = mode_a_results
self.debug_info['decision_reason'] = f'Single mode score ({a_score:.1f}) > lamp mode ({b_score:.1f}) * 1.5'
else:
# 保持上一帧决策(迟滞效应)
if self.last_mode:
selected_mode = self.last_mode
selected_results = mode_a_results if self.last_mode == 'mode_a' else mode_b_results
self.debug_info['decision_reason'] = f'Hysteresis:保持{"单点" if self.last_mode == "mode_a" else "灯盘"}模式'
else:
# 首次决策
if a_score > b_score:
selected_mode = 'mode_a'
selected_results = mode_a_results
self.debug_info['decision_reason'] = 'First frame: single mode'
else:
selected_mode = 'mode_b'
selected_results = mode_b_results
self.debug_info['decision_reason'] = 'First frame: lamp mode'
# 更新历史状态
if selected_mode == self.last_mode:
self.consecutive_mode_count += 1
else:
self.consecutive_mode_count = 1
self.last_mode = selected_mode
self.last_a_score = a_score
self.last_b_score = b_score
# 处理模式失效
if selected_mode == 'mode_a' and self.mode_a_failure_count >= self.max_failure_count:
if self.enable_mode_b:
selected_mode = 'mode_b'
selected_results = mode_b_results
self.debug_info['decision_reason'] = 'Mode A failed, switching to mode B'
elif selected_mode == 'mode_b' and self.mode_b_failure_count >= self.max_failure_count:
if self.enable_mode_a:
selected_mode = 'mode_a'
selected_results = mode_a_results
self.debug_info['decision_reason'] = 'Mode B failed, switching to mode A'
# 计算处理时间
self.debug_info['processing_time'] = time.time() - start_time
return selected_mode, selected_results, self.debug_info
def reset(self):
"""重置仲裁器状态"""
self.last_mode = None
self.last_a_score = 0
self.last_b_score = 0
self.consecutive_mode_count = 0
self.mode_a_failure_count = 0
self.mode_b_failure_count = 0
self.current_frame_parity = 0
self.debug_info = {
'mode_a_score': 0,
'mode_b_score': 0,
'decision_reason': '',
'processing_time': 0
}
def get_debug_info(self):
"""获取调试信息"""
return self.debug_info
def get_mode_failure_status(self):
"""获取模式失效状态"""
return {
'mode_a_failed': self.mode_a_failure_count >= self.max_failure_count,
'mode_b_failed': self.mode_b_failure_count >= self.max_failure_count,
'mode_a_failure_count': self.mode_a_failure_count,
'mode_b_failure_count': self.mode_b_failure_count
}