从视频中提取为ppt或图片

从视频中提取为ppt或图片

缘由

在观看视频或会议讲座时,有时会发现演讲者的ppt内容精彩非凡,渴望能够获取到主持人的演示幻灯片。然而,由于一些限制,我们无法直接下载这些ppt文件,有时只能去录制视频去截图某一帧然后合成pdf保存。

为了解决这个问题,我推荐以下软件,它可以从视频中自动识别并提取出其中的ppt内容,并将其转化为pdf文件,方便保存和分享。

简介

这个软件是video2pdfslides, 它的主要作用就是从一个视频里提取有效图片, 去重后并转为 PDF。
官方地址

使用

这是一款开源代码,不属于模块,所以无法通过pip直接安装调用。

安装与运行

安装:

git clone https://github.com/kaushikj/video2pdfslides

cd video2pdfslides

pip install -r requirements.txt

使用命令行运行

python video2pdfslides.py video/test.mp4

python video2pdfslides.py "./input/Test Video 1.mp4"

改进-批量

官方提供代码每次只能转换一个文件(也可能可以批量,但是我没发现调用方法),所以我们可以对其进行改进。

import os
import pathlib
import time
import cv2
import imutils
import shutil
import img2pdf
import glob
import argparse

############# 定义常量

OUTPUT_SLIDES_DIR = f"./output"  # 默认输出文件夹

FRAME_RATE = 3  # 帧率:每秒需要处理的帧数越少,速度越快
WARMUP = FRAME_RATE  # 被跳过的初始帧数
FGBG_HISTORY = FRAME_RATE * 15  # 背景对象中的帧数
VAR_THRESHOLD = 16  # 方差阈值,用于判断当前像素是前景还是背景。一般默认为 16,如果光照变化明显,如阳光下的水面,建议设为 25,值越大灵敏度越低
DETECT_SHADOWS = False  # 是否检测影子,设为 True 为检测,False 为不检测,检测影子会增加程序时间复杂度,一般设置为 False
MIN_PERCENT = 0.1  # 在前景和背景之间的最小差值百分比,以检测运动是否已经停止
MAX_PERCENT = 3  # 在前景和背景之间的最大百分比的差异,以检测帧是否仍在运动


def get_frames(video_path):
    '''从位于 video_path 的视频返回帧的函数
    此函数跳过 FRAME_RATE 中定义的帧'''

    # 打开指向视频文件的指针初始化帧的宽度和高度
    vs = cv2.VideoCapture(video_path)
    if not vs.isOpened():
        raise Exception(f'unable to open file {video_path}')

    total_frames = vs.get(cv2.CAP_PROP_FRAME_COUNT)
    frame_time = 0
    frame_count = 0
    print("total_frames: ", total_frames)
    print("FRAME_RATE", FRAME_RATE)

    # 循环播放视频的帧
    while True:
        # 从视频中抓取一帧

        vs.set(cv2.CAP_PROP_POS_MSEC, frame_time * 1000)  # 将帧移动到时间戳
        frame_time += 1 / FRAME_RATE

        (_, frame) = vs.read()
        # 如果帧为None,那么我们已经到了视频文件的末尾
        if frame is None:
            break

        frame_count += 1
        yield frame_count, frame_time, frame

    vs.release()


def detect_unique_screenshots(video_path, output_folder_screenshot_path):
    ''''''
    # 用参数初始化 fgbg 一个背景对象
    # history = 影响背景减法器的帧历史数
    # varThreshold = 像素与模型之间的平方马氏距离的阈值,以决定像素是否被背景模型很好地描述。该参数不影响后台更新。
    # detectShadows = 如果为真,算法将检测阴影并标记它们。它会稍微降低速度,因此如果您不需要此功能,请将参数设置为 false。

    fgbg = cv2.createBackgroundSubtractorMOG2(history=FGBG_HISTORY, varThreshold=VAR_THRESHOLD,
                                              detectShadows=DETECT_SHADOWS)

    captured = False
    start_time = time.time()
    (W, H) = (None, None)

    screenshoots_count = 0
    for frame_count, frame_time, frame in get_frames(video_path):
        orig = frame.copy()  # clone the original frame (so we can save it later),
        frame = imutils.resize(frame, width=600)  # resize the frame
        mask = fgbg.apply(frame)  # apply the background subtractor

        # apply a series of erosions and dilations to eliminate noise
        #            eroded_mask = cv2.erode(mask, None, iterations=2)
        #            mask = cv2.dilate(mask, None, iterations=2)

        # if the width and height are empty, grab the spatial dimensions
        if W is None or H is None:
            (H, W) = mask.shape[:2]

        # compute the percentage of the mask that is "foreground"
        p_diff = (cv2.countNonZero(mask) / float(W * H)) * 100

        # if p_diff less than N% then motion has stopped, thus capture the frame

        if p_diff < MIN_PERCENT and not captured and frame_count > WARMUP:
            captured = True
            filename = f"{screenshoots_count:03}_{round(frame_time / 60, 2)}.png"

            path = str(pathlib.Path(output_folder_screenshot_path, filename))

            print("saving {}".format(path))
            cv2.imencode('.png', orig)[1].tofile(path)  # 防止imwrite中文乱码
            screenshoots_count += 1

        # otherwise, either the scene is changing or we're still in warmup
        # mode so let's wait until the scene has settled or we're finished
        # building the background model
        elif captured and p_diff >= MAX_PERCENT:
            captured = False
    print(f'{screenshoots_count} screenshots Captured!')
    print(f'Time taken {time.time() - start_time}s')
    return


def initialize_output_folder(video_path):
    '''Clean the output folder if already exists'''
    (filesname, extension) = os.path.splitext(video_path)
    output_folder_screenshot_path = f"{OUTPUT_SLIDES_DIR}/{video_path.rsplit('/')[-1].replace(extension, '')}"

    if os.path.exists(output_folder_screenshot_path):
        shutil.rmtree(output_folder_screenshot_path)

    os.makedirs(output_folder_screenshot_path, exist_ok=True)
    print('initialized output folder', output_folder_screenshot_path)
    return output_folder_screenshot_path


def convert_screenshots_to_pdf(output_folder_screenshot_path):
    (filesname, extension) = os.path.splitext(video_path)
    output_pdf_path = f"{OUTPUT_SLIDES_DIR}/{video_path.rsplit('/')[-1].replace(extension, '')}" + '.pdf'
    print('output_folder_screenshot_path', output_folder_screenshot_path)
    print('output_pdf_path', output_pdf_path)
    print('converting images to pdf..')
    with open(output_pdf_path, "wb") as f:
        f.write(img2pdf.convert(sorted(glob.glob(f"{output_folder_screenshot_path}/*.png"))))
    print('Pdf Created!')
    print('pdf saved at', output_pdf_path)


if __name__ == "__main__":

    input_dir_name = 'test'#要转换的视频所在的文件夹

    for file_name in os.listdir(input_dir_name):
        print(f"正在转换:{file_name}")
        video_path = str(pathlib.Path(input_dir_name, file_name))
        output_folder_screenshot_path = initialize_output_folder(video_path)
        detect_unique_screenshots(video_path, output_folder_screenshot_path)

        # 提取的图片转换为pdf
        convert_screenshots_to_pdf(output_folder_screenshot_path)

食用方法:

input_dir_name 代表要转换的视频所在文件夹

修改后直接运行即可,默认是提取后的图片自动转为pdf

  • 5
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

飞得更高肥尾沙鼠

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

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

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

打赏作者

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

抵扣说明:

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

余额充值