如何用Python 3.10的MoviePy实现不改变分辨率的视频放大?或OpenCV方案?
解决方案:视频内容放大但保持原分辨率
一、基于MoviePy的实现
MoviePy的resize方法会直接修改视频分辨率,要实现内容放大但输出分辨率不变,核心是先放大单帧内容,再裁剪回原分辨率(模拟镜头拉近的效果)。利用fl_image方法逐帧处理:
from moviepy.editor import VideoFileClip import cv2 def process_zoom(frame, scale_factor): h, w = frame.shape[:2] # 放大当前帧 zoomed_frame = cv2.resize(frame, (int(w * scale_factor), int(h * scale_factor))) # 计算裁剪区域,取放大后帧的中间部分,匹配原分辨率 new_h, new_w = zoomed_frame.shape[:2] start_x = (new_w - w) // 2 start_y = (new_h - h) // 2 # 裁剪回原分辨率尺寸 cropped_frame = zoomed_frame[start_y:start_y+h, start_x:start_x+w] return cropped_frame # 加载输入视频 input_clip = VideoFileClip("input.mp4") # 应用放大处理,这里设置放大倍数为2 zoomed_clip = input_clip.fl_image(lambda f: process_zoom(f, 2)) # 保存输出视频,保持原分辨率参数 zoomed_clip.write_videofile("output_moviepy.mp4", codec="libx264")
如果需要放大后保留完整内容、周围补黑边(而非裁剪局部),可以修改process_zoom函数,创建原分辨率的黑色画布,将放大后的帧居中放置:
import numpy as np def process_zoom_with_pad(frame, scale_factor): h, w = frame.shape[:2] zoomed_frame = cv2.resize(frame, (int(w * scale_factor), int(h * scale_factor))) new_h, new_w = zoomed_frame.shape[:2] # 创建原分辨率的黑色画布 padded_frame = np.zeros((h, w, 3), dtype=np.uint8) # 计算居中放置的坐标 x_offset = (w - new_w) // 2 if new_w < w else 0 y_offset = (h - new_h) // 2 if new_h < h else 0 # 将放大后的帧放入画布 padded_frame[y_offset:y_offset+new_h, x_offset:x_offset+new_w] = zoomed_frame return padded_frame
二、基于OpenCV的实现
OpenCV通过逐帧读取-处理-写入的流程,直接实现内容放大且保持原分辨率:
import cv2 # 打开输入视频 cap = cv2.VideoCapture("input.mp4") # 获取原视频的核心参数 orig_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) orig_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) fps = cap.get(cv2.CAP_PROP_FPS) fourcc = cv2.VideoWriter_fourcc(*"mp4v") # 创建输出视频写入器,严格匹配原分辨率 out = cv2.VideoWriter("output_opencv.mp4", fourcc, fps, (orig_width, orig_height)) scale_factor = 2 # 设置放大倍数 while cap.isOpened(): ret, frame = cap.read() if not ret: break # 放大帧内容 zoomed_frame = cv2.resize(frame, (int(orig_width * scale_factor), int(orig_height * scale_factor))) # 裁剪中间区域,回到原分辨率 new_h, new_w = zoomed_frame.shape[:2] x_start = (new_w - orig_width) // 2 y_start = (new_h - orig_height) // 2 cropped_frame = zoomed_frame[y_start:y_start+orig_height, x_start:x_start+orig_width] # 写入输出视频 out.write(cropped_frame) # 释放资源 cap.release() out.release() cv2.destroyAllWindows()
内容的提问来源于stack exchange,提问作者barelydrown
相关产品推荐
相关产品推荐

