我有一段人们说话的视频。我还有一份成绩单。我将单词分成句子,这样我就可以在屏幕上一次显示一个句子,就像电影中的普通字幕一样。为此,我创建了一个 csv,其中每个帧都有一行,并且每行都包含该句子时间块内的完整句子。这样,我循环遍历所有帧,并将该句子的文本放在该句子内的每个帧上。我在 OpenCV 中做的。
样本成绩单 csv:
frame sentence
0 hello
1 hello
2 how are you
3 how are you
4 how are you
5 how are you
6 how are you
7 how are you
8 fine
...
csv的长度与视频中的帧数相同。要绘制字幕,我这样做:
import cv2
import pandas as pd
df = pd.read_csv('data.csv')
video = cv2.VideoCapture('vid.mp4')
num_frames = video.get(cv2.CAP_PROP_FRAME_COUNT)
assert len(df) == num_frames
for i in list(range(0, num_frames)):
ret, frame = video.read()
cv2.putText(frame, str(df.sentence), (0,50),cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 0), 3, cv2.LINE_AA, True)
# additional standard cv2 code below...
这可行,但现在我没有任何音频。我知道 OpenCV 不适用于任何音频,但是还有其他解决方法吗?这种方法在我的管道中效果很好,因此我希望能够将这些帧写入新视频,但保留音频,同时使用尽可能少的附加库。
使用建议的 moviepy 解决方案后,我得到一个没有音频的带字幕视频,并出现以下错误:
Moviepy - Building video vidout.mp4.
MoviePy - Writing audio in vidoutTEMP_MPY_wvf_snd.mp3
MoviePy - Done.
Moviepy - Writing video vidout.mp4
t: 100%|████████████████████████████████████████████▉| 23069/23084 [07:26<00:00, 66.35it/s, now=None]Traceback (most recent call last):
File "/Users/asi/anaconda3/lib/python3.7/site-packages/moviepy/Clip.py", line 472, in iter_frames
frame = self.get_frame(t)
File "<decorator-gen-11>", line 2, in get_frame
File "/Users/asi/anaconda3/lib/python3.7/site-packages/moviepy/decorators.py", line 89, in wrapper
return f(*new_a, **new_kw)
File "/Users/asi/anaconda3/lib/python3.7/site-packages/moviepy/Clip.py", line 93, in get_frame
return self.make_frame(t)
File "/Users/asi/anaconda3/lib/python3.7/site-packages/moviepy/Clip.py", line 136, in <lambda>
newclip = self.set_make_frame(lambda t: fun(self.get_frame, t))
File "/Users/asi/anaconda3/lib/python3.7/site-packages/moviepy/video/VideoClip.py", line 490, in <lambda>
return self.fl(lambda gf, t: image_func(gf(t)), apply_to)
File "make_demo.py", line 65, in pipeline
cv2.putText(frame, str(next(dfi)[1].word), (0, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 0), 3, cv2.LINE_AA, True)
StopIteration
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "make_demo.py", line 72, in <module>
out_video.write_videofile("vidout.mp4", audio=True)
File "<decorator-gen-55>", line 2, in write_videofile
File "/Users/asi/anaconda3/lib/python3.7/site-packages/moviepy/decorators.py", line 54, in requires_duration
return f(clip, *a, **k)
File "<decorator-gen-54>", line 2, in write_videofile
File "/Users/asi/anaconda3/lib/python3.7/site-packages/moviepy/decorators.py", line 135, in use_clip_fps_by_default
return f(clip, *new_a, **new_kw)
File "<decorator-gen-53>", line 2, in write_videofile
File "/Users/asi/anaconda3/lib/python3.7/site-packages/moviepy/decorators.py", line 22, in convert_masks_to_RGB
return f(clip, *a, **k)
File "/Users/asi/anaconda3/lib/python3.7/site-packages/moviepy/video/VideoClip.py", line 307, in write_videofile
logger=logger)
File "/Users/asi/anaconda3/lib/python3.7/site-packages/moviepy/video/io/ffmpeg_writer.py", line 221, in ffmpeg_write_video
fps=fps, dtype="uint8"):
RuntimeError: generator raised StopIteration
如果可以添加一个额外的库,您可以使用具有音频支持的
moviepy
:
import cv2
import pandas as pd
from moviepy.editor import VideoFileClip
def pipeline(frame):
try:
cv2.putText(frame, str(next(dfi)[1].sentence), (0, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 0), 3, cv2.LINE_AA, True)
except StopIteration:
pass
# additional frame manipulation
return frame
dfi = pd.read_csv('data.csv').iterrows()
video = VideoFileClip("vid.mp4")
out_video = video.fl_image(pipeline)
out_video.write_videofile("vidout.mp4", audio=True)
我这里有一个替代方案,在新行中使用字幕文本 subtitles.txt 文件代替。在此示例中,替换 “/path/to/input_folder” 为包含您的文件夹的路径 video.mp4 和 subtitle.txt 文件。同样,替换 “/path/to/output_folder”为输出视频所需的路径。 该脚本将创建一个带有指定字幕的新视频 输出文件夹。
from moviepy.editor import VideoFileClip, TextClip, CompositeVideoClip
def create_video(input_folder, output_folder):
# Load the video clip
video_path = os.path.join(input_folder, "video.mp4")
video_clip = VideoFileClip(video_path)
# Load subtitles from the subtitles.txt file
subtitles_path = os.path.join(input_folder, "subtitles.txt")
with open(subtitles_path, "r", encoding="utf-8") as subtitles_file:
subtitles_lines = subtitles_file.readlines()
# Create TextClip for each subtitle
subtitle_clips = []
for i, line in enumerate(subtitles_lines):
caption_clip = TextClip(line.strip(), fontsize=24, color="yellow", bg_color="transparent")
caption_clip = caption_clip.set_pos(("center", "bottom"))
caption_clip = caption_clip.set_duration(video_clip.duration / len(subtitles_lines))
caption_clip = caption_clip.set_start(i * (video_clip.duration / len(subtitles_lines)))
subtitle_clips.append(caption_clip)
# Combine all caption clips into a single CompositeVideoClip
subtitles = CompositeVideoClip(subtitle_clips)
# Overlay subtitles at the bottom of the video
final_clip = CompositeVideoClip([video_clip, subtitles.set_pos(("center", "bottom"))])
# Write the final video
output_path = os.path.join(output_folder, "output_video.mp4")
final_clip.write_videofile(output_path, codec="libx264", audio_codec="aac", fps=24)
# Example usage:
input_folder = "/path/to/input_folder"
output_folder = "/path/to/output_folder"
create_video(input_folder, output_folder)