通过Python实现B站60帧和30帧看到的视频不一样的脚本

相信大家最近在B站看到了不少用1080p60帧看和用30帧看会看到不同画面的视频,其原理主要是因为B站视频的规则是遇到120帧的视频时,在生成60帧视频时,会将该视频每两帧为一组,取每组第二针作为60帧视频的其中一帧,而生成30帧视频则会将视频每四帧为一组,取每组第一帧作为30帧视频的其中一帧

知道原理了,代码自然就好实现了

import os, glob
import shutil

import cv2

from matplotlib import pyplot as plt

frame_rate2 = 0
frame_rate1 = 0


def extract_frames(video_path, fold_name):
    # 使用OpenCV打开视频
    the_video_fold = get_video_fold(video_path)
    if not os.path.exists(the_video_fold + fold_name):
        os.makedirs(the_video_fold + fold_name)
    output_folder = the_video_fold + fold_name
    video = cv2.VideoCapture(video_path)

    # 初始化帧计数器
    count = 0

    # 遍历视频中的每一帧
    while True:
        # 读取下一帧
        success, frame = video.read()

        # 如果读取失败,说明已到视频末尾
        if not success:
            break

        # 构造输出图片的文件名
        frame_filename = f"{output_folder}/frame_{count:010d}.png"

        # 保存帧为图片
        cv2.imwrite(frame_filename, frame)
        print("导出:" + frame_filename)  # debug
        # cel_filter(frame_filename)  # 转描
        # 帧计数器加1
        count += 1

    # 释放VideoCapture对象
    video.release()
    print("导出了" + str(count) + "帧。")


def images_to_video(image_folder1, image_folder2, output_video, frame_rate):
    # 获取文件夹中的图片列表
    images1 = glob.glob(f'{image_folder1}/*.png')
    images2 = glob.glob(f'{image_folder2}/*.png')
    # 按文件名排序,确保图片按正确的顺序读取
    images1.sort()
    images2.sort()
    # 读取第一张图片以获取视频尺寸
    frame1 = cv2.imread(images1[0])
    height1, width1, layers1 = frame1.shape

    frame2 = cv2.imread(images2[0])
    height2, width2, layers2 = frame2.shape

    height = max(height1, height2)
    width = max(width1, width2)

    # 定义视频编码和创建VideoWriter对象
    fourcc = cv2.VideoWriter_fourcc(*'avc1')
    video = cv2.VideoWriter(output_video, fourcc, frame_rate, (width, height))

    frame_num1 = 0
    frame_num2 = 0
    increment1 = frame_rate1 / 60  # 计算步长
    increment2 = frame_rate2 / 60

    while True:
        if int(frame_num1) < len(images1):
            video.write(cv2.imread(images1[int(frame_num1)]))
            print("编码:" + images1[int(frame_num1)])
        if int(frame_num2) < len(images2):
            video.write(cv2.imread(images2[int(frame_num2)]))
            print("编码:" + images2[int(frame_num2)])
        if int(frame_num1) >= len(images1) and int(frame_num2) >= len(images2):
            break
        frame_num1 += increment1
        frame_num2 += increment2


    cv2.destroyAllWindows()
    video.release()


def get_frame_rate(video_path):
    # 使用OpenCV打开视频
    video = cv2.VideoCapture(video_path)

    # 获取视频的帧率
    frame_rate = video.get(cv2.CAP_PROP_FPS)

    # 释放VideoCapture对象
    video.release()

    return round(frame_rate, 2)


def remove_quotation_marks(the_video_path):
    tmp = list(the_video_path)
    if tmp[0] == '"' and tmp[len(the_video_path) - 1] == '"':
        the_video_path = the_video_path[1:len(the_video_path) - 1]

    return the_video_path


def get_video_fold(the_video_path):
    lastSlash = 0
    dir = 0
    for c in the_video_path:
        if c == '\\':
            lastSlash = dir
        dir = dir + 1
    return the_video_path[:lastSlash + 1]


def is_mp4(the_video_path):
    film_type = the_video_path[len(the_video_path) - 3:len(the_video_path)]
    if film_type != "mp4":
        print("视频格式必须是mp4格式")
        # os.system("pause")
        return False
    return True


if __name__ == '__main__':
    plt.rcParams['font.sans-serif'] = ['SimHei']

    print("LoongLy大会员专属视频脚本")
    video_path1 = input("输入文件路径或将视频拖拽到此处,注意,视频格式必须是mp4格式且目录中不能存在中文")

    video_path1 = remove_quotation_marks(video_path1)
    if not is_mp4(video_path1):
        print("NO.1 Video ERROR")
        exit(1)

    video_path2 = input("输入文件路径或将视频拖拽到此处,注意,视频格式必须是mp4格式且目录中不能存在中文")
    video_path2 = remove_quotation_marks(video_path2)
    if not is_mp4(video_path2):
        print("NO.2 Video ERROR")
        exit(1)

    video_fold1 = get_video_fold(video_path1)
    video_fold2 = get_video_fold(video_path2)

    frame_rate1 = get_frame_rate(video_path1)
    frame_rate2 = get_frame_rate(video_path2)
    print(f"'{video_path1}'\n 帧率: {frame_rate1} FPS")
    print(f"'{video_path2}'\n 帧率: {frame_rate2} FPS")

    print("开始导出帧到文件...")
    extract_frames(video_path1, "img_fold1")
    extract_frames(video_path2, "img_fold2")
    images_to_video(video_fold1 + "img_fold1", video_fold2 + "img_fold2", video_fold1 + "output.mp4", 120)
    print("成功导出为:" + video_fold1 + "output.mp4")
    os.system('pause')

# LZX completed this script in 2024/07/23
# LZX-TC-2024-07-23-001

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

想换电脑的LoongLy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值