如何用OpenCV和Python处理不同尺寸图片与视频的互转?
异尺寸图片集与视频互转方案(保留原图片尺寸)
一、生成兼容异尺寸图片的视频
OpenCV的VideoWriter要求视频帧尺寸固定,直接写入不同尺寸图片会触发尺寸不匹配错误。解决思路:
- 遍历所有图片,取最大宽高作为视频帧固定尺寸,确保所有原始图片能完整放入画布
- 将每张图片放置在黑色画布左上角(无任何缩放),保留原始像素信息
- 同步保存元数据文件,记录每一帧对应的原始图片尺寸和文件名,为后续提取做准备
实现代码
import cv2 import json import os import numpy as np def images_to_video(image_list, output_video, fps=1): # 遍历图片获取最大宽高,筛选有效图片 max_width = 0 max_height = 0 valid_images = [] for img_path in image_list: img = cv2.imread(img_path) if img is None: print(f"警告:跳过无法读取的图片 {img_path}") continue h, w = img.shape[:2] max_width = max(max_width, w) max_height = max(max_height, h) valid_images.append(img_path) if not valid_images: raise ValueError("没有可处理的有效图片") # 初始化视频写入器 codec = cv2.VideoWriter_fourcc(*"mp4v") video_writer = cv2.VideoWriter(output_video, codec, fps, (max_width, max_height)) # 写入视频并记录元数据 metadata = [] for img_path in valid_images: img = cv2.imread(img_path) h, w = img.shape[:2] # 创建与最大尺寸一致的黑色画布 canvas = np.zeros((max_height, max_width, 3), dtype=np.uint8) # 将原始图片放置在画布左上角(无缩放) canvas[:h, :w] = img video_writer.write(canvas) # 记录元数据:文件名、原始宽高 metadata.append({ "filename": os.path.basename(img_path), "original_width": w, "original_height": h }) video_writer.release() # 保存元数据到JSON文件 metadata_file = f"{os.path.splitext(output_video)[0]}_metadata.json" with open(metadata_file, "w") as f: json.dump(metadata, f, indent=2) print(f"视频生成完成:{output_video}") print(f"元数据文件已保存:{metadata_file}") # 示例调用 image_list = ["img1.jpg", "img2.jpg", "img3.jpg", "img4.jpg", "img5.jpg"] images_to_video(image_list, "output.mp4", fps=1)
二、从视频提取原尺寸图片
借助生成视频时保存的元数据,从每一帧对应区域裁剪出原始尺寸的图片,完全保留原始像素,无缩放或变形。
实现代码
import cv2 import json import os def video_to_images(input_video, output_dir="extracted_images"): # 创建输出目录 os.makedirs(output_dir, exist_ok=True) # 读取元数据文件 metadata_file = f"{os.path.splitext(input_video)[0]}_metadata.json" if not os.path.exists(metadata_file): raise FileNotFoundError(f"未找到对应元数据文件:{metadata_file}") with open(metadata_file, "r") as f: metadata = json.load(f) # 读取视频 cap = cv2.VideoCapture(input_video) if not cap.isOpened(): raise ValueError(f"无法打开视频文件:{input_video}") frame_idx = 0 while cap.isOpened(): ret, frame = cap.read() if not ret: break if frame_idx >= len(metadata): print(f"警告:视频帧数({frame_idx+1})多于元数据记录数({len(metadata)}),跳过后续帧") break # 获取当前帧对应的原始图片信息 img_info = metadata[frame_idx] orig_w, orig_h = img_info["original_width"], img_info["original_height"] # 裁剪出原始尺寸区域(左上角) original_img = frame[:orig_h, :orig_w] # 保存图片 output_path = os.path.join(output_dir, img_info["filename"]) cv2.imwrite(output_path, original_img) print(f"已保存:{output_path}") frame_idx += 1 cap.release() print(f"图片提取完成,所有文件保存至:{output_dir}") # 示例调用 video_to_images("output.mp4")
核心优势
- 完全保留原始图片的尺寸和像素信息,提取后的图片与上传时完全一致
- 解决了异尺寸图片生成视频的尺寸不匹配问题
- 元数据文件轻量易读取,确保提取过程的准确性
内容的提问来源于stack exchange,提问作者Gevin Hasmitha
相关产品推荐
相关产品推荐

