基于OpenCV从会议视频提取幻灯片并去除冗余帧
解决会议视频幻灯片提取的冗余帧问题
你的问题根源是逐帧保存所有画面,但会议视频中绝大多数时间幻灯片内容没有变化,只有切换时刻才产生有效新画面。要避免冗余,核心逻辑是只保存与上一帧存在显著差异的帧——也就是幻灯片切换的关键帧。
下面是具体改进方案和代码实现:
核心思路
- 对比当前帧与上一帧的内容差异,设置合理的差异阈值
- 仅当差异超过阈值时,才将当前帧判定为新幻灯片并保存
- 对帧做预处理(转灰度、模糊),过滤演讲者手势、光线抖动等微小干扰
改进后的代码
这里使用**结构相似性指数(SSIM)**衡量帧差异,它比简单像素差更能精准反映画面内容的实质性变化:
import cv2 import os from skimage.metrics import structural_similarity as ssim def calculate_frame_diff(frame1, frame2): # 转灰度图,降低计算复杂度 gray1 = cv2.cvtColor(frame1, cv2.COLOR_BGR2GRAY) gray2 = cv2.cvtColor(frame2, cv2.COLOR_BGR2GRAY) # 高斯模糊,过滤噪声干扰 gray1 = cv2.GaussianBlur(gray1, (5, 5), 0) gray2 = cv2.GaussianBlur(gray2, (5, 5), 0) # 计算SSIM,返回值越接近1表示两帧越相似 similarity_score, _ = ssim(gray1, gray2, full=True) return 1 - similarity_score # 转换为差异值,值越大差异越明显 # 初始化视频捕获 cam = cv2.VideoCapture("C:\\Users\\zoomrx\\Desktop\\Video\\1.mp4") output_dir = 'data_clean' # 创建输出目录 if not os.path.exists(output_dir): os.makedirs(output_dir) current_frame_idx = 0 previous_frame = None # 差异阈值,可根据视频实际情况调整(推荐范围0.1-0.3) diff_threshold = 0.2 while True: ret, frame = cam.read() if not ret: break roi = frame[166:959, 24:1433] # 保留你原有的ROI区域 if previous_frame is None: # 第一帧直接保存 save_path = f'./{output_dir}/slide_{current_frame_idx}.jpg' print(f'保存新幻灯片: {save_path}') cv2.imwrite(save_path, roi) previous_frame = roi.copy() current_frame_idx += 1 else: # 计算当前帧与上一帧的差异 diff_value = calculate_frame_diff(roi, previous_frame) if diff_value > diff_threshold: # 差异超过阈值,判定为新幻灯片并保存 save_path = f'./{output_dir}/slide_{current_frame_idx}.jpg' print(f'保存新幻灯片: {save_path}') cv2.imwrite(save_path, roi) previous_frame = roi.copy() current_frame_idx += 1 if cv2.waitKey(1) & 0xFF == 27: break cam.release() cv2.destroyAllWindows()
关键说明
- SSIM差异计算:从亮度、对比度、结构三个维度评估图像相似性,能有效过滤演讲者手势、屏幕反光等非幻灯片内容的微小变化。
- 预处理步骤:转灰度和高斯模糊既减少了计算量,又避免了噪声导致的误判。
- 阈值调整:如果幻灯片切换时画面差异大,可适当提高
diff_threshold;如果视频存在较多抖动,可降低阈值。
备选方案(无需额外依赖)
若不想安装scikit-image库,可使用简单的像素差均值判断:
def calculate_frame_diff(frame1, frame2): gray1 = cv2.cvtColor(frame1, cv2.COLOR_BGR2GRAY) gray2 = cv2.cvtColor(frame2, cv2.COLOR_BGR2GRAY) # 计算像素差的绝对值均值 diff_map = cv2.absdiff(gray1, gray2) return diff_map.mean()
此时阈值建议设为10-30之间,根据视频实际情况微调。
内容的提问来源于stack exchange,提问作者Shishir
相关产品推荐
相关产品推荐

