同步算法修改
This commit is contained in:
@@ -79,7 +79,7 @@ class KadianDetector:
|
|||||||
|
|
||||||
# 1. 业务判定时间阈值
|
# 1. 业务判定时间阈值
|
||||||
self.TIME_THRESHOLD_ONLY_ONE = 3.0 # 单人单检判定时长
|
self.TIME_THRESHOLD_ONLY_ONE = 3.0 # 单人单检判定时长
|
||||||
self.TIME_THRESHOLD_NOBODY = 2.0 # 无人检查判定时长
|
self.TIME_THRESHOLD_NOBODY = 3.0 # 无人检查判定时长
|
||||||
|
|
||||||
# 后备箱检查判定阈值
|
# 后备箱检查判定阈值
|
||||||
self.TIME_THRESHOLD_TRUNK_OPEN = 0.5
|
self.TIME_THRESHOLD_TRUNK_OPEN = 0.5
|
||||||
@@ -129,6 +129,15 @@ class KadianDetector:
|
|||||||
logger.info(f" 制服合规恢复缓冲帧数: {self.frame_buffer_uniform} 帧")
|
logger.info(f" 制服合规恢复缓冲帧数: {self.frame_buffer_uniform} 帧")
|
||||||
logger.info(f" 判定 'Too Fast' (视为Nobody) 最小停留: {self.frame_thresh_car_min_duration} 帧")
|
logger.info(f" 判定 'Too Fast' (视为Nobody) 最小停留: {self.frame_thresh_car_min_duration} 帧")
|
||||||
|
|
||||||
|
self.onlyone_counter = 0
|
||||||
|
self.onlyone_lost_counter = 0
|
||||||
|
self.onlyone_buffer_limit = self.frame_buffer_limit_person # 10帧(1秒)
|
||||||
|
self.onlyone_thresh = self.frame_thresh_one # 30帧(3秒)
|
||||||
|
|
||||||
|
self.nobody_counter = 0
|
||||||
|
self.nobody_present_counter = 0
|
||||||
|
self.nobody_buffer_limit = 10 # 10帧(1秒)
|
||||||
|
self.nobody_thresh = self.frame_thresh_nobody # 20帧(2秒)
|
||||||
|
|
||||||
self.current_frame_idx = 0
|
self.current_frame_idx = 0
|
||||||
self.cnt_frame_one_person = 0
|
self.cnt_frame_one_person = 0
|
||||||
@@ -161,21 +170,14 @@ class KadianDetector:
|
|||||||
用于 pointPolygonTest 和 polylines
|
用于 pointPolygonTest 和 polylines
|
||||||
"""
|
"""
|
||||||
if self.roi_points is None:
|
if self.roi_points is None:
|
||||||
# 使用默认相对坐标
|
raise ValueError("ROI points must be provided; cannot be None.")
|
||||||
default_rel = np.array([
|
|
||||||
[0.15, 0.01],
|
if self.roi_points.max() <= 1.0:
|
||||||
[0.45, 0.01],
|
# 相对坐标 → 转换为绝对
|
||||||
[0.95, 0.95],
|
roi_abs = self.roi_points * np.array([frame_width, frame_height])
|
||||||
[0.35, 0.95]
|
|
||||||
], dtype=np.float64)
|
|
||||||
roi_abs = default_rel * np.array([frame_width, frame_height])
|
|
||||||
else:
|
else:
|
||||||
if self.roi_points.max() <= 1.0:
|
# 绝对坐标,直接使用
|
||||||
# 相对坐标 → 转换为绝对
|
roi_abs = self.roi_points.copy()
|
||||||
roi_abs = self.roi_points * np.array([frame_width, frame_height])
|
|
||||||
else:
|
|
||||||
# 绝对坐标,直接使用
|
|
||||||
roi_abs = self.roi_points.copy()
|
|
||||||
|
|
||||||
# 强制转为 int32(关键!解决 OpenCV 断言错误)
|
# 强制转为 int32(关键!解决 OpenCV 断言错误)
|
||||||
return roi_abs.astype(np.int32)
|
return roi_abs.astype(np.int32)
|
||||||
@@ -529,34 +531,87 @@ class KadianDetector:
|
|||||||
# ==========================================
|
# ==========================================
|
||||||
# 9. 业务逻辑判定 (Only One / Nobody)
|
# 9. 业务逻辑判定 (Only One / Nobody)
|
||||||
# ==========================================
|
# ==========================================
|
||||||
status_text = ""
|
# status_text = ""
|
||||||
|
#
|
||||||
|
# if effective_car_count > 0:
|
||||||
|
# # --- Only One ---
|
||||||
|
# if current_roi_person_count == 1:
|
||||||
|
# self.cnt_frame_one_person += 1
|
||||||
|
# self.cnt_missing_buffer_person = 0
|
||||||
|
# self.cnt_frame_nobody = 0
|
||||||
|
#
|
||||||
|
# # --- Nobody ---
|
||||||
|
# elif current_roi_person_count == 0:
|
||||||
|
# if self.cnt_frame_one_person > 0 and self.cnt_missing_buffer_person < self.frame_buffer_limit_person:
|
||||||
|
# self.cnt_frame_one_person += 1
|
||||||
|
# self.cnt_missing_buffer_person += 1
|
||||||
|
# self.cnt_frame_nobody = 0
|
||||||
|
# status_text = f"Person Buffer ({self.cnt_missing_buffer_person}/{self.frame_buffer_limit_person})"
|
||||||
|
# else:
|
||||||
|
# self.cnt_frame_one_person = 0
|
||||||
|
# self.cnt_missing_buffer_person = 0
|
||||||
|
# self.cnt_frame_nobody += 1
|
||||||
|
# else:
|
||||||
|
# self.cnt_frame_one_person = 0
|
||||||
|
# self.cnt_missing_buffer_person = 0
|
||||||
|
# self.cnt_frame_nobody = 0
|
||||||
|
# else:
|
||||||
|
# self.cnt_frame_one_person = 0
|
||||||
|
# self.cnt_missing_buffer_person = 0
|
||||||
|
# self.cnt_frame_nobody = 0
|
||||||
|
|
||||||
if effective_car_count > 0:
|
# ==========================================
|
||||||
# --- Only One ---
|
# 9. 业务逻辑判定 (Only One / Nobody) - 重构版
|
||||||
if current_roi_person_count == 1:
|
# ==========================================
|
||||||
self.cnt_frame_one_person += 1
|
if effective_car_count >= 0: # 只要没人就检测,不用等到来了车再检测
|
||||||
self.cnt_missing_buffer_person = 0
|
# ----- 定义条件 -----
|
||||||
self.cnt_frame_nobody = 0
|
onlyone_condition = (current_roi_person_count == 1 and self.pose_person_count == 1)
|
||||||
|
nobody_condition = (current_roi_person_count == 0 and self.pose_person_count == 0)
|
||||||
|
|
||||||
# --- Nobody ---
|
# ----- Onlyone 计数器更新 -----
|
||||||
elif current_roi_person_count == 0:
|
if onlyone_condition:
|
||||||
if self.cnt_frame_one_person > 0 and self.cnt_missing_buffer_person < self.frame_buffer_limit_person:
|
self.onlyone_counter += 1
|
||||||
self.cnt_frame_one_person += 1
|
self.onlyone_lost_counter = 0
|
||||||
self.cnt_missing_buffer_person += 1
|
|
||||||
self.cnt_frame_nobody = 0
|
|
||||||
status_text = f"Person Buffer ({self.cnt_missing_buffer_person}/{self.frame_buffer_limit_person})"
|
|
||||||
else:
|
|
||||||
self.cnt_frame_one_person = 0
|
|
||||||
self.cnt_missing_buffer_person = 0
|
|
||||||
self.cnt_frame_nobody += 1
|
|
||||||
else:
|
else:
|
||||||
self.cnt_frame_one_person = 0
|
if self.onlyone_counter > 0:
|
||||||
self.cnt_missing_buffer_person = 0
|
self.onlyone_lost_counter += 1
|
||||||
self.cnt_frame_nobody = 0
|
if self.onlyone_lost_counter > self.onlyone_buffer_limit:
|
||||||
|
self.onlyone_counter = 0
|
||||||
|
self.onlyone_lost_counter = 0
|
||||||
|
# 没有累积的 Onlyone 则不做任何事
|
||||||
|
|
||||||
|
# ----- Nobody 计数器更新 -----
|
||||||
|
if nobody_condition:
|
||||||
|
self.nobody_counter += 1
|
||||||
|
self.nobody_present_counter = 0
|
||||||
|
else:
|
||||||
|
if self.nobody_counter > 0:
|
||||||
|
self.nobody_present_counter += 1
|
||||||
|
if self.nobody_present_counter > self.nobody_buffer_limit:
|
||||||
|
self.nobody_counter = 0
|
||||||
|
self.nobody_present_counter = 0
|
||||||
|
# 没有累积的 Nobody 则不做任何事
|
||||||
|
|
||||||
|
# ----- 准备显示状态文字(可选)-----
|
||||||
|
if self.onlyone_counter > 0:
|
||||||
|
if onlyone_condition:
|
||||||
|
status_text = f"OnlyOne: {self.onlyone_counter}/{self.onlyone_thresh}"
|
||||||
|
else:
|
||||||
|
status_text = f"OnlyOne Lost: {self.onlyone_lost_counter}/{self.onlyone_buffer_limit}"
|
||||||
|
elif self.nobody_counter > 0:
|
||||||
|
if nobody_condition:
|
||||||
|
status_text = f"Nobody: {self.nobody_counter}/{self.nobody_thresh}"
|
||||||
|
else:
|
||||||
|
status_text = f"Nobody Interrupted: {self.nobody_present_counter}/{self.nobody_buffer_limit}"
|
||||||
|
else:
|
||||||
|
status_text = ""
|
||||||
|
|
||||||
else:
|
else:
|
||||||
self.cnt_frame_one_person = 0
|
# 无活跃车辆,清零所有计数器
|
||||||
self.cnt_missing_buffer_person = 0
|
self.onlyone_counter = 0
|
||||||
self.cnt_frame_nobody = 0
|
self.onlyone_lost_counter = 0
|
||||||
|
self.nobody_counter = 0
|
||||||
|
self.nobody_present_counter = 0
|
||||||
|
|
||||||
# ==========================================
|
# ==========================================
|
||||||
# 10. 显示报警 (UI分层优化)
|
# 10. 显示报警 (UI分层优化)
|
||||||
@@ -581,25 +636,37 @@ class KadianDetector:
|
|||||||
# 第一层:实时状态 (Real-time Status)
|
# 第一层:实时状态 (Real-time Status)
|
||||||
# ------------------------------------------------
|
# ------------------------------------------------
|
||||||
# A. 显示 Only One
|
# A. 显示 Only One
|
||||||
if self.cnt_frame_one_person >= self.frame_thresh_one:
|
# if self.cnt_frame_one_person >= self.frame_thresh_one:
|
||||||
current_frame_alerts.append(
|
# current_frame_alerts.append(
|
||||||
{
|
# {
|
||||||
'time': current_time_sec,
|
# 'time': current_time_sec,
|
||||||
'action': "Only One",
|
# 'action': "Only One",
|
||||||
}
|
# }
|
||||||
)
|
# )
|
||||||
self.draw_alert(frame, "Only One", (0, 255, 255), status_text, offset_y=alert_offset)
|
# self.draw_alert(frame, "Only One", (0, 255, 255), status_text, offset_y=alert_offset)
|
||||||
|
# alert_offset += 100
|
||||||
|
#
|
||||||
|
# # B. 显示 Nobody (实时状态)
|
||||||
|
# elif self.cnt_frame_nobody >= self.frame_thresh_nobody:
|
||||||
|
# current_frame_alerts.append(
|
||||||
|
# {
|
||||||
|
# 'time': current_time_sec,
|
||||||
|
# 'action': "Nobody",
|
||||||
|
# }
|
||||||
|
# )
|
||||||
|
# self.draw_alert(frame, "Nobody", (0, 0, 255), offset_y=alert_offset)
|
||||||
|
# alert_offset += 100
|
||||||
|
|
||||||
|
# A. 显示 Only One(当累积帧数达到阈值时)
|
||||||
|
if self.onlyone_counter >= self.onlyone_thresh:
|
||||||
|
current_frame_alerts.append({'time': current_time_sec, 'action': "Only One"})
|
||||||
|
self.draw_alert(frame, "Only One", (0, 255, 255), None, offset_y=alert_offset)
|
||||||
alert_offset += 100
|
alert_offset += 100
|
||||||
|
|
||||||
# B. 显示 Nobody (实时状态)
|
# B. 显示 Nobody(当累积帧数达到阈值时)
|
||||||
elif self.cnt_frame_nobody >= self.frame_thresh_nobody:
|
elif self.nobody_counter >= self.nobody_thresh:
|
||||||
current_frame_alerts.append(
|
current_frame_alerts.append({'time': current_time_sec, 'action': "Nobody"})
|
||||||
{
|
self.draw_alert(frame, "Nobody", (0, 0, 255), None, offset_y=alert_offset)
|
||||||
'time': current_time_sec,
|
|
||||||
'action': "Nobody",
|
|
||||||
}
|
|
||||||
)
|
|
||||||
self.draw_alert(frame, "Nobody", (0, 0, 255), offset_y=alert_offset)
|
|
||||||
alert_offset += 100
|
alert_offset += 100
|
||||||
|
|
||||||
# C. 显示 Trunk Checked (在车辆存活期间)
|
# C. 显示 Trunk Checked (在车辆存活期间)
|
||||||
@@ -619,28 +686,28 @@ class KadianDetector:
|
|||||||
if self.phone_alert_active:
|
if self.phone_alert_active:
|
||||||
# 可以显示检测的持续时间
|
# 可以显示检测的持续时间
|
||||||
duration_seconds = self.phone_detection_frames / self.fps
|
duration_seconds = self.phone_detection_frames / self.fps
|
||||||
sub_text = f"Detected for {duration_seconds:.1f}s"
|
#sub_text = f"Detected for {duration_seconds:.1f}s"
|
||||||
current_frame_alerts.append(
|
current_frame_alerts.append(
|
||||||
{
|
{
|
||||||
'time': current_time_sec,
|
'time': current_time_sec,
|
||||||
'action': "Playing Phone",
|
'action': "Playing Phone",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
self.draw_alert(frame, "Playing Phone", (255, 0, 0), sub_text, offset_y=alert_offset)
|
self.draw_alert(frame, "Playing Phone", (255, 0, 0), None, offset_y=alert_offset)
|
||||||
alert_offset += 100
|
alert_offset += 100
|
||||||
|
|
||||||
# E. 新增:显示 Unvaild Uniform!!
|
# E. 新增:显示 Unvaild Uniform!!
|
||||||
if self.uniform_alert_active:
|
if self.uniform_alert_active:
|
||||||
# 显示具体数量差异
|
# 显示具体数量差异
|
||||||
diff = self.pose_person_count - current_roi_person_count
|
diff = self.pose_person_count - current_roi_person_count
|
||||||
sub_text = f"Missing {diff} uniform(s)"
|
#sub_text = f"Missing {diff} uniform(s)"
|
||||||
current_frame_alerts.append(
|
current_frame_alerts.append(
|
||||||
{
|
{
|
||||||
'time': current_time_sec,
|
'time': current_time_sec,
|
||||||
'action': "Unvaild Uniform!!",
|
'action': "Unvaild Uniform!!",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
self.draw_alert(frame, "Unvaild Uniform!!", (255, 165, 0), sub_text, offset_y=alert_offset)
|
self.draw_alert(frame, "Unvaild Uniform!!", (255, 165, 0), None, offset_y=alert_offset)
|
||||||
alert_offset += 100
|
alert_offset += 100
|
||||||
|
|
||||||
# 第二层:离场违规 (Post-Event Alerts)
|
# 第二层:离场违规 (Post-Event Alerts)
|
||||||
@@ -663,18 +730,18 @@ class KadianDetector:
|
|||||||
self.draw_alert(frame, alert_text, (0, 0, 255), offset_y=alert_offset)
|
self.draw_alert(frame, alert_text, (0, 0, 255), offset_y=alert_offset)
|
||||||
alert_offset += 100
|
alert_offset += 100
|
||||||
|
|
||||||
# G. 显示 Nobody (离场结果)
|
# G. 显示 Ignore (离场结果)
|
||||||
expired_fast_alerts = [cid for cid, end_frame in self.fast_pass_alerts.items() if
|
expired_fast_alerts = [cid for cid, end_frame in self.fast_pass_alerts.items() if
|
||||||
self.current_frame_idx > end_frame]
|
self.current_frame_idx > end_frame]
|
||||||
for cid in expired_fast_alerts:
|
for cid in expired_fast_alerts:
|
||||||
del self.fast_pass_alerts[cid]
|
del self.fast_pass_alerts[cid]
|
||||||
|
|
||||||
if len(self.fast_pass_alerts) > 0:
|
if len(self.fast_pass_alerts) > 0:
|
||||||
alert_text = f"Nobody (ID:{list(self.fast_pass_alerts.keys())})"
|
alert_text = f"Ignore: (ID:{list(self.fast_pass_alerts.keys())})"
|
||||||
current_frame_alerts.append(
|
current_frame_alerts.append(
|
||||||
{
|
{
|
||||||
'time': current_time_sec,
|
'time': current_time_sec,
|
||||||
'action': "Nobody",
|
'action': "Ignore",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
self.draw_alert(frame, alert_text, (0, 0, 255), offset_y=alert_offset)
|
self.draw_alert(frame, alert_text, (0, 0, 255), offset_y=alert_offset)
|
||||||
|
|||||||
Reference in New Issue
Block a user