Python+OpenCV读写视频的方法详解

目录
  • 读视频,提取帧
    • 接口函数:cv2.VideoCapture()
    • 获取视频信息
    • 使用set(cv2.CAP_PROP_POS_FRAMES)读取指定帧
    • 读取函数(重点)
  • 将图像写为视频
    • 示例
    • fourcc

读视频,提取帧

接口函数:cv2.VideoCapture()

通过video_capture = cv2.VideoCapture(video_path)可以获取读取视频的句柄。而后再通过flag, frame = video_capture.read()可以读取当前帧,flag表示读取是否成功,读取成功后,句柄会自动移动到下一帧的位置。读取结束后使用video_capture.release()释放句柄。

一个简单的逐帧读取的程序如下:

import cv2

video_capture = cv2.VideoCapture(video_path)
while True:
    flag, frame = video_capture.read()
    if not flag:
        break
    # do something with frame
video_capture.release()

获取视频信息

为了能更好更灵活地了解并读取视频,我们有时候需要获取视频的一些信息,比如帧率,总帧数等等。获取这些信息的方法是调用video_capture.get(PROP_ID)方法,其中PROP_ID是OpenCV定义的一些常量。

常用的信息及示例如下:

import cv2

video_path = r'D:\peppa\Muddy_Puddles.mp4'
video_capture = cv2.VideoCapture(video_path)

frame_num = video_capture.get(cv2.CAP_PROP_FRAME_COUNT) # ==> 总帧数
fps = video_capture.get(cv2.CAP_PROP_FPS)               # ==> 帧率
width = video_capture.get(cv2.CAP_PROP_FRAME_WIDTH)     # ==> 视频宽度
height = video_capture.get(cv2.CAP_PROP_FRAME_HEIGHT)   # ==> 视频高度
pos = video_capture.get(cv2.CAP_PROP_POS_FRAMES)        # ==> 句柄位置

video_capture.set(cv2.CAP_PROP_POS_FRAMES, 1000)        # ==> 设置句柄位置
pos = video_capture.get(cv2.CAP_PROP_POS_FRAMES)        # ==> 此时 pos = 1000.0

video_capture.release()

句柄位置指的是下一次调用read()方法读取到的帧号,帧号索引从0开始。

使用set(cv2.CAP_PROP_POS_FRAMES)读取指定帧

从上面代码中可以看到我们使用了set方法来设置句柄的位置,这个功能在读取指定帧时很有用,这样我们不必非要使用read()遍历到指定位置。

但问题来了,这种方式读取到的内容和read()遍历读取到的内容是否完全相同?

做个简单的实验,下面用两种方法分别读取同一个视频的[100, 200)帧,然后检查读取的内容是否完全相同,结果是True。

import cv2
import numpy as np

video_path = r'D:\peppa\Muddy_Puddles.mp4'
video_capture = cv2.VideoCapture(video_path)
cnt = -1
frames1 = []
while True:
    cnt += 1
    flag, frame = video_capture.read()
    assert flag
    if 100 <= cnt < 200:
        frames1.append(frame)
    if cnt >= 200:
        break
video_capture.release()

video_capture = cv2.VideoCapture(video_path)
frames2 = []
for i in range(100, 200):
    video_capture.set(cv2.CAP_PROP_POS_FRAMES, i)
    flag, frame = video_capture.read()
    assert flag
    frames2.append(frame)
video_capture.release()

frames1 = np.array(frames1)
frames2 = np.array(frames2)
print(np.all(frames1 == frames2))  # ==> check whether frames1 is same as frames2, result is True

接下来看看利用set读取的效率。还是利用小猪佩奇第一集做实验,这个视频共7788帧,下面分别用两种方法遍历读取视频中所有帧。第二种方法明显比第一种慢得多,所以这就很苦逼了。。。如果帧间隔比较小的话,单纯用read()进行遍历效率高;如果帧间隔比较大的话,用set()设置位置,然后read()读取效率高。

(如果给第二种方法加个判断,每隔n帧读取一次,那么效率确实会提高n倍,可以自行尝试)

import cv2
import numpy as np
import time

