当前位置: 首页 > 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. 选择完成后自动执行拆帧操作

http://www.xdnf.cn/news/422911.html

相关文章:

  • Web 架构之攻击应急方案
  • workman进阶应用 GatewayWorker 仿微信 做聊天室
  • Spring WebFlux 与 WebClient 使用指南
  • Linux513 rsync本地传输 跨设备传输 一
  • 原型和原型链
  • list基础用法
  • API安全
  • 【PmHub后端篇】PmHub中基于自定义注解和AOP的服务接口鉴权与内部认证实现
  • 【fastadmin开发实战】在前端页面中使用bootstraptable以及表格中实现文件上传
  • 我的五周年创作纪念日
  • 系统稳定性之上线三板斧
  • 嵌入式开发学习日志(数据结构--顺序结构单链表)Day19
  • upload-labs通关笔记-第4关 文件上传之.htacess绕过
  • Spring Boot 应用中实现基本的 SSE 功能
  • 鸿蒙 核心与非核心装饰器
  • [Java实战]Spring Boot 3 整合 Ehcache 3(十九)
  • Python慕课学习记录报告
  • c# UTC 时间赋值注意事项
  • Linux:进程控制2
  • 医疗实时操作系统方案:手术机器人的微秒级运动控制
  • 单反和无反(私人笔记)
  • 高并发系统设计需要考虑哪些问题
  • 极限学习机进行电厂相关数据预测
  • 目标检测任务常用脚本1——将YOLO格式的数据集转换成VOC格式的数据集
  • 滑动窗口——水果成篮
  • 正则表达式常用验证(一)
  • vim,gcc/g++,makefile,cmake
  • 如何用URDF文件构建机械手模型并与MoveIt集成
  • 获取accesstoken时,提示证书解析有问题,导致无法正常获取token
  • do while