从视频中截取ppt,整理为pdf

server/2025/1/10 22:34:36/

见仓库:
https://github.com/MaybeBio/video2ppt
以下是修改后的代码,并附有每一行的详细解释。修改的主要部分包括:

  1. 使用绝对路径:确保输出目录使用绝对路径,避免相对路径引起的问题。
  2. 增加调试信息:在保存图像前后添加更多的打印语句,以便更好地了解程序运行状态。
  3. 检查输出目录权限:确保程序有权限在指定目录下创建和写入文件。
  4. 优化错误处理:提供更详细的错误信息,帮助定位问题。
import os
from datetime import datetime
import cv2
from fpdf import FPDF# 指定视频文件所在的目录路径 (绝对路径)
directory_path = r'D:\download\gene\动植物基因表达调控(研)_于明\ppt_real'# 指定输出图像和PDF的目录 (绝对路径)
output_directory = os.path.join(directory_path, 'output_directory')
os.makedirs(output_directory, exist_ok=True)  # 如果目录不存在,则创建# 获取目录下所有文件的列表
file_list = os.listdir(directory_path)# 按照文件的修改时间进行排序
file_list.sort(key=lambda x: os.path.getmtime(os.path.join(directory_path, x)))# 遍历排序后的文件列表
for file_name in file_list:file_path = os.path.join(directory_path, file_name)# 检查是否为文件而非子目录if not os.path.isfile(file_path):continue  # 跳过非文件项# 获取文件的修改时间modified_time = datetime.fromtimestamp(os.path.getmtime(file_path))print(f"正在处理文件: {file_path}")print(f"文件名:{file_name},修改时间:{modified_time}")# 打开视频文件cap = cv2.VideoCapture(file_path)# 检查视频是否成功打开if not cap.isOpened():print(f"无法打开视频文件: {file_path}")continue  # 跳过无法打开的视频文件# 初始化变量prev_frame_gray_1 = Noneprev_frame_gray_2 = Nonepage_images = []i = 0while True:ret, frame = cap.read()if not ret:break  # 读取完毕或发生错误# 检查帧是否为空if frame is None:continue# 确保感兴趣区域的坐标在帧的边界内if frame.shape[0] < 720 or frame.shape[1] < 1280:print(f"帧尺寸不足,跳过该帧,帧尺寸:{frame.shape}")continue# 调整感兴趣区域的坐标以适应帧的实际尺寸roi_1 = frame[660:720, 1180:1280]  # 感兴趣区域1roi_2 = frame[300:460, 360:500]    # 感兴趣区域2# 将感兴趣区域转换为灰度图像roi_gray_1 = cv2.cvtColor(roi_1, cv2.COLOR_BGR2GRAY)roi_gray_2 = cv2.cvtColor(roi_2, cv2.COLOR_BGR2GRAY)# 初始化前一帧灰度图像if prev_frame_gray_1 is None:prev_frame_gray_1 = roi_gray_1.copy()prev_frame_gray_2 = roi_gray_2.copy()continue  # 跳过第一帧的差分检测# 计算当前帧和前一帧的差分图像frame_diff_1 = cv2.absdiff(roi_gray_1, prev_frame_gray_1)frame_diff_2 = cv2.absdiff(roi_gray_2, prev_frame_gray_2)# 对差分图像进行阈值处理_, threshold_1 = cv2.threshold(frame_diff_1, 30, 255, cv2.THRESH_BINARY)_, threshold_2 = cv2.threshold(frame_diff_2, 30, 255, cv2.THRESH_BINARY)# 统计阈值图像中非零像素的数量diff_pixels_1 = cv2.countNonZero(threshold_1)diff_pixels_2 = cv2.countNonZero(threshold_2)# 如果两个区域的差分像素数量都超过阈值,则认为帧发生了变化if (diff_pixels_1 > 100 and diff_pixels_2 > 300) or diff_pixels_1 > 150 or diff_pixels_2 > 1000:print(f"帧发生变化: {i + 1}, 差分像素1: {diff_pixels_1}, 差分像素2: {diff_pixels_2}")# 生成安全的文件名,移除特殊字符safe_file_name = ''.join(c for c in file_name if c.isalnum() or c in (' ', '_')).rstrip()page_path = os.path.join(output_directory, f"{safe_file_name}_page_{i + 1}.jpg")# 尝试保存图像try:# 检查输出目录是否存在if not os.path.exists(output_directory):os.makedirs(output_directory, exist_ok=True)print(f"创建输出目录: {output_directory}")# 保存图像success = cv2.imwrite(page_path, frame)if success:print(f"图像已保存: {page_path}")page_images.append(page_path)else:print(f"图像保存失败: {page_path}")except Exception as e:print(f"保存图像时发生错误: {str(e)}")i += 1# 更新前一帧prev_frame_gray_1 = roi_gray_1.copy()prev_frame_gray_2 = roi_gray_2.copy()# 显示当前帧 (可选,运行时可关闭窗口加快速度)# cv2.imshow("Frame", frame)# 跳过一定数量的帧以加快处理速度current_frame = cap.get(cv2.CAP_PROP_POS_FRAMES)max_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))# 计算目标帧的索引(例如跳500帧)target_frame = current_frame + 500if target_frame >= max_frames:break  # 超过总帧数,结束处理cap.set(cv2.CAP_PROP_POS_FRAMES, target_frame)# 按下 'q' 键退出循环 (可选,已注释)# if cv2.waitKey(1) & 0xFF == ord('q'):#     breakcap.release()cv2.destroyAllWindows()# 创建PDF文件pdf = FPDF()pdf.set_auto_page_break(auto=True, margin=15)for image_path in page_images:if os.path.exists(image_path):pdf.add_page()# 计算图片的宽度和高度,以适应PDF页面pdf_width = pdf.w - 20  # 左右各10的边距pdf.image(image_path, x=10, y=10, w=pdf_width)else:print(f"图像文件不存在: {image_path}")# 保存PDFpdf_file_name = os.path.splitext(file_name)[0] + '.pdf'pdf_path = os.path.join(output_directory, pdf_file_name)try:pdf.output(pdf_path)print(f"已保存PDF: {pdf_path}")except Exception as e:print(f"保存PDF时发生错误: {str(e)}")