video_path = r'D:\peppa\Muddy_Puddles.mp4'
video_capture = cv2.VideoCapture(video_path)
t0 = time.time()
while True:
    flag, frame = video_capture.read()
    if not flag:
        break
t1 = time.time()
video_capture.release()

video_capture = cv2.VideoCapture(video_path)
t2 = time.time()
frame_num = int(video_capture.get(cv2.CAP_PROP_FRAME_COUNT))
for i in range(frame_num):
    video_capture.set(cv2.CAP_PROP_POS_FRAMES, i)
    flag, frame = video_capture.read()
    assert flag
t3 = time.time()
video_capture.release()

print(t1 - t0)  # ==> 76.3 s
print(t3 - t2)  # ==> 345.1 s

读取函数(重点)

上面我们使用了两种方法读取视频帧,第一种是使用read()进行暴力遍历,第二种是使用set()设置帧号,再使用read()读取。两种方法读取到的结果完全一样,但是效率在不同的情况下各有优势,所以为了最大化发挥两者的优势,在写读取帧函数时,就要把两种方式都写进去,由参数来决定使用哪种模式,这样用户可以针对电脑的硬件做一些简单实验后自行决定。

# -*- coding: utf-8 -*-
import os
import cv2

def _extract_frame_mode_1(video_capture, frame_list, root_folder, ext='png'):
    """
    extract video frames and save them to disk. this method will go through all
    the frames using video_capture.read()

    Parameters:
    -----------
    video_capture: obtained by cv2.VideoCapture()
    frame_list: list
        list of frame numbers
    root_folder: str
        root folder to save frames
    ext: str
        extension of filename
    """
    frame_list = sorted(frame_list)
    video_capture.set(cv2.CAP_PROP_POS_FRAMES, 0)
    cnt = -1
    index = 0
    while True:
        cnt += 1
        flag, frame = video_capture.read()
        if not flag:
            break
        if cnt == frame_list[index]:
            filename = os.path.join(root_folder, str(cnt) + '.' + ext)
            cv2.imwrite(filename, frame)
            index += 1

def _extract_frame_mode_2(video_capture, frame_list, root_folder, ext='png'):
    """
        extract video frames and save them to disk. this method will use
        video_capture.set() to locate the frame position and then use
        video_capture.read() to read

        Parameters:
        -----------
        video_capture: obtained by cv2.VideoCapture()
        frame_list: list
            list of frame numbers
        root_folder: str
            root folder to save frames
        ext: str
            extension of image filename
        """
    for i in frame_list:
        video_capture.set(cv2.CAP_PROP_POS_FRAMES, i)
        flag, frame = video_capture.read()
        assert flag
        filename = os.path.join(root_folder, str(i) + '.' + ext)
        cv2.imwrite(filename, frame)

def extract_frame(video_path, increment=None, frame_list=None,
                  mode=1, ext='png'):
    """
    extract video frames and save them to disk. the root folder to save frames
    is same as video_path (without extension)

    Parameters:
    -----------
    video_path: str
        video path
    increment: int of 'fps'
        increment of frame indexes
    frame_list: list
        list of frame numbers
    mode: int, 1 or 2
        1: go through all the frames using video_capture.read()
        2: use video_capture.set() to locate the frame position and then use
        video_capture.read() to read
    ext: str
        extension of image filename
    """
    video_capture = cv2.VideoCapture(video_path)
    frame_num = int(video_capture.get(cv2.CAP_PROP_FRAME_COUNT))

    if increment is None:
        increment = 1
    elif increment == 'fps':
        fps = video_capture.get(cv2.CAP_PROP_FPS)
        increment = round(fps)

    if frame_list is None:
        frame_list = [i for i in range(0, frame_num, increment)]

    if frame_num // len(frame_list) > 5 and mode == 1:
        print("the frames to be extracted is too sparse, "
              "please consider setting mode = 2 to accelerate")

    root_folder = os.path.splitext(video_path)[0]
    os.makedirs(root_folder, exist_ok=True)
    if mode == 1:
        _extract_frame_mode_1(video_capture, frame_list, root_folder, ext)
    elif mode == 2:
        _extract_frame_mode_2(video_capture, frame_list, root_folder, ext)
    video_capture.release()

