在许多视频编辑任务中,我们常常需要将视频和音频进行对齐,并添加字幕。本文将详细介绍如何使用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 result
def 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 // 2
y = 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 frame
def 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 = 0
for 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 += 1
out.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 seconds
final_clip = final_clip.subclip(0, final_clip.duration - 0.3)
# Write the final video file
final_clip.write_videofile(output_path, codec="libx264", audio_codec="aac")
# Close the clips to release the file
final_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轻松地实现视频和音频的对齐,并在视频中添加中文字幕。如果你有任何问题或建议,请在评论区留言!