代码详解

  1. 导入所需模块
import os
from datetime import datetime
import cv2
from fpdf import FPDF
- `os`:用于处理文件和目录路径。
- `datetime`:用于获取文件的修改时间。
- `cv2`:OpenCV库,用于视频处理和图像保存。
- `fpdf`:用于生成PDF文件。
  1. 指定视频文件所在的目录路径
directory_path = r'D:\download\gene\动植物基因表达调控(研)_于明\ppt_real'
- `directory_path`:视频文件存放的绝对路径。
  1. 指定输出图像和PDF的目录
output_directory = os.path.join(directory_path, 'output_directory')
os.makedirs(output_directory, exist_ok=True)
- `output_directory`:生成的图像和PDF将保存到该目录下。
- `os.makedirs`:创建输出目录,如果目录已存在则不会报错。
  1. 获取目录下所有文件的列表并按修改时间排序
file_list = os.listdir(directory_path)
file_list.sort(key=lambda x: os.path.getmtime(os.path.join(directory_path, x)))
- 获取目录中所有文件,并按文件的修改时间进行排序,确保按时间顺序处理视频文件。
  1. 遍历排序后的文件列表
for file_name in file_list:file_path = os.path.join(directory_path, file_name)
- 遍历每个文件,构建文件的绝对路径。
  1. 检查是否为文件
if not os.path.isfile(file_path):continue
- 跳过子目录或非文件项,确保只处理文件。
  1. 获取文件的修改时间并打印信息
modified_time = datetime.fromtimestamp(os.path.getmtime(file_path))
print(f"正在处理文件: {file_path}")
print(f"文件名:{file_name},修改时间:{modified_time}")
- 获取并打印当前处理文件的名称和修改时间。
  1. 打开视频文件并检查是否成功
cap = cv2.VideoCapture(file_path)
if not cap.isOpened():print(f"无法打开视频文件: {file_path}")continue
- 使用OpenCV打开视频文件,如果无法打开,则跳过该文件。
  1. 初始化变量
prev_frame_gray_1 = None
prev_frame_gray_2 = None
page_images = []
i = 0
- `prev_frame_gray_1` 和 `prev_frame_gray_2` 用于存储前一帧的灰度图像。
- `page_images` 用于存储检测到变化的帧的图像路径。
- `i` 用于计数保存的图像数量。
  1. 读取视频帧并处理
