功能介绍

在项目测试过程中,有时候需要测试某一时刻,左侧右侧的画面是否同步,这是一个简单脚本,把视频分成的左侧和右侧,通过输入列坐标控制划分,为了制作不同步视频,左侧右侧就按照一个顺序,一个逆序,进行排序后重新组成一个新的视频。

在视频处理中,有时我们需要对视频帧进行特殊处理以达到特定效果。本文将介绍一个实用的Python脚本,该脚本能够将视频每一帧按照指定列分割为左右两部分,然后将右侧部分替换为逆序帧序列的对应右侧部分,最终合并输出新的视频。这种处理方式可以实现类似“左右部分时间反向”的视觉效果,适用于创意视频制作、特殊视觉效果实现等场景。

实现思路

该脚本的核心思路如下:

  1. 读取输入视频并获取其基本信息(帧数、宽高、帧率等)
  2. 验证分割列坐标的有效性
  3. 读取视频所有帧并保存
  4. 生成帧序列的逆序列表(用于右侧部分)
  5. 逐帧处理:左侧保留当前帧部分,右侧替换为逆序帧的对应部分
  6. 合并处理后的帧并写入输出视频文件

代码实现

以下是完整的实现代码,包含详细注释:

import cv2
import numpy as np
import os
import tempfile


def process_video(input_path, output_path, split_col):
    """
    处理视频,将每一帧分割为左右两部分,右侧按帧数逆序排列后合并

    参数:
    input_path: 输入视频路径
    output_path: 输出视频路径
    split_col: 分割列的坐标
    """
    # 打开输入视频
    cap = cv2.VideoCapture(input_path)
    if not cap.isOpened():
        raise Exception(f"无法打开视频文件: {input_path}")

    # 获取视频基本信息
    frame_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
    frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
    frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
    fps = cap.get(cv2.CAP_PROP_FPS)

    # 验证分割列是否有效
    if split_col < 0 or split_col >= frame_width:
        raise ValueError(f"分割列坐标 {split_col} 超出视频宽度范围 [0, {frame_width - 1}]")

    print(f"视频信息: 帧数={frame_count}, 宽度={frame_width}, 高度={frame_height}, FPS={fps}")
    print(f"使用分割列: {split_col}")

    # 读取所有帧
    frames = []
    for i in range(frame_count):
        ret, frame = cap.read()
        if not ret:
            raise Exception(f"读取第 {i} 帧失败")
        frames.append(frame)
        # 显示进度
        if (i + 1) % 100 == 0 or i + 1 == frame_count:
            print(f"已读取 {i + 1}/{frame_count} 帧")

    cap.release()

    # 创建逆序的帧列表(用于右侧)
    reversed_frames = frames[::-1]

    # 处理每一帧,合并左右部分
    processed_frames = []
    for i in range(frame_count):
        # 当前帧的左侧部分
        left_part = frames[i][:, :split_col]

        # 逆序帧的右侧部分
        right_part = reversed_frames[i][:, split_col:]

        # 确保左右部分宽度合适(处理可能的边缘情况)
        if left_part.shape[1] + right_part.shape[1] != frame_width:
            # 调整右侧部分宽度以匹配原始宽度
            right_part = right_part[:, :frame_width - left_part.shape[1]]

        # 合并左右部分
        processed_frame = np.hstack((left_part, right_part))
        processed_frames.append(processed_frame)

        # 显示进度
        if (i + 1) % 100 == 0 or i + 1 == frame_count:
            print(f"已处理 {i + 1}/{frame_count} 帧")

    # 定义输出视频编码器并创建VideoWriter对象
    # 尝试不同的编码器以确保兼容性
    fourcc = cv2.VideoWriter_fourcc(*'mp4v')  # 对于MP4格式
    out = cv2.VideoWriter(output_path, fourcc, fps, (frame_width, frame_height))

    if not out.isOpened():
        # 尝试其他编码器
        fourcc = cv2.VideoWriter_fourcc(*'avc1')
        out = cv2.VideoWriter(output_path, fourcc, fps, (frame_width, frame_height))

    if not out.isOpened():
        raise Exception("无法创建输出视频文件,请检查编码器是否支持")

    # 写入处理后的帧
    for i, frame in enumerate(processed_frames):
        out.write(frame)
        # 显示进度
        if (i + 1) % 100 == 0 or i + 1 == frame_count:
            print(f"已写入 {i + 1}/{frame_count} 帧")

    # 释放资源
    out.release()
    print(f"视频处理完成,已保存至: {output_path}")


