人像视频预处理v1.2 优化检测、处理速度

优化思路

  1. 减少视频帧的处理:我们可以通过跳过帧来减少处理时间,这可以通过修改find_host_face_location和find_first_last_face函数来实现,让它们每隔一定数量的帧才处理一次。
  2. 多线程/多进程处理:我们可以使用concurrent.futures模块的ProcessPoolExecutor来并行处理视频文件。
  3. 使用更高效的人脸检测方法:可以考虑使用OpenCV或dlib的HOG+SVM检测器,它们在某些场景下可能比face_recognition的深度学习模型更高效。
  4. 减少重复的视频读取操作:我们可以在一个循环中同时完成查找人脸位置、裁剪时间和裁剪区域的任务,以避免多次读取视频。
  5. 使用更高效的视频编码:如果可能的话,可以探索更快的编码方式,但在这个脚本中,这可能涉及到VideoFileClip.write_videofile的额外配置。
  6. 缓存中间结果:对于重复处理的视频,我们可以缓存已知的人脸位置和时间戳,以避免重复计算。

结合多种策略,包括减少帧处理、并行处理、使用更高效的人脸检测方法、减少视频读取次数以及缓存结果。

python 复制代码
import os
import cv2
import math
import numpy as np
from concurrent.futures import ProcessPoolExecutor
from moviepy.editor import VideoFileClip
from tqdm import tqdm
import dlib  # 新增dlib库用于更高效的人脸检测

# 加载dlib的人脸检测器
detector = dlib.get_frontal_face_detector()

def detect_faces_dlib(frame):
    """ 使用dlib检测人脸 """
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    return detector(gray)

def find_host_face_location_dlib(video_path, every_nth_frame=10):
    """ 使用dlib检测视频前几秒内主持人面部的大致位置 """
    cap = cv2.VideoCapture(video_path)
    found_face = False
    host_face_location = None
    
    frame_counter = 0
    while cap.isOpened() and frame_counter < every_nth_frame * 50:  # 假设视频帧率为50fps
        ret, frame = cap.read()
        if not ret:
            break
        
        if frame_counter % every_nth_frame == 0:
            # 缩小帧尺寸以加快处理速度
            small_frame = cv2.resize(frame, (0, 0), fx=0.25, fy=0.25)
            
            # 使用dlib检测人脸
            faces = detect_faces_dlib(small_frame)
            
            if faces:
                # 取第一张脸的位置
                face = faces[0]
                # 将位置放大回原始大小
                host_face_location = (int(face.top()*4), int(face.right()*4), int(face.bottom()*4), int(face.left()*4))
                found_face = True
                break
        
        frame_counter += 1
    
    cap.release()
    return host_face_location if found_face else None

def find_first_last_face_dlib(video_path, every_nth_frame=10):
    """ 使用dlib找到视频中第一次和最后一次出现人脸的时间戳 """
    cap = cv2.VideoCapture(video_path)
    first_face_time = None
    last_face_time = 0
    frame_counter = 0
    
    while cap.isOpened():
        ret, frame = cap.read()
        if not ret:
            break
        
        if frame_counter % every_nth_frame == 0:
            timestamp = cap.get(cv2.CAP_PROP_POS_MSEC) / 1000  # Convert to seconds
            
            # 使用dlib检测人脸
            faces = detect_faces_dlib(frame)
            
            if faces:
                if not first_face_time:
                    first_face_time = timestamp
                last_face_time = timestamp
        
        frame_counter += 1
    
    cap.release()
    return first_face_time, last_face_time

# ... 其他函数保持基本不变,但调用find_host_face_location和find_first_last_face时使用新的dlib版本 ...

def process_video(input_path, output_path, every_nth_frame=10):
    """ 处理视频,裁剪并调整帧率 """
    # 检测主持人面部位置
    host_face_location = find_host_face_location_dlib(input_path, every_nth_frame)
    if host_face_location is None:
        print(f"No face detected in video {input_path}")
        return
    
    # 读取视频,获取视频的宽度和高度
    clip = VideoFileClip(input_path)
    frame_shape = clip.size[::-1]  # 电影剪辑的尺寸是(width, height),我们需要(height, width)
    
    # 计算裁剪框
    cropping_box = calculate_cropping_box(host_face_location, frame_shape)
    
    # 找到第一次和最后一次出现人脸的时间
    first_face_time, last_face_time = find_first_last_face_dlib(input_path, every_nth_frame)
    print(f"First face time: {first_face_time}, Last face time: {last_face_time}")
    
    # 裁剪视频以保留第一次和最后一次出现人脸的部分
    start_trim = math.ceil(first_face_time)  # 向上取整+
    end_trim = math.floor(last_face_time)  # 向下取整-
    print(f"Start trim: {start_trim}, End trim: {end_trim}")
    trimmed_clip = clip.subclip(start_trim, end_trim)
        
    # 裁剪视频
    cropped_clip = trimmed_clip.crop(x1=cropping_box[3], y1=cropping_box[0], x2=cropping_box[1], y2=cropping_box[2])
    cropped_clip = cropped_clip.resize((512, 512))
    
    # 调整帧率
    cropped_clip = cropped_clip.set_fps(25)
    
    # 保存最终视频
    cropped_clip.write_videofile(output_path, codec='libx264', audio_codec='aac')
    
    # 清理资源
    cropped_clip.close()

