基于opencv,使用python提取视频帧以及提取TVL1光流

     处理视频,最常用的开源工具箱非opencv莫属了,python可以很好的支持它。

一 从视频读取帧、得到相关属性、并设置保存哪些帧

     首先;我们得新建一个videocapture对象;

cap=cv2.VideoCapture(videopath)

通过上面建立的对象,可以获取视频的相关属性,一般使用中用到的属性主要有如下:

     cv2.CAP_PROP_FRAME_WIDTH 视频的宽度。

    cv2.CAP_PROP_FRAME_HEIGHT 视频的高度。

    cv2.CAP_PROP_FPS 视频的帧率
通过函数:
 

cap.get(pID) # cap.get(cv2.CAP_PROP_FPS) 

当从视频中读取帧的时候,我们可以设置时间或者帧序数读取指定的帧,通过set函数可以实现:

set(cv2.CAP_PROP_POS_MSEC,time)  #time为设置的时间,以毫秒计(1s = 1000ms)

set(cv2.CAP_PROP_POS_FRAMES,frame)  #frame为帧序数

下面一个实例来展现完整的用法:

cap = cv2.VideoCapture('test.avi') #创建一个视频获取对象
flag = 0  #用于指定帧的序号
fr=1
time=0    #用于指定帧的时长
while (cap.isOpened()):
    cap.set(cv2.CAP_PROP_POS_MSEC,time)
    
    #cap.set(cv2.CAP_PROP_POS_FRAMES,flag) #设置帧数标记
    ret,im = cap.read()#获取图像
    if not ret:  #如果获取失败,则结束
        print("exit")
        break
    #cv2.waitKey(2000)#延时
    #cv2.imshow('a',im)#显示图像,用在循环中可以播放视频
    cv2.imwrite('output/{0:05d}.jpg'.format(fr),im)#保存图片
    time+=50  #设置每隔50ms读取帧
    #flag+=10  #每隔10帧读取一帧
    fr+=1

二 、通过连续的帧提取TVL1光流

安装依赖包:

pip3 install opencv-python==4.1.2.30

pip3 install opencv-contrib-python==4.1.2.30

def cal_for_frames(video_path):
    frames = glob(os.path.join(video_path, '*.jpg'))
    frames.sort()

    flow = []
    prev = cv2.imread(frames[0])
    prev = cv2.cvtColor(prev, cv2.COLOR_BGR2GRAY)
    for i, frame_curr in enumerate(frames[1:]):
        curr = cv2.imread(frame_curr)
        curr = cv2.cvtColor(curr, cv2.COLOR_BGR2GRAY)
        tmp_flow = compute_TVL1(prev, curr)
        flow.append(tmp_flow)
        prev = curr

    return flow


def compute_TVL1(prev, curr, bound=15):
    """Compute the TV-L1 optical flow."""
    TVL1=cv2.optflow.DualTVL1OpticalFlow_create()
    # TVL1 = cv2.DualTVL1OpticalFlow_create()
    # TVL1=cv2.createOptFlow_DualTVL1()
    flow = TVL1.calc(prev, curr, None)
    assert flow.dtype == np.float32

    flow = (flow + bound) * (255.0 / (2 * bound))
    flow = np.round(flow).astype(int)
    flow[flow >= 255] = 255
    flow[flow <= 0] = 0

    return flow


def save_flow(video_flows, flow_path):
    if not os.path.exists(os.path.join(flow_path, 'u')):
        os.mkdir(os.path.join(flow_path, 'u'))
    if not os.path.exists(os.path.join(flow_path, 'v')):
        os.mkdir(os.path.join(flow_path, 'v'))
    for i, flow in enumerate(video_flows):
        cv2.imwrite(os.path.join(flow_path,'u', "{:06d}.jpg".format(i)),
                    flow[:, :, 0])
        cv2.imwrite(os.path.join(flow_path,'v', "{:06d}.jpg".format(i)),
                    flow[:, :, 1])


def extract_flow(video_path, flow_path):
    flow = cal_for_frames(video_path)
    save_flow(flow, flow_path)
    print('complete:' + flow_path)
    return


if __name__ == '__main__':
    video_path=path_to_video  #预先提取好的视频帧
    save_path=path_to_save    #保存光流的路径
    extract_flow(video_path,save_path)

---------------------------------------------------------------------------------------------------------------

import cv2 cap = cv2.VideoCapture(file_path.encode('utf-8')) # file_path是文件的绝对路径,防止路径中含有中文时报错,需要解码
if cap.isOpened(): # 当成功打开视频时
    cap.isOpened()返回True,否则返回False # get方法参数按顺序对应下表(从0开始编号) 
    rate = cap.get(5) # 帧速率
    FrameNumber = cap.get(7) # 视频文件的帧数
    duration = FrameNumber/rate/60 # 帧速率/视频总帧数 是时间,除以60之后单位是分钟 

