背景:为了做一个滴水检测的demo,自己配置了滴水装置的实验环境,需要用摄像头实时拍摄滴水画面,进行检测,生成滴水位置的bbox,保存检测后的视频。opencv可以实时捕捉usb摄像头拍摄的画面,因此稍微学习了一下
通常,我们必须用摄像机捕捉直播。OpenCV提供了一个非常简单的接口来实现这一点。让我们从相机捕捉视频(我使用的是usb摄像头),将其转换成灰度视频并显示出来。
要捕获视频,需要创建VideoCapture的对象cap。它的参数可以是设备索引或视频文件的名称。设备索引只是指定哪个摄像头的数字。通常电脑内置摄像头的设备索引是0,外接的usb摄像头是1,以此类推。之后就可以逐帧捕获usb摄像头拍摄的视频。任务的最后,要release VideoCapture的对象cap。
要保存视频,我们需要创建一个VideoWriter对象out。传入的参数包括:输出文件名(例如:output.avi)、FourCC代码(详见下一段)。然后每秒帧数(fps)、帧大小。最后一个是isColor的flag,如果为True,表示输入视频编码器的是color frame,否则使用greyscale frame。
FourCC是一个4字节的代码,用来指定视频的编码解码器。对于XVID格式的编码解码器,传递cv.VideoWriter_fourcc('M','J','P','G')
或cv.VideoWriter_fourcc(*'MJPG')
。一般我们使用XVID格式的编码解码器,对应的视频后缀是.avi
有时,cap可能没有初始化。我们可以通过cap.isOpened()方法检查它是否被初始化,如果是False,使用cap.open()打开它。
cap.get(propId)方法访问本视频的一些属性,比如fps和分辨率,其中propId可以是一个从0到18的数字,每个数字表示视频的一个属性,也可以直接是属性的名称,比如cv2.CAP_PROP_FPS表示帧速率。
cap.set(propId, value)可以修改视频的属性,比如帧速、分辨率,value是你想要的新值。
import cv2
import numpy as np
# 创建VideoCapture的对象cap。传入的参数可以是设备索引1,也可以是自己本地的视频
cap = cv2.VideoCapture(1)
video_path = 'C:\\Users\\HP\\Desktop\\Accusefive.mp4'
#cap = cv2.VideoCapture(video_path)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1920)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 1080)
fps = cap.get(cv2.CAP_PROP_FPS) #获取视频的帧率
# 生成fourcc code
fourcc = cv2.VideoWriter_fourcc(*'XVID')
# 需要保存,创建VideoWriter对象out
out = cv2.VideoWriter('C:\\Users\\HP\\Desktop\\vv.avi', fourcc, 20.0, (640, 480))
# 确保cap打开了
if not cap.isOpened():
print("cap is not opened, open the cap")
cap.open()
exit()
else:
print('cap is opened, read the video stream...')
# 使用一个While循环不间断地对usb摄像头进行读取,一直到遇到键盘终止事件时break掉
while cap.isOpened():
# 使用cap.read()从摄像头读取一帧
ret, frame = cap.read()
# 用read()返回的布尔值ret判断有没有正确读取到
if not ret:
print(' cannot receive frames(stream end?). Exiting...')
break
# frame = cv.flip()
# 写入对象out调用write()写入这一帧
out.write(frame)
# 同时,把我们写入视频的这一帧显示出来,这样能实时看到我们处理和保存的内容
cv2.imshow('frame', frame)
# 等待1ms按键事件,如果未在规定时间按键,返回-1.如果在规定时间按键,返回所按键的ascII码值
if cv2.waitKey(1) == ord('q'):
break
# release你的cap对象和out对象
cap.release()
out.release()
cv2.destroyAllWindows() # 销毁所有打开的HighGUI窗口。
cap.read() 实时地从摄像机读取一个视频帧,read()返回一个布尔值和读取的帧,如果视频帧正确地读取了,该布尔值为True,否则为False。因此我们可以通过判断这个布尔值确定if the frame is received correctly.
out.write(frame) 把当前的帧frame写入目的视频中,VideoWriter对象out调用write()方法
cv2.imshow(‘frame’, frame) 传入一张图片,通过窗口显示这张图片,第一个参数是窗口的名称。
cv2.waitKey(1) 程序会卡在这里,等待一个按键的事件,等待时间即为传入的t毫秒。
retval = cv.waitKey( [,delay])
当delay≤0时,函数waitKey无限等待键事件(即按下按键),当delay>0时,等待正数时长的延迟(单位:毫秒)。如果在延迟时长之内有按键,则返回该按键的ASCII码,如果在延迟时长内没有按键发生,返回-1。
因此在显示的窗口中播放的视频的速率,限制因素不是视频的fps,而是等待代码waitKey(10)所花费的时间,该代码使程序在每帧之间等待10ms。如果设为150,窗口中视频将看起来非常慢。