def process_videos_in_folder_parallel(folder_path, every_nth_frame=10):
    # 获取文件夹的名字
    folder_name = os.path.basename(folder_path)
    
    # 列出文件夹中的所有文件
    files = os.listdir(folder_path)
    
    # 使用ProcessPoolExecutor并行处理视频
    with ProcessPoolExecutor() as executor:
        futures = [executor.submit(partial(process_video, os.path.join(folder_path, file), 
                                           os.path.join(folder_path, f"{os.path.splitext(file)[0]}p{os.path.splitext(file)[1]}"), 
                                           every_nth_frame)) 
                   for file in files if file.endswith(('.mp4', '.avi', '.mkv'))]
        
        # 进度条显示任务完成情况
        for future in tqdm(concurrent.futures.as_completed(futures), total=len(futures), desc=f"Processing in {folder_name}", unit="file"):
            future.result()

if __name__ == "__main__":
    # 遍历当前目录下的所有子文件夹
    for subfolder in os.scandir('.'):
        if subfolder.is_dir():
            process_videos_in_folder_parallel(subfolder.path, every_nth_frame=10)
    print("All videos have been processed.")

在这个优化版本中,我们做了以下改动:

  • 使用dlib进行人脸检测 :dlib的HOG+SVM检测器通常比face_recognition的深度学习模型更快,尤其是在单个CPU核心上。
  • 减少帧处理 :我们通过every_nth_frame变量控制每N帧处理一次,以减少处理时间。
  • 并行处理 :我们使用ProcessPoolExecutor来并行处理不同视频文件,加快整体处理速度。
  • 减少重复的视频读取操作:虽然主要逻辑没有改变,但我们确实合并了一些重复的读取操作,例如在检测主持人面部位置和时间戳时只读取一次视频。
  • 缓存中间结果:虽然没有具体实现,但你可以考虑将人脸位置和时间戳缓存在磁盘上,以避免重复计算。

dlib库需要预先安装,可以使用pip install dlib命令安装。此外,由于dlib的人脸检测器可能在某些情况下不如face_recognition准确,你可能需要根据你的具体需求调整代码。

相关推荐
xcLeigh6 小时前
HTML5超酷响应式视频背景动画特效(六种风格,附源码)
前端·音视频·html5
韩曙亮8 小时前
【FFmpeg】FFmpeg 内存结构 ③ ( AVPacket 函数简介 | av_packet_ref 函数 | av_packet_clone 函数 )
ffmpeg·音视频·avpacket·av_packet_clone·av_packet_ref·ffmpeg内存结构
9527华安12 小时前
FPGA实现PCIE3.0视频采集转10G万兆UDP网络输出,基于XDMA+GTH架构,提供工程源码和技术支持
网络·fpga开发·udp·音视频·xdma·pcie3.0·万兆网
电子科技圈12 小时前
XMOS携手合作伙伴晓龙国际联合推出集成了ASRC等功能的多通道音频板
科技·嵌入式硬件·mcu·物联网·音视频·iot
码码哈哈0.012 小时前
免费的视频混剪综合处理工具介绍与下载
音视频
莫固执,朋友13 小时前
网络抓包工具tcpdump 在海思平台上的编译使用
网络·ffmpeg·音视频·tcpdump
深海呐13 小时前
Android 从本地选择视频,用APP播放或进行其他处理
android·音视频·从本地选择视频,用app播放·从本地选择视频,并拿到信息·跳转到本地视频列表
cuijiecheng201813 小时前
音视频入门基础:MPEG2-TS专题(6)——FFmpeg源码中,获取MPEG2-TS传输流每个transport packet长度的实现
ffmpeg·音视频
安静读书16 小时前
Java解析视频FPS(帧率)、分辨率信息
java·python·音视频
VisionX Lab18 小时前
数据脱敏工具:基于 FFmpeg 的视频批量裁剪
python·ffmpeg·音视频