【Python】提取视频画面并生成PPT

比较笨的方法,用来提取PPT课程视频画面,并生成对应的PPT,代码检测黑屏但没有检测白屏,没有检测重复画面(因为有些人讲课会来回翻PPT),因此还有优化空间。内存占用会逐渐增多,不过测试没有出现崩溃的情况。

PS:做完发现可以直接问讲课人要PPT原件,我,,,

import cv2
import os
import numpy as np
from pptx import Presentation
from pptx.util import Inches
from skimage.metrics import structural_similarity as ssim
import tkinter as tk
from tkinter import filedialog, messagebox

# 选择视频和输出目录
def select_video_and_output():
    video_path = filedialog.askopenfilename(title="选择视频文件", filetypes=[("MP4 files", "*.mp4")])
    if not video_path:
        messagebox.showwarning("选择视频", "未选择视频文件")
        return None, None
    
    output_dir = filedialog.askdirectory(title="选择输出目录")
    if not output_dir:
        messagebox.showwarning("选择输出目录", "未选择输出目录")
        return None, None

    pptx_path = os.path.join(output_dir, "output_presentation.pptx")
    return video_path, pptx_path

# 处理视频并生成 PPT
def process_video_to_ppt(video_path, pptx_path):
    os.makedirs("ppt_images", exist_ok=True)
    
    cap = cv2.VideoCapture(video_path)
    _, prev_frame = cap.read()
    prev_gray = cv2.cvtColor(prev_frame, cv2.COLOR_BGR2GRAY)

    frame_count = 0
    slide_count = 0
    images = []
    similarity_threshold = 0.95  # 提高 SSIM 阈值,减少相似图片
    brightness_threshold = 10  # 黑屏检测(平均亮度 < 10 认为是黑屏)

    def process_frame(frame):
        """ 计算 SSIM 相似度,判断是否保存该帧 """
        nonlocal prev_gray, slide_count
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        score = ssim(prev_gray, gray)

        # 计算平均亮度,过滤黑屏
        avg_brightness = np.mean(gray)
        if avg_brightness < brightness_threshold:
            return  # 跳过黑屏帧

        if score < similarity_threshold:  
            img_path = os.path.join("ppt_images", f"slide_{slide_count}.jpg")

            # 确保不同的幻灯片才保存
            if len(images) == 0 or images[-1] != img_path:  
                cv2.imwrite(img_path, frame)
                images.append(img_path)
                slide_count += 1
                prev_gray = gray  # 只在确认变化时更新参考帧

    while cap.isOpened():
        ret, frame = cap.read()
        if not ret:
            break

        # 仅每隔 15 帧处理一次
        if frame_count % 15 == 0:
            process_frame(frame)

        frame_count += 1

    cap.release()
    # cv2.destroyAllWindows()

    # 创建 PPT
    prs = Presentation()
    for img in images:
        slide = prs.slides.add_slide(prs.slide_layouts[5])  # 空白幻灯片
        left, top, width, height = Inches(0), Inches(0), Inches(10), Inches(7.5)
        slide.shapes.add_picture(img, left, top, width, height)

    prs.save(pptx_path)
    messagebox.showinfo("完成", f"PPTX 生成完成: {pptx_path}")

# 主函数
def main():
    root = tk.Tk()
    root.withdraw()  # 隐藏主窗口
    video_path, pptx_path = select_video_and_output()
    if video_path and pptx_path:
        process_video_to_ppt(video_path, pptx_path)

if __name__ == "__main__":
    main()

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注