video_frame_extractor.py 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. """
  4. 视频画面提取工具
  5. 从指定视频文件的特定时间段提取画面帧并保存为图像文件
  6. """
  7. import cv2
  8. import os
  9. import sys
  10. from pathlib import Path
  11. def extract_frames_from_video(video_path, start_time_seconds, end_time_seconds, output_dir, target_frame_count=500, image_extension="jpg", image_params=None):
  12. """
  13. 从视频中提取指定时间段的画面帧
  14. 参数:
  15. video_path (str): 视频文件路径
  16. start_time_seconds (int): 开始时间(秒)
  17. end_time_seconds (int): 结束时间(秒)
  18. output_dir (str): 输出目录路径
  19. target_frame_count (int): 目标提取帧数,默认500帧
  20. 返回:
  21. bool: 提取是否成功
  22. """
  23. # 检查视频文件是否存在
  24. if not os.path.exists(video_path):
  25. print(f"错误:视频文件不存在 - {video_path}")
  26. return False
  27. # 创建输出目录
  28. output_path = Path(output_dir)
  29. output_path.mkdir(parents=True, exist_ok=True)
  30. # 打开视频文件
  31. cap = cv2.VideoCapture(video_path)
  32. if not cap.isOpened():
  33. print(f"错误:无法打开视频文件 - {video_path}")
  34. return False
  35. # 获取视频基本信息
  36. fps = cap.get(cv2.CAP_PROP_FPS)
  37. total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
  38. duration = total_frames / fps
  39. print(f"视频信息:")
  40. print(f" 帧率: {fps:.2f} FPS")
  41. print(f" 总帧数: {total_frames}")
  42. print(f" 总时长: {duration:.2f} 秒")
  43. # 计算开始和结束帧号
  44. start_frame = int(start_time_seconds * fps)
  45. end_frame = int(end_time_seconds * fps)
  46. # 检查时间范围是否有效
  47. if start_frame >= total_frames:
  48. print(f"错误:开始时间超出视频长度")
  49. cap.release()
  50. return False
  51. if end_frame > total_frames:
  52. print(f"警告:结束时间超出视频长度,将提取到视频结尾")
  53. end_frame = total_frames
  54. # 计算实际提取的帧数范围
  55. frame_range = end_frame - start_frame
  56. if frame_range <= 0:
  57. print(f"错误:无效的时间范围")
  58. cap.release()
  59. return False
  60. # 计算帧间隔以获得目标帧数
  61. if frame_range <= target_frame_count:
  62. # 如果总帧数少于目标帧数,提取所有帧
  63. frame_interval = 1
  64. actual_frame_count = frame_range
  65. else:
  66. # 计算间隔以获得约500帧
  67. frame_interval = frame_range // target_frame_count
  68. actual_frame_count = frame_range // frame_interval
  69. print(f"提取参数:")
  70. print(f" 开始时间: {start_time_seconds}秒 (第{start_frame}帧)")
  71. print(f" 结束时间: {end_time_seconds}秒 (第{end_frame}帧)")
  72. print(f" 帧间隔: {frame_interval}")
  73. print(f" 预计提取帧数: {actual_frame_count}")
  74. # 跳转到开始帧
  75. cap.set(cv2.CAP_PROP_POS_FRAMES, start_frame)
  76. extracted_count = 0
  77. current_frame = start_frame
  78. print(f"开始提取画面...")
  79. while current_frame < end_frame:
  80. ret, frame = cap.read()
  81. if not ret:
  82. print(f"警告:读取帧失败,停止提取")
  83. break
  84. # 只保存指定间隔的帧
  85. if (current_frame - start_frame) % frame_interval == 0:
  86. # 计算时间戳
  87. timestamp_seconds = current_frame / fps
  88. minutes = int(timestamp_seconds // 60)
  89. seconds = int(timestamp_seconds % 60)
  90. milliseconds = int((timestamp_seconds % 1) * 1000)
  91. # 生成文件名
  92. filename = f"frame_{extracted_count:04d}_time_{minutes:02d}m{seconds:02d}s{milliseconds:03d}ms.{image_extension}"
  93. output_file = output_path / filename
  94. # 保存图像
  95. success = cv2.imwrite(str(output_file), frame, image_params if image_params is not None else [])
  96. if success:
  97. extracted_count += 1
  98. if extracted_count % 50 == 0:
  99. print(f" 已提取 {extracted_count} 帧...")
  100. else:
  101. print(f"警告:保存图像失败 - {output_file}")
  102. current_frame += 1
  103. cap.release()
  104. print(f"提取完成!")
  105. print(f" 成功提取 {extracted_count} 帧")
  106. print(f" 输出目录: {output_dir}")
  107. return True
  108. def main():
  109. """主函数"""
  110. # 视频文件路径
  111. video_path = r"E:\20251204\D15_20251130235724.mp4"
  112. # 时间设置(28分钟到30分钟)
  113. start_time_minutes = 0
  114. end_time_minutes = 15
  115. start_time_seconds = start_time_minutes * 60 # 28分钟 = 1680秒
  116. end_time_seconds = end_time_minutes * 60 # 30分钟 = 1800秒
  117. # 输出目录
  118. output_dir = r"D:\data\20251204\OUT5"
  119. # 目标提取帧数
  120. target_frame_count = 100
  121. print(f"视频画面提取工具")
  122. print(f"=" * 50)
  123. print(f"输入视频: {video_path}")
  124. print(f"提取时间段: {start_time_minutes}:00 - {end_time_minutes}:00")
  125. print(f"目标帧数: {target_frame_count}")
  126. print(f"输出目录: {output_dir}")
  127. print(f"=" * 50)
  128. # 执行提取
  129. success = extract_frames_from_video(
  130. video_path=video_path,
  131. start_time_seconds=start_time_seconds,
  132. end_time_seconds=end_time_seconds,
  133. output_dir=output_dir,
  134. target_frame_count=target_frame_count
  135. )
  136. if success:
  137. print(f"\n✓ 画面提取成功完成!")
  138. else:
  139. print(f"\n✗ 画面提取失败!")
  140. sys.exit(1)
  141. if __name__ == "__main__":
  142. main()