update target fps

This commit is contained in:
ykcheungab-dragonq6a
2026-02-18 12:52:26 +08:00
parent 54baf1ecde
commit 524f750ec9
+41 -26
View File
@@ -28,7 +28,7 @@ from multiprocessing import Queue, Process
import time import time
def sensor_worker(sensor_id, vid_src, config_name, cal_path, result_queue, stop_event): def sensor_worker(sensor_id, vid_src, config_name, cal_path, result_queue, stop_event, target_fps=None):
""" """
传感器工作进程函数 传感器工作进程函数
@@ -36,8 +36,10 @@ def sensor_worker(sensor_id, vid_src, config_name, cal_path, result_queue, stop_
sensor_id: 传感器编号 sensor_id: 传感器编号
vid_src: 视频源(文件路径或摄像头索引) vid_src: 视频源(文件路径或摄像头索引)
config_name: 配置名称 config_name: 配置名称
cal_path: 标定路径
result_queue: 结果队列,用于向主进程发送数据 result_queue: 结果队列,用于向主进程发送数据
stop_event: 停止事件,用于通知工作进程退出 stop_event: 停止事件,用于通知工作进程退出
target_fps: 目标帧率;若设置则用定时器限速,使多传感器 FPS 接近一致
""" """
try: try:
# 在每个进程中创建独立的传感器实例 # 在每个进程中创建独立的传感器实例
@@ -50,9 +52,12 @@ def sensor_worker(sensor_id, vid_src, config_name, cal_path, result_queue, stop_
cal_path=cal_path cal_path=cal_path
) )
print(f"传感器 {sensor_id} 已启动") print(f"传感器 {sensor_id} 已启动" + (f" (target_fps={target_fps})" if target_fps else ""))
frame_interval = 1.0 / target_fps if target_fps and target_fps > 0 else 0.0
while not stop_event.is_set(): while not stop_event.is_set():
t_start = time.perf_counter()
try: try:
# 步骤1: 获取图像 # 步骤1: 获取图像
sensor.get_img() sensor.get_img()
@@ -90,7 +95,7 @@ def sensor_worker(sensor_id, vid_src, config_name, cal_path, result_queue, stop_
# 步骤6: 发送数据到主进程(非阻塞) # 步骤6: 发送数据到主进程(非阻塞)
try: try:
result_queue.put_nowait(data) result_queue.put_nowait(data)
except: except Exception:
# 如果队列已满,跳过这一帧 # 如果队列已满,跳过这一帧
pass pass
@@ -98,6 +103,13 @@ def sensor_worker(sensor_id, vid_src, config_name, cal_path, result_queue, stop_
print(f"传感器 {sensor_id} 处理错误: {e}") print(f"传感器 {sensor_id} 处理错误: {e}")
time.sleep(0.1) time.sleep(0.1)
# 步骤7: 按 target_fps 限速,使多传感器 FPS 接近
if frame_interval > 0:
elapsed = time.perf_counter() - t_start
sleep_time = frame_interval - elapsed
if sleep_time > 0.001: # 至少 1ms 才 sleep,避免无意义调度
time.sleep(sleep_time)
# 清理资源 # 清理资源
sensor.disconnect() sensor.disconnect()
print(f"传感器 {sensor_id} 已停止") print(f"传感器 {sensor_id} 已停止")
@@ -111,6 +123,9 @@ def main():
# ========================================================================= # =========================================================================
# 1. 配置多个传感器 # 1. 配置多个传感器
# ========================================================================= # =========================================================================
# 目标帧率:设为正数时,两路传感器会按此帧率限速,使 FPS 接近一致;设为 None 则不限速
target_fps = 15
num_sensors = 2 num_sensors = 2
sensor_configs = [ sensor_configs = [
{ {
@@ -131,9 +146,8 @@ def main():
# 2. 创建进程间通信对象 # 2. 创建进程间通信对象
# ========================================================================= # =========================================================================
# 增大队列大小以缓冲更多帧,避免因主进程处理延迟导致的丢帧 # 增大队列大小以缓冲更多帧,避免因主进程处理延迟导致的丢帧
# 使用更大的缓冲区以平滑FPS波动 result_queues = [Queue(maxsize=30) for _ in sensor_configs]
result_queues = [Queue(maxsize=30) for _ in sensor_configs] # 每个传感器一个队列,缓冲30帧 stop_events = [mp.Event() for _ in sensor_configs]
stop_events = [mp.Event() for _ in sensor_configs] # 停止事件
# ========================================================================= # =========================================================================
# 3. 启动传感器工作进程 # 3. 启动传感器工作进程
@@ -142,7 +156,8 @@ def main():
for i, config in enumerate(sensor_configs): for i, config in enumerate(sensor_configs):
p = Process( p = Process(
target=sensor_worker, target=sensor_worker,
args=(i, config['vid_src'], config['config_name'], config['cal_path'], result_queues[i], stop_events[i]) args=(i, config['vid_src'], config['config_name'], config['cal_path'],
result_queues[i], stop_events[i], target_fps)
) )
p.start() p.start()
processes.append(p) processes.append(p)
@@ -196,27 +211,27 @@ def main():
grid_spacing=10, grid_spacing=10,
arrow_scale=1.0 arrow_scale=1.0
) )
cv2.imshow(f"形变场 Deformation {sid}", arrows) cv2.imshow(f"Deformation {sid}", arrows)
# 显示触碰点和区域 # # 显示触碰点和区域
if data['img'] is not None: # if data['img'] is not None:
image_with_foe = orisys.util.draw_contact( # image_with_foe = orisys.util.draw_contact(
data['img'], # data['img'],
data['contour'], # data['contour'],
data['centroid'] # data['centroid']
) # )
cv2.imshow(f"Contact Centroid {sid}", image_with_foe) # cv2.imshow(f"Contact Centroid {sid}", image_with_foe)
# 显示深度图 # # 显示深度图
if data['depth_map'] is not None and data['depth_map'].size > 0: # if data['depth_map'] is not None and data['depth_map'].size > 0:
div_abs = data['depth_map'] # div_abs = data['depth_map']
if div_abs.max() > div_abs.min(): # if div_abs.max() > div_abs.min():
div_normalized = ((div_abs - div_abs.min()) / # div_normalized = ((div_abs - div_abs.min()) /
(div_abs.max() - div_abs.min()) * 255).astype(np.uint8) # (div_abs.max() - div_abs.min()) * 255).astype(np.uint8)
else: # else:
div_normalized = np.zeros_like(div_abs, dtype=np.uint8) # div_normalized = np.zeros_like(div_abs, dtype=np.uint8)
cv2.imshow(f"Depth Map {sid}", # cv2.imshow(f"Depth Map {sid}",
cv2.applyColorMap(div_normalized, cv2.COLORMAP_JET)) # cv2.applyColorMap(div_normalized, cv2.COLORMAP_JET))
# 降低打印频率以减少I/O开销(在主循环级别控制) # 降低打印频率以减少I/O开销(在主循环级别控制)
print_counter += 1 print_counter += 1