OpenCV C++简单的视频读取和保存入门
1 视频编码概述
根据百度百科的定义,视频编码本质上就是一种视频的压缩技术,不同的视频编码方式代表不同的压缩方式,其压缩率和视频质量都存在一定的差异。不同编码的视频往往需要通过工具进行视频格式转换。目前来说,视频流传输中最为重要的编解码标准有:国际电联的H.263、H.264和H.265;运动静止图像专家组的M-JPEG;运动图像专家组的MPEG系列标准。
视频的本质可以看作是连续的图像序列,图像序列中的每一个图像被称为帧,换句话说:一帧就是一幅图像。由于人眼的视觉暂留效应,当帧序列以一定的速率播放时,比如1秒24帧,那么往我们看到的就是连续的动作比较流畅的视频。由于连续的帧之间相似性极高,为便于储存传输,需要对原始的视频进行编码压缩,以去除空间、时间维度的冗余。
2 重要的视频编码概述
视频编码方式非常的多,但是基于标准的视频编码系列可以总结如下几类 :(1)MPEG系列,由ISO(国际标准组织机构)下属的运动图象专家组开发的视频编码方案,其中主要是Mpeg1(VCD)、Mpeg2(DVD)、Mpeg4(如divx,xvid等)、Mpeg4 AVC。主要应用于视频存储、广播电视、互联网或无线网络的流媒体等。(2)H.26X系列,侧重网络传输,主要应用于实时视频通信领域,如可视电话、实时视频会议、视频监控、流媒体、多媒体视频和Internet视频及多媒体等;H.262标准等同于 MPEG-2的视频编码标准,而H.264/AVC标准则被纳入 MPEG-4的第10部分。 如今广泛使用的 H.264 视频压缩标准(如.mp4文件)可以基于H5进行视频播放,目前还有一种更高的压缩率以及更高质量的编码标准H.265/HEVC标准。H.265的压缩有了显著提高,一样质量的编码视频能节省40%至50%的码流,还提高了并行机制。
3 OpenCV 视频入门
首先用Visual Studio 工具新建一个C++项目,并进行相关配置,具体可以参考上一篇博文《OpenCV 4 C++环境快速搭建》,这里不再赘述。下面给出一个视频操作的核心代码,具体如下所示:
#include <opencv2/core.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>
#include <stdio.h>
using namespace cv;
using namespace std;
int main(int, char**)
{
//Matrix 对象,存储图像的数值,处理图像而引入的一个封装类
Mat src;
//默认摄像头
VideoCapture cap(0);
// 检查摄像头是否打开
if (!cap.isOpened()) {
cerr << "Unable to open camera\n";
return -1;
}
//获取帧的宽和高,以及每秒帧数
cout << "Frame width: " << cap.get(CAP_PROP_FRAME_WIDTH) << endl;
cout << "Frame height: " << cap.get(CAP_PROP_FRAME_HEIGHT) << endl;
cout << "FPS: " << cap.get(CAP_PROP_FPS) << endl; // 0
//读取
cap >> src;
// 检测读取视频情况
if (src.empty()) {
cerr << "blank frame grabbed\n";
return -1;
}
//是否是彩色的
bool isColor = (src.type() == CV_8UC3);
//VideoWriter可以将图像生成视频
VideoWriter writer;
double fps = 24.0;
if (cap.get(CAP_PROP_FPS) > 0) {
fps = cap.get(CAP_PROP_FPS);
}
// !!! fourcc 编码和 视频扩展名,需要匹配,而且不同平台是不同的
///////////////////////////////////////////////////////////////
int codec = VideoWriter::fourcc('X', 'V', 'I', 'D');
string filename = "./live_xvid.mp4";
///////////////////////////////////////////////////////////////
writer.open(filename, codec, fps, src.size(), isColor);
//检查是否可以正常打开文件
if (!writer.isOpened()) {
cerr << "Could not open the output video file for write\n";
return -1;
}
cout << "###################### " << endl;
for (;;)
{
//检查是否读取正常
if (!cap.read(src)) {
cerr << " blank frame grabbed\n";
break;
}
//将帧图像写入视频文件
writer.write(src);
//显示标题为Live的窗口来显示视频
imshow("Live", src);
//监听键盘任意键,退出
if (waitKey(5) >= 0)
break;
}
return 0;
}
首先,需要用 include 引入相关的头文件,然后用 using namespace cv 引入 opencv命令空间,int main(int, char**) 是函数入口,Mat src中的Mat是一个Matrix 对象,存储图像的数值,处理图像而引入的一个封装类。VideoCapture cap(0) 从默认摄像头进行捕获,cap.isOpened()可以判断是否可以正常捕获视频,cap.get(CAP_PROP_FRAME_WIDTH)和cap.get(CAP_PROP_FRAME_HEIGHT)可以获取获取帧的宽和高。
cap >> src 则读取视频数据到Mat src中,VideoWriter可以将图像生成视频,这是opencv图像操作的核心类,int codec = VideoWriter::fourcc('X', 'V', 'I', 'D');则给出了视频的编码方案Xvid,它是一个开放源代码的MPEG-4视频编解码器,它是基于OpenDivX而编写的,同时它是世界上最常用的视频编码解码器(codec),它的总体表现非常的好。还有一种DivX视频编码,支持MPEG-4, H.264和H.265标准的视频,分辨率可高达4K超高清。
注意:XviD编码的的视频文件扩展名可以是AVI、MKV、MP4等。需要说明的是,仅从扩展名并不能看出这个视频的编码格式。
那么,opencv能否支持H.264呢,比较将设置如下所示:
int codec = VideoWriter::fourcc('H', '2', '6', '4');
string filename = "./live_h264.mp4";
在Windows平台上运行此代码,则抛出如下信息:
Failed to load OpenH264 library : openh264 - 1.8.0 - win64.dll
Please check environment and /or download library : https://github.com/cisco/openh264/releases
其中让我们使用OpenH264,从 https://github.com/cisco/openh264/releases 上下载 openh264-1.8.0-win64.dll ,放于 文件源码目录中即可加载。再次运行,则抛出如下信息:
PluginBackend::initWriterAPI Video I / O: plugin is ready to use 'FFmpeg OpenCV Video I/O Writer plugin'
OpenCV : FFMPEG : tag 0x34363248 / 'H264' is not supported with codec id 27 and format 'mp4 / MP4 (MPEG-4 Part 14)'
OpenCV : FFMPEG : fallback to use tag 0x31637661 / 'avc1'
OpenH264 Video Codec provided by Cisco Systems, Inc.
Writing videofile : . / live.mp4
Press any key to terminate
其中正确加载了 openh264-1.8.0-win64.dll ,显示OpenH264 Video Codec 相关字样。但是提示了 'H264' is not supported with codec id 27 and format 'mp4 / MP4 (MPEG-4 Part 14)' 。说明H264和mp4文件不兼容,系统回退到OpenH264提供的 AVC1编码,因此修改编码如下即可:
int codec = VideoWriter::fourcc('a', 'v', 'c', '1'); //avc1 //openh264
string filename = "./live.mp4";
我尝试了另外一种编码,也成功了,代码如下:
int codec = VideoWriter::fourcc('X', '2', '6', '4');
string filename = "./live_x264.mkv";
如何查看视频的编码信息呢,可以按照 ffmpeg 工具,其中一个组件为 ffprobe ,下面给出命令:
C:\ffmpeg\bin>ffprobe.exe live_x264.mkv
输出如下信息:
Metadata:
ENCODER : Lavf58.76.100
Duration: 00:00:46.04, start: 0.000000, bitrate: 3681 kb/s
Stream #0:0: Video: h264 (Constrained Baseline), yuv420p(progressive), 640x480, 24 fps, 24 tbr, 1k tbn, 2k tbc (default)
Metadata:
DURATION : 00:00:46.042000000
其中的 h264 (Constrained Baseline), yuv420p(progressive), 640x480, 24 fps 则表示h264编码,视频宽高为640x480,帧数为24 。下面给出AVC1编码生成的视频信息:
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'live.mp4':
Metadata:
major_brand : isom
minor_version : 512
compatible_brands: isomiso2avc1mp41
encoder : Lavf58.76.100
Duration: 00:01:13.75, start: 0.000000, bitrate: 1847 kb/s
Stream #0:0(und): Video: h264 (Constrained Baseline) (avc1 / 0x31637661), yuv420p, 640x480, 1847 kb/s, 12 fps, 12 tbr, 12288 tbn, 24576 tbc (default)
Metadata:
handler_name : VideoHandler
vendor_id : [0][0][0][0]
其中显示的是 h264 (Constrained Baseline) (avc1 / 0x31637661) 。下面给出另外的编码及输出信息:
int codec = VideoWriter::fourcc('M', 'J', 'P', 'G');
string filename = "./live_mjpg.avi";
#######################################
Input #0, avi, from 'live_mjpg.avi':
Metadata:
software : Lavf58.76.100
Duration: 00:00:11.08, start: 0.000000, bitrate: 7185 kb/s
Stream #0:0: Video: mjpeg (Baseline) (MJPG / 0x47504A4D), yuvj420p(pc, bt470bg/unknown/unknown), 640x480, 7203 kb/s, 24 fps, 24 tbr, 24 tbn, 24 tbc
说明此时是mjpeg (Baseline) (MJPG / 0x47504A4D) 编码。下面给出本文示例中的编码及输出信息:
int codec = VideoWriter::fourcc('X', 'V', 'I', 'D');
string filename = "./live_xvid.mp4";
#############################
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'live_xvid.mp4':
Metadata:
major_brand : isom
minor_version : 512
compatible_brands: isomiso2mp41
encoder : Lavf58.76.100
Duration: 00:00:05.38, start: 0.000000, bitrate: 5824 kb/s
Stream #0:0(und): Video: mpeg4 (Simple Profile) (mp4v / 0x7634706D), yuv420p, 640x480 [SAR 1:1 DAR 4:3], 5822 kb/s, 24 fps, 24 tbr, 12288 tbn, 24 tbc (default)
Metadata:
handler_name : VideoHandler
vendor_id : [0][0][0][0]
由此可见,XVID编码使用的是 mpeg4 (Simple Profile) (mp4v / 0x7634706D) 。
- 点赞
- 收藏
- 关注作者
评论(0)