python将照片集导出成视频

server/2024/10/17 15:32:16/

shigen坚持更新文章的博客写手,记录成长,分享认知,留住感动。个人IP:shigen

背景

一个安静的下午,看着电脑里乱七八糟的照片,有大有小,宽高不一,突然想找个方式把他们统一起来,然后做成视频更好(其实我在上高中的时候就喜欢把照片做成视频,觉得意义很大)。要满足批量、自动化,肯定得动用代码了。于是首先我列举了下我希望的功能:

  1. 照片来源:制定的目录下所有的文件格式为照片的文件,按照照片的文件名进行排序
  2. 照片质量:按照目前的720P、1080P、甚至是2K、4K的画质来生成照片视频
  3. 照片横竖:可以自定义指定照片是横屏还是竖屏
  4. 照片时间:可以自定义每一张照片的放映时间
  5. 照片比例:这个也是最为重要的,对此我分成了如下几种case:
    1. 图片的宽度 < 视频宽度 * 50% or 图片的高度 < 视频高度 * 50%:舍弃掉
    2. 图片宽度 < 视频宽度 or 图片的高度 < 视频高度:居中等比放大,直到高度 = 视频高度 or 宽度 = 视频宽度=
    3. 其它尺寸,图片居中等比缩小,直到高度 = 视频高度 or 宽度 = 视频宽度

这种照片比例的放大居中,基本上是强迫症患者的福音了,严格的居中对齐。

实现

依托强大的python库,这里主要用到的工具库有:

  1. Pillow,源代码有简单、精炼的解释:**Pillow is the friendly PIL fork by Alex Clark and Contributors.PIL is the Python Imaging Library by Fredrik Lundh and Contributors.**机器学习、图像识别等场景用到的最多,这里主要使用它来调整图片的大小
  2. MoviePy, 是一个用于视频编辑的 Python 库。可以剪辑视频添加音频和字幕调整视频帧简单的特效等等。这里主要是根据照片序列生成视频。

介绍完主要的库之后,就是代码环节了,代码里注释较多,轻松入手,不做过多的解释:

python"># create viode from a dictionary which contains image or video files
import os
from PIL import Image
from moviepy.editor import ImageSequenceClipdef resize_and_crop(image, target_size):"""将图片根据给定的大小进行缩放和裁剪1. 图片的宽度 < 视频宽度 * 50% or 图片的高度 < 视频高度 * 50%:舍弃掉2. 图片宽度 < 视频宽度 or 图片的高度 < 视频高度:居中等比放大,直到高度 = 视频高度 or 宽度 = 视频宽度3. 图片居中等比缩小,直到高度 = 视频高度 or 宽度 = 视频宽度Args:image (str): 原图片文件路径target_size (tuple): 视频大小(宽度, 高度)Returns:Image: 调整后的图片,可能为空"""img = Image.open(image)video_width, video_height = target_size# 检查条件1:如果原图宽度或高度小于视频尺寸的50%,则返回Noneif img.width < video_width * 0.5 or img.height < video_height * 0.5:return None# 计算目标缩放比例scale_x = video_width / img.widthscale_y = video_height / img.height# 根据需要的宽度和高度选择缩放比例if img.width < video_width or img.height < video_height:# 居中等比放大scale = max(scale_x, scale_y)else:# 居中等比缩小scale = min(scale_x, scale_y)# 放大或缩小图片new_size = (int(img.width * scale), int(img.height * scale))img = img.resize(new_size, Image.ANTIALIAS)# 计算裁剪框的位置left = (img.width - video_width) // 2top = (img.height - video_height) // 2right = left + video_widthbottom = top + video_height# 裁剪并返回最终图片img = img.crop((left, top, right, bottom))return imgdef create_video_from_images(folder_path,out_put_file_name='output_video.mp4',resolution='720p',is_horizontal=True,duration=3):"""通过照片生成视频Args:folder_path (_type_): 文件夹路径out_put_file_name (str, optional): _description_. 视频输出路径 Defaults to 'output_video.mp4'.resolution (str, optional): _description_. 视频清晰度 Defaults to '720p'.is_horizontal (bool, optional): _description_. 是否是横屏 Defaults to True.duration (int, optional): _description_. 每张照片的放映时长 Defaults to 3.Raises:ValueError: 视频清晰度错误"""resolution_mapping = {'720p': (1280, 720),'1080p': (1920, 1080),'2k': (2560, 1440),'4k': (3840, 2160),}if resolution not in resolution_mapping:raise ValueError("Invalid resolution. Choose from '720p', '1080p', '2k', '4k'.")target_size = resolution_mapping[resolution]if not is_horizontal:target_size = (target_size[1], target_size[0])images = []# 读取文件夹下的文件并按照文件名排序for filename in sorted(os.listdir(folder_path)):if filename.lower().endswith(('.png', '.jpg', '.jpeg', '.bmp')):img = resize_and_crop(os.path.join(folder_path, filename),target_size)if img:images.append(img)# 照片的临时位置temp_files = []for i, img in enumerate(images):temp_file = f'temp_image_{i}.png'img.save(temp_file)temp_files.append(temp_file)# 创建视频clip = ImageSequenceClip(temp_files, fps=1 / duration)output_file = os.path.join(folder_path, out_put_file_name)clip.write_videofile(output_file, codec='libx264')# 清除临时文件for temp_file in temp_files:os.remove(temp_file)if __name__ == '__main__':create_video_from_images(folder_path='/Users/xxxx/Downloads/xxx/imgs',is_horizontal=False,resolution='720p')

