This commit is contained in:
2025-10-28 18:46:04 +08:00
parent 16894b7fd7
commit eb544da71d
95 changed files with 3330 additions and 1 deletions

140
run_live_demo.py Normal file
View File

@@ -0,0 +1,140 @@
import os
import cv2
import re
from surround_view import CaptureThread, CameraProcessingThread
from surround_view import FisheyeCameraModel, BirdView
from surround_view import MultiBufferManager, ProjectedImageBuffer
import surround_view.param_settings as settings
def is_rtsp_url(input_str):
"""检查输入是否为RTSP URL"""
return input_str.startswith('rtsp://')
def main():
# 配置四个RTSP摄像头地址前、后、左、右
camera_ids = [
"rtsp://admin:@192.168.112.153:554/video", # 前
"rtsp://admin:@192.168.112.152:554/video", # 后
"rtsp://admin:@192.168.112.150:554/video", # 左
"rtsp://admin:@192.168.112.151:554/video" # 右
]
# 摄像头ID映射使用索引作为设备ID
camera_id_mapping = {i: cam_id for i, cam_id in enumerate(camera_ids)}
# 摄像头翻转参数(根据实际安装方向调整)
flip_methods = [0, 0, 0, 0] # 0:不翻转, 1:水平翻转, 2:垂直翻转, 3:水平+垂直
# 加载相机内参模型
yamls_dir = os.path.join(os.getcwd(), "yaml")
camera_files = [os.path.join(yamls_dir, name + ".yaml") for name in settings.camera_names]
camera_models = [FisheyeCameraModel(camera_file, name)
for camera_file, name in zip(camera_files, settings.camera_names)]
# 初始化捕获线程针对RTSP特殊处理
capture_tds = []
for idx, (cam_id, flip) in enumerate(zip(camera_ids, flip_methods)):
# 使用索引作为设备ID解决KeyError问题
if is_rtsp_url(cam_id):
# RTSP流配置使用FFmpeg后端
capture_tds.append(CaptureThread(
device_id=idx, # 使用索引作为设备ID
flip_method=flip,
use_gst=False, # 关闭GStreamer使用FFmpeg
api_preference=cv2.CAP_FFMPEG, # 强制使用FFmpeg
resolution=(960, 640)
))
# 手动打开RTSP流
if not capture_tds[-1].cap.open(cam_id, cv2.CAP_FFMPEG):
print(f"无法打开RTSP流: {cam_id}")
return
# 设置RTSP参数兼容不同OpenCV版本
try:
# 尝试通用参数设置方式
capture_tds[-1].cap.set(cv2.CAP_PROP_BUFFERSIZE, 1) # 减少缓冲
capture_tds[-1].cap.set(cv2.CAP_PROP_FRAME_WIDTH, 960)
capture_tds[-1].cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 640)
# 处理FFMPEG选项兼容旧版本
if hasattr(cv2, 'CAP_PROP_FFMPEG_OPTION'):
capture_tds[-1].cap.set(cv2.CAP_PROP_FFMPEG_OPTION, "rtsp_transport", "tcp")
capture_tds[-1].cap.set(cv2.CAP_PROP_FFMPEG_OPTION, "stimeout", "5000000")
else:
print(f"RTSP流 {cam_id} 使用兼容模式,部分参数可能无法设置")
except Exception as e:
print(f"设置RTSP参数警告: {e}")
else:
# 普通USB/CSI相机配置
capture_tds.append(CaptureThread(
device_id=idx, # 使用索引作为设备ID
flip_method=flip,
use_gst=True,
resolution=(960, 640)
))
if not capture_tds[-1].connect_camera():
print(f"启动摄像头 {cam_id} 失败,退出程序")
return
# 绑定捕获缓冲区管理器
capture_buffer_manager = MultiBufferManager()
for td in capture_tds:
capture_buffer_manager.bind_thread(td, buffer_size=8)
td.start()
# 初始化处理线程使用索引作为device_id
proc_buffer_manager = ProjectedImageBuffer()
process_tds = [
CameraProcessingThread(
capture_buffer_manager,
device_id=idx, # 使用索引作为设备ID
camera_model=model
)
for idx, model in enumerate(camera_models)
]
# 启动处理线程
for td in process_tds:
proc_buffer_manager.bind_thread(td)
td.start()
# 初始化环视拼接
birdview = BirdView(proc_buffer_manager)
birdview.load_weights_and_masks("./weights.png", "./masks.png")
birdview.start()
# 主循环显示
try:
while True:
birdview_img = birdview.get()
if birdview_img is not None:
display_img = cv2.resize(birdview_img, (800, 600))
cv2.imshow("Surround View", display_img)
key = cv2.waitKey(1) & 0xFF
if key == ord("q"):
break
# 打印帧率信息
status = []
for td in capture_tds:
cam_id = camera_id_mapping[td.device_id]
status.append(f"捕获 {cam_id.split('@')[-1].split(':')[0]} FPS: {td.stat_data.average_fps:.1f}")
for td in process_tds:
cam_name = settings.camera_names[td.device_id]
status.append(f"处理 {cam_name} FPS: {td.stat_data.average_fps:.1f}")
status.append(f"全景 FPS: {birdview.stat_data.average_fps:.1f}")
print(" | ".join(status), end="\r")
finally:
for td in process_tds:
td.stop()
for td in capture_tds:
td.stop()
td.disconnect_camera()
birdview.stop()
cv2.destroyAllWindows()
if __name__ == "__main__":
main()