diff --git a/example2_two_sensor_pipeline.py b/example2_two_sensor_pipeline.py index ac7193c..3e52d53 100644 --- a/example2_two_sensor_pipeline.py +++ b/example2_two_sensor_pipeline.py @@ -28,41 +28,46 @@ from multiprocessing import Queue, Process 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): """ 传感器工作进程函数 - + Args: sensor_id: 传感器编号 vid_src: 视频源(文件路径或摄像头索引) config_name: 配置名称 + cal_path: 标定路径 result_queue: 结果队列,用于向主进程发送数据 stop_event: 停止事件,用于通知工作进程退出 + target_fps: 目标帧率;若设置则用定时器限速,使多传感器 FPS 接近一致 """ try: # 在每个进程中创建独立的传感器实例 sensor = orisys.Sensor( - vid_src, - isstitch=True, - cuda=True, + vid_src, + isstitch=True, + cuda=True, verbose=False, # 减少子进程输出 config_name=config_name, 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(): + t_start = time.perf_counter() try: # 步骤1: 获取图像 sensor.get_img() - + # 步骤2: 计算形变场 sensor.compute_deformation() - + # 步骤3: 计算触碰点 sensor.compute_contact() - + # 步骤4: 读取信息 fps, flow, vnormal, img, contour, centroid, depth_map = sensor.read_info( sensor.info.FPS, @@ -73,7 +78,7 @@ def sensor_worker(sensor_id, vid_src, config_name, cal_path, result_queue, stop_ sensor.info.CENTROID, sensor.info.DEPTH ) - + # 步骤5: 准备数据字典(确保所有数据都是可序列化的) data = { 'sensor_id': sensor_id, @@ -86,17 +91,24 @@ def sensor_worker(sensor_id, vid_src, config_name, cal_path, result_queue, stop_ 'depth_map': depth_map.copy() if depth_map is not None else None, 'timestamp': time.time() } - + # 步骤6: 发送数据到主进程(非阻塞) try: result_queue.put_nowait(data) - except: + except Exception: # 如果队列已满,跳过这一帧 pass - + except Exception as e: print(f"传感器 {sensor_id} 处理错误: {e}") 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() @@ -111,6 +123,9 @@ def main(): # ========================================================================= # 1. 配置多个传感器 # ========================================================================= + # 目标帧率:设为正数时,两路传感器会按此帧率限速,使 FPS 接近一致;设为 None 则不限速 + target_fps = 15 + num_sensors = 2 sensor_configs = [ { @@ -126,15 +141,14 @@ def main(): 'cal_path': './config/dd01a_0_720p.npy' }, ] - + # ========================================================================= # 2. 创建进程间通信对象 # ========================================================================= # 增大队列大小以缓冲更多帧,避免因主进程处理延迟导致的丢帧 - # 使用更大的缓冲区以平滑FPS波动 - result_queues = [Queue(maxsize=30) for _ in sensor_configs] # 每个传感器一个队列,缓冲30帧 - stop_events = [mp.Event() for _ in sensor_configs] # 停止事件 - + result_queues = [Queue(maxsize=30) for _ in sensor_configs] + stop_events = [mp.Event() for _ in sensor_configs] + # ========================================================================= # 3. 启动传感器工作进程 # ========================================================================= @@ -142,7 +156,8 @@ def main(): for i, config in enumerate(sensor_configs): p = Process( 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() processes.append(p) @@ -196,27 +211,27 @@ def main(): grid_spacing=10, arrow_scale=1.0 ) - cv2.imshow(f"形变场 Deformation {sid}", arrows) + cv2.imshow(f"Deformation {sid}", arrows) - # 显示触碰点和区域 - if data['img'] is not None: - image_with_foe = orisys.util.draw_contact( - data['img'], - data['contour'], - data['centroid'] - ) - cv2.imshow(f"Contact Centroid {sid}", image_with_foe) + # # 显示触碰点和区域 + # if data['img'] is not None: + # image_with_foe = orisys.util.draw_contact( + # data['img'], + # data['contour'], + # data['centroid'] + # ) + # cv2.imshow(f"Contact Centroid {sid}", image_with_foe) - # 显示深度图 - if data['depth_map'] is not None and data['depth_map'].size > 0: - div_abs = data['depth_map'] - if div_abs.max() > div_abs.min(): - div_normalized = ((div_abs - div_abs.min()) / - (div_abs.max() - div_abs.min()) * 255).astype(np.uint8) - else: - div_normalized = np.zeros_like(div_abs, dtype=np.uint8) - cv2.imshow(f"Depth Map {sid}", - cv2.applyColorMap(div_normalized, cv2.COLORMAP_JET)) + # # 显示深度图 + # if data['depth_map'] is not None and data['depth_map'].size > 0: + # div_abs = data['depth_map'] + # if div_abs.max() > div_abs.min(): + # div_normalized = ((div_abs - div_abs.min()) / + # (div_abs.max() - div_abs.min()) * 255).astype(np.uint8) + # else: + # div_normalized = np.zeros_like(div_abs, dtype=np.uint8) + # cv2.imshow(f"Depth Map {sid}", + # cv2.applyColorMap(div_normalized, cv2.COLORMAP_JET)) # 降低打印频率以减少I/O开销(在主循环级别控制) print_counter += 1