Linux环境下使用OpenCV合成的视频播放速度过快如何解决
问题根因
- 文件格式不匹配:你在
save_frames函数中存储的是.jpg格式的帧文件,但make_video函数中筛选文件的条件是if ".png" in f,这会导致你实际读取合成的根本不是本次捕获的帧,大概率是路径下之前遗留的旧png文件,所以你修改fps参数自然不会生效。 - 帧读取逻辑错误:捕获帧的循环中没有判断
cap.read()返回的ret值,视频读取到末尾后ret会变为False,此时frame是空值,你依然执行了存图和计数自增逻辑,会多存大量无效的空帧:原视频10秒30fps实际只有300帧有效帧,你统计到的600帧是包含无效帧的错误数据,最终合成时长自然不对。 - 文件排序错误:
os.listdir()返回的文件名是按照系统字典序排列,不是按帧号的自然顺序,比如frame00010.jpg会排在frame00002.jpg前面,帧顺序混乱也会导致播放异常。 - fps参数未正确传递:你
save_frames已经返回了原视频的fps值,调用make_video时需要把这个值传入,不要用默认的25。
修复代码
修复后的视频捕获函数
def save_frames(video_file, path_in): cap = cv2.VideoCapture(video_file) if not cap.isOpened(): raise IOError(f"无法打开视频文件{video_file}") fps = cap.get(cv2.CAP_PROP_FPS) count = 1 while cap.isOpened(): ret, frame = cap.read() # 读取失败直接退出循环,不存无效帧 if not ret: break cv2.imwrite(path_in + f"frame{str(count).zfill(5)}.jpg", frame) # 本地读视频不需要waitKey判断,可直接删除 count += 1 cap.release() cv2.destroyAllWindows() print(f"共捕获有效帧{count-1}张,原视频帧率{fps}") return fps
修复后的视频合成函数
def make_video(path_out, outvid, fps=25, size=None, is_color=True, format='mp4v'): # 筛选后缀改为jpg,按帧号自然排序 images = sorted([f for f in os.listdir(path_out) if f.endswith(".jpg")], key=lambda x:int(x.split("frame")[1].split(".jpg")[0])) if not images: raise ValueError(f"路径{path_out}下没有找到jpg格式的帧文件") from cv2 import VideoWriter, VideoWriter_fourcc, imread, resize fourcc = VideoWriter_fourcc(*'mp4v') vid = None for idx, image in enumerate(images): img_path = os.path.join(path_out, image) if not os.path.exists(img_path): raise FileNotFoundError(img_path) img = imread(img_path) if vid is None: if size is None: size = img.shape[1], img.shape[0] vid = VideoWriter(outvid, fourcc, float(fps), size, is_color) # 宽或高不匹配就resize,原逻辑的and判断错误 if size[0] != img.shape[1] or size[1] != img.shape[0]: img = resize(img, size) vid.write(img) if idx % 100 == 0: print("Progress: %0.2f%%" % (idx / len(images) * 100,), flush=True) vid.release() print(f"合成完成,共写入{len(images)}帧,输出帧率{fps}") return
调用示例
# 先捕获帧,拿到原视频的真实帧率 source_fps = save_frames("你的原视频路径.mp4", "./帧存储目录/") # 合成时传入原视频帧率 make_video("./帧存储目录/", "./输出视频路径.mp4", fps=source_fps)
内容的提问来源于stack exchange,提问作者vimal
相关产品推荐
相关产品推荐