我们执行脚本,这里是控制台输出:

控制台输出

再来看看视频输出:

生成的视频

标准的720P H264编码,3&,21s的时长。有一张图是横屏的图,这里生成的视频中也根据高度放大进行了居中裁剪:

图片居中裁剪

整体的感觉还不错,特此写个博客分享出来。当然还有很多的优化点:

优化项

其实做的还是相当的粗糙,但是基本上还是省事儿了。考虑到的优化点有:

  1. 指定背景音乐并实现照片卡点
  2. 加上随机的特效切换

咳,目前想到的就这么多。作为工具,我觉得越简单越好,需要效率和我开发时间的权衡。

与shigen一起,每天不一样!


http://www.ppmy.cn/server/132514.html

相关文章

python实现归并排序

文章目录 归并排序NB三人组总结 归并排序 """ 归并排序 """""" 时间复杂度 &#xff1a; O(N*logN) 空间复杂度 &#xff1a; O(N) 需要额外生成一个临时变量&#xff0c;最大是N长 思路&#xf…

java脚手架系列8-统一授权OAuth2

之所以想写这一系列&#xff0c;是因为之前工作过程中有几次项目是从零开始搭建的&#xff0c;而且项目涉及的内容还不少。在这过程中&#xff0c;遇到了很多棘手的非业务问题&#xff0c;在不断实践过程中慢慢积累出一些基本的实践经验&#xff0c;认为这些与业务无关的基本的…

【C++贪心】2086. 喂食仓鼠的最小食物桶数|1622

本文涉及知识点 C贪心 LeetCode2086. 喂食仓鼠的最小食物桶数 给你一个下标从 0 开始的字符串 hamsters &#xff0c;其中 hamsters[i] 要么是&#xff1a; ‘H’ 表示有一个仓鼠在下标 i &#xff0c;或者’.’ 表示下标 i 是空的。 你将要在空的位置上添加一定数量的食物桶…

NIO(Non-blocking I/O)处理机制

典型的 NIO 事件处理流程 在 Java NIO (Non-blocking I/O) 中&#xff0c;事件驱动模型使得应用程序能够高效地管理多个并发的 I/O 操作。通过 Selector&#xff0c;NIO 使得单个线程可以监听多个通道的事件&#xff08;如连接请求、读写数据&#xff09;。以下是对典型 NIO 事…

EasyExcel读入数字类型数据时出现小数位丢失精度问题

这里写自定义目录标题 问题现象解决方案 问题现象 目前使用easyExcel读取导入文档时发现文档中的小数值4076204076.65会被读取为4076204076.6500001 尝试去查看了excel解压后的文件&#xff0c;发现这条数据在xml里存储的值就是4076204076.6500001&#xff0c;即是excel存储小…

【Bug】docker容器之间网络通讯失败

目录 报错起因报错内容解决方案 报错起因 我启动了Milvus数据库 # docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS …

React Query 和 React Context

React Query最佳特性之一是你可以在组件树中的任何位置使用查询&#xff1a;你的 <ProductTable> 组件可以在其需要的地方自带数据获取&#xff1a; function ProductTable() {const productQuery useProductQuery()if (productQuery.data) {return <table>...<…

【NVIDIA NIM 黑客松训练营】文生图小应用

项目简介 以下是一个使用 NIM 平台的生成式 AI模型构建的简单 Demo。 Demo使用了模型meta / llama3-70b-instruct和nvidia / consistory&#xff0c;首先是优化了模型meta / llama3-70b-instruct默认的英文输出&#xff0c;使其对中文用户更友好&#xff1b;其次根据用户输入判…