from moviepy.editor import ImageClip, ColorClip, concatenate_videoclips, CompositeVideoClip import os import re import natsort from PIL import Image import numpy as np from concurrent.futures import ThreadPoolExecutor def process_image(file, duration, target_size): with Image.open(file) as img: width, height = img.size ratio = width / height new_width, new_height = target_size if width > target_size[0] or height > target_size[1]: if ratio > target_size[0] / target_size[1]: new_width = target_size[0] new_height = int(new_width / ratio) else: new_height = target_size[1] new_width = int(new_height * ratio) resized_img = img.resize((new_width, new_height), resample=Image.Resampling.LANCZOS) img_clip = ImageClip(np.array(resized_img)).set_duration(duration).set_position('center') return img_clip def images_to_video_with_durations(input_image_path, output_video_path, durations, fps, base_name): # 获取所有符合条件的图片,并按文件名中的数字排序 pattern = re.compile(rf'^{re.escape(base_name)}_(\d+)\.png$') image_files = [ os.path.join(input_image_path, file) for file in os.listdir(input_image_path) if pattern.match(file) ] image_files = natsort.natsorted(image_files, key=lambda x: int(pattern.match(os.path.basename(x)).group(1))) # 确定视频的背景尺寸 target_size = (1280, 720) # 创建背景剪辑 bg_clip = ColorClip(size=target_size, color=(255, 255, 255), duration=sum(durations)) # 使用多线程处理图像文件 with ThreadPoolExecutor() as executor: clips = list(executor.map(process_image, image_files, durations, [target_size] * len(image_files))) # 将所有剪辑叠加到背景上 composite_clips = [CompositeVideoClip([bg_clip.subclip(sum(durations[:i]), sum(durations[:i+1])), clip]) for i, clip in enumerate(clips)] # 使用concatenate_videoclips函数将所有剪辑串联起来 final_clip = concatenate_videoclips(composite_clips, method="compose") # 写入视频文件 output_filename = f"{base_name}.mp4" final_clip.write_videofile(os.path.join(output_video_path, output_filename), fps=fps)