You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何缓存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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 19:04:53