opencv-python 视频处理

发布时间 2023-08-10 21:52:28作者: 寒水浮云

视频是由图片组成的,视频的每一帧就是一幅图片,一般是30帧,表示一秒钟显示30张图片。

opencv中可以用 VideoCapture 来捕获摄像头,用数字表示不同的设备,比如0,1。如果是视频文件,直接指定路径即可。

VideoCapture 类提供了初始化,打开视频文件或设备,视频帧捕获,视频文件或设备关闭,属性设置或获取等功能。

其成员函数isOpened用来检查视频是否能成功打开。

其成员函数get用于获取视频的一些参数或属性,比如帧率(cv2.CAP_PROP_FPS),视频的宽(cv2.CAP_PROP_FRAME_WIDTH),视频的高(cv2.CAP_PROP_FRAME_HEIGHT),视频的总帧数(cv2.CAP_PROP_FRAME_COUNT)。

其成员函数read用于捕获,解码并返回下一帧的视频图像。

1 视频读取

首先用video = cv2.VideoCapture('test.mp4') 来捕获视频类,然后用video.isOpened() 判断是否打开成功,如果打开成功,用video.read() 来循环读取每一帧图片,然后依次显示图片,waitKey可以控制帧率。

import cv2   #打开/显示视频 

video = cv2.VideoCapture('D:/05.OpenCV图像处理课程资料/第2-7章notebook课件/图像操作/test.mp4') #参数改成0可以直接打开设备的摄像头

if video.isOpened():
    print('视频打开成功')
     
    while True:
        ret,frame = video.read()  # ret 视频捕获成功的标志,没有视频帧时返回false;frame 返回视频帧图像
        if ret == False:  #只要视频帧还没结束就继续读取
            break
        else:
            cv2.imshow('frame',frame) #显示视频帧 
            if cv2.waitKey(10) == ord('q'): #按q结束视频播放
                break
            
else:
    print('视频打开失败')
video.release()  #释放设备资源然后关闭显示窗口
cv2.destroyAllWindows()

如果要打开摄像头并显示图像的话,直接把代码中的捕获视频类改成 device = cv2.VideoCapture(0) 即可。

2 获取视频某些帧保存为图片

1)获取视频前两帧的图片

import cv2  

video = cv2.VideoCapture('D:/05.OpenCV图像处理课程资料/第2-7章notebook课件/图像操作/test.mp4') #初始化视频类

if video.isOpened():   #video视频对象的成员函数,判断视频是否成功打开,返回bool类型
    print('视频打开成功')
    
    fps = video.get(cv2.CAP_PROP_FPS) #获取视频的帧率
    fcount = video.get(cv2.CAP_PROP_FRAME_COUNT) #获取视频的总帧数
    width = video.get(cv2.CAP_PROP_FRAME_WIDTH) #获取视频的宽
    height = video.get(cv2.CAP_PROP_FRAME_HEIGHT) #获取视频的高
    print('fps:',fps,'fcount:',fcount,'width:',width,'height:',height)
    
    i=0
    while True:
        if i==2:
            break   #获取视频的前两帧
        else:
            i=i+1
            ret,frame = video.read() #读取视频
            cv2.imshow('frame'+str(i),frame) #显示视频帧
            cv2.waitKey(0)
else:
    print('视频打开失败')
cv2.destroyAllWindows()

2)截取视频的前n帧图像,保存到文件夹中

import cv2  #截取视频的前n帧图像,保存到文件夹中

frameNum=20  #需要截取的视频帧数

video = cv2.VideoCapture('D:/05.OpenCV图像处理课程资料/第2-7章notebook课件/图像操作/test.mp4') #初始化视频类

if video.isOpened():   #video视频对象的成员函数,判断视频是否成功打开,返回bool类型
    print('视频打开成功')
    
    i=0 
    while True:
        if i==frameNum:
            break   #获取视频的前两帧
        else:
            i=i+1
            ret,frame = video.read() #读取视频
          #  cv2.imshow('frame'+str(i),frame) #显示视频帧
            cv2.imwrite('C:/Users/86188/Desktop/opencv/images/'+str(i)+'.png',frame)
            cv2.waitKey(0)