if __name__ == '__main__':
    video_path = r'D:\peppa\Muddy_Puddles.mp4'
    extract_frame(video_path, increment=30, mode=2)

将图像写为视频

写视频没有那么多需要注意的地方,主要使用的接口函数是cv2.VideoWriter(video_path, fourcc, fps, size),该函数的主要注意点是入参的设置,video_path是输出视频的文件名,fps是帧率,size是视频的宽高,待写入视频的图像的尺寸必需与size一致。其中不太容易理解的是与视频编码相关的fourcc,该参数的设置需要使用另外一个接口函数:cv2.VideoWriter_fourcc(c1, c2, c3, c4),c1-c4分别是四个字符。

示例

因为获取图像的方式多种多样,而写视频又比较简单,所以不太适合将这部分写成函数,下面以一个例子呈现。

video_path = r'D:\peppa\Muddy_Puddles.avi'
root_folder = r'D:\peppa\Muddy_Puddles'

fourcc = cv2.VideoWriter_fourcc('X', 'V', 'I', 'D')
fps = 25
size = (1920, 1080)

video_writer = cv2.VideoWriter(video_path, fourcc, fps, size)
for i in range(0, 7788, 30):
    filename = os.path.join(root_folder, str(i) + '.png')
    image = cv2.imread(filename)
    video_writer.write(image)
video_writer.release()

fourcc

fourcc有时候需要多尝试一下,因为不同电脑里安装的编解码器可能不太一样,不见得随便设置一个参数就一定能成功,fourcc有非常多,比如:

paramters codec extension
(‘P’,‘I’,‘M’,‘1’) MPEG-1 avi
(‘M’,‘J’,‘P’,‘G’) motion-jpeg mp4
(‘M’,‘P’,‘4’,‘V’) MPEG-4 mp4
(‘X’,‘2’,‘6’,‘4’) H.264 mp4
(‘M’, ‘P’, ‘4’, ‘2’) MPEG-4.2  
(‘D’, ‘I’, ‘V’, ‘3’)  MPEG-4.3  
(‘D’, ‘I’, ‘V’, ‘X’) MPEG-4 avi
(‘U’, ‘2’, ‘6’, ‘3’) H263  
(‘I’, ‘2’, ‘6’, ‘3’)  H263I flv
(‘F’, ‘L’, ‘V’, ‘1’)  FLV1  
(‘X’,‘V’,‘I’,‘D’)  MPEG-4 avi
(‘I’,‘4’,‘2’,‘0’)  YUV avi

上表中的后缀名似乎并不需要严格遵守。

以上就是Python+OpenCV读写视频的方法详解的详细内容,更多关于Python OpenCV读写视频的资料请关注我们其它相关文章!

(0)

