【Opencv-Python 官方教程】2.视频的存取显示

本节目标

  • 学会读取、显示和保存视频
  • 学会从摄像头捕获视频并显示
  • 将会学到以下几个函数:cv2.VideoCapture()、cv2.VideoWrite()

原文地址:Getting Started with Videos


从摄像头捕获视频

通常,我们需要从摄像设备捕获在线的视频流,Opencv为此提供了非常简便的操作接口。这里我将使用我的笔记本内置的摄像头,然后捕获视频,转换成灰度视频,并显示。

为了捕获视频,首先你需要创建一个VideoCapture对象,它的构造参数既可以是设备索引(device index)也可以是视频文件名。设备索引是一个数字用以指定是哪个摄像头,通常情况下设备都装载一个摄像头,所以只需要简单的传递参数0(或者-1)就可以了,你可以选择传1或者其他来选择第二个摄像设备。之后你就能逐帧捕获视频了。最后,不要忘记释放设备资源。代码如下

import numpy as np
import cv2

cap = cv2.VideoCapture(0)
while(True):
    # 逐帧捕获视频
    ret, frame = cap.read()
    # 对帧操作: 转成灰度图
    gray = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
    # 显示视频帧
    cv2.imshow('frame',gray)
    # 1毫秒显示逐帧显示,按q退出
    if cv2.waitKey(1) == ord('q'):
        break

# 释放资源
cap.release()
cv2.destroyAllWindows()

cap.read()返回一个bool类型的结果,用来表示视频帧是否被正确读取,True正确。故你可以通过检查这个返回值来检查视频的结尾。

有时,cap可能没有获取到初始化好的设备,这种情况下,这个代码将会显示error,你可以用过调用方法:cap.isOpened()来检查设备是否已经初始化完成。如果返回True表示完成,否则你需要手动调用cap.open()来打开它。

cap = cv2.VideoCapture(0)
if (not cap.isOpened()):
    cap.open(0)
cap.read()  
# ... some other operations

你也可以通过方法cap.get(propId)访问该视频的其他熟悉,此处propId是一个从0到18的数字。每一个数字代表一个属性(若该属性在该video可用的话)。全部的属性标识见下表。你可以通过方法cap.set(propId,value)修改这些属性值,参数value就是你想要修改的目标值。

propId property
CV_CAP_PROP_POS_MSEC 当前帧在视频中的位置(毫秒)或是在线捕获视频的时间戳
CV_CAP_PROP_POS_FRAMES 以0开始的下一个被解码(视频文件)/ 捕获(在线视频流)的帧的索引
CV_CAP_PROP_POS_AVI_RATIO 当前帧的相对位置,0表示视频开始帧,-1表示视频结尾
CV_CAP_PROP_FRAME_WIDTH 视频流中一帧图像的宽度
CV_CAP_PROP_FRAME_HEIGHT 视频流中一帧图像的高度
CV_CAP_PROP_FPS 帧率,FPS
CV_CAP_PROP_FOURCC 编译码的4字符码【1】
CV_CAP_PROP_FRAME_COUNT 视频文件的总帧数
CV_CAP_PROP_FORMAT retrieve()返回的Mat对象的格式
CV_CAP_PROP_MODE 后端特定值,用来指示当前捕获模式
CV_CAP_PROP_BRIGHTNESS 图像的亮度(仅相机设备可用)
CV_CAP_PROP_CONTRAST 图像的对比度(仅相机设备可用)
CV_CAP_PROP_SATURATION 图像的饱和度(仅相机设备可用)
CV_CAP_PROP_HUE 图像的色调(仅相机设备可用)
CV_CAP_PROP_GAIN 图像的增益(仅相机设备可用)
CV_CAP_PROP_EXPOSURE 图像的曝光(仅相机设备可用)
CV_CAP_PROP_CONVERT_RGB 一个bool类型的标志用来指示是否图像需要被转换成RGB图像(通道顺序)
CV_CAP_PROP_WHITE_BALANCE_U 白平衡的U值(仅支持DC1394 v2.x)
CV_CAP_PROP_WHITE_BALANCE_V 白平衡的V值(仅支持DC1394 v2.x)
CV_CAP_PROP_RECTIFICATION 立体相机的校正标志
CV_CAP_PROP_ISO_SPEED 相机的ISO(感光速率)
CV_CAP_PROP_BUFFERSIZE 当前存于缓冲中的帧的总数