else:
    print('视频打开失败')
cv2.destroyAllWindows()

3)将视频分割为单帧图片并保存到指定文件夹,方法一(视频结束就停止读取保存图片,最终的图片数量时是609)

import cv2  

video = cv2.VideoCapture('D:/05.OpenCV图像处理课程资料/第2-7章notebook课件/图像操作/test.mp4') #初始化视频类

if video.isOpened():   #video视频对象的成员函数,判断视频是否成功打开,返回bool类型
    print('视频打开成功')
    
    i=0
    while True:
        ret,frame = video.read() #读取视频
        if ret==False:
            break   #只要视频帧还没结束就继续读取
        else:
            i=i+1
            cv2.imwrite('C:/Users/86188/Desktop/opencv/images1/'+str(i)+'.png',frame)
            cv2.waitKey(0)
    print('i:',i)
else:
    print('视频打开失败')
cv2.destroyAllWindows()

4)将视频分割为单帧图片并保存到指定文件夹,方法二(先计算视频帧总数,将所有视频帧读取保存,最终的图片数量时是622,609之后的图像是空的)

import cv2  

video = cv2.VideoCapture('D:/05.OpenCV图像处理课程资料/第2-7章notebook课件/图像操作/test.mp4') #初始化视频类

fcount = video.get(cv2.CAP_PROP_FRAME_COUNT) #获取视频的总帧数
if video.isOpened():   #video视频对象的成员函数,判断视频是否成功打开,返回bool类型
    print('视频打开成功')
    
    i=0
    while True:
        ret,frame = video.read() #读取视频
        if i==fcount:
            break   #只要视频帧还没结束就继续读取
        else:
            i=i+1
            cv2.imwrite('C:/Users/86188/Desktop/opencv/images2/'+str(i)+'.png',frame)
            cv2.waitKey(0)
    print('i:',i)
else:
    print('视频打开失败')
cv2.destroyAllWindows()

3 视频保存

opencv中提供了用于视频保存的类VideoWriter,该类可以将图像文件写入到视频文件中。

VideoWriter第一个参数filename表示目标存储的文件名或路径;第二个参数是fourcc,该参数由cv2.VideoWriter_fourcc返回。

VideoWriter_fourcc(c1, c2, c3, c4) -> retval   

c1, c2, c3, c4 表示4字符 编码,表示视频编码格式,常用的有:

‘I’,‘4’,‘2’,‘0’ 或 *'I420':未压缩的YUV颜色编码,4:2:0色度子采样,兼容性好,但文件较大,文件扩展名.avi。

 ‘P’,‘I’,‘M’,‘1’ 或 *‘PIM1‘:MPEG-1编码类型,文件扩展名.avi。随机访问,灵活的帧率、可变的图像尺寸。

‘X’,‘V’,‘I’,‘D’ 或 *'XVID':MPEG-4编码类型,视频大小为平均值,MPEG4所需要的空间是MPEG1的1/10,它对运动物体可以保证有良好的清晰度,间/时间/画质具有可调性。文件扩展名.avi。

‘M’,‘P’,‘4’,‘V’ 或 *'MP4V':MPEG-4编码,这种编码器常用于存储和传输视频文件,例如MP4格式。

1)保存相机采集的视频

import cv2

device = cv2.VideoCapture(0) #用相机设备初始化视频捕获类

fourcc = cv2.VideoWriter_fourcc('I','4','2','0')  #创建视频编解码器

fps = device.get(cv2.CAP_PROP_FPS)  #没法直接获取摄像头的fps,只能逐步遍历每一帧并将当前帧数除以当前时间获得fps
print(fps)
width = device.get(cv2.CAP_PROP_FRAME_WIDTH)
height = device.get(cv2.CAP_PROP_FRAME_HEIGHT)