相关推荐

  • python opencv 读取本地视频文件 修改ffmpeg的方法

    Python + opencv 读取视频的三种情况: 情况一:通过摄像头采集视频 情况二:通过本地视频文件获取视频 情况三:通过摄像头录制视频,再读取录制的视频 摄像头采集.本地视频文件的读取.写视频文件,网上都有代码. 我发现情况一和情况三都没有问题,大家注意读取自己通过摄像头录制的视频文件是没有问题的.但读取其他视频都会发现帧率为0(如果你获取视频的帧率并打印出来的话),并且退出读取.这时候读取是不成功的. 进去正题:如何解决读取视频失败的情况.这个问题很普遍,以至在官方教程的程序下面都提示

  • python-opencv 将连续图片写成视频格式的方法

    如下所示: import cv2 import os #图片路径 im_dir = '/home/suanfa/data/out/201708231503440' #输出视频路径 video_dir = '/home/suanfa/data/out/201708231503440-1018.avi' #帧率 fps = 30 #图片数 num = 426 #图片尺寸 img_size = (841,1023) #fourcc = cv2.cv.CV_FOURCC('M','J','P','G')

  • Python OpenCV读取显示视频的方法示例

    目标 学习读取视频,显示视频和保存视频. 学习从相机捕捉并显示它. 你将学习以下功能:cv.VideoCapture(),cv.VideoWriter() 从相机中读取视频 通常情况下,我们必须用摄像机捕捉实时画面.提供了一个非常简单的界面.让我们从摄像头捕捉一段视频(我使用的是我笔记本电脑内置的网络摄像头) ,将其转换成灰度视频并显示出来.只是一个简单的任务开始. 要捕获视频,你需要创建一个 VideoCapture 对象.它的参数可以是设备索引或视频文件的名称.设备索引就是指定哪个摄像头的数

  • python opencv读mp4视频的实例

    如下所示: #获得视频的格式 videoCapture = cv2.VideoCapture('/home/lw/3661.mp4') #获得码率及尺寸 fps = videoCapture.get(cv2.CAP_PROP_FPS) size = (int(videoCapture.get(cv2.CAP_PROP_FRAME_WIDTH)), int(videoCapture.get(cv2.CAP_PROP_FRAME_HEIGHT))) fNUMS = videoCapture.get(

  • Python OpenCV超详细讲解读取图像视频和网络摄像头

    0.准备工作 右击新建的项目,选择Python File,新建一个Python文件,然后在开头import cv2导入cv2库. 1.读取图像调用imread()方法获取我们资源文件夹中的图片使用imshow()方法显示图片,窗口名称为OutputwaitKey(0)这句可以让窗口一直保持,如果去掉这句,窗口会一闪而过 我们来看下效果: 2.读取视频VideoCapture()方法的参数就是视频文件循环中通过read不断地去读视频的每一帧,再通过imshow显示出来最后if语句代表按q可以退出程

  • 使用python-opencv读取视频,计算视频总帧数及FPS的实现

    如下所示: 1.计算总帧数 import os import cv2 video_cap = cv2.VideoCapture('ffmpeg_test.avi') frame_count = 0 all_frames = [] while(True): ret, frame = video_cap.read() if ret is False: break all_frames.append(frame) frame_count = frame_count + 1 # The value be

  • Python+OpenCV读写视频的方法详解

    目录 读视频,提取帧 接口函数:cv2.VideoCapture() 获取视频信息 使用set(cv2.CAP_PROP_POS_FRAMES)读取指定帧 读取函数(重点) 将图像写为视频 示例 fourcc 读视频,提取帧 接口函数:cv2.VideoCapture() 通过video_capture = cv2.VideoCapture(video_path)可以获取读取视频的句柄.而后再通过flag, frame = video_capture.read()可以读取当前帧,flag表示读取

  • Python+Opencv实战之人脸追踪详解

    目录 前言 人脸追踪技术简介 使用基于 dlib DCF 的跟踪器进行人脸跟踪 使用基于 dlib DCF 的跟踪器进行对象跟踪 小结 前言 人脸处理是人工智能中的一个热门话题,人脸处理可以使用计算机视觉算法从人脸中自动提取大量信息,例如身份.意图和情感:而目标跟踪试图估计目标在整个视频序列中的轨迹,其中只有目标的初始位置是已知的,将这两者进行结合将产生许多有趣的应用.由于外观变化.遮挡.快速运动.运动模糊和比例变化等多种因素,人脸追踪非常具有挑战性. 人脸追踪技术简介 基于判别相关滤波器 (d

  • Python OpenCV使用dlib进行多目标跟踪详解

    目录 1.使用dlib进行多目标跟踪 2.项目结构 3.dlib多对象跟踪的简单“朴素”方法 4.快速.高效的dlib多对象跟踪实现 5.完整代码 6.改进和建议 在本教程中,您将学习如何使用 dlib 库在实时视频中有效地跟踪多个对象. 我们当然可以使用 dlib 跟踪多个对象:但是,为了获得可能的最佳性能,我们需要利用多处理并将对象跟踪器分布在处理器的多个内核上. 正确利用多处理使我们能够将 dlib 多对象跟踪每秒帧数 (FPS) 提高 45% 以上! 1.使用 dlib 进行多目标跟踪

  • 使用Python实现控制摄像头的方法详解

    目录 前言 第一部分:环境搭建 步骤一:安装 Python 步骤二:安装 OpenCV 步骤三:连接摄像头 第二部分:摄像头基本操作 1. 捕获视频帧 2.保存视频 总结 前言 当今,随着计算机技术的发展,摄像头已经成为了人们生活中不可或缺的一部分.而Python作为一种流行的编程语言,也可以轻松地控制和操作摄像头.无论你是想用Python写一个简单的摄像头应用程序,还是想在机器学习和计算机视觉项目中使用摄像头,Python都可以帮助你实现.本文将介绍如何使用Python中的常用库(例如Open

  • python文件处理fileinput使用方法详解

    这篇文章主要介绍了python文件处理fileinput使用方法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 一.介绍 fileinput模块可以对一个或多个文件中的内容进行迭代.遍历等操作,我们常用的open函数是对一个文件进行读写操作. fileinput模块的input()函数比open函数更高效和好用,体现在: input()函数生成一个迭代器,保证了在遇到大文件的读取时不会占用太大的内存. 用fileinput对文件进行循环遍历

  • Python OpenCV实现图像模板匹配详解

    目录 1.什么是模板匹配及模板匹配方法matchTemplate() 介绍 素材准备 2.单模板匹配 2.1 单目标匹配 2.2 多目标匹配 3.多模板匹配 1.什么是模板匹配及模板匹配方法matchTemplate() 介绍 提供一个模板图像,一个目标图像,且满足模板图像是目标图像的一部分,从目标图像中寻找特定的模板图像的过程,即为模板匹配.OpenCV提供了matchTemplate()方法帮助我们实现模板匹配. 该方法语法如下: cv2.matchTemplate(image, templ

  • Python OpenCV之常用滤波器使用详解

    目录 1. 滤波器 1.1 什么是滤波器 1.2 关于滤波核 1.3 素材选择 2.均值滤波器 cv2.blur() 2.1 语法简介 2.2 代码示例 3. 中值滤波器 cv2.medianBlur() 代码示例 4. 高斯滤波器 cv2.GaussianBlur() 5. 双边滤波器 cv2.bilateralFilter() 1. 滤波器 1.1 什么是滤波器 滤波器是对图像做平滑处理 的一种常用工具. 平滑处理即在尽可能地保留原图像信息的情况下,对像素值进行微调,使邻近的像素值之间,值的

  • Python OpenCV实现图形检测示例详解

    目录 1. 轮廓识别与描绘 1.1 cv2.findComtours()方法 1.2 cv2.drawContours() 方法 1.3 代码示例 2. 轮廓拟合 2.1 矩形包围框拟合 - cv2.boundingRect() 2.2圆形包围框拟合 - cv2.minEnclosingCircle() 3. 凸包 绘制 4. Canny边缘检测 - cv2.Canny() 4.1 cv2.Canny() 用法简介 4.2 代码示例 5. 霍夫变换 5.1 概述 5.2 cv2.HoughLin

  • Python特效之数字成像方法详解

    目录 一.特效预览 二.程序原理 三.程序源码 一.特效预览 处理前 处理后 细节放大后 二.程序原理 1.将图片转为灰白图片后,将图片分成了三块,明.暗.阴影区域 2.明区域使用空白进行填充 3.阴影区域使用横线进行填充 4.暗区域使用数字进行填充,通过对暗区域的像素进行分类,不同像素使用不同数字进行填充即可 三.程序源码 #!/usr/bin/env python # encoding: utf-8 import cv2 import random import numpy as np cl

  • Python+Opencv实现图像模板匹配详解

    目录 引言 一.匹配方法 二.匹配单个对象 三.匹配多个对象 引言 什么是模板匹配呢? 看到这里大家是否会觉得很熟悉的感觉涌上心头!在人脸识别是不是也会看见 等等. 模板匹配可以看作是对象检测的一种非常基本的形式.使用模板匹配,我们可以使用包含要检测对象的“模板”来检测输入图像中的对象. 一.匹配方法 cv2.matchTemplate(img, templ, method) 参数:(img: 原始图像.temple: 模板图像.method: 匹配度计算方法) 方法如下: cv2.TM_SQD

随机推荐