while True:ret, frame = cap.read()if not ret:breakif frame is None:continueif frame.shape[0] < 720 or frame.shape[1] < 1280:print(f"帧尺寸不足,跳过该帧,帧尺寸:{frame.shape}")continueroi_1 = frame[660:720, 1180:1280]roi_2 = frame[300:460, 360:500]roi_gray_1 = cv2.cvtColor(roi_1, cv2.COLOR_BGR2GRAY)roi_gray_2 = cv2.cvtColor(roi_2, cv2.COLOR_BGR2GRAY)if prev_frame_gray_1 is None:prev_frame_gray_1 = roi_gray_1.copy()prev_frame_gray_2 = roi_gray_2.copy()continueframe_diff_1 = cv2.absdiff(roi_gray_1, prev_frame_gray_1)frame_diff_2 = cv2.absdiff(roi_gray_2, prev_frame_gray_2)_, threshold_1 = cv2.threshold(frame_diff_1, 30, 255, cv2.THRESH_BINARY)_, threshold_2 = cv2.threshold(frame_diff_2, 30, 255, cv2.THRESH_BINARY)diff_pixels_1 = cv2.countNonZero(threshold_1)diff_pixels_2 = cv2.countNonZero(threshold_2)if (diff_pixels_1 > 100 and diff_pixels_2 > 300) or diff_pixels_1 > 150 or diff_pixels_2 > 1000:print(f"帧发生变化: {i + 1}, 差分像素1: {diff_pixels_1}, 差分像素2: {diff_pixels_2}")safe_file_name = ''.join(c for c in file_name if c.isalnum() or c in (' ', '_')).rstrip()page_path = os.path.join(output_directory, f"{safe_file_name}_page_{i + 1}.jpg")try:if not os.path.exists(output_directory):os.makedirs(output_directory, exist_ok=True)print(f"创建输出目录: {output_directory}")success = cv2.imwrite(page_path, frame)if success:print(f"图像已保存: {page_path}")page_images.append(page_path)else:print(f"图像保存失败: {page_path}")except Exception as e:print(f"保存图像时发生错误: {str(e)}")i += 1prev_frame_gray_1 = roi_gray_1.copy()prev_frame_gray_2 = roi_gray_2.copy()current_frame = cap.get(cv2.CAP_PROP_POS_FRAMES)max_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))target_frame = current_frame + 500if target_frame >= max_frames:breakcap.set(cv2.CAP_PROP_POS_FRAMES, target_frame)
- **读取帧**:使用 `cap.read()` 读取视频的每一帧。
- **检查帧有效性**:确保帧不为空且尺寸符合要求。
- **定义感兴趣区域(ROI)**:选取视频帧中需要监测变化的区域。
- **转换为灰度图像**:便于进行差分计算。
- **初始化前一帧**:为第一帧设置前一帧的灰度图像。
- **计算帧差分**:通过 `cv2.absdiff` 计算当前帧与前一帧的差异。
- **阈值处理**:将差分图像进行二值化,突出变化区域。
- **统计变化像素**:计算二值化图像中非零像素的数量,作为变化的指标。
- **变化检测**:根据阈值判断是否发生了显著变化。
- **保存变化帧**:如果检测到变化,尝试保存当前帧为图像文件。
- **跳帧处理**:每检测到一次变化后,跳过500帧以加快处理速度。
  1. 释放资源并关闭窗口
cap.release()
cv2.destroyAllWindows()
- 释放视频捕捉对象并关闭所有OpenCV窗口。
  1. 创建PDF文件
pdf = FPDF()
pdf.set_auto_page_break(auto=True, margin=15)for image_path in page_images:if os.path.exists(image_path):pdf.add_page()pdf_width = pdf.w - 20  # 左右各10的边距pdf.image(image_path, x=10, y=10, w=pdf_width)else:print(f"图像文件不存在: {image_path}")
- 初始化 `FPDF` 对象,并设置自动分页。
- 遍历保存的图像,将每张图像添加到PDF中,调整图片宽度以适应页面。
  1. 保存PDF文件
pdf_file_name = os.path.splitext(file_name)[0] + '.pdf'
pdf_path = os.path.join(output_directory, pdf_file_name)
try:pdf.output(pdf_path)print(f"已保存PDF: {pdf_path}")
except Exception as e:print(f"保存PDF时发生错误: {str(e)}")
- 生成PDF文件的名称,并保存到输出目录中。
- 捕捉保存过程中的异常,打印错误信息。

可能的修复点

  1. 使用绝对路径:确保输出目录使用绝对路径,避免因为当前工作目录不同导致的路径错误。
  2. 权限问题:确保程序有权限在指定的输出目录下创建和写入文件,特别是在Windows系统中。
  3. 文件名安全性:通过移除文件名中的特殊字符,避免因非法字符导致保存失败。
  4. 检查帧数据:确保 frame 数据在保存前是有效的,可以通过打印 frame.shape 或其他方式进行验证。
  5. OpenCV 编码器支持:确保OpenCV支持保存JPEG格式,必要时可以尝试保存为其他格式(如PNG)以测试。