size = (int(width),int(height))

video = cv2.VideoWriter('./video_capture.avi',fourcc,25,size) #创建视频写入对象,这里直接用fps会报错,返回的fps为0

if video.isOpened():
    if device.isOpened():
        print('摄像头打开成功')
        while True:
            ret,frame = device.read()
            video.write(frame)
            cv2.imshow('device_frame',frame)
            if cv2.waitKey(1) == ord('q'):
                break
        device.release()
        cv2.destroyAllWindows()
    else:
        print('摄像头打开失败')
else:
    print('视频保存失败')
print(fps) 

通过VideoWriter创建视频写入对象,然后循环中用write把每一帧图像保存到文件对象中。摄像头采集的视频保存到当前文件夹下,文件名为 video_capture,文件格式为avi类型。

可以自定义视频的尺寸,也可以保存为mp4格式:

import cv2

device = cv2.VideoCapture(0)

fourcc = cv2.VideoWriter_fourcc(*'mp4v')   #mp4格式的编码

video = cv2.VideoWriter('./output.mp4',fourcc,20,(640,480))

if device.isOpened():
    print('success')
    while True:
        ret,frame = device.read()
        if ret == False:
            break
        else:
            video.write(frame)
            cv2.imshow('frame',frame)
            if cv2.waitKey(1) == ord('q'):
                break
else:
    print('failed')
device.release()
video.release()
cv2.destroyAllWindows()

2)用图片文件创建视频

方法一:知道图片路径和图片名,图片名命名规范(如1.png,2.png),可以直接根据图片文件名称依次读入到视频文件中。

import cv2  #将images2文件夹下的图像合并为视频,方法一

path = './images2/'

fourcc = cv2.VideoWriter_fourcc('I','4','2','0')  ##创建视频编解码器

fps = 2  #视频帧,每秒钟2帧图像
size = (960,544) #设置带转换图像的尺寸

video = cv2.VideoWriter('./images2/img2video.avi',fourcc,fps,size)  #创建视频写入对象
if video.isOpened():
    for item in range(622):  #遍历图像并将其写入视频文件
        item = str(item+1)
        item = path + item + '.png' #图片路径
        img = cv2.imread(item)  #把图片读取出来
        video.write(img)  #写入到视频对象中
        print(item)
    video.release()
    print('sucess')
else:
    print('video failed') 

方法二:用listdir返回文件中的所有图片(注意:返回的list列表是按照二进制进行排序,所以对于其他字符来说可能是乱序的)。然后用sort函数对图片进行排序,最后根据图片文件名称依次读入到视频文件中。

import os  #文件操作库  将images1文件夹下的图像合并为视频,方法二
import cv2

path = './images1/'
filelist = os.listdir(path) #返回一个list列表,列表包含path中的所有文件,按照二进制进行排序,所以对于其他字符来说可能是乱序的
# filelist.remove('img2video.avi')  #删除filelist中的avi视频,否则下面切片分割的时候,img2video没法转换成int会报错

filelist.sort(key=lambda x:int(x.split('.')[0]))  #sort是排序函数,参数key可以自定义排序的标准,lambda是匿名函数,split()是分割函数,[0]取第一个切片
# filelist.sort(key=lambda x:int(x[:-4])  # x[:-4] 取倒数第四个之前的字符
print(filelist)

fourcc = cv2.VideoWriter_fourcc('I','4','2','0')  #创建视频编解码器

fps = 25  #视频帧,每秒钟25帧图像
size = (960,544)  #设置带转换图像的尺寸

video = cv2.VideoWriter('./images1/img2video.avi',fourcc,fps,size)   #创建视频写入对象
if video.isOpened():
    for item in filelist:  #遍历图像并将其写入视频文件
        if item.endswith('.png'):   #将后缀为png的图像写入视频
            item = path + item
            img = cv2.imread(item)
            video.write(img)
    video.release()  #释放资源
    print('sucess')
else:
    print('video failed')