由于本人的项目需要对一小段一小段的视频进行研究提取特征,所以目前首要任务是将我录制的长视频剪辑成一小段一小段的视频。
代码参考链接:
import cv2
cap = cv2.VideoCapture("F:/datasets_1/video_1.mp4") #获取视频(用绝对路径)
#cv2.videocapture读取视频必须要绝对路径正确,要用/,不用\
cap.isOpened() #判断视频是否能顺利打开读取,True为能打开,False为不能打开
#获取视频信息
width = cap.get(cv2.CAP_PROP_FRAME_WIDTH)
height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT) #获得视频帧宽和帧高
print(width, height)
if cap.isOpened(): #当成功打开视频时cap.isOpened()返回True, 否则返回False
rate = cap.get(5) #cap.get()括号中的参数为5代表获取帧速率
FrameNumber = int(cap.get(7)) #获取视频文件的总帧数
duration = FrameNumber/rate #视频总帧数除以帧速率等于视频时间,除以60之后的单位就是分钟
fps = int(rate)# 每一段小视频帧数(我这个视频1秒钟的视频17帧),也用于后面的写入视频的帧速率
print(rate)
print(FrameNumber)
print(duration)
print(fps)
success, frame = cap.read()
#cap.read() 返回一个布尔值给sucess(True/False)。如果帧读取的是正确的,
#就是True。所以最后你可以通过检查他的返回值来查看视频文件是否已经到
#了结尾。返回视频帧给frame
print(success)
print(frame) #打印出来的是帧图像的矩阵(为三维矩阵)
i = 0
while (True):
success, frame = cap.read()
# cap.read()表示按帧读取视频,success,frame获得cap.read()的两个返回值
# 其中success是布尔值,取帧是正确的则返回TRUE,如果文件读到结尾它的返回值就是False
# frame就是每一帧图像,是一个三维矩阵
if success:
i += 1
if (i % (5*fps) == 1): #每5秒保存一段小视频,每一秒的视频有17帧,这里一共保存了5秒(如果你想保存其他时长的视频,你只需要更改5这个数字)
# cap.read()按帧读取视频,每读取一帧,i就+1,
# 当读取到的帧数能整除每段小视频的帧数了,那就把视频保存下来
videoWriter = cv2.VideoWriter(str(i) + '.mp4', cv2.VideoWriter_fourcc('D', 'I', 'V', 'X'), fps, (int(width), int(height)))
#videoWriter = cv2.VideoWriter(str(i) + '.mp4', -1, fps, (int(width), int(height)))
# 分别是:保存文件名、编码器、帧率、视频宽高
# 视频全部保存在了本代码所在的文件夹中,若你保存的小视频长度都为1秒,因为保存的是帧速率大小的帧图像,也就是每秒17帧的速率,就刚好保存了每秒17帧的小视频
videoWriter.write(frame) # 写入帧图像
else:
videoWriter.write(frame)
else:
print('end')
break
cap.release() #释放摄像头
1. cap = cv2.VideoCapture(0)
打开视频
VideoCapture()
中参数是0,表示打开笔记本的内置摄像头,参数是视频文件路径则打开视频,如cap = cv2.VideoCapture("F:/datasets_1/video_1.mp4")
**注意:**cv2.videocapture()读取视频必须要绝对路径正确,要用/,不用\。如果这里路径写法不正确就打不开你的视频。
2. cap.isOpened()
判断视频是否能顺利打开读取,True为能打开,False为不能打开
3. cap.read()
返回一个布尔值(True/False)。如果帧读取的是正确的,
就是True。所以最后你可以通过检查他的返回值来查看视频文件是否已经到
了结尾
4. success, frame = cap.read()
cap.read()
表示按帧读取视频,success, frame
是获cap.read()
方法的两个返回值。其中success
是布尔值,如果读取帧是正确的则返回True
,如果文件读取到结尾,它的返回值就为False
。frame
就是每一帧的图像,是个三维矩阵。
5. OpenCV VideoCapture.get()
参数详解
函数cap.get(propId) 来获得视频的一些参数信息。这里
propId 可以是0 到18 之间的任何整数。每一个数代表视频的一个属性,见下表:
参考链接:
https://www.jianshu.com/p/676bef32e655
param | define |
---|---|
cv2.VideoCapture.get(0) | 视频文件的当前位置(播放)以毫秒为单位 |
cv2.VideoCapture.get(1) | 基于以0开始的被捕获或解码的帧索引 |
cv2.VideoCapture.get(2) | 视频文件的相对位置(播放):0=电影开始,1=影片的结尾。 |
cv2.VideoCapture.get(3) | 在视频流的帧的宽度 |
cv2.VideoCapture.get(4) | 在视频流的帧的高度 |
cv2.VideoCapture.get(5) | 帧速率 |
cv2.VideoCapture.get(6) | 编解码的4字-字符代码 |
cv2.VideoCapture.get(7) | 视频文件中的帧数 |
cv2.VideoCapture.get(8) | 返回对象的格式 |
cv2.VideoCapture.get(9) | 返回后端特定的值,该值指示当前捕获模式 |
cv2.VideoCapture.get(10) | 图像的亮度(仅适用于照相机) |
cv2.VideoCapture.get(11) | 图像的对比度(仅适用于照相机) |
cv2.VideoCapture.get(12) | 图像的饱和度(仅适用于照相机) |
cv2.VideoCapture.get(13) | 色调图像(仅适用于照相机) |
cv2.VideoCapture.get(14) | 图像增益(仅适用于照相机)(Gain在摄影中表示白平衡提升) |
cv2.VideoCapture.get(15) | 曝光(仅适用于照相机) |
cv2.VideoCapture.get(16) | 指示是否应将图像转换为RGB布尔标志 |
cv2.VideoCapture.get(17) | × 暂时不支持 |
cv2.VideoCapture.get(18) | 立体摄像机的矫正标注(目前只有DC1394 v.2.x后端支持这个功能) |
具体属性名及英文说明:
属性名 | 说明 |
---|---|
CV_CAP_PROP_POS_MSEC | Current position of the video file in milliseconds or video capture timestamp. |
CV_CAP_PROP_POS_FRAMES | 0-based index of the frame to be decoded/captured next. |
CV_CAP_PROP_POS_AVI_RATIO | Relative position of the video file: 0 - start of the film, 1 - end of the film. |
CV_CAP_PROP_FRAME_WIDTH | Width of the frames in the video stream. |
CV_CAP_PROP_FRAME_HEIGHT | Height of the frames in the video stream. |
CV_CAP_PROP_FPS | Frame rate. |
CV_CAP_PROP_FOURCC | 4-character code of codec. |
CV_CAP_PROP_FRAME_COUNT | Number of frames in the video file. |
CV_CAP_PROP_FORMAT | Format of the Mat objects returned by retrieve() . |
CV_CAP_PROP_MODE | Backend-specific value indicating the current capture mode. |
CV_CAP_PROP_BRIGHTNESS | Brightness of the image (only for cameras). |
CV_CAP_PROP_CONTRAST | Contrast of the image (only for cameras). |
CV_CAP_PROP_SATURATION | Saturation of the image (only for cameras). |
CV_CAP_PROP_HUE | Hue of the image (only for cameras). |
CV_CAP_PROP_GAIN | Gain of the image (only for cameras). |
CV_CAP_PROP_EXPOSURE | Exposure (only for cameras). |
CV_CAP_PROP_CONVERT_RGB | Boolean flags indicating whether images should be converted to RGB. |
CV_CAP_PROP_WHITE_BALANCE | Currently not supported |
CV_CAP_PROP_RECTIFICATION | Rectification flag for stereo cameras (note: only supported by DC1394 v 2.x backend currently) |
Note: 如果查询的视频属性是VideoCapture类不支持的,将会返回0
6. 保存视频
在我们捕获视频,并对每一帧都进行加工之后我们想要保存这个视频。对于图片来时很简单只需要使用 cv2.imwrite()
。但对于视频来说就要多做点工作。以上面的代码为例cv2.VideoWriter(str(i) + '.mp4', cv2.VideoWriter_fourcc('D', 'I', 'V', 'X'), fps, (int(width), int(height)))
cv.videoWriter()
写入视频:
str(i)+'.mp4'
cv2.VideoWriter_fourcc()
函数的作用是输入四个字符代码即可得到对应的视频编码器。CV_FOURCC获取编码格式编码:
CV_FOURCC(‘P’, ‘I’, ‘M’, ‘1’) = MPEG-1 codec
CV_FOURCC(‘M’, ‘J’, ‘P’, ‘G’) = motion-jpeg codec
CV_FOURCC(‘M’, ‘P’, ‘4’, ‘2’) = MPEG-4.2 codec
CV_FOURCC(‘D’, ‘I’, ‘V’, ‘3’) = MPEG-4.3 codec
CV_FOURCC(‘D’, ‘I’, ‘V’, ‘X’) = MPEG-4 codec (mp4可以用这个)
CV_FOURCC(‘U’, ‘2’, ‘6’, ‘3’) = H263 codec CV_FOURCC(‘I’, ‘2’, ‘6’, ‘3’) = H263Icodec
CV_FOURCC(‘F’, ‘L’, ‘V’, ‘1’) = FLV1 codec
扩展理解:
参考链接:
7. 遇到无法保存视频的问题
*可能的问题:*选择编码器错误
*解决办法一:*若是你不知道选择什么编码,或者是运行环境没有相对应的视频编码器,故无法生成视频,或者是第二个参数设置不合适,你可以将cv2.VideoWriter()
函数中的第二个参数设为-1
**,程序运行时则会交互的弹出一个对话框,让你从已有的编码中选择一个。
例:v = cv2.VideoWriter('output_video.mp4', -1, fps, size)
*解决办法二:*直接查看你电脑中现有的编码器有哪些。
如果你不能正常保存视频,也有可能是你的系统没有对应的编码库。指的是MJPEG 编码格式,那么需要你的系统里支持MJPEG编码(光支持解码是不够的)。我的系统里面安装了ffmpeg, 在我编译opencv库时已经配置了这一选项。因此ffmpeg支持的编解码库,我的opencv 也是支持的。现在我们来查看我的电脑里面的ffmpeg支持的编解码形式。
在你的终端中输入命令:
ffmpeg -codecs
查询ffmpeg支持的编解码形式
或者输入:
ffmpeg -codecs | grep 264
查询是否支持264编码
如下图所示,我的电脑中有decoder也有encoder,且支持MPEG,所以我直接使用CV_FOURCC('D', 'I', 'V', 'X')
即可。
参考链接:
8. 调用release()
释放摄像头
为了将长视频剪成批量的小视频,我还花了挺长时间来找合适的方式的,还好最后去尝试了这种方法。其实我早几天前已经看到相似的代码了,但是我没有去尝试,主要是自己对OpenCV处理视频图像的代码太不熟悉了,自己看不懂代码,所以导致自己错过了正确的解决方法。所以以后要解决问题的时候,先要把代码看懂,才能真正的解决一个问题。