发布时间:2025-06-24 19:46:31  作者:北方职教升学中心  阅读量:201


转码、

  • 内存使用:第一个脚本在处理过程中不需要额外的内存来存储帧图像,因为它直接在视频流上进行操作。可扩展的 Python 进度条库,可以在长循环中添加一个进度提示信息,为长时间的循环操作提供视觉反馈。YOLOv8通常需要Python 3.7或更高版本,并且依赖于一些常见的Python库,如ultralytics
  • FFmpeg的使用:第一个脚本利用FFmpeg的高效视频处理能力,直接在视频文件上进行裁剪,而不需要先将帧提取出来再重新编码。

    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}")

    运行后结果如下:

    帧合成视频过程
    ​​​​​​
    运行结束

    性能比较

    第一种方法比第二种方法运行得快得多,原因如下:

    1. 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已经成功安装并且配置正确。

  • tqdm是一个快速、

    裁剪出来的很多包含人的片段
    ​​
    视频裁剪完毕

    3.2 方法二:基于帧提取和目标检测的视频裁剪

    第二个个方法则首先将视频的每一帧提取出来,然后使用YOLOv8模型检测每帧中是否包含人物,筛选只保留包含人物的帧,最后,将所有包含人物的帧重新组合成一个新的视频。这大大减少了I/O操作,提高了处理速度。

    2.3 安装ffmpeg-python库和tqdm库

    ffmpeg-python是一个Python库,提供了对FFmpeg命令的封装,使得我们可以在Python脚本中方便地调用FFmpeg。

    1. 项目背景

    在视频素材的搜集过程中,尤其是针对人的动作素材,我们常需要从大量包含无人画面的视频中筛选出有人出现的片段。当视频处理完成后,将使用FFmpeg将这些片段合并成一个新的视频文件。