update target fps
This commit is contained in:
@@ -28,41 +28,46 @@ 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):
|
||||||
"""
|
"""
|
||||||
传感器工作进程函数
|
传感器工作进程函数
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
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:
|
||||||
# 在每个进程中创建独立的传感器实例
|
# 在每个进程中创建独立的传感器实例
|
||||||
sensor = orisys.Sensor(
|
sensor = orisys.Sensor(
|
||||||
vid_src,
|
vid_src,
|
||||||
isstitch=True,
|
isstitch=True,
|
||||||
cuda=True,
|
cuda=True,
|
||||||
verbose=False, # 减少子进程输出
|
verbose=False, # 减少子进程输出
|
||||||
config_name=config_name,
|
config_name=config_name,
|
||||||
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()
|
||||||
|
|
||||||
# 步骤2: 计算形变场
|
# 步骤2: 计算形变场
|
||||||
sensor.compute_deformation()
|
sensor.compute_deformation()
|
||||||
|
|
||||||
# 步骤3: 计算触碰点
|
# 步骤3: 计算触碰点
|
||||||
sensor.compute_contact()
|
sensor.compute_contact()
|
||||||
|
|
||||||
# 步骤4: 读取信息
|
# 步骤4: 读取信息
|
||||||
fps, flow, vnormal, img, contour, centroid, depth_map = sensor.read_info(
|
fps, flow, vnormal, img, contour, centroid, depth_map = sensor.read_info(
|
||||||
sensor.info.FPS,
|
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.CENTROID,
|
||||||
sensor.info.DEPTH
|
sensor.info.DEPTH
|
||||||
)
|
)
|
||||||
|
|
||||||
# 步骤5: 准备数据字典(确保所有数据都是可序列化的)
|
# 步骤5: 准备数据字典(确保所有数据都是可序列化的)
|
||||||
data = {
|
data = {
|
||||||
'sensor_id': sensor_id,
|
'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,
|
'depth_map': depth_map.copy() if depth_map is not None else None,
|
||||||
'timestamp': time.time()
|
'timestamp': time.time()
|
||||||
}
|
}
|
||||||
|
|
||||||
# 步骤6: 发送数据到主进程(非阻塞)
|
# 步骤6: 发送数据到主进程(非阻塞)
|
||||||
try:
|
try:
|
||||||
result_queue.put_nowait(data)
|
result_queue.put_nowait(data)
|
||||||
except:
|
except Exception:
|
||||||
# 如果队列已满,跳过这一帧
|
# 如果队列已满,跳过这一帧
|
||||||
pass
|
pass
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
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()
|
||||||
@@ -111,6 +123,9 @@ def main():
|
|||||||
# =========================================================================
|
# =========================================================================
|
||||||
# 1. 配置多个传感器
|
# 1. 配置多个传感器
|
||||||
# =========================================================================
|
# =========================================================================
|
||||||
|
# 目标帧率:设为正数时,两路传感器会按此帧率限速,使 FPS 接近一致;设为 None 则不限速
|
||||||
|
target_fps = 15
|
||||||
|
|
||||||
num_sensors = 2
|
num_sensors = 2
|
||||||
sensor_configs = [
|
sensor_configs = [
|
||||||
{
|
{
|
||||||
@@ -126,15 +141,14 @@ def main():
|
|||||||
'cal_path': './config/dd01a_0_720p.npy'
|
'cal_path': './config/dd01a_0_720p.npy'
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
# =========================================================================
|
# =========================================================================
|
||||||
# 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
|
||||||
|
|||||||
Reference in New Issue
Block a user