从视频中每隔10帧截取一帧并保存为图片

  • 要从视频中每隔10帧截取一帧并保存为图片,可以使用 OpenCV 库。
复制代码
import cv2

# 视频文件的路径
video_path = 'path/to/your/video.mp4'

# 创建一个 VideoCapture 对象
cap = cv2.VideoCapture(video_path)

# 检查是否成功打开视频文件
if not cap.isOpened():
    print("Error opening video file")

# 获取视频的帧率
fps = cap.get(cv2.CAP_PROP_FPS)
print(f"Frames per second: {fps:.2f}")

# 初始化帧计数器
frame_count = 0

# 循环读取视频帧
while cap.isOpened():
    # 读取一帧
    ret, frame = cap.read()

    # 如果读取成功,ret 将为 True
    if ret:
        # 每隔10帧保存一次
        if frame_count % 10 == 0:
            # 构建输出图片的文件名
            output_path = f'output/frame_{frame_count}.jpg'
            
            # 保存图片
            cv2.imwrite(output_path, frame)
            print(f"Frame saved at {output_path}")

        # 增加帧计数器
        frame_count += 1
    else:
        # 如果读取失败(到达视频末尾),则退出循环
        break

# 释放 VideoCapture 对象
cap.release()

# 关闭所有 OpenCV 窗口(如果有打开的话)
cv2.destroyAllWindows()

在这段代码中:

  1. 我们首先导入 cv2 模块。
  2. 使用 cv2.VideoCapture() 函数打开视频文件。
  3. 检查视频是否成功打开。
  4. 获取视频的帧率,这可以帮助你了解视频的播放速度。
  5. 初始化一个帧计数器 frame_count
  6. 使用一个无限循环来读取视频帧,直到视频结束。
  7. 在循环中,我们使用 cap.read() 函数读取每一帧。ret 变量将返回一个布尔值,表示读取是否成功;frame 变量将包含实际的图像数据。
  8. 如果读取成功,我们检查 frame_count 是否是10的倍数。如果是,我们就保存当前帧为图片。
  9. 使用 cv2.imwrite() 函数保存图片,文件名格式为 frame_{frame_count}.jpg
  10. 增加帧计数器。
  11. 如果读取失败(通常是因为到达了视频的末尾),我们跳出循环。
  12. 最后,我们释放 VideoCapture 对象并关闭所有 OpenCV 窗口。

确保将 'path/to/your/video.mp4' 替换为你的视频文件的实际路径。

  • 如果你想要按照更精确的时间间隔(比如每秒一次)从视频中提取帧,而不只是简单地每隔一定数量的帧提取,你可以利用视频的编码时间戳。OpenCV 的 VideoCapture 类提供了访问这些时间戳的方法,但默认情况下并不直接提供它们。为了获取时间戳,你需要在读取每一帧时同时读取它们。

下面是一个修改后的示例,展示如何根据时间戳每秒提取一帧:

复制代码
import cv2
import time

# 视频文件的路径
video_path = 'path/to/your/video.mp4'

# 创建一个 VideoCapture 对象
cap = cv2.VideoCapture(video_path)

# 检查是否成功打开视频文件
if not cap.isOpened():
    print("Error opening video file")

# 获取视频的帧率
fps = cap.get(cv2.CAP_PROP_FPS)
print(f"Frames per second: {fps:.2f}")

# 获取视频的总时间(以毫秒为单位)
total_time_ms = cap.get(cv2.CAP_PROP_POS_MSEC)

# 计算视频的总帧数
total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))

# 初始化当前时间戳
current_time_ms = 0

# 循环读取视频帧
for frame_num in range(total_frames):
    # 设置视频的位置到特定的时间戳
    cap.set(cv2.CAP_PROP_POS_MSEC, current_time_ms)
    
    # 读取一帧
    ret, frame = cap.read()

    # 如果读取成功,ret 将为 True
    if ret:
        # 构建输出图片的文件名
        output_path = f'output/frame_{int(current_time_ms / 1000)}.jpg'
        
        # 保存图片
        cv2.imwrite(output_path, frame)
        print(f"Frame saved at {output_path}")
        
        # 更新时间戳,增加一秒
        current_time_ms += 1000
    else:
        # 如果读取失败(到达视频末尾),则退出循环
        break

# 释放 VideoCapture 对象
cap.release()

# 关闭所有 OpenCV 窗口(如果有打开的话)
cv2.destroyAllWindows()

然而,上述代码有一个关键问题:它假设视频的帧率是恒定的,并且每一帧的持续时间都是相等的。在实际情况中,视频的帧率可能不是完全恒定的,特别是对于一些编码方式更为复杂的视频。因此,使用时间戳来定位帧可能不会总是准确的,尤其是在视频的某些部分帧率发生变化时。

  • 一个更可靠的方法是使用视频的解码时间戳,但这需要额外的库,如 ffmpeg-pythonmoviepy,它们可以提供更高级的视频处理功能,包括对时间戳的精确访问。如果你需要非常精确的时间控制,你可能需要考虑使用这些库之一。

例如,使用 ffmpeg-python 库,你可以如下操作:

复制代码
import ffmpeg

# 视频文件的路径
video_path = 'path/to/your/video.mp4'

# 使用 ffmpeg 接口读取视频
input_video = ffmpeg.input(video_path)

# 获取视频的总时间(以秒为单位)
probe = ffmpeg.probe(video_path)
video_info = next(s for s in probe['streams'] if s['codec_type'] == 'video')
total_time_s = float(video_info['duration'])

# 循环遍历每一秒
for sec in range(int(total_time_s)):
    # 使用 ffmpeg 接口截取视频中的特定帧
    out, _ = (
        ffmpeg
        .filter(input_video, 'select', f'gte(t,{sec}')
        .output('pipe:', format='rawvideo', pix_fmt='rgb24')
        .run(capture_stdout=True)
    )
    
    # 将字节流转换为 numpy 数组
    image = np.frombuffer(out, np.uint8).reshape([int(video_info['height']), int(video_info['width']), 3])
    
    # 构建输出图片的文件名
    output_path = f'output/frame_{sec}.jpg'
    
    # 保存图片
    cv2.imwrite(output_path, image)
    print(f"Frame saved at {output_path}")

请注意,使用 ffmpeg-pythonmoviepy 可能需要安装额外的依赖项,并且它们的使用方法与 OpenCV 有所不同。上述 ffmpeg-python 示例代码需要你有 ffmpeg 工具安装在你的系统上,并且熟悉 ffmpeg 的命令行语法。

相关推荐
用户8356290780514 小时前
Python 实现 PDF 文件加密与解密方法
后端·python
用户8356290780514 小时前
使用 Python 冻结与拆分 Excel 窗格教程
后端·python
你好潘先生12 小时前
别再记命令了,用 yeero do 说句人话就能跑脚本,而且不烧 token
服务器·python·命令行
Agent_大师13 小时前
WebSocket 行情重连成功,K线缺口不会自动消失
python
荣码13 小时前
LLM结构化输出:让AI返回JSON而不是废话,我踩了4个坑
java·python
copyer_xyf13 小时前
FastAPI 如何连接 MySQL
后端·python
apocelipes1 天前
常用编程语言和库的正则表达式性能对比
c语言·c++·python·性能优化·golang·开发工具和环境
用户8356290780511 天前
使用 Python 在 PDF 中创建与管理书签
后端·python
MeixianAgent1 天前
Python 回测数据入口怎么验?历史 K 线入库前先做 5 个检查
后端·python
咕白m6251 天前
用 Python 实现一键批量查找与替换 Excel 数据
后端·python