近期,出现了许多AI服务,可以让你借助AI把长视频变成短视频。你可能想知道这些服务背后的技术,这些技术到底是如何工作的。在这篇文章里,我们将探讨如何利用AI和公开的库来实现同样的效果。那么,让我们开始吧!
如果你更喜欢视频教程,可以直接跳过文章,观看下面的视频。要是你想看一个更全面的教程,有代码示例,可以跟着教程做下去。
要把长视频变成短视频,通常需要经过三个主要步骤,包括:
让我们来看看如何单独完成这些步骤
首先,我们首先需要下载一个YouTube视频。为此,我们将使用Pytube库。下载之后,我们需要生成视频的转录文本。我们将使用本地安装的Whisper模型来完成此任务。如果你的电脑性能不够强,你可以改用Whisper的API。
我们将使用Faster-Whisper(即优化版的Whisper),这是OpenAI的Whisper的一个优化版本,运行速度更快,但不影响准确性。以下是使用Whisper进行转写的代码片段:
准备好字幕后,我们需要从视频中挑选一个精彩片段。我们将使用OpenAI API,通过一个特定的提示词来找到视频中的爆火片段。通过设置一个大于0的温度值,每次运行脚本时都能得到不同的精彩片段。一旦我们得到了选择的精彩片段的开始和结束时间,就可以用Moviepy来剪辑视频了。
现在来谈谈有意思的部分。我们将上一步的精彩视频转换为短片格式(9:16),通过裁剪视频并将讲话者保持在画面中央来实现。由于视频中可能有多个人物,识别讲话者需要解决主动说话人识别的问题。我们可以通过多种方法实现这一目标,例如TalkNet、Fast-ASD等,但在本文中,我们将专注于使用简单的线索组合方法。
我们使用深度学习模型来识别帧中的所有脸部,并通过分析每个脸部的唇部动作来确定说话者。此外,我们使用WebRTC VAD通过分析从视频中提取的音频信号来判断某个帧是否有活跃的说话者。通过结合深度学习模型提供的视觉线索和WebRTC VAD提供的音频线索,我们可以准确地识别出活跃的说话者。现在我们使用OpenCV库对活跃的说话者进行裁切,然后再把所有帧拼接起来以生成最终的视频。
这里是一段代码片段,用于使用DNN模型进行人脸检测和嘴部动作的检测,并利用Webrtc VAD进行音频帧中的说话人检测。
import cv2 import numpy as np import webrtcvad import wave import contextlib from pydub import AudioSegment import os # 更新模型文件路径为 prototxt_path = "models/deploy.prototxt" model_path = "models/res10_300x300_ssd_iter_140000_fp16.caffemodel" temp_audio_path = "temp_audio.wav" # 加载DNN模型 net = cv2.dnn.readNetFromCaffe(prototxt_path, model_path) # 初始化VAD vad = webrtcvad.Vad(2) # 从0到3的激进程度 def voice_activity_detection(audio_frame, sample_rate=16000): return vad.is_speech(audio_frame, sample_rate) def extract_audio_from_video(video_path, audio_path): audio = AudioSegment.from_file(video_path) audio = audio.set_frame_rate(16000).set_channels(1) audio.export(audio_path, format="wav") def process_audio_frame(audio_data, sample_rate=16000, frame_duration_ms=30): n = int(sample_rate * frame_duration_ms / 1000) * 2 # 每个样本2字节 offset = 0 while offset + n <= len(audio_data): frame = audio_data[offset:offset + n] offset += n yield frame global Frames Frames = [] # [x,y,w,h] def detect_faces_and_speakers(input_video_path, output_video_path): # 返回人脸框列表: global Frames # 从视频中提取音频 extract_audio_from_video(input_video_path, temp_audio_path) # 读取提取的音频文件 with contextlib.closing(wave.open(temp_audio_path, 'rb')) as wf: sample_rate = wf.getframerate() audio_data = wf.readframes(wf.getnframes()) cap = cv2.VideoCapture(input_video_path) fourcc = cv2.VideoWriter_fourcc(*'mp4v') out = cv2.VideoWriter(output_video_path, fourcc, 30.0, (int(cap.get(3)), int(cap.get(4)))) frame_duration_ms = 30 # 30ms帧的时长 audio_generator = process_audio_frame(audio_data, sample_rate, frame_duration_ms) while cap.isOpened(): ret, frame = cap.read() if not ret: break h, w = frame.shape[:2] blob = cv2.dnn.blobFromImage(cv2.resize(frame, (300, 300)), 1.0, (300, 300), (104.0, 177.0, 123.0)) net.setInput(blob) detections = net.forward() audio_frame = next(audio_generator, None) if audio_frame is None: break is_speaking_audio = voice_activity_detection(audio_frame, sample_rate) MaxDif = 0 Add = [] for i in range(detections.shape[2]): confidence = detections[0, 0, i, 2] if confidence > 0.3: # 置信度阈值 box = detections[0, 0, i, 3:7] * np.array([w, h, w, h]) (x, y, x1, y1) = box.astype("int") face_width = x1 - x face_height = y1 - y # 绘制边界框 cv2.rectangle(frame, (x, y), (x1, y1), (0, 255, 0), 2) # 假设嘴唇大致位于脸部下三分之一处 lip_distance = abs((y + 2 * face_height // 3) - (y1)) Add.append([[x, y, x1, y1], lip_distance]) MaxDif = max(lip_distance, MaxDif) # 结合视觉和音频线索 if lip_distance >= MaxDif and is_speaking_audio: # 根据需要调整阈值大小,如果嘴唇距离大于等于最大差异,则标记为活跃说话者 cv2.putText(frame, "Active Speaker", (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2) Frames.append([x, y, x1, y1]) out.write(frame) cv2.imshow('Frame', frame) if cv2.waitKey(1) & 0xFF == ord('q'): break cap.release() out.release() cv2.destroyAllWindows() os.remove(temp_audio_path) if __name__ == "__main__": detect_faces_and_speakers() print(Frames) print(len(Frames)) print(Frames[1:5])
接下来的一个步骤是用任何本地运行的大模型(如LLama或Mistral)来替代OpenAI API。这样可以摆脱任何第三方依赖,这样你可以免费运行整个脚本。整个代码可以在下面的Github仓库里找到。
如果你想跳过编码的部分,并且正在寻找一个无需编码的工具,可以看看下面这个工具