发布时间:2025-06-24 19:46:31 作者:北方职教升学中心 阅读量:201
转码、
ultralytics
、pip install ffmpeg-python
pip install tqdm
3. 代码实现(两种方法实现)
3.1 方法一:基于帧检测的视频裁剪
这是第一个脚本,它通过逐帧检测视频中的人物,并在发现人物时标记视频片段的开始和结束时间。可以通过以下命令安装这些依赖库:
pip install ultralytics opencv-python
2.2 安装FFmpeg
FFmpeg是一个强大的多媒体处理工具,支持视频和音频的编解码、opencv-python
等。为了提高效率,我写了一个基于YOLOv8的自动裁剪视频脚本,能够自动检测视频中是否存在人物,并提取出包含人物的片段,最后将这些片段拼接在一起,以便进一步筛选和使用。
# 导入必要的库import cv2from ultralytics import YOLOimport osimport ffmpegimport timefrom tqdm import tqdmimport subprocess# 获取当前目录current_directory = os.getcwd()# 加载YOLOv8模型model_path = os.path.join(current_directory, 'yolov8n.pt')model = YOLO(model_path) # 使用当前目录中的YOLOv8模型# 定义视频文件路径和输出文件夹input_video_path = '27.mp4'output_folder = 'output27/'# 确保输出文件夹存在if not os.path.exists(output_folder): os.makedirs(output_folder)# 打开视频文件cap = cv2.VideoCapture(input_video_path)# 获取视频的基本信息fps = cap.get(cv2.CAP_PROP_FPS)frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) # 获取总帧数# 初始化变量start_time = Noneclip_count = 0min_clip_duration = 0.5 # 最小片段长度阈值,单位为秒def extract_video_segment(input_path, start_time, end_time, output_path): ( ffmpeg .input(input_path, ss=start_time, to=end_time) .output(output_path, c='copy', an=None) .run(overwrite_output=True) )# 开始计时start_time_total = time.time()# 创建进度条pbar = tqdm(total=total_frames, desc="Processing Frames")while cap.isOpened(): ret, frame = cap.read() if not ret: break # 将帧转换为YOLOv8可以处理的格式 results = model(frame) # 检查是否有人的检测结果 has_person = False for result in results: for box in result.boxes: if box.cls == 0: # 0 对应 'person' 类别 has_person = True break if has_person: break # 如果有人的检测结果 if has_person: if start_time is None: start_time = cap.get(cv2.CAP_PROP_POS_MSEC) / 1000.0 else: if start_time is not None: end_time = cap.get(cv2.CAP_PROP_POS_MSEC) / 1000.0 clip_duration = end_time - start_time if clip_duration >= min_clip_duration: output_path = f"{output_folder}clip_{clip_count}.mp4" extract_video_segment(input_video_path, start_time, end_time, output_path) clip_count += 1 start_time = None # 更新进度条 pbar.update(1)# 处理最后一个片段if start_time is not None: end_time = cap.get(cv2.CAP_PROP_POS_MSEC) / 1000.0 clip_duration = end_time - start_time if clip_duration >= min_clip_duration: output_path = f"{output_folder}clip_{clip_count}.mp4" extract_video_segment(input_video_path, start_time, end_time, output_path)# 释放视频捕获对象cap.release()# 关闭进度条pbar.close()# 结束计时end_time_total = time.time()total_time = end_time_total - start_time_totalprint(f"处理完成,总运行时间: {total_time:.2f} 秒")# 生成 input.txt 文件def generate_input_txt(folder_path, output_file): with open(output_file, 'w') as f: for filename in sorted(os.listdir(folder_path)): if filename.endswith(('.mp4', '.avi', '.mkv')): video_path = os.path.join(folder_path, filename) f.write(f"file '{video_path}'\n")# 合并视频def merge_videos(input_file, output_video_path): command = [ 'ffmpeg', '-f', 'concat', '-safe', '0', '-i', input_file, '-c', 'copy', # 直接复制视频和音频流,不重新编码 output_video_path ] subprocess.run(command, check=True)folder_path = output_folder # 你的视频文件夹路径output_file = 'input.txt' # 生成的 input.txt 文件路径output_video_path = 'output27.mp4' # 合并后的视频输出路径# 生成 input.txt 文件generate_input_txt(folder_path, output_file)# 定义 input_file 变量input_file = output_file# 合并视频merge_videos(input_file, output_video_path)print("视频合并完成")
运行后如下,1个G的视频完整处理时间大概二十多分钟,最好用gpu跑cpu跑要慢很多,我用的4060跑的,cuda版本是12.1的。剪辑等操作。手动进行这一筛选过程不仅耗时,而且容易遗漏关键片段。我们需要安装FFmpeg以便在Python脚本中使用。
# 导入必要的库import cv2from ultralytics import YOLOimport osimport numpy as npfrom tqdm import tqdmimport subprocess# 加载YOLOv8模型model = YOLO('yolov8n.pt') # 使用YOLOv8模型# 定义视频文件路径input_video_path = '14.mp4'output_video_path = 'output_14.mp4'# 打开视频文件cap = cv2.VideoCapture(input_video_path)# 获取视频的基本信息fps = cap.get(cv2.CAP_PROP_FPS)frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) # 获取总帧数# 创建临时文件夹temp_folder = 'temp_frames'if not os.path.exists(temp_folder): os.makedirs(temp_folder)# 提取视频帧frame_count = 0while cap.isOpened(): ret, frame = cap.read() if not ret: break frame_path = os.path.join(temp_folder, f'frame_{frame_count:04d}.jpg') cv2.imwrite(frame_path, frame) frame_count += 1# 释放视频捕获对象cap.release()# 使用YOLOv8进行目标检测person_frames = []pbar = tqdm(total=frame_count, desc="Detecting People")for i in range(frame_count): frame_path = os.path.join(temp_folder, f'frame_{i:04d}.jpg') results = model(frame_path) for result in results: for box in result.boxes: if box.cls == 0: # 0 对应 'person' 类别 person_frames.append(frame_path) break pbar.update(1)pbar.close()# 重新组合视频output_frames_folder = 'output_frames'if not os.path.exists(output_frames_folder): os.makedirs(output_frames_folder)for i, frame_path in enumerate(person_frames): output_frame_path = os.path.join(output_frames_folder, f'frame_{i:04d}.jpg') os.rename(frame_path, output_frame_path)# 使用FFmpeg重新组合视频subprocess.run([ 'ffmpeg', '-framerate', str(fps), '-i', os.path.join(output_frames_folder, 'frame_%04d.jpg'), '-c:v', 'libx264', '-r', '30', '-pix_fmt', 'yuv420p', output_video_path])# 清理临时文件for file_name in os.listdir(temp_folder): file_path = os.path.join(temp_folder, file_name) os.remove(file_path)os.rmdir(temp_folder)for file_name in os.listdir(output_frames_folder): file_path = os.path.join(output_frames_folder, file_name) os.remove(file_path)os.rmdir(output_frames_folder)print(f"处理完成,新视频文件保存在 {output_video_path}")
运行后结果如下:


性能比较
第一种方法比第二种方法运行得快得多,原因如下:
- I/O操作减少:第一个脚本直接在内存中处理视频帧,而不需要将每一帧写入磁盘。
不过第二个脚本相较于第一个更加灵活一些,提取出来的帧可以用做其他分析。
2. 环境配置
2.1 安装YOLOv8环境
首先,确保已经安装了能够正常运行YOLOv8的环境。
2.2.1 使用conda安装FFmpeg(适用于Windows和macOS)
如果你使用的是Anaconda或Miniconda,可以通过以下命令从conda-forge渠道安装FFmpeg:
conda install -c conda-forge ffmpeg
2.2.2 使用apt安装FFmpeg(适用于Linux)
如果你使用的是Linux系统,可以通过以下命令安装FFmpeg:
sudo apt install ffmpeg
2.2.3 验证FFmpeg安装
安装完成后,可以通过以下命令验证FFmpeg是否安装成功:
ffmpeg -version
如果输出了版本信息,则说明FFmpeg已经成功安装并且配置正确。