You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将16:9视频转为9:16并确保说话人始终在画面内?

问题分析与修复方案

原代码核心问题

  • 使用通用目标检测模型yolov8n.pt,未针对人脸/人物优化,容易误识别其他高置信度物体
  • 中心点计算错误:x_center = x2 - x1、y_center = y2 - y1实际是计算目标宽度/高度,而非中心坐标
  • 未过滤目标类别,可能选中非人物/人脸物体作为ROI
  • 逐帧裁剪无平滑处理,画面易出现抖动
  • 未处理检测失效场景,导致部分帧丢失

修复后的代码

from ultralytics import YOLO
from moviepy.editor import VideoFileClip, concatenate_videoclips
from moviepy.video.fx.crop import crop
import numpy as np

# 加载YOLOv8人脸专用检测模型(比通用模型更精准)
model = YOLO("yolov8n-face.pt")

# 加载输入视频
clip = VideoFileClip("short_test.mp4")
original_w, original_h = clip.size
target_aspect_ratio = 9 / 16  # 目标裁剪比例
target_w = int(original_h * target_aspect_ratio)
target_h = original_h

tacked_clips = []
prev_x_center = original_w // 2  # 初始化上一帧中心点,防止检测失效时画面失控
prev_y_center = original_h // 2
smooth_factor = 0.7  # 平滑系数,越小画面越稳定(0-1之间)

for frame_no, frame in enumerate(clip.iter_frames()):
    results = model(frame)
    current_x_center = prev_x_center
    current_y_center = prev_y_center

    # 只保留人脸检测结果,过滤其他类别
    if results[0].boxes:
        # 筛选人脸(YOLOv8-face的类别id为0)
        face_boxes = [box for box in results[0].boxes if box.cls == 0]
        if face_boxes:
            # 取置信度最高的人脸
            main_face = max(face_boxes, key=lambda x: x.conf)
            x1, y1, x2, y2 = [int(val) for val in main_face.xyxy[0].tolist()]
            
            # 计算人脸中心点,同时调整y轴位置预留身体空间(比如把中心点上移,让画面包含更多身体)
            face_x_center = (x1 + x2) / 2
            face_y_center = (y1 + y2) / 2 - (y2 - y1) * 0.3  # 上移人脸高度的30%,留出身体区域
            
            # 用移动平均平滑中心点,避免画面抖动
            current_x_center = smooth_factor * face_x_center + (1 - smooth_factor) * prev_x_center
            current_y_center = smooth_factor * face_y_center + (1 - smooth_factor) * prev_y_center

    # 限制中心点在合法范围内,防止裁剪区域超出原视频边界
    current_x_center = np.clip(current_x_center, target_w/2, original_w - target_w/2)
    current_y_center = np.clip(current_y_center, target_h/2, original_h - target_h/2)

    # 获取当前帧的时间片段
    start_time = frame_no / clip.fps
    end_time = (frame_no + 1) / clip.fps
    subclip = clip.subclip(start_time, end_time)

    # 应用裁剪
    cropped_clip = crop(
        subclip, 
        x_center=int(current_x_center), 
        y_center=int(current_y_center), 
        width=target_w, 
        height=target_h
    )

    tacked_clips.append(cropped_clip)
    # 更新上一帧中心点
    prev_x_center, prev_y_center = current_x_center, current_y_center

# 拼接所有裁剪后的片段
reframed_clip = concatenate_videoclips(tacked_clips, method="compose")
reframed_clip.write_videofile("output_video.mp4", codec="libx264")

关键修改说明

  • 替换专用模型:使用yolov8n-face.pt,专门针对人脸优化,检测精度更高,避免误识别其他物体
  • 修正中心点计算:改为(x1+x2)/2和(y1+y2)/2,并调整y轴位置预留身体空间
  • 添加平滑处理:用移动平均算法稳定中心点,解决逐帧裁剪的抖动问题
  • 边界限制:用np.clip确保裁剪区域不会超出原视频范围
  • 失效处理:检测不到人脸时沿用前一帧的中心点,避免画面跳变
  • 类别过滤:只保留人脸检测结果,确保ROI始终指向说话人

内容的提问来源于stack exchange,提问作者user16638844

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 22:07:49