import cv2 import threading import sys import os import argparse import numpy as np from surround_view import FisheyeCameraModel, BirdView import surround_view.param_settings as settings class MultiCameraBirdView: def __init__(self): self.running = True self.names = settings.camera_names self.yamls = [os.path.join(os.getcwd(), "yaml", name + ".yaml") for name in self.names] self.camera_models = [FisheyeCameraModel(camera_file, camera_name) for camera_file, camera_name in zip(self.yamls, self.names)] # 初始化摄像头 self.caps = [] self.which_cameras = { "front": 0, "left": 1, "back": 2, "right":3 } # 初始化摄像头捕获 for name in self.names: cap = cv2.VideoCapture(self.which_cameras[name], cv2.CAP_V4L2) cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc(*"YUYV")) cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720) cap.set(cv2.CAP_PROP_BUFFERSIZE, 3) if not cap.isOpened(): print(f"[ERROR] Cannot open {name} camera", file=sys.stderr) self.running = False return self.caps.append(cap) # 初始化鸟瞰图 self.birdview = BirdView() # 预先加载一次静态图像来初始化权重矩阵 self._initialize_weights() def _initialize_weights(self): """使用静态图像初始化权重矩阵""" try: # 加载静态图像用于初始化权重 images = [os.path.join(os.getcwd(), "images", name + ".png") for name in self.names] static_frames = [] for image_file, camera_model in zip(images, self.camera_models): img = cv2.imread(image_file) if img is None: print(f"[ERROR] Cannot load static image: {image_file}") continue img = camera_model.undistort(img) img = camera_model.project(img) img = camera_model.flip(img) static_frames.append(img) if len(static_frames) == 4: # 初始化权重和掩码矩阵 Gmat, Mmat = self.birdview.get_weights_and_masks(static_frames) print("[INFO] Weights and masks initialized successfully") else: print("[WARNING] Could not load all static images for weight initialization") except Exception as e: print(f"[ERROR] Failed to initialize weights: {e}", file=sys.stderr) def process_frame(self, img, camera_model): """处理单帧图像:去畸变 -> 投影 -> 翻转""" img = camera_model.undistort(img) img = camera_model.project(img) img = camera_model.flip(img) return img def run(self): # 获取屏幕分辨率(假设为 1920x1080,如果不同可以手动指定) # 在 Linux 下全屏显示通常需要先创建一个窗口 # cv2.namedWindow("SurroundView_System", cv2.WND_PROP_FULLSCREEN) # cv2.setWindowProperty("SurroundView_System", cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN) cv2.namedWindow("SurroundView_System", cv2.WINDOW_NORMAL) # 2. 指定窗口大小 (宽度, 高度) cv2.resizeWindow("SurroundView_System", 1024, 600) SCREEN_W = 1024 SCREEN_H = 600 # 计算布局比例 # 鸟瞰图占 1/3 宽度: 1920 / 3 = 640 # 原始画面占 2/3 宽度: 1920 * 2 / 3 = 1280 BIRD_W = SCREEN_W // 3 FRONT_W = SCREEN_W - BIRD_W while self.running: frames = [] raw_front_frame = None for i, (cap, camera_model) in enumerate(zip(self.caps, self.camera_models)): ret, frame = cap.read() if not ret or frame is None: continue # 保存一份原始的前向画面用于监视 (假设 front 是第一个摄像头) if self.names[i] == "front": raw_front_frame = frame.copy() processed_frame = self.process_frame(frame, camera_model) frames.append(processed_frame) if len(frames) == 4 and raw_front_frame is not None: try: # 1. 处理鸟瞰图 self.birdview.update_frames(frames) self.birdview.stitch_all_parts() self.birdview.make_white_balance() self.birdview.copy_car_image() # 2. 缩放鸟瞰图 (保持比例,填满左侧 1/3) # 假设原始 birdview.image 比较长,我们将其 resize 到 BIRD_W x SCREEN_H bird_part = cv2.resize(self.birdview.image, (BIRD_W, SCREEN_H)) # 3. 处理前向原始画面 (缩放至右侧 2/3) # raw_front_frame 是 1280x720, 缩放到 FRONT_W x SCREEN_H front_part = cv2.resize(raw_front_frame, (FRONT_W, SCREEN_H)) # 4. 水平拼接 (左鸟瞰 + 右前视) display_all = np.hstack((bird_part, front_part)) # 5. 全屏显示 cv2.imshow("SurroundView_System", display_all) if cv2.waitKey(1) & 0xFF == ord('q'): self.running = False break except Exception as e: print(f"[ERROR] Processing error: {e}") continue for cap in self.caps: cap.release() cv2.destroyAllWindows() def main(): parser = argparse.ArgumentParser(description="Real-time 4-Camera Bird's Eye View") parser.add_argument("--mode", type=str, required=True, choices=["realtime", "static"], help="Mode: 'realtime' for live video, 'static' for static images") args = parser.parse_args() if args.mode == "static": # 原有的静态图像处理代码 names = settings.camera_names images = [os.path.join(os.getcwd(), "images", name + ".png") for name in names] yamls = [os.path.join(os.getcwd(), "yaml", name + ".yaml") for name in names] camera_models = [FisheyeCameraModel(camera_file, camera_name) for camera_file, camera_name in zip(yamls, names)] projected = [] for image_file, camera in zip(images, camera_models): img = cv2.imread(image_file) img = camera.undistort(img) img = camera.project(img) img = camera.flip(img) projected.append(img) birdview = BirdView() Gmat, Mmat = birdview.get_weights_and_masks(projected) # 初始化权重矩阵 birdview.update_frames(projected) # birdview.get_weights_and_masks.stitch_all_parts() # birdview.make_white_balance() birdview.copy_car_image() img_small = cv2.resize(birdview.image, (600, 1024)) cv2.imshow("BirdView Result", img_small) while True: key = cv2.waitKey(1) & 0xFF if key == ord("q"): cv2.destroyAllWindows() return -1 elif args.mode == "realtime": # 实时视频处理 print("Starting real-time 4-camera bird's eye view...") print("Press 'q' to quit") multi_cam = MultiCameraBirdView() if multi_cam.running: multi_cam.run() else: print("[ERROR] Failed to initialize cameras") if __name__ == "__main__": main()