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

使用cv2.VideoWriter()修改fps无法降低视频速度的原因排查

问题描述

使用cv2.VideoWriter()实现图片合成视频功能时,修改传入的fps参数(如从30调整为20)后,输出视频的实际播放速度无任何变化,始终高于预期速度。

原实现代码
def video_Writer(images_path_read, output_vid_path, fps=30):

    '''
    parameters:
        - images_path_read - the path containing images to be combined and make a video
        - output_vid_path - the path and file name of output video (must include .mp4)
    method:
        - the function get the images path, read the sorted images and make a video according
        to the first image size.

    '''

    dir_images_list = os.listdir(images_path_read)
    dir_images_list = natsorted(dir_images_list)

    # get the size of the first image
    fourcc = VideoWriter_fourcc(*'mp4v')
    img_0 = cv2.imread(images_path_read + dir_images_list[0])

    # find the image shape
    size = (img_0.shape[1], img_0.shape[0])

    # Creating VideoWriter Object and open it to start in the loop
    vid_writer = cv2.VideoWriter(output_vid_path, fourcc, fps, size)
    vid_writer.open(output_vid_path, fourcc, fps, size)

    for image in dir_images_list:
        # Reading the images from the path folder
        img = cv2.imread(images_path_read + image)
        
        # Checking the size of frames
        if size[0] != img.shape[1] or size[1] != img.shape[0]:
            img = resize(img, size)
            print('Resizing Happend')
        # Adding images to Video
        vid_writer.write(img)
    #     print(image)

    # Releasing VideoWriter Object
    vid_writer.release()
问题原因
  • 重复调用open()方法导致参数异常:cv2.VideoWriter构造函数在传入合法参数时会自动完成流初始化、打开写入通道,实例化对象后再次手动调用open()方法,部分OpenCV版本会在二次打开时重置配置,导致传入的自定义fps参数失效,回退到编码器默认帧率(通常为25/30fps),因此无论怎么修改传入的fps值,最终写入视频的帧率都是固定值。
  • mp4v编码器兼容性缺陷:使用的mp4v(MPEG-4 Part 2)编码器在pip源分发的轻量版OpenCV中,存在帧率元数据写入bug,经常出现自定义fps不生效、文件头帧率信息错误的问题,直接导致播放器读取到错误的帧率参数,按固定高速播放。
  • 缺少写入流有效性校验:代码没有判断VideoWriter是否真的初始化成功,部分环境下编码器加载失败时,写入操作会走异常回退逻辑,所有自定义参数都不会生效。
修复方案
  • 删除重复的open()调用,仅在构造函数中传入配置参数,同时增加初始化成功校验,避免异常回退导致参数失效。
  • 更换兼容性更好的编码器:输出mp4格式时将fourcc替换为*'avc1'(H.264编码),该编码器对自定义帧率的支持更稳定,兼容绝大多数播放器;如果无H.264依赖,也可先输出avi格式搭配*'XVID'编码器验证帧率逻辑。
  • 修复代码中的隐性bug:路径拼接改用os.path.join()避免跨平台路径错误,resize调用补全cv2命名空间,避免调用到非OpenCV的resize方法导致帧写入异常。
  • 增加写入结果校验:视频生成后可用OpenCV读取生成的文件,打印cap.get(cv2.CAP_PROP_FPS)确认实际写入的帧率是否符合预期,排除部分播放器强制按固定帧率播放的干扰。
修复后参考代码
import os
import cv2
from natsort import natsorted

def video_Writer(images_path_read, output_vid_path, fps=30):
    '''
    parameters:
        - images_path_read - the path containing images to be combined and make a video
        - output_vid_path - the path and file name of output video (must include .mp4)
    method:
        - the function get the images path, read the sorted images and make a video according
        to the first image size.
    '''
    dir_images_list = [f for f in os.listdir(images_path_read) if f.lower().endswith(('.png', '.jpg', '.jpeg'))]
    dir_images_list = natsorted(dir_images_list)
    if not dir_images_list:
        raise ValueError("指定目录下未找到有效图片文件")

    # 优先使用avc1(H.264)编码器,兼容性更好
    fourcc = cv2.VideoWriter_fourcc(*'avc1')
    img_0 = cv2.imread(os.path.join(images_path_read, dir_images_list[0]))
    if img_0 is None:
        raise ValueError("首帧图片读取失败,请检查路径")
    size = (img_0.shape[1], img_0.shape[0])

    # 仅在构造函数中初始化,不重复调用open
    vid_writer = cv2.VideoWriter(output_vid_path, fourcc, fps, size)
    if not vid_writer.isOpened():
        # 如果avc1加载失败,回退到mp4v
        fourcc = cv2.VideoWriter_fourcc(*'mp4v')
        vid_writer = cv2.VideoWriter(output_vid_path, fourcc, fps, size)
        if not vid_writer.isOpened():
            raise RuntimeError("视频写入流初始化失败,请检查编码器依赖和输出路径")

    for image in dir_images_list:
        img_path = os.path.join(images_path_read, image)
        img = cv2.imread(img_path)
        if img is None:
            print(f"跳过无效图片: {img_path}")
            continue
        # 补全cv2命名空间调用resize
        if size[0] != img.shape[1] or size[1] != img.shape[0]:
            img = cv2.resize(img, size)
            print(f"图片{image}尺寸不匹配,已自动缩放")
        vid_writer.write(img)

    # 释放资源前强制刷新缓冲区
    vid_writer.release()
    cv2.destroyAllWindows()

    # 校验实际写入的帧率
    verify_cap = cv2.VideoCapture(output_vid_path)
    actual_fps = verify_cap.get(cv2.CAP_PROP_FPS)
    verify_cap.release()
    print(f"视频生成完成,实际写入帧率为: {actual_fps}")

内容的提问来源于stack exchange,提问作者Moheb Zandinezhad

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 04:45:37