【1】关于解码器的四字符表示:比较全的fourcc含义

若出现error,请在其他应用中使用摄像头以确保设备是可以正常工作的


播放视频文件

这和使用摄像设备捕获实时视频流一样,只需要将camera的参数从index变成视频文件名即可。同样,我们还是推荐在播放视频帧的时候,使用cv2.waitKey()并设置合适的时间参数,如果设置太小,视频会加速播放,太大又会视频变慢。通常25milliseconds是比较合适的值。

import numpy as np
import cv2

cap = cv2.VideoCapture('image\\test2.mp4')

while(cap.isOpened()):
    ret, frame = cap.read()
    # 这里必须判断视频是否读取完毕,否则最后一帧播放出现问题
    if ret == True:
        #gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        #cv2.imshow('frame', gray)
        cv2.imshow('frame',frame)
        if cv2.waitKey(1) == ord('q'):
            break
    else:
        break

cap.release()
cv2.destroyAllWindows()
  • 问题1:cap = cv2.VideoCapture('image\\test2.mp4'),这个路径一定要小心,路径的分隔符最好写成‘\\’形式,而不要写成image/test2.mp4,我的理解是,这个路径会送到ffmpeg中,ffmpeg是c++实现的库,它在拼接路径的时候不能识别第二种在Python中常用的路径形式。
  • 问题2:英文原文给出的demo代码中,没有对ret做判断,这会导致视频播放最后一帧出错,因为视频最后会捕获到一个空帧,此时再操作frame,就会error。而ret是一个标志,指示这个frame是否有效。false表示frame为空,也可认为是视频结尾。

请确保安装好了合适版本的ffmpeg或是gstreamer。大多数时候在视频捕获、播放中的那些令人头疼的错误是源自于ffmpeg/gstreamer安装不当。


保存视频

当我们捕获到视频,逐帧处理之后,我们可能想要去保存视频。若是图片,简单的调用cv2.imwrite()即可。那么视频就需要稍微复杂一些了。

我们需要先创建一个VideoWrtie对象,需要指定输出的文件名(如output.avi)。之后我们应该指定FourCC码(下文会说到其细节)。然后是FPS以及帧的大小(frame size),最后是标志isColor,若是True,表示编码的时候得到彩色帧,否则是灰度帧。

FourCC是一种4字节码,用于去指定视屏的编码解码器。在fourcc.org可以找到一系列可用的码值,它依赖于具体的平台,笔者的平台可用以下编解码器

  • Fedora:DIVX, XVID, MJPG, X264, WMV1, WMV2. (XVID更好, MJPG会产生很大的视频文件 ,X264得到小文件的视频 )
  • Windows:DIVX

FourCC码可以在调用函数的时候这样传递,以MJPG为例。cv2.VideoWriter_fourcc('M','J','P','G')或者cv2.VideoWriter_fourcc(*'MJPG)

【Wiki】FourCC

下面的代码演示从相机捕获视频,然后逐帧反正之后保存。

cv2.flip(frame, 0),第一个参数为帧对象,第二个是反正操作标志,取值如下

  • 1,水平反转
  • 0,垂直翻转
  • -1,水平垂直翻转
import numpy as np
import cv2

cap = cv2.VideoCapture(0)
# 定义编解码器,创建VideoWriter对象
fourcc = cv2.VideoWriter_fourcc(*'XVID')
# 参数依次为:out_file_name, codec, fps, frame_size, isColor(default=True)
out = cv2.VideoWriter('output.avi', fourcc, 20.0, (640, 480))

while (cap.isOpened()):
    ret, frame = cap.read()
    if ret == True:
        # 垂直翻转
        frame = cv2.flip(frame, 0)
        # 将数据帧写入out对象(VideoWriter对象)
        out.write(frame)
        # 播放帧
        cv2.imshow('frame', frame)
        if cv2.waitKey(1) == ord('q'):
            break
    else:
        break

# 释放资源
cap.release()
out.release()
cv2.destroyAllWindows()

猜你喜欢

转载自blog.csdn.net/u013095718/article/details/80422909