基于python实现视频和音频长度对齐合成并添加字幕
在许多视频编辑任务中,我们常常需要将视频和音频进行对齐,并添加字幕。本文将详细介绍如何使用Python实现这一功能,并在视频中添加中文字幕。我们将使用OpenCV处理视频帧,使用MoviePy处理音频和视频的合成,使用PIL库绘制中文字幕。
环境设置
首先,我们需要安装必要的库。可以使用以下命令来安装它们:
pip install opencv-python moviepy Pillow
准备工作
- 准备音频和视频文件:确保你有需要对齐的音频和视频文件。
- 下载支持中文的字体文件:例如SimHei.ttf,并将其保存到合适的位置。在示例中,我们使用NotoSansCJKsc-Regular.ttf。
实现代码
以下是实现音视频对齐并添加中文字幕的完整Python代码。你可以将这段代码保存为一个Python文件,并根据需要进行调用。
import cv2
import numpy as np
from moviepy.editor import AudioFileClip, VideoFileClip
from pydub import AudioSegment
from PIL import Image, ImageDraw, ImageFont
import tempfile
import os
import re def replace_punctuation_with_at(input_string):# 使用正则表达式匹配所有标点符号并替换为 @result = re.sub(r'[^\w\s]', '@', input_string)return resultdef add_chinese_subtitle_to_frame(frame, subtitle_text, position, font_path, font_size, font_color):# 将OpenCV图像转换为PIL图像img_pil = Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))draw = ImageDraw.Draw(img_pil)font = ImageFont.truetype(font_path, font_size)# 获取字幕文本的宽度和高度text_bbox = draw.textbbox((0, 0), subtitle_text, font=font)text_width = text_bbox[2] - text_bbox[0]text_height = text_bbox[3] - text_bbox[1]# 计算字幕的放置位置x = position[0] - text_width // 2y = position[1] - text_height // 2# 在PIL图像上添加字幕draw.text((x, y), subtitle_text, font=font, fill=font_color)# 将PIL图像转换回OpenCV图像frame = cv2.cvtColor(np.array(img_pil), cv2.COLOR_RGB2BGR)return framedef sync_audio_video_add_subtitle(audio_path, video_path, output_path, subtitle_text, font_path, font_size=24, font_color=(255, 255, 255), subtitle_bottom_margin=30, audio_volume=1.0):# 加载音频文件并调整音量original_audio = AudioSegment.from_file(audio_path)original_audio = original_audio + (audio_volume * 10 - 10) # 调整音量silence = AudioSegment.silent(duration=500) # 0.5秒的静音audio_with_silence = silence + original_audio + silence# 创建临时文件以保存修改后的音频temp_audio_path = os.path.join(tempfile.gettempdir(), "temp_audio.mp3")audio_with_silence.export(temp_audio_path, format="mp3")# 加载修改后的音频文件audio_clip = AudioFileClip(temp_audio_path)audio_duration = audio_clip.duration# 加载视频文件cap = cv2.VideoCapture(video_path)fps = cap.get(cv2.CAP_PROP_FPS)frame_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))video_duration = frame_count / fps# 计算新的视频帧率new_fps = fps * (video_duration / audio_duration)# 获取视频尺寸width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))# 创建临时文件以存储中间视频结果temp_video_path = os.path.join(tempfile.gettempdir(), "temp_video.mp4")# 创建VideoWriter对象out = cv2.VideoWriter(temp_video_path, cv2.VideoWriter_fourcc(*'mp4v'), new_fps, (width, height))# 分批读取和写入视频帧,并添加字幕subtitle_text = replace_punctuation_with_at(subtitle_text)subtitle_text_list = [text for text in subtitle_text.split("@") if text]print(subtitle_text_list)subtitles_per_frame = frame_count // len(subtitle_text_list)current_subtitle_index = 0for frame_idx in range(frame_count):ret, frame = cap.read()if not ret:break# 添加当前字幕到帧if frame_idx // subtitles_per_frame >= current_subtitle_index and current_subtitle_index < len(subtitle_text_list):frame = add_chinese_subtitle_to_frame(frame, subtitle_text_list[current_subtitle_index], (width // 2, height - subtitle_bottom_margin), font_path, font_size, font_color)if frame_idx // subtitles_per_frame > current_subtitle_index:current_subtitle_index += 1out.write(frame)cap.release()out.release()# 使用MoviePy将音频和调整后的视频合并video_clip = VideoFileClip(temp_video_path).set_duration(audio_duration)final_clip = video_clip.set_audio(audio_clip)# Trim the last 0.3 secondsfinal_clip = final_clip.subclip(0, final_clip.duration - 0.3)# Write the final video filefinal_clip.write_videofile(output_path, codec="libx264", audio_codec="aac")# Close the clips to release the filefinal_clip.close()video_clip.close()audio_clip.close()# 删除临时文件os.remove(temp_audio_path)os.remove(temp_video_path)if __name__ == "__main__":# 示例用法audio_path = r"C:\Users\60568\Pictures\create\屈原\mp3\00000002.mp3"video_path = r"C:\Users\60568\Pictures\create\屈原\mp4\03.mp4"subtitle_text='然而屈原的直言进谏,引来了朝中权臣的嫉恨,他成为了政治斗争的牺牲品。'output_path = "synced_video.mp4"sync_audio_video_add_subtitle(audio_path, video_path, output_path,subtitle_text=subtitle_text,font_path="./NotoSansCJKsc-Regular.ttf",font_size=40, # 设置字体大小font_color=(255, 255, 255), # 设置字体颜色subtitle_bottom_margin=80, # 设置字幕底部的位置audio_volume=2) # 调整音频音量,1.0为原始音量,1.5为增加50%音量
代码说明
- add_chinese_subtitle_to_frame: 这个函数将字幕添加到给定的帧上。它使用PIL库来绘制字幕,然后将图像转换回OpenCV格式。
- sync_audio_video_add_subtitle: 这个函数处理音频和视频的对齐,并将字幕添加到每一帧上。最终,它将处理好的视频和音频合并,并生成输出文件。
保证音频长度不变,调整视频长度
在此代码中,我们特别强调了保证音频长度不变,通过调整视频的帧率来匹配音频长度。这是通过计算新的帧率 new_fps 实现的:
new_fps = fps * (video_duration / audio_duration)
调整参数
你可以通过调整以下参数来修改字幕的显示效果和位置:
font_size: 字体大小。font_color: 字体颜色。subtitle_bottom_margin: 字幕距离视频底部的距离。
运行示例
你可以使用提供的示例用法来运行代码,只需将audio_path、video_path和font_path替换为你自己的文件路径即可。
通过这个教程,你应该能够使用Python轻松地实现视频和音频的对齐,并在视频中添加中文字幕。如果你有任何问题或建议,请在评论区留言!
相关文章:
基于python实现视频和音频长度对齐合成并添加字幕
在许多视频编辑任务中,我们常常需要将视频和音频进行对齐,并添加字幕。本文将详细介绍如何使用Python实现这一功能,并在视频中添加中文字幕。我们将使用OpenCV处理视频帧,使用MoviePy处理音频和视频的合成,使用PIL库绘…...
爬虫-模拟登陆博客
import requests from bs4 import BeautifulSoupheaders {user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36 } # 登录参数 login_data {log: codetime,pwd: shanbay520,wp-submit: …...
【深度学习】【NLP】Bert理论,代码
论文 : https://arxiv.org/abs/1810.04805 文章目录 一、Bert理论BERT 模型公式1. 输入表示 (Input Representation)2. 自注意力机制 (Self-Attention Mechanism)3. Transformer 层 (Transformer Layer) 二、便于理解Bert的代码1. 自注意力机制2. Transformer 层3. …...
element table 点击某一行中按钮加载
在Element UI中,实现表格(element-table)中的这种功能通常涉及到数据处理和状态管理。当你点击某一行的按钮时,其他行的按钮需要动态地切换为加载状态,这可以通过以下步骤实现: 1.表格组件:使用…...
Linux开机自启/etc/init.d和/etc/rc.d/rc.local
文章目录 /etc/init.d和/etc/rc.d/rc.local的区别/etc/init.dsystemd介绍 /etc/init.d和/etc/rc.d/rc.local的区别 目的不同: /etc/rc.d/rc.local:用于在系统启动后执行用户自定义命令,适合简单的启动任务。 /etc/init.d:用于管理…...
DP:两个数组的dp问题
解决两个数组的dp问题的常用状态表示: 1、选取第一个字符串[0-i]区间以及第二个字符串[0,j]区间作为研究对象 2、根据题目的要求确定状态表示 字符串dp的常见技巧 1、空串是有研究意义的,引入空串可以帮助我们思考虚拟的边界如何进行初始化。 2、如…...
嵌入式Linux:格式化I/O
目录 1、格式化输出函数 1.1、printf()函数 1.2、fprintf()函数 1.3、dprintf()函数 1.4、sprintf()函数 1.5、snprintf()函数 2、格式化输入函数 2.1、scanf()函数 2.2、fscanf()函数 2.3、sscanf()函数 在Linux中,格式化I/O(formatted I/O&a…...
【elementui源码解析】如何实现自动渲染md文档-第二篇
目录 1.概要 2.引用文件 1)components.json 2)json-template/string 3)os.EOL 3.变量定义 4.模版填充 5.MAIN_TEMPLATE填充 6.src下的index.js文件 1)install 2)export 7.总结 1.概要 今天看第二个命令no…...
热门开源项目OpenHarmony
目录 1.概述 1.1.开源项目的意义 1.2.开源项目对软件行业的促进作用 1.3.小结 2.OpenHarmony 2.1.技术架构 2.2.分布式软总线 2.2.1.架构 2.2.2.代码介绍 2.2.2.1.代码目录 2.2.2.2.说明 2.2.2.3.发现组网和传输 2.2.2.3.1.发现 2.2.2.3.2.组网 2.2.2.3.3.传输…...
NewspaceAi之GPT使用新体验
GPT功能 使用地址:https://newspace.ai0.cn/ 上车 挂挡 踩油门,一脚到底,开始你的表演 问题1:你能做什么详细告诉我? 下面内容是GPT的回答 当然!作为一个基于GPT-4架构的AI,我能够在许多方面为…...
详解红黑树
红黑树规则 节点是红色或黑色。根节点是黑色。每个叶子节点都是黑色的空节点(NIL节点)。每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。 红黑树…...
探索JavaScript逆向工程与风控等级
探索JavaScript逆向工程与风控等级 在当今的网络安全领域,JavaScript逆向工程(简称JS逆向)已成为许多开发者和安全专家关注的焦点。JS逆向主要涉及对JavaScript代码的分析与理解,以发现其内部逻辑、数据流及潜在漏洞。这种技术常用…...
C++ 22 之 立方体案例
c22立方体案例.cpp #include <iostream> #include <string>using namespace std;class Cube{ private:int cube_l; // 长int cube_w; // 宽int cube_h; // 高public:// 设置长void set_l(int l){cube_l 1;}// 设置宽void set_w(int w){cube_w w;}// 设置高void …...
vue2使用antv/g6-editor实现可拖拽流程图
依赖下载 照着这个引入就好,然后npm install 源码 <template><div id"vue-g6-editor"><el-row><el-col :span"24"></el-col></el-row><!-- 工具栏 --><el-row><el-col :span"24&qu…...
springboot学习小结
背景 业务上需要开发,组里一位前辈给我指路 spring基础 什么是spring spring提供一个容器称为spring应用上下文,容器里可以创建和管理组件,组件会在容器里装配好,组件也可以叫bean。 装配不由组件创建他依赖的组件࿰…...
vue聊天发送Emoji表情
在用web端写聊天发送表情的功能中,使用web端有系统自带的unicode表情会出现每端不统一的情况,不好用不能统一,在这里我想到了一个非常好的思路,可以解决这个问题! 那就是发送表情用图片的形式呈现,然后发给…...
360数字安全:2024年4月勒索软件流行态势分析报告
勒索软件传播至今,360 反勒索服务已累计接收到数万勒索软件感染求助。随着新型勒索软件的快速蔓延,企业数据泄露风险不断上升,勒索金额在数百万到近亿美元的勒索案件不断出现。勒索软件给企业和个人带来的影响范围越来越广,危害性…...
【MySQL】日志详解
本文使用的MySQL版本是8 日志概览 它们记录了数据库系统中的不同操作和事件,以便于故障排除、性能优化和数据恢复。本文将介绍MySQL中常见的几种日志,同时也会介绍一点常用的选项。 官方文档:MySQL :: MySQL 8.0 Reference Manual :: 7.4 M…...
MyBatis 延迟加载,一级缓存,二级缓存设置
MyBatis不仅提供了一级缓存和二级缓存机制,还支持延迟加载(Lazy Loading),以进一步优化性能。 1. 延迟加载(Lazy Loading) 延迟加载是在需要时才加载数据,而不是在查询时立即加载所有相关数据。…...
Linux 基本指令2
cp 指令 cp[选项]源文件 目标文件 将源文件的内容复制到目标文件中,源文件可以有多个,最后一个文件为目标文件,目标文件也可以是一段路径,若目的地不是一个目录的话会拷贝失败。若没有路径上的目录则会新建一个,若源是…...
Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误
HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误,它们的含义、原因和解决方法都有显著区别。以下是详细对比: 1. HTTP 406 (Not Acceptable) 含义: 客户端请求的内容类型与服务器支持的内容类型不匹…...
如何在看板中有效管理突发紧急任务
在看板中有效管理突发紧急任务需要:设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP(Work-in-Progress)弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中,设立专门的紧急任务通道尤为重要,这能…...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...
【2025年】解决Burpsuite抓不到https包的问题
环境:windows11 burpsuite:2025.5 在抓取https网站时,burpsuite抓取不到https数据包,只显示: 解决该问题只需如下三个步骤: 1、浏览器中访问 http://burp 2、下载 CA certificate 证书 3、在设置--隐私与安全--…...
【单片机期末】单片机系统设计
主要内容:系统状态机,系统时基,系统需求分析,系统构建,系统状态流图 一、题目要求 二、绘制系统状态流图 题目:根据上述描述绘制系统状态流图,注明状态转移条件及方向。 三、利用定时器产生时…...
2025盘古石杯决赛【手机取证】
前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来,实在找不到,希望有大佬教一下我。 还有就会议时间,我感觉不是图片时间,因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...
HTML前端开发:JavaScript 常用事件详解
作为前端开发的核心,JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例: 1. onclick - 点击事件 当元素被单击时触发(左键点击) button.onclick function() {alert("按钮被点击了!&…...
【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)
升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点,但无自动故障转移能力,Master宕机后需人工切换,期间消息可能无法读取。Slave仅存储数据,无法主动升级为Master响应请求ÿ…...
汇编常见指令
汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX(不访问内存)XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南 在数字化营销时代,邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天,我们将深入解析邮件打开率、网站可用性、页面参与时…...
