如何缓存OpenStitching平面变形器生成的变形点以避免逐帧重算?
固定双摄像头全景拼接:复用变形点与参数提升帧率
我正在编写Python脚本,基于OpenStitching(OpenCV衍生库)处理固定位置双摄像头的视频,目标是校准后合成为全景画面。由于摄像头位置固定,希望仅计算一次seam mask和变形点并复用,但当前逐帧执行平面变形导致全景生成帧率无法达到30FPS,求可行的参数保存与复用方案,避免逐帧重复计算。
当前使用的两个核心函数:
getCamSeammask(校准并存储参数)
def getCamSeammask (frameLeft, frameRight): global cameraMask images = Images.of([frameLeft, frameRight]) medium_imgs = images.resize(Images.Resolution.MEDIUM) final_imgs = list(images.resize(Images.Resolution.FINAL)) features = [FINDER.detect_features(img) for img in medium_imgs] matches = MATCHER.match_features(features) conf = MATCHER.get_confidence_matrix(matches) cameras = CAMERA_ESTIMATOR.estimate(features,matches) cameras = CAMERA_ADJUSTER.adjust(features,matches,cameras) cameras = WAVE_CORRECTOR.correct(cameras) WARPER.set_scale(cameras) final_sizes = images.get_scaled_img_sizes(Images.Resolution.FINAL) camera_aspect = images.get_ratio(Images.Resolution.MEDIUM, Images.Resolution.FINAL) warped_final_imgs = list(WARPER.warp_images(final_imgs, cameras, camera_aspect)) warped_final_masks = list(WARPER.create_and_warp_masks(final_sizes, cameras, camera_aspect)) final_corners, final_sizes = WARPER.warp_rois(final_sizes, cameras, camera_aspect) seamMask = SEAM_FINDER.find(warped_final_imgs, final_corners, warped_final_masks) cameraMask = (cameras, seamMask)
getPanorama(生成全景)
def getPanorama(frameLeft, frameRight): cam = cameraMask[0] seammask = cameraMask[1] images = Images.of([frameLeft, frameRight]) final_sizes = images.get_scaled_img_sizes(Images.Resolution.FINAL) camera_aspect = images.get_ratio(Images.Resolution.MEDIUM, Images.Resolution.FINAL) warped_final_imgs = list(WARPER.warp_images([frameLeft,frameRight], cam, camera_aspect)) final_corners, final_sizes = WARPER.warp_rois(final_sizes, cam, camera_aspect) BLENDER.prepare(final_corners, final_sizes) for img, mask, corner in zip(warped_final_imgs, seammask, final_corners): BLENDER.feed(img, mask, corner) panorama,_ = BLENDER.blend() return panorama
解决方案:序列化保存固定参数,逐帧复用
核心思路是把相机校准参数、变形映射表、seam mask这些固定值提前计算并序列化存储,后续帧直接加载复用,跳过特征检测、匹配、相机估计等最耗时的步骤。
1. 添加参数保存函数
使用pickle序列化保存所有固定参数,包括预计算的变形映射表(避免逐帧调用warp_images重复计算):
import pickle import os import cv2 def save_calibration_params(save_path="calib_params.pkl", frameLeft=None, frameRight=None): if 'cameraMask' not in globals(): raise ValueError("请先调用getCamSeammask完成首次校准") cameras, seamMask = cameraMask # 基于第一帧获取固定尺寸参数 if frameLeft is None or frameRight is None: raise ValueError("需要传入第一帧左右图像以计算变形映射") images = Images.of([frameLeft, frameRight]) final_sizes = images.get_scaled_img_sizes(Images.Resolution.FINAL) camera_aspect = images.get_ratio(Images.Resolution.MEDIUM, Images.Resolution.FINAL) # 预计算左右帧的变形映射表 warper_left = WARPER.create_warp(cameras[0], camera_aspect) warper_right = WARPER.create_warp(cameras[1], camera_aspect) map_left_x, map_left_y = warper_left.build_map(final_sizes[0]) map_right_x, map_right_y = warper_right.build_map(final_sizes[1]) # 打包所有参数 params = { "cameras": cameras, "seamMask": seamMask, "final_sizes": final_sizes, "camera_aspect": camera_aspect, "map_left_x": map_left_x, "map_left_y": map_left_y, "map_right_x": map_right_x, "map_right_y": map_right_y } with open(save_path, 'wb') as f: pickle.dump(params, f)
2. 添加参数加载函数
def load_calibration_params(load_path="calib_params.pkl"): with open(load_path, 'rb') as f: params = pickle.load(f) global cameraMask, WARP_PARAMS cameraMask = (params["cameras"], params["seamMask"]) WARP_PARAMS = params
3. 优化getPanorama函数
直接使用预存的变形映射表执行图像变形,彻底跳过WARPER.warp_images的重复计算:
def getPanorama(frameLeft, frameRight): params = WARP_PARAMS # 用预存映射表快速变形 warped_left = cv2.remap(frameLeft, params["map_left_x"], params["map_left_y"], cv2.INTER_LINEAR) warped_right = cv2.remap(frameRight, params["map_right_x"], params["map_right_y"], cv2.INTER_LINEAR) warped_final_imgs = [warped_left, warped_right] final_corners, final_sizes = WARPER.warp_rois(params["final_sizes"], params["cameras"], params["camera_aspect"]) BLENDER.prepare(final_corners, final_sizes) for img, mask, corner in zip(warped_final_imgs, params["seamMask"], final_corners): BLENDER.feed(img, mask, corner) panorama,_ = BLENDER.blend() return panorama
注意事项
- 首次运行流程:取第一帧左右图像 → 调用
getCamSeammask校准 → 调用save_calibration_params保存参数。 - 后续运行流程:调用
load_calibration_params加载参数 → 直接逐帧调用getPanorama生成全景。 - 若OpenStitching版本不支持
build_map方法,可跳过映射表保存,仅复用cameras、seamMask等参数,仍能大幅减少耗时。 - 若
pickle无法序列化部分对象,可改用dill库替代,兼容性更强。
内容的提问来源于stack exchange,提问作者Tibe Demeulemeester
相关产品推荐
相关产品推荐

