当前位置: 首页 > news >正文

python视频拆帧并根据所选区域保存指定区域

import cv2
import os# ----------- 区域选择部分(修复版)------------
roi_coordinates = {'x1':0, 'y1':0, 'x2':0, 'y2':0}
drawing = Falsedef select_region(event, x, y, flags, param):global roi_coordinates, drawingif event == cv2.EVENT_LBUTTONDOWN:drawing = Trueroi_coordinates = {'x1': x, 'y1': y, 'x2': x, 'y2': y}elif event == cv2.EVENT_MOUSEMOVE:if drawing:roi_coordinates['x2'] = xroi_coordinates['y2'] = yelif event == cv2.EVENT_LBUTTONUP:drawing = Falseroi_coordinates['x2'] = xroi_coordinates['y2'] = ydef preview_and_select(video_path, frame_num=0):global roi_coordinates, drawingroi_coordinates = {'x1':0, 'y1':0, 'x2':0, 'y2':0}  # 重置状态cap = cv2.VideoCapture(video_path)if not cap.isOpened():raise ValueError("视频打开失败,请检查路径或文件格式")cap.set(cv2.CAP_PROP_POS_FRAMES, frame_num)ret, frame = cap.read()if not ret:cap.release()raise ValueError("无法读取指定帧,可能超出视频范围")cv2.namedWindow('Select ROI (Q=确认 R=重置 A/D=跳帧)')cv2.setMouseCallback('Select ROI (Q=确认 R=重置 A/D=跳帧)', select_region)clone = frame.copy()while True:current_frame = clone.copy()if roi_coordinates['x1'] != roi_coordinates['x2'] or roi_coordinates['y1'] != roi_coordinates['y2']:x1 = min(roi_coordinates['x1'], roi_coordinates['x2'])y1 = min(roi_coordinates['y1'], roi_coordinates['y2'])x2 = max(roi_coordinates['x1'], roi_coordinates['x2'])y2 = max(roi_coordinates['y1'], roi_coordinates['y2'])cv2.rectangle(current_frame, (x1, y1), (x2, y2), (0, 255, 0), 2)cv2.putText(current_frame, f"X: {x1}-{x2}", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0,255,0), 2)cv2.putText(current_frame, f"Y: {y1}-{y2}", (10, 60), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0,255,0), 2)cv2.imshow('Select ROI (Q=确认 R=重置 A/D=跳帧)', current_frame)key = cv2.waitKey(1) & 0xFFif key == ord('r'):clone = frame.copy()roi_coordinates = {'x1':0, 'y1':0, 'x2':0, 'y2':0}elif key == ord('q'):breakelif key == ord('d'):frame_num += 10cap.set(cv2.CAP_PROP_POS_FRAMES, frame_num)ret, frame = cap.read()if ret:clone = frame.copy()roi_coordinates = {'x1':0, 'y1':0, 'x2':0, 'y2':0}elif key == ord('a'):frame_num = max(0, frame_num-10)cap.set(cv2.CAP_PROP_POS_FRAMES, frame_num)ret, frame = cap.read()if ret:clone = frame.copy()roi_coordinates = {'x1':0, 'y1':0, 'x2':0, 'y2':0}cv2.destroyAllWindows()cap.release()# 计算有效区域x = min(roi_coordinates['x1'], roi_coordinates['x2'])y = min(roi_coordinates['y1'], roi_coordinates['y2'])w = abs(roi_coordinates['x1'] - roi_coordinates['x2'])h = abs(roi_coordinates['y1'] - roi_coordinates['y2'])return (x, y, w, h) if w > 10 and h > 10 else None  # 最小尺寸校验# ----------- 视频拆帧部分(增强版)------------
def crop_and_save_frames(video_path, output_dir, region, interval=1):"""增强功能:- 自动路径创建- 进度显示- 区域有效性验证- 错误处理"""if not os.path.exists(video_path):raise FileNotFoundError(f"视频文件不存在:{video_path}")os.makedirs(output_dir, exist_ok=True)cap = cv2.VideoCapture(video_path)if not cap.isOpened():raise IOError("无法打开视频文件,可能是不支持的格式")# 验证区域有效性total_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))total_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))x, y, w, h = regionif (x + w > total_width) or (y + h > total_height):cap.release()raise ValueError(f"选择区域超出视频尺寸(视频分辨率:{total_width}x{total_height})")frame_count = 0saved_count = 0total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))try:while True:ret, frame = cap.read()if not ret:breakif frame_count % interval == 0:roi = frame[y:y+h, x:x+w]if roi.size == 0:  # 空图像检查continueoutput_path = os.path.join(output_dir, f"frame_{saved_count:05d}.jpg")cv2.imwrite(output_path, roi, [cv2.IMWRITE_JPEG_QUALITY, 95])saved_count += 1frame_count += 1if frame_count % 10 == 0:print(f"\r处理进度: {frame_count}/{total_frames} ({frame_count/total_frames:.1%})", end='')print(f"\n完成!共保存 {saved_count} 张图片到:{os.path.abspath(output_dir)}")finally:cap.release()# ----------- 完整使用示例 ------------
if __name__ == "__main__":# 配置参数video_path = r"E:\photo\video\1.mp4"   # 替换为实际视频路径output_folder = r"E:\photo\video\1" # 输出目录preview_frame = 50               # 预览起始帧号frame_interval = 30              # 抽帧间隔(每30帧抽1帧)# 步骤1:选择区域selected_region = preview_and_select(video_path, preview_frame)if not selected_region:print("未选择有效区域,程序终止")exit()print(f"已选择区域:{selected_region}")# 步骤2:执行拆帧try:crop_and_save_frames(video_path=video_path,output_dir=output_folder,region=selected_region,interval=frame_interval)except Exception as e:print(f"处理出错:{str(e)}")

