写了两个脚本。一个用于将视频按帧率一次转为图片,另一个将图片合成的为视频的脚本。
一、环境配置:安装opencv2
用到了os库、cv2、glob
pip install opencv-contrib-python二、代码
1.首先是第一个视频转为图片的代码:
可以按需修改最后几行的代码。输入视频路径和输出图片的路径一定要改;输出照片的格式默认是jpg,按需改成png啥的都可以;保存帧数默认是0,就是将所有的帧数都提取出来,但是这样就会有很多相似的照片,反正按需求来吧,设置30帧提取一帧都可以。
video_path='D:\\data\\1080p.mp4', #输入转换的视频
output_dir='D:\\data\\1080p', #输出图片的文件夹
frame_format='png', #输出照片的格式
skip_frames=9 # 0=保存所有帧,1=每2帧保存1帧,依此类推
import cv2 import os def video_to_frames(video_path, output_dir, frame_format='jpg', skip_frames=0): """ 将视频逐帧提取为图片 参数: video_path: 输入视频的路径(如 "test.mp4") output_dir: 输出图片的文件夹路径 frame_format: 保存图片的格式,可选 'jpg' 或 'png' skip_frames: 跳帧间隔(0表示不跳帧,1表示每2帧取1帧,以此类推) """ # 创建输出文件夹(如果不存在) if not os.path.exists(output_dir): os.makedirs(output_dir) # 打开视频文件 cap = cv2.VideoCapture(video_path) if not cap.isOpened(): raise ValueError(f"无法打开视频文件: {video_path}") frame_count = 0 # 总帧数计数器 saved_count = 0 # 保存的帧数计数器 # 逐帧读取视频 while True: # 读取一帧 ret, frame = cap.read() # ret 为 False 表示读取完毕(到视频末尾) if not ret: break # 跳帧处理(按需保存) if frame_count % (skip_frames + 1) == 0: # 定义图片文件名(格式:frame_0001.jpg) frame_filename = f"frame_{saved_count:04d}.{frame_format}" frame_path = os.path.join(output_dir, frame_filename) # 保存帧为图片 cv2.imwrite(frame_path, frame) saved_count += 1 frame_count += 1 # 释放视频资源 cap.release() print(f"视频帧提取完成!") print(f"总帧数: {frame_count}, 保存的帧数: {saved_count}") print(f"图片保存路径: {os.path.abspath(output_dir)}") # ------------------- 示例调用 ------------------- if __name__ == "__main__": # 替换为你的视频路径和输出文件夹路径 video_to_frames( video_path='D:\\data\\1080p.mp4', #输入转换的视频 output_dir='D:\\data\\1080p', #输出图片的文件夹 frame_format='jpg', #输出照片的格式 skip_frames=0 # 0=保存所有帧,1=每2帧保存1帧,依此类推 )2.图片依次转换为视频的代码
逻辑基本上差不多,调整的参数:
frames_dir=FRAMES_DIR #替换为你的图片文件夹路径
output_video_path=OUTPUT_VIDEO, #替换为你预计保存视频的路径
fps=25, # 帧率,根据原视频调整(比如原视频是25FPS就设为25)
frame_format='jpg' # 图片格式,和之前保存的一致
import cv2 import os import glob def frames_to_video(frames_dir, output_video_path, fps=30, frame_format='jpg'): """ 将按顺序命名的图片帧合并为视频 参数: frames_dir: 存放图片帧的文件夹路径 output_video_path: 输出视频的路径(如 "output_video.mp4") fps: 输出视频的帧率(默认30帧/秒,可根据原视频调整) frame_format: 图片帧的格式(如 'jpg'、'png') """ # 检查输入文件夹是否存在 if not os.path.exists(frames_dir): raise ValueError(f"图片文件夹不存在: {frames_dir}") # 获取所有图片帧的路径,并按文件名排序(保证帧顺序) frame_paths = glob.glob(os.path.join(frames_dir, f"*.{frame_format}")) if not frame_paths: raise ValueError(f"在 {frames_dir} 中未找到 {frame_format} 格式的图片") # 按文件名排序(关键!确保帧顺序正确) frame_paths.sort(key=lambda x: int(os.path.splitext(os.path.basename(x))[0].split('_')[1])) # 读取第一张图片,获取视频分辨率 first_frame = cv2.imread(frame_paths[0]) if first_frame is None: raise ValueError(f"无法读取第一张图片: {frame_paths[0]}") height, width = first_frame.shape[:2] # 设置视频编码格式和写入对象 # MP4格式推荐使用 'mp4v' 编码,兼容性更好 fourcc = cv2.VideoWriter_fourcc(*'mp4v') video_writer = cv2.VideoWriter( output_video_path, fourcc, fps, (width, height) # 视频分辨率(宽, 高) ) if not video_writer.isOpened(): raise ValueError(f"无法创建视频写入对象,请检查输出路径和编码格式") # 逐帧写入视频 total_frames = len(frame_paths) for i, frame_path in enumerate(frame_paths): # 读取图片帧 frame = cv2.imread(frame_path) if frame is None: print(f"警告:跳过损坏的图片 {frame_path}") continue # 确保图片尺寸和视频分辨率一致(防止尺寸不匹配报错) if frame.shape[:2] != (height, width): frame = cv2.resize(frame, (width, height)) # 写入视频 video_writer.write(frame) # 打印进度(可选) if (i + 1) % 100 == 0 or (i + 1) == total_frames: print(f"已处理 {i + 1}/{total_frames} 帧") # 释放资源 video_writer.release() print(f"\n视频生成完成!") print(f"输出视频路径: {os.path.abspath(output_video_path)}") print(f"视频参数:分辨率 {width}x{height},帧率 {fps} FPS") if __name__ == "__main__": # 替换为你的图片文件夹路径和输出视频路径 FRAMES_DIR = "D:/data/img" # 存放图片帧的文件夹(和之前转帧的输出路径一致) OUTPUT_VIDEO = "D:/data/img.mp4" # 输出视频文件名 # 调用函数(帧率建议和原视频一致,通常为24/30 FPS) frames_to_video( frames_dir=FRAMES_DIR, output_video_path=OUTPUT_VIDEO, fps=25, # 帧率,根据原视频调整(比如原视频是25FPS就设为25) frame_format='jpg' # 图片格式,和之前保存的一致 )