另外,cv2.VideoCapture(0)是打开本地摄像头

以下是opencv-python可以获取视频的相关信息,可以通过从0开始的序号获取

CAP_PROP_POS_MSEC 视频文件的当前位置(以毫秒为单位)或视频捕获时间戳。
CAP_PROP_POS_FRAMES 接下来要解码/捕获的帧的基于0的索引。
CAP_PROP_POS_AVI_RATIO 视频文件的相对位置:0 - 电影的开始,1 - 电影的结尾。
CAP_PROP_FRAME_WIDTH 视频流中帧的宽度。
CAP_PROP_FRAME_HEIGHT 视频流中帧的高度。
CAP_PROP_FPS 帧速率。
CAP_PROP_FOURCC 编解码器的4字符代码。

CAP_PROP_FRAME_COUNT 视频文件中的帧数。
CAP_PROP_FORMAT 返回的Mat对象的格式 retrieve() 。

CAP_PROP_MODE 指示当前捕获模式的特定于后端的值。
CAP_PROP_BRIGHTNESS 图像的亮度(仅适用于相机)。
CAP_PROP_CONTRAST 图像对比度(仅适用于相机)。
CAP_PROP_SATURATION 图像的饱和度(仅适用于相机)。
CAP_PROP_HUE 图像的色调(仅适用于相机)。
CAP_PROP_GAIN 图像的增益(仅适用于相机)。
CAP_PROP_EXPOSURE 曝光(仅适用于相机)。
CAP_PROP_CONVERT_RGB 布尔标志,指示是否应将图像转换为RGB。
CAP_PROP_WHITE_BALANCE_U 白平衡设置的U值(注意:目前仅支持DC1394 v 2.x后端)
CAP_PROP_WHITE_BALANCE_V 白平衡设置的V值(注意:目前仅支持DC1394 v 2.x后端)
CAP_PROP_RECTIFICATION 立体摄像机的整流标志(注意:目前仅支持DC1394 v 2.x后端)
CAP_PROP_ISO_SPEED摄像机 的ISO速度(注意:目前仅支持DC1394 v 2.x后端)
CAP_PROP_BUFFERSIZE 存储在内部缓冲存储器中的帧数(注意:目前仅支持DC1394 v 2.x后端)

注意:以上属性在获取时,通过对应的编号进行,上面所列出的属性,从0开始编号;

如: cap=cv2.VideoCapture(video_path)

      number_of_frame=cap.get(7)  //获取视频的帧数

来源 opencv-python获取视频时长_weixin_43249191的博客-CSDN博客_opencv获取视频时长
--------------------------------------------------------------------------------------------------------------------------------------------------------------

三、可视化光流

import cv2 as cv
import numpy as np
import os
path = 'path_to_videos'
videos = os.listdir(path)
TVL1 = cv.optflow.DualTVL1OpticalFlow_create()
for video in videos:
    video_path = path + '/' + video
    cap = cv.VideoCapture(video_path)
    ret, frame1 = cap.read()
    prvs = cv.cvtColor(frame1,cv.COLOR_BGR2GRAY)
    hsv = np.zeros_like(frame1)
    hsv[...,1] = 255
    count = 0
    while(True):
        ret, frame2 = cap.read()
        if not ret:
            break
        next = cv.cvtColor(frame2,cv.COLOR_BGR2GRAY)

        # 返回一个两通道的光流向量,实际上是每个点的像素位移值
        flow = TVL1.calc(prvs,next, None)

        # 笛卡尔坐标转换为极坐标,获得极轴和极角
        mag, ang = cv.cartToPolar(flow[...,0], flow[...,1])

        hsv[...,0] = ang*180/np.pi/2  #角度
        hsv[...,2] = cv.normalize(mag,None,0,255,cv.NORM_MINMAX)
        bgr = cv.cvtColor(hsv,cv.COLOR_HSV2BGR)
        path_ = path + '/' + os.path.basename(video).split('.')[0]
        if not os.path.exists(path_):
            os.makedirs(path_)
        cv.imwrite(path_ + "/frame{0:06d}.jpg".format(count), bgr)
        count += 1
        prvs = next
    cap.release()
    cv.destroyAllWindows()

参考资料:win10+python3+opencv3 读取视频中的指定帧并存为图片_li_huifei的博客-CSDN博客

你可能感兴趣的:(opencv,python,音视频)