调试建议

  1. 打印更多信息:在 cv2.imwrite 之前后打印 frame 的相关信息,如数据类型、尺寸等。
  2. 尝试不同的图像格式:将保存格式从 .jpg 改为 .png 以测试是否为编码器问题。
page_path = os.path.join(output_directory, f"{safe_file_name}_page_{i + 1}.png")
  1. 检查磁盘空间:确保目标磁盘有足够的空间来保存图像文件。
  2. 手动测试保存图像:在脚本外部,手动使用OpenCV保存一张图像,确保环境配置正确。
sample_image_path = os.path.join(output_directory, "test_image.jpg")
cv2.imwrite(sample_image_path, frame)

如果这一步失败,说明问题可能出在环境配置或路径权限上。

通过以上修改和调试,应该能够定位并解决“图像保存失败”的问题。如果问题依然存在,可以提供更多的错误日志或环境信息,以便进一步分析。

修改之后:


```plain
import os
from datetime import datetime
import cv2
from fpdf import FPDF
import re# 指定视频文件所在的目录路径 (绝对路径)
directory_path = r'D:\download\gene\ppt_real'# 指定输出图像和PDF的目录 (绝对路径)
output_directory = os.path.join(directory_path, 'ppt_directory')
os.makedirs(output_directory, exist_ok=True)  # 如果目录不存在,则创建# 获取目录下所有文件的列表
file_list = os.listdir(directory_path)# 按照文件的修改时间进行排序
file_list.sort(key=lambda x: os.path.getmtime(os.path.join(directory_path, x)))# 遍历排序后的文件列表
for file_name in file_list:file_path = os.path.join(directory_path, file_name)# 检查是否为文件而非子目录if not os.path.isfile(file_path):continue  # 跳过非文件项# 获取文件的修改时间modified_time = datetime.fromtimestamp(os.path.getmtime(file_path))print(f"正在处理文件: {file_path}")print(f"文件名:{file_name},修改时间:{modified_time}")# 打开视频文件cap = cv2.VideoCapture(file_path)# 检查视频是否成功打开if not cap.isOpened():print(f"无法打开视频文件: {file_path}")continue  # 跳过无法打开的视频文件# 初始化变量prev_frame_gray_1 = Noneprev_frame_gray_2 = Nonepage_images = []i = 0while True:ret, frame = cap.read()if not ret:break  # 读取完毕或发生错误# 检查帧是否为空if frame is None:continue# 确保感兴趣区域的坐标在帧的边界内if frame.shape[0] < 720 or frame.shape[1] < 1280:print(f"帧尺寸不足,跳过该帧,帧尺寸:{frame.shape}")continue# 调整感兴趣区域的坐标以适应帧的实际尺寸roi_1 = frame[660:720, 1180:1280]  # 感兴趣区域1roi_2 = frame[300:460, 360:500]    # 感兴趣区域2# 在帧上绘制感兴趣区域的矩形框cv2.rectangle(frame, (1180, 660), (1280, 720), (0, 255, 0), 2)  # 绘制感兴趣区域1cv2.rectangle(frame, (360, 300), (500, 460), (0, 255, 0), 2)    # 绘制感兴趣区域2# 将感兴趣区域转换为灰度图像roi_gray_1 = cv2.cvtColor(roi_1, cv2.COLOR_BGR2GRAY)roi_gray_2 = cv2.cvtColor(roi_2, cv2.COLOR_BGR2GRAY)# 初始化前一帧灰度图像if prev_frame_gray_1 is None:prev_frame_gray_1 = roi_gray_1.copy()prev_frame_gray_2 = roi_gray_2.copy()continue  # 跳过第一帧的差分检测# 计算当前帧和前一帧的差分图像frame_diff_1 = cv2.absdiff(roi_gray_1, prev_frame_gray_1)frame_diff_2 = cv2.absdiff(roi_gray_2, prev_frame_gray_2)# 对差分图像进行阈值处理_, threshold_1 = cv2.threshold(frame_diff_1, 30, 255, cv2.THRESH_BINARY)_, threshold_2 = cv2.threshold(frame_diff_2, 30, 255, cv2.THRESH_BINARY)# 统计阈值图像中非零像素的数量diff_pixels_1 = cv2.countNonZero(threshold_1)diff_pixels_2 = cv2.countNonZero(threshold_2)# 如果两个区域的差分像素数量都超过阈值,则认为帧发生了变化if (diff_pixels_1 > 100 and diff_pixels_2 > 300) or diff_pixels_1 > 150 or diff_pixels_2 > 1000:print(f"帧发生变化: {i + 1}, 差分像素1: {diff_pixels_1}, 差分像素2: {diff_pixels_2}")# 提取文件名中的编号部分match = re.search(r'第(\d+)讲', file_name)if match:lecture_number = match.group(1)else:lecture_number = 'unknown'# 生成简化的文件名simplified_file_name = f"{lecture_number}_{i + 1}.jpg"page_path = os.path.join(output_directory, simplified_file_name)# 尝试保存图像try:# 检查输出目录是否存在if not os.path.exists(output_directory):os.makedirs(output_directory, exist_ok=True)print(f"创建输出目录: {output_directory}")# 保存图像success = cv2.imwrite(page_path, frame)if success:print(f"图像已保存: {page_path}")page_images.append(page_path)else:print(f"图像保存失败: {page_path}")except Exception as e:print(f"保存图像时发生错误: {str(e)}")i += 1# 更新前一帧prev_frame_gray_1 = roi_gray_1.copy()prev_frame_gray_2 = roi_gray_2.copy()# 显示当前帧 (可选,运行时可关闭窗口加快速度)cv2.imshow("Frame", frame)# 跳过一定数量的帧以加快处理速度current_frame = cap.get(cv2.CAP_PROP_POS_FRAMES)max_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))# 计算目标帧的索引(例如跳500帧)target_frame = current_frame + 500if target_frame >= max_frames:break  # 超过总帧数,结束处理cap.set(cv2.CAP_PROP_POS_FRAMES, target_frame)# 按下 'q' 键退出循环 (可选,已注释)if cv2.waitKey(1) & 0xFF == ord('q'):breakcap.release()cv2.destroyAllWindows()# 创建PDF文件pdf = FPDF()pdf.set_auto_page_break(auto=True, margin=15)for image_path in page_images:if os.path.exists(image_path):pdf.add_page()# 计算图片的宽度和高度,以适应PDF页面pdf_width = pdf.w - 20  # 左右各10的边距pdf.image(image_path, x=10, y=10, w=pdf_width)else:print(f"图像文件不存在: {image_path}")# 保存PDFpdf_file_name = os.path.splitext(file_name)[0] + '.pdf'pdf_path = os.path.join(output_directory, pdf_file_name)try:pdf.output(pdf_path)print(f"已保存PDF: {pdf_path}")except Exception as e:print(f"保存PDF时发生错误: {str(e)}")

中间那个区域方框还可以,但是右下角那个就有点不起作用了;

中间那个可以放大一下,右边那个可以左上角移动一下:

import os
from datetime import datetime
import cv2
from fpdf import FPDF
import re# 指定视频文件所在的目录路径 (绝对路径)
directory_path = r'D:\download\gene\ppt_real'# 指定输出图像和PDF的目录 (绝对路径)
output_directory = os.path.join(directory_path, 'output_directory')
os.makedirs(output_directory, exist_ok=True)  # 如果目录不存在,则创建# 获取目录下所有文件的列表
file_list = os.listdir(directory_path)# 按照文件的修改时间进行排序
file_list.sort(key=lambda x: os.path.getmtime(os.path.join(directory_path, x)))# 遍历排序后的文件列表
for file_name in file_list:file_path = os.path.join(directory_path, file_name)# 检查是否为文件而非子目录if not os.path.isfile(file_path):continue  # 跳过非文件项# 获取文件的修改时间modified_time = datetime.fromtimestamp(os.path.getmtime(file_path))print(f"正在处理文件: {file_path}")print(f"文件名:{file_name},修改时间:{modified_time}")# 打开视频文件cap = cv2.VideoCapture(file_path)# 检查视频是否成功打开if not cap.isOpened():print(f"无法打开视频文件: {file_path}")continue  # 跳过无法打开的视频文件# 初始化变量prev_frame_gray_1 = Noneprev_frame_gray_2 = Nonepage_images = []i = 0while True:ret, frame = cap.read()if not ret:break  # 读取完毕或发生错误# 检查帧是否为空if frame is None:continue# 确保感兴趣区域的坐标在帧的边界内if frame.shape[0] < 720 or frame.shape[1] < 1280:print(f"帧尺寸不足,跳过该帧,帧尺寸:{frame.shape}")continue# 调整感兴趣区域的坐标以适应帧的实际尺寸roi_1 = frame[620:680, 1140:1240]  # 感兴趣区域1,左上移动一些roi_2 = frame[280:500, 340:540]    # 感兴趣区域2,扩大一些# 在帧上绘制感兴趣区域的矩形框cv2.rectangle(frame, (1140, 620), (1240, 680), (0, 255, 0), 2)  # 绘制感兴趣区域1cv2.rectangle(frame, (340, 280), (540, 500), (0, 255, 0), 2)    # 绘制感兴趣区域2# 将感兴趣区域转换为灰度图像roi_gray_1 = cv2.cvtColor(roi_1, cv2.COLOR_BGR2GRAY)roi_gray_2 = cv2.cvtColor(roi_2, cv2.COLOR_BGR2GRAY)# 初始化前一帧灰度图像if prev_frame_gray_1 is None:prev_frame_gray_1 = roi_gray_1.copy()prev_frame_gray_2 = roi_gray_2.copy()continue  # 跳过第一帧的差分检测# 计算当前帧和前一帧的差分图像frame_diff_1 = cv2.absdiff(roi_gray_1, prev_frame_gray_1)frame_diff_2 = cv2.absdiff(roi_gray_2, prev_frame_gray_2)# 对差分图像进行阈值处理_, threshold_1 = cv2.threshold(frame_diff_1, 30, 255, cv2.THRESH_BINARY)_, threshold_2 = cv2.threshold(frame_diff_2, 30, 255, cv2.THRESH_BINARY)# 统计阈值图像中非零像素的数量diff_pixels_1 = cv2.countNonZero(threshold_1)diff_pixels_2 = cv2.countNonZero(threshold_2)# 如果两个区域的差分像素数量都超过阈值,则认为帧发生了变化if (diff_pixels_1 > 100 and diff_pixels_2 > 300) or diff_pixels_1 > 150 or diff_pixels_2 > 1000:print(f"帧发生变化: {i + 1}, 差分像素1: {diff_pixels_1}, 差分像素2: {diff_pixels_2}")# 提取文件名中的编号部分match = re.search(r'第(\d+)讲', file_name)if match:lecture_number = match.group(1)else:lecture_number = 'unknown'# 生成简化的文件名simplified_file_name = f"{lecture_number}_{i + 1}.jpg"page_path = os.path.join(output_directory, simplified_file_name)# 尝试保存图像try:# 检查输出目录是否存在if not os.path.exists(output_directory):os.makedirs(output_directory, exist_ok=True)print(f"创建输出目录: {output_directory}")# 保存图像success = cv2.imwrite(page_path, frame)if success:print(f"图像已保存: {page_path}")page_images.append(page_path)else:print(f"图像保存失败: {page_path}")except Exception as e:print(f"保存图像时发生错误: {str(e)}")i += 1# 更新前一帧prev_frame_gray_1 = roi_gray_1.copy()prev_frame_gray_2 = roi_gray_2.copy()# 显示当前帧 (可选,运行时可关闭窗口加快速度)cv2.imshow("Frame", frame)# 跳过一定数量的帧以加快处理速度current_frame = cap.get(cv2.CAP_PROP_POS_FRAMES)max_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))# 计算目标帧的索引(例如跳500帧)target_frame = current_frame + 500if target_frame >= max_frames:break  # 超过总帧数,结束处理cap.set(cv2.CAP_PROP_POS_FRAMES, target_frame)# 按下 'q' 键退出循环 (可选,已注释)if cv2.waitKey(1) & 0xFF == ord('q'):breakcap.release()cv2.destroyAllWindows()# 创建PDF文件pdf = FPDF()pdf.set_auto_page_break(auto=True, margin=15)for image_path in page_images:if os.path.exists(image_path):pdf.add_page()# 计算图片的宽度和高度,以适应PDF页面pdf_width = pdf.w - 20  # 左右各10的边距pdf.image(image_path, x=10, y=10, w=pdf_width)else:print(f"图像文件不存在: {image_path}")# 保存PDFpdf_file_name = os.path.splitext(file_name)[0] + '.pdf'pdf_path = os.path.join(output_directory, pdf_file_name)try:pdf.output(pdf_path)print(f"已保存PDF: {pdf_path}")except Exception as e:print(f"保存PDF时发生错误: {str(e)}")

最后还要考虑视频中截取的每一帧的图片的尺寸与最后pdf的尺寸之间的区别

import os
from datetime import datetime
import cv2
from fpdf import FPDF
import re# 指定视频文件所在的目录路径 (绝对路径)
directory_path = r'D:\download\gene\ppt_real'# 指定输出图像和PDF的目录 (绝对路径)
output_directory = os.path.join(directory_path, 'ppt')
os.makedirs(output_directory, exist_ok=True)  # 如果目录不存在,则创建# 获取目录下所有文件的列表
file_list = os.listdir(directory_path)# 按照文件的修改时间进行排序
file_list.sort(key=lambda x: os.path.getmtime(os.path.join(directory_path, x)))# 遍历排序后的文件列表
for file_name in file_list:file_path = os.path.join(directory_path, file_name)# 检查是否为文件而非子目录if not os.path.isfile(file_path):continue  # 跳过非文件项# 获取文件的修改时间modified_time = datetime.fromtimestamp(os.path.getmtime(file_path))print(f"正在处理文件: {file_path}")print(f"文件名:{file_name},修改时间:{modified_time}")# 打开视频文件cap = cv2.VideoCapture(file_path)# 检查视频是否成功打开if not cap.isOpened():print(f"无法打开视频文件: {file_path}")continue  # 跳过无法打开的视频文件# 初始化变量prev_frame_gray_1 = Noneprev_frame_gray_2 = Nonepage_images = []i = 0while True:ret, frame = cap.read()if not ret:break  # 读取完毕或发生错误# 检查帧是否为空if frame is None:continue# 确保感兴趣区域的坐标在帧的边界内if frame.shape[0] < 720 or frame.shape[1] < 1280:print(f"帧尺寸不足,跳过该帧,帧尺寸:{frame.shape}")continue# 调整感兴趣区域的坐标以适应帧的实际尺寸roi_1 = frame[480:660, 1060:1200]  # 感兴趣区域1,往上移动100像素roi_2 = frame[280:500, 340:540]    # 感兴趣区域2,扩大一些# 将感兴趣区域转换为灰度图像roi_gray_1 = cv2.cvtColor(roi_1, cv2.COLOR_BGR2GRAY)roi_gray_2 = cv2.cvtColor(roi_2, cv2.COLOR_BGR2GRAY)# 初始化前一帧灰度图像if prev_frame_gray_1 is None:prev_frame_gray_1 = roi_gray_1.copy()prev_frame_gray_2 = roi_gray_2.copy()continue  # 跳过第一帧的差分检测# 计算当前帧和前一帧的差分图像frame_diff_1 = cv2.absdiff(roi_gray_1, prev_frame_gray_1)frame_diff_2 = cv2.absdiff(roi_gray_2, prev_frame_gray_2)# 对差分图像进行阈值处理_, threshold_1 = cv2.threshold(frame_diff_1, 30, 255, cv2.THRESH_BINARY)_, threshold_2 = cv2.threshold(frame_diff_2, 30, 255, cv2.THRESH_BINARY)# 统计阈值图像中非零像素的数量diff_pixels_1 = cv2.countNonZero(threshold_1)diff_pixels_2 = cv2.countNonZero(threshold_2)# 如果两个区域的差分像素数量都超过阈值,则认为帧发生了变化if (diff_pixels_1 > 100 and diff_pixels_2 > 300) or diff_pixels_1 > 150 or diff_pixels_2 > 1000:print(f"帧发生变化: {i + 1}, 差分像素1: {diff_pixels_1}, 差分像素2: {diff_pixels_2}")# 提取文件名中的编号部分match = re.search(r'第(\d+)讲', file_name)if match:lecture_number = match.group(1)else:lecture_number = 'unknown'# 生成简化的文件名simplified_file_name = f"{lecture_number}_{i + 1}.jpg"page_path = os.path.join(output_directory, simplified_file_name)# 尝试保存图像try:# 检查输出目录是否存在if not os.path.exists(output_directory):os.makedirs(output_directory, exist_ok=True)print(f"创建输出目录: {output_directory}")# 保存图像success = cv2.imwrite(page_path, frame)if success:print(f"图像已保存: {page_path}")page_images.append(page_path)else:print(f"图像保存失败: {page_path}")except Exception as e:print(f"保存图像时发生错误: {str(e)}")i += 1# 更新前一帧prev_frame_gray_1 = roi_gray_1.copy()prev_frame_gray_2 = roi_gray_2.copy()# 显示当前帧 (可选,运行时可关闭窗口加快速度)cv2.imshow("Frame", frame)# 跳过一定数量的帧以加快处理速度current_frame = cap.get(cv2.CAP_PROP_POS_FRAMES)max_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))# 计算目标帧的索引(例如跳500帧)target_frame = current_frame + 100if target_frame >= max_frames:break  # 超过总帧数,结束处理cap.set(cv2.CAP_PROP_POS_FRAMES, target_frame)# 按下 'q' 键退出循环 (可选,已注释)# if cv2.waitKey(1) & 0xFF == ord('q'):#     breakcap.release()cv2.destroyAllWindows()# 创建PDF文件pdf = FPDF(orientation='L', unit='mm', format='A4')  # 使用横向A4纸pdf.set_auto_page_break(auto=True, margin=15)for image_path in page_images:if os.path.exists(image_path):pdf.add_page()# 计算图片的宽度和高度,以适应PDF页面pdf_width = pdf.w   # 左右各5的边距pdf_height = pdf.h - 20  # 上下各10的边距pdf.image(image_path, x=5, y=10, w=pdf_width, h=pdf_height)else:print(f"图像文件不存在: {image_path}")# 保存PDFpdf_file_name = os.path.splitext(file_name)[0] + '.pdf'pdf_path = os.path.join(output_directory, pdf_file_name)try:pdf.output(pdf_path)print(f"已保存PDF: {pdf_path}")except Exception as e:print(f"保存PDF时发生错误: {str(e)}")

跳的帧数需要经验参考,此处使用100帧,当然有些ppt跳的快,可能需要50帧以内等,有些需要更多;

总之设置一个尽可能小的rough的数目,然后再去调整哪些ppt是没有用的。


http://www.ppmy.cn/server/157304.html

相关文章

什么是VLAN?

VLAN&#xff08;Virtual Local Area Network&#xff0c;虚拟局域网&#xff09;是一种将物理局域网划分成多个逻辑上独立的虚拟网络的技术。VLAN不依赖于设备的物理位置&#xff0c;而是通过逻辑划分&#xff0c;将局域网内的设备虚拟地组织到同一组。这种技术允许网络管理员…

[java基础-集合篇]LinkedList源码粗析

LinkedList 的数据结构 实现List、Deque 接口&#xff0c;基于 双向链表实现的列表。与基于数组的 ArrayList 不同&#xff0c;基于链表的LinkedList 允许在列表的任何位置快速地插入和删除元素。 Java中LinkedList实现了Deque&#xff0c;它提供了 add, offer, remove, poll, …

SQL编程语言

第一章 1. 数据库是长期储存在计算机内&#xff0c;由专门的数据管理软件(数据库管理系统)&#xff0c;进行统一组织和管理控制的大量数据的集合。 2.数据库的基本特点不包括可以快速检索。 3. 数据管理技术的发展经历了&#xff1a;人工管理阶段、文件系统阶段、数据库系统阶…

第四章补充:线性代数预备知识(B站:小崔说数)

视频1&#xff1a;向量及方程组 原视频&#xff1a;线性代数预备知识——向量及方程组_哔哩哔哩_bilibili 很多同学没办法把线性代数的前后章节联系到一起&#xff0c;比如第三章的向量组和第四章的方程组它们之间到底有什么关系&#xff1f;为了解决大家的疑惑&#xff0c;我…

Mysql--基础篇--视图,存储过程,触发器

1、视图 MySQL视图&#xff08;View&#xff09;是一个虚拟表&#xff0c;其内容由查询定义。同真实的表一样&#xff0c;视图包含一系列带有名称的列和行数据。但是&#xff0c;视图并不在数据库中以存储的数据值集形式存在。行和列数据来自由定义视图的查询所引用的表&#…

使用强化学习训练神经网络玩俄罗斯方块

一、说明 在 2024 年暑假假期期间&#xff0c;Tim学习并应用了Q-Learning &#xff08;一种强化学习形式&#xff09;来训练神经网络玩简化版的俄罗斯方块游戏。在本文中&#xff0c;我将详细介绍我是如何做到这一点的。我希望这对任何有兴趣将强化学习应用于新领域的人有所帮助…

将 vue3 项目打包后部署在 springboot 项目运行

目录 前端vite打包 vite 打包路径配置 打包命令&#xff08;可选&#xff09; 执行打包 后端springboot配置 静态资源路径配置&#xff08;可选&#xff09; thymeleaf依赖 转移打包文件 请求返回html文件 启动项目 可能遇到的问题 页面一刷新就404 页面空白 页面…

Android中Activity

一、AndroidManifest中的<activity>标签 <activity>标签在AndroidManifest.xml文件中用于定义和配置应用中的每一个Activity。Activity是Android应用的基本构建块之一&#xff0c;主要负责展示用户界面&#xff0c;并处理用户与之的交互。每个在应用中显示给用户的…