使用MoviePy制作图片缩放视频:消除初始黑边实现全屏启动缩放
问题描述
我是StackOverflow新手,需要Python代码帮助。我写了一段代码,能把文件夹里的图片转成5秒视频,实现单张图片渐进放大的效果,但现在有问题:生成的视频初始阶段图片周围有黑边,随着放大黑边才消失。我想要图片从视频开始就占满整个屏幕,之后继续放大,允许视频结束时部分图像超出视频边界。
原代码:
import os import glob import numpy as np import moviepy.editor as mp def create_zooming_video(image_path, output_path, duration=5, resolution=(1080, 1920)): img = mp.ImageClip(image_path) # Calculate the initial and final zoom scales initial_zoom = 1.0 final_zoom = 1.5 # Calculate the zooming scale for each frame zoom_scales = np.linspace(initial_zoom, final_zoom, int(duration * 30)) # 30 frames per second # Calculate the dimensions for the cropped image cropped_width = resolution[0] cropped_height = int(resolution[0] * (img.size[1] / img.size[0])) # Resize the image to fit the cropped dimensions img = img.resize((cropped_width, cropped_height)) # Create a list to hold each frame of the zooming animation zooming_frames = [] for scale in zoom_scales: frame = img.resize(scale) frame = frame.set_position(("center", "center")) frame = frame.set_duration(1 / 30) # Each frame lasts 1/30 seconds zooming_frames.append(frame) # Create the zooming animation clip zooming_clip = mp.concatenate_videoclips(zooming_frames, method="compose") # Calculate position to keep the zoomed image centered position = ("center", "center") zooming_clip = zooming_clip.set_position(position) zooming_clip = zooming_clip.set_duration(duration) zooming_clip = zooming_clip.set_fps(30) zooming_clip.write_videofile(output_path, codec="libx264") def main(): output_folder = "output_videos" os.makedirs(output_folder, exist_ok=True) png_files = glob.glob("*.png") for png_file in png_files: filename_without_extension = os.path.splitext(png_file)[0] output_path = os.path.join(output_folder, f"{filename_without_extension}.mp4") create_zooming_video(png_file, output_path) if __name__ == "__main__": main()
解决方案
问题根源在于你最初的缩放逻辑:你把图片固定缩放到视频宽度,但如果图片长宽比和目标视频(1080x1920竖屏)不匹配,高度就会不足,导致初始状态下屏幕出现黑边。要实现“从满屏开始放大”的效果,需要先计算能让图片刚好覆盖整个视频的初始缩放比例,之后在这个基础上继续放大,同时每帧都对图片进行居中裁剪,确保始终填满屏幕。
修改后的代码:
import os import glob import numpy as np import moviepy.editor as mp def create_zooming_video(image_path, output_path, duration=5, resolution=(1080, 1920)): img = mp.ImageClip(image_path) video_w, video_h = resolution # 计算让图片刚好覆盖整个视频的初始缩放比例 scale_w = video_w / img.size[0] scale_h = video_h / img.size[1] initial_zoom = max(scale_w, scale_h) # 最终缩放比例:在满屏基础上再放大1.5倍 final_zoom = initial_zoom * 1.5 # 生成逐帧的缩放比例序列 zoom_scales = np.linspace(initial_zoom, final_zoom, int(duration * 30)) zooming_frames = [] for scale in zoom_scales: # 按当前比例缩放图片 scaled_img = img.resize(scale) # 居中裁剪到视频分辨率,确保无黑边 cropped_img = scaled_img.crop( x_center=scaled_img.size[0]/2, y_center=scaled_img.size[1]/2, width=video_w, height=video_h ) cropped_img = cropped_img.set_duration(1/30) zooming_frames.append(cropped_img) # 拼接所有帧组成视频 zooming_clip = mp.concatenate_videoclips(zooming_frames, method="compose") zooming_clip = zooming_clip.set_fps(30) zooming_clip.write_videofile(output_path, codec="libx264") def main(): output_folder = "output_videos" os.makedirs(output_folder, exist_ok=True) png_files = glob.glob("*.png") for png_file in png_files: filename_without_extension = os.path.splitext(png_file)[0] output_path = os.path.join(output_folder, f"{filename_without_extension}.mp4") create_zooming_video(png_file, output_path) if __name__ == "__main__": main()
关键修改说明
- 初始缩放比例计算:对比图片与视频的宽高比例,取较大值作为初始缩放倍数,保证图片一开始就能完全覆盖视频屏幕,彻底消除初始黑边。
- 居中裁剪:每帧缩放后都对图片进行居中裁剪,无论放大到多大,视频画面始终被图片填满,超出屏幕的部分会被自动裁切,完全符合你的需求。
- 调整缩放范围:最终缩放在初始满屏的基础上再放大1.5倍,实现“从满屏开始放大,结束时部分图像超出边界”的效果。
内容的提问来源于stack exchange,提问作者Boris Razmiki
相关产品推荐
相关产品推荐

