Python 自定义抽取视频关键帧 (可设置抽样频率和相似程度要求) CV2&Skimage V1.0

原目的是侦测文字游戏录屏的画面的变化以推送至负责OCR和翻译的第二个程序处理为字幕文件(就是自动生成文字游戏录屏字幕的项目的一个环节),不过,或许也可以有一些别的用途?注释非常非常之详细,可以看了注释做改动

By 某不知名的B站文字游戏博主 @符若_float

**注意 默认的threshold值(0.98)非常高,如非监控文字变动等微小变化请适度调低

import cv2 #使用了这个库进行fps读取和图片的读取
import os #使用这个库进行输入和输出
import time #使用这个库对程序的运行进行计时
from skimage.metrics import structural_similarity as ssim #使用这个库进行对于生成图片的细筛

'''
Author: AleryXiao
Date: 2022.10.15
Title: 抽取视频关键帧(可设置抽样频率和相似程度要求) v1.0
Content: 
    0. *两个用户可设定参数*(分别位于Line27和Line28)
        a. 抽帧频率targetFPS (每秒钟抽取几帧)
        b. 目标相似度threshold (低于此相似度的图片将会被保存)
        更高的targetFPS会消耗更多的时间, 但是会生成更精确的时间码
        **注意 默认的threshold值非常高,如非监控文字变动等微小变化请适度调低
    1. 通过弹出的文件资源窗口选择一个或多个视频文件
    2. 对于每个视频文件:
        按给定的每秒帧数进行抽帧(cv2.VideoCapture) 抽取的帧存储在temp.jpg中
        对于第0个满足条件的帧, 存储至cache中
        对于其它满足条件的帧, 将之与cache作比较: 
            如果相似度大于threshold  ->储存至本地和cache, 更新cache为这一图片, 输出储存信息
            如果相速度小于threshold  ->输出舍弃信息
            (SSIM的运行速度较为有限, 或许可以考虑使用多线程运行?)
        完成后, 关闭抽帧相机, 输出完成的信息
'''

targetFPS = 3  # 目标每秒选取的帧数(越低越快,相对的,时间轴精度就比较低)
threshold = 0.98  # 目标相似度(低于此相似度的图片才会被保存)

def frames2time(frames, fps):  # 给定fps,将帧数转化为指定格式的视频时间(匹配popsub,小时数是假的2333,不能超过1小时,想要什么格式可以自己改ww)
    fpm = fps*60
    a = int(frames/fpm)  # 分钟数(取整)
    frames %= fpm  # 余下帧数
    b = frames/fps
    return "0_"+f"{str(a):0>2}"+"_"+f"{b:0>5.2f}"

def video_to_frames(video_path, outPutDirName, frame_frequency):
    if not os.path.exists(outPutDirName):  # 如果文件目录不存在则创建目录
        os.makedirs(outPutDirName)
    camera = cv2.VideoCapture(video_path)  # 创建一个相机,读取视频帧
    frames = -1
    T = int(frame_frequency/targetFPS)  # 周期每秒3帧
    while True:
        frames = frames + 1  # 第frames帧(0base)
        res, image = camera.read()
        if not res:
            print('Completed!')
            break
        if frames % T == 0: #按照周期抽帧,不到周期就跳过
            cv2.imwrite(outPutDirName + '/temp.jpg', image)
            img1 = cv2.imread(outPutDirName + '/temp.jpg')  # 每周期保存一个临时文件
            if frames==0:
                cv2.imwrite(outPutDirName + '/' +frames2time(frames, frame_frequency)+'.jpg', image)
                cache = img1 #每次遇到“新图片”就存储,并刷新缓存
                print('OvO '+str(frames)+' OwO')
            else:
                if ssim(img1, cache, multichannel=True) > threshold:
                    print('___ '+str(frames)+' ___')
                else:
                    cv2.imwrite(outPutDirName + '/' +frames2time(frames, frame_frequency)+'.jpg', image)
                    cache = img1 #每次遇到“新图片”就存储,并刷新缓存
                    print('OvO '+str(frames)+' OwO')

    os.remove(outPutDirName + '/temp.jpg')  # 删除临时文件
    camera.release()  # 释放相机


if __name__ == "__main__":
    start=time.time()
    from tkinter import filedialog as fd  # 窗口式输入
    import tkinter as tk
    root = tk.Tk()
    root.withdraw()
    input_list = fd.askopenfilenames(filetypes=[('视频文件', ['.flv', '.mp4', '.mov'])])  # 可以批量选取!结果输出在相同目录的同名文件夹

    for video_name in input_list:
        videoCapture = cv2.VideoCapture(video_name)
        print("正在处理视频: "+video_name)
        fps = videoCapture.get(cv2.CAP_PROP_FPS)        # 获取帧速率(frames per second)
        video_to_frames(video_name, video_name[:-4], fps)  # 输出在同一目录下的同名文件夹
        print("视频"+video_name+"已处理完成~\n****************")

    end=time.time()
    print(f"用时共计{end-start}秒")

ヽ(✿゚▽゚)ノ

《母语是C草但是因为python的优良库生态努力地学习了异国他乡的语言》的感觉……作为python萌新的我能写到这里应该给自己鼓个掌!(掌声!)

这段代码感觉比较难受的一个地方就是那个temp文件,明明都是cv2的读取格式但是不知道怎么传参image到img2……这一部分可能是有一些性能损失的,不过最卡时间的地方应该还是那个相似度判断,就看想要怎么用啦。

我个人测试了一些视频,感觉这个方法算下来耗时和效果还是比较能够兼顾的,如果后面我有学到新的方法再对它进行改进吧~

  • 6
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python视频关键帧抽取是指使用Python编程语言来从视频中提取关键帧(Key Frames)的过程。 关键帧是在视频中起关键作用的帧,它们能够概括和表示视频内容的主要信息。一般来说,关键帧视频中发生剧烈变化或重要场景的帧,与其它连续帧相比具有较高的信息量。 在Python中,可以使用一些现有的库和工具来实现视频关键帧抽取。其中最常用的是OpenCV库,它提供了强大的图像和视频处理功能。 以下是一个简单的Python代码示例,演示了如何使用OpenCV来进行视频关键帧抽取: ```python import cv2 def extract_keyframes(video_path, interval): video_capture = cv2.VideoCapture(video_path) keyframes = [] frame_count = 0 while True: success, frame = video_capture.read() if not success: break if frame_count % interval == 0: keyframes.append(frame) frame_count += 1 video_capture.release() return keyframes # 调用抽取函数,提取每隔10帧的关键帧 keyframes = extract_keyframes('input_video.mp4', 10) # 保存关键帧为图像文件 for i, keyframe in enumerate(keyframes): cv2.imwrite(f'keyframe_{i}.jpg', keyframe) ``` 在这个示例中,我们首先导入了OpenCV库。然后定义了一个`extract_keyframes`函数,它接受视频路径和关键帧间隔作为参数。 在函数内部,我们使用`cv2.VideoCapture()`打开视频文件,并通过`read()`方法逐帧读取视频。然后根据设定的关键帧间隔,选择每隔一定帧数的帧作为关键帧,并将其存储在`keyframes`列表中。 最后,我们通过`cv2.imwrite()`将提取到的关键帧保存为图像文件。 通过以上代码,我们可以方便地使用Python来实现视频关键帧抽取,从而获得视频的主要内容信息。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值