使用流程:

  1. 修改video_path为实际视频路径

  2. 运行后会弹出预览窗口:

    • 鼠标拖拽选择区域

    • 按Q确认选择

    • 按R重置选择

    • 按A/D前后跳转10帧

  3. 选择完成后自动执行拆帧操作

相关文章:

  • Memcached 的特性和使用场景介绍,以及集群搭建
  • 基于机器学习的卫星钟差预测方法研究HPSO-BP
  • 腾讯发布数字人框架MuseTalk 1.5,开放训练逻辑,生成效果进一步优化~
  • MCP Server多节点滚动升级一致性治理
  • 爆肝整理!软件测试面试题整理(项目+接口问题)
  • 2025年真实面试问题汇总(二)
  • 如何检测和解决服务器端口被占用的问题
  • 分布式异步强化学习框架训练32B大模型:INTELLECT-2
  • vue2将文字转为拼音
  • 【Python生活】如何构建一个跌倒检测的算法?
  • 8天Python从入门到精通【itheima】-6~10
  • 蓝桥杯 10. 全球变暖
  • H5S视频平台-Ascend昇腾 GPU转码
  • 双种群进化算法:动态约束处理与资源分配解决约束多目标优化问题
  • 鹅厂面试数学题
  • C 语言_基础语法全解析_深度细化版
  • 传输层:UDP协议
  • 迅龙3号基于兆讯MH22D3适配CST328多点触摸驱动开发笔记
  • 仿正点原子驱动BMP280气压传感器实例
  • 深度学习 自然语言处理(RNN) day_02
  • 西安市未央区委书记刘国荣已任西咸新区党工委书记
  • 字母哥动了离开的心思,他和雄鹿队的缘分早就到了头
  • 季子文化与江南文化的根脉探寻与融合
  • 外交部:愿同拉美国家共同维护多边贸易体制
  • 《致1999年的自己》:千禧之年的你在哪里?
  • 代理销售保险存在误导行为,农业银行重庆市分行相关负责人被罚款0.1万元