140 lines
5.3 KiB
Python
140 lines
5.3 KiB
Python
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() |