def main():
    # 示例用法
    input_video = r"right.mp4"  # 输入视频路径
    output_video = r"right_r.mp4"  # 输出视频路径
    # split_column = 1700  # 分割列的坐标,根据实际视频宽度调整
    split_column = 1000  # 分割列的坐标,根据实际视频宽度调整

    try:
        process_video(input_video, output_video, split_column)
    except Exception as e:
        print(f"处理过程中出错: {str(e)}")


if __name__ == "__main__":
    main()

代码解析

1. 依赖库导入

脚本使用了以下几个关键库:

  • cv2:OpenCV库,用于视频的读取、处理和写入
  • numpy:用于数组操作,实现帧的合并
  • ostempfile:提供文件系统相关功能

2. 核心函数process_video

该函数是整个脚本的核心,接收三个参数:输入视频路径、输出视频路径和分割列坐标,实现视频的分割与逆序合并功能。

2.1 视频读取与信息获取

首先通过cv2.VideoCapture打开视频文件,并获取视频的基本信息:

  • 帧数:cv2.CAP_PROP_FRAME_COUNT
  • 宽度:cv2.CAP_PROP_FRAME_WIDTH
  • 高度:cv2.CAP_PROP_FRAME_HEIGHT
  • 帧率:cv2.CAP_PROP_FPS

同时对分割列坐标进行有效性验证,确保其在合理范围内。

2.2 帧数据处理

读取所有帧并存储在列表中,然后创建帧列表的逆序副本(reversed_frames = frames[::-1]),用于右侧部分的替换。

对于每一帧,执行以下操作:

  • 提取当前帧的左侧部分(frames[i][:, :split_col]
  • 提取逆序帧列表中对应位置帧的右侧部分(reversed_frames[i][:, split_col:]
  • 处理可能的宽度不匹配问题
  • 使用np.hstack合并左右两部分,形成新的帧

2.3 视频输出

为了提高兼容性,脚本尝试了两种编码器(mp4vavc1)来创建视频写入对象。将处理后的所有帧写入输出视频文件,完成后释放资源。

3. 主函数main

主函数提供了示例用法,用户可以通过修改以下参数来使用脚本:

  • input_video:输入视频的路径
  • output_video:输出视频的路径
  • split_column:分割列的坐标(根据视频实际宽度调整)

使用方法

  1. 确保已安装必要的依赖库:
pip install opencv-python numpy
  1. 修改main函数中的参数:

    • input_video改为你的输入视频路径
    • 设置output_video为输出视频的保存路径
    • 根据视频宽度设置合适的split_column分割列坐标
  2. 运行脚本,程序会显示处理进度,完成后输出视频文件将保存到指定路径。

注意事项

  1. 分割列坐标需要根据视频实际宽度进行调整,确保在[0, 视频宽度-1]范围内
  2. 脚本支持MP4格式视频,其他格式可能需要调整编码器
  3. 处理大型视频时可能需要较多内存,因为会一次性读取所有帧
  4. 若输出视频无法打开,可能是编码器不支持,可以尝试修改fourcc参数使用其他编码器
  5. 视频处理时间与视频帧数和计算机性能有关,帧数较多时需要耐心等待

总结

本文介绍的视频分割与逆序合并工具能够实现特殊的视频视觉效果,通过将视频帧左右分割并对右侧部分进行逆序处理,创造出独特的画面效果。脚本具有较好的兼容性和容错处理,适合用于创意视频制作等场景。根据实际需求调整分割列坐标,可以获得不同的视觉效果,有兴趣的读者可以尝试不同的参数设置,探索